From c0dab333eff8c65bf2d2cd5ed14294a7f218a949 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 26 Feb 2021 15:26:00 -0700 Subject: [PATCH 01/18] Per #1684, move an instance of the ClimoCDFInfo class into PairBase. Also define derive_climo_vals() and derive_climo_prob() utility functions. --- met/src/libcode/vx_statistics/pair_base.cc | 80 +++++++++++++++++----- met/src/libcode/vx_statistics/pair_base.h | 48 ++++++++----- 2 files changed, 92 insertions(+), 36 deletions(-) diff --git a/met/src/libcode/vx_statistics/pair_base.cc b/met/src/libcode/vx_statistics/pair_base.cc index bfcebaad0c..73ee637f86 100644 --- a/met/src/libcode/vx_statistics/pair_base.cc +++ b/met/src/libcode/vx_statistics/pair_base.cc @@ -74,6 +74,8 @@ void PairBase::clear() { interp_mthd = InterpMthd_None; interp_shape = GridTemplateFactory::GridTemplate_None; + cdf_info.clear(); + o_na.clear(); x_na.clear(); y_na.clear(); @@ -121,6 +123,8 @@ void PairBase::erase() { interp_mthd = InterpMthd_None; interp_shape = GridTemplateFactory::GridTemplate_None; + cdf_info.clear(); + o_na.erase(); x_na.erase(); y_na.erase(); @@ -267,6 +271,15 @@ void PairBase::set_interp_shape(GridTemplateFactory::GridTemplates shape) { //////////////////////////////////////////////////////////////////////// +void PairBase::set_climo_cdf_info(const ClimoCDFInfo &info) { + + cdf_info = info; + + return; +} + +//////////////////////////////////////////////////////////////////////// + void PairBase::set_fcst_ut(unixtime ut){ fcst_ut = ut; @@ -1016,11 +1029,32 @@ bool set_climo_flag(const NumArray &f_na, const NumArray &c_na) { //////////////////////////////////////////////////////////////////////// -NumArray derive_climo_prob(const NumArray &mn_na, const NumArray &sd_na, +void derive_climo_vals(const ClimoCDFInfo &cdf_info, + double m, double s, + NumArray &climo_vals) { + + // Initialize + climo_vals.erase(); + + // Check for bad data + if(is_bad_data(m) || is_bad_data(s)) return; + + // Skip the first (>=0.0) and last (>=1.0) climo CDF thresholds + for(int i=1; i " + mlog << Error << "\nderive_climo_prob() -> " << "climatological threshold \"" << othresh.get_str() << "\" cannot be converted to a probability!\n\n"; exit(1); @@ -1067,22 +1101,15 @@ NumArray derive_climo_prob(const NumArray &mn_na, const NumArray &sd_na, else if(n_mn > 0 && n_sd > 0) { mlog << Debug(2) - << "Deriving normal approximation of climatological " - << "probabilities for threshold " << othresh.get_str() - << ".\n"; + << "Deriving climatological probabilities for threshold " + << othresh.get_str() << " by sampling " << cdf_info.cdf_ta.n() + << " values from the normal climatological distribution.\n"; - // Compute probability value for each point + // Compute the probability by sampling from the climo distribution + // and deriving the event frequency for(i=0; i Date: Fri, 26 Feb 2021 15:27:08 -0700 Subject: [PATCH 02/18] Add to VxPairDataPoint and VxPairDataEnsemble functions to set the ClimoCDFInfo class. --- .../vx_statistics/pair_data_ensemble.cc | 35 ++----------------- .../vx_statistics/pair_data_ensemble.h | 8 +---- .../libcode/vx_statistics/pair_data_point.cc | 15 ++++++++ .../libcode/vx_statistics/pair_data_point.h | 2 ++ 4 files changed, 21 insertions(+), 39 deletions(-) diff --git a/met/src/libcode/vx_statistics/pair_data_ensemble.cc b/met/src/libcode/vx_statistics/pair_data_ensemble.cc index 8a8c3b410a..5d6bc00820 100644 --- a/met/src/libcode/vx_statistics/pair_data_ensemble.cc +++ b/met/src/libcode/vx_statistics/pair_data_ensemble.cc @@ -92,8 +92,6 @@ void PairDataEnsemble::clear() { obs_error_entry.clear(); obs_error_flag = false; - cdf_info.clear(); - for(i=0; i=0.0) and last (>=1.0) climo CDF thresholds - for(int i=1; i Date: Fri, 26 Feb 2021 15:29:11 -0700 Subject: [PATCH 03/18] Per #1684, update ensemble_stat and point_stat to set the ClimoCDFInfo object based on the contents of the config file. --- met/src/tools/core/ensemble_stat/ensemble_stat.cc | 2 +- met/src/tools/core/ensemble_stat/ensemble_stat_conf_info.cc | 4 ++-- met/src/tools/core/point_stat/point_stat.cc | 2 +- met/src/tools/core/point_stat/point_stat_conf_info.cc | 3 +++ 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/met/src/tools/core/ensemble_stat/ensemble_stat.cc b/met/src/tools/core/ensemble_stat/ensemble_stat.cc index 31ab7b8b56..f3affe5895 100644 --- a/met/src/tools/core/ensemble_stat/ensemble_stat.cc +++ b/met/src/tools/core/ensemble_stat/ensemble_stat.cc @@ -1735,7 +1735,7 @@ void process_grid_vx() { // Initialize pd_all.clear(); pd_all.set_ens_size(n_vx_vld[i]); - pd_all.set_climo_cdf(conf_info.vx_opt[i].cdf_info); + pd_all.set_climo_cdf_info(conf_info.vx_opt[i].cdf_info); pd_all.skip_const = conf_info.vx_opt[i].vx_pd.pd[0][0][0].skip_const; // Apply the current mask to the fields and compute the pairs diff --git a/met/src/tools/core/ensemble_stat/ensemble_stat_conf_info.cc b/met/src/tools/core/ensemble_stat/ensemble_stat_conf_info.cc index 0461bc1b7f..e4361e041a 100644 --- a/met/src/tools/core/ensemble_stat/ensemble_stat_conf_info.cc +++ b/met/src/tools/core/ensemble_stat/ensemble_stat_conf_info.cc @@ -877,8 +877,8 @@ void EnsembleStatVxOpt::set_vx_pd(EnsembleStatConfInfo *conf_info) { // Define the dimensions vx_pd.set_pd_size(n_msg_typ, n_mask, n_interp); - // Store climo CDF - vx_pd.set_climo_cdf(cdf_info); + // Store the climo CDF info + vx_pd.set_climo_cdf_info(cdf_info); // Store the list of surface message types vx_pd.set_msg_typ_sfc(conf_info->msg_typ_sfc); diff --git a/met/src/tools/core/point_stat/point_stat.cc b/met/src/tools/core/point_stat/point_stat.cc index f61583f3ee..d1edfdb935 100644 --- a/met/src/tools/core/point_stat/point_stat.cc +++ b/met/src/tools/core/point_stat/point_stat.cc @@ -1762,7 +1762,7 @@ void do_hira_ens(int i_vx, const PairDataPoint *pd_ptr) { hira_pd.clear(); hira_pd.extend(pd_ptr->n_obs); hira_pd.set_ens_size(gt->size()); - hira_pd.set_climo_cdf(conf_info.vx_opt[i_vx].cdf_info); + hira_pd.set_climo_cdf_info(conf_info.vx_opt[i_vx].cdf_info); f_ens.extend(gt->size()); // Process each observation point diff --git a/met/src/tools/core/point_stat/point_stat_conf_info.cc b/met/src/tools/core/point_stat/point_stat_conf_info.cc index 0d8dd3fa43..ecd6b8b3dc 100644 --- a/met/src/tools/core/point_stat/point_stat_conf_info.cc +++ b/met/src/tools/core/point_stat/point_stat_conf_info.cc @@ -932,6 +932,9 @@ void PointStatVxOpt::set_vx_pd(PointStatConfInfo *conf_info) { // Define the dimensions vx_pd.set_pd_size(n_msg_typ, n_mask, n_interp); + // Store the climo CDF info + vx_pd.set_climo_cdf_info(cdf_info); + // Store the surface message type group cs = surface_msg_typ_group_str; if(conf_info->msg_typ_group_map.count(cs) == 0) { From 4d655d80a88a34b92351c069310a0c2a39ef5e23 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 26 Feb 2021 15:34:15 -0700 Subject: [PATCH 04/18] Per #1684, update the vx_statistics library and stat_analysis to make calls to the new derive_climo_vals() and derive_climo_prob() functions. --- .../libcode/vx_statistics/compute_stats.cc | 3 +- met/src/libcode/vx_statistics/ens_stats.cc | 3 +- .../core/stat_analysis/aggr_stat_line.cc | 40 ++++++++++++------- .../tools/core/stat_analysis/aggr_stat_line.h | 1 + 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/met/src/libcode/vx_statistics/compute_stats.cc b/met/src/libcode/vx_statistics/compute_stats.cc index 7e6e74f66f..211fe9860e 100644 --- a/met/src/libcode/vx_statistics/compute_stats.cc +++ b/met/src/libcode/vx_statistics/compute_stats.cc @@ -743,7 +743,8 @@ void compute_pctinfo(const PairDataPoint &pd, bool pstd_flag, // Use input climatological probabilities or derive them if(cmn_flag) { if(cprob_in) climo_prob = *cprob_in; - else climo_prob = derive_climo_prob(pd.cmn_na, pd.csd_na, + else climo_prob = derive_climo_prob(pd.cdf_info, + pd.cmn_na, pd.csd_na, pct_info.othresh); } diff --git a/met/src/libcode/vx_statistics/ens_stats.cc b/met/src/libcode/vx_statistics/ens_stats.cc index 4748b186ac..becf1976cd 100644 --- a/met/src/libcode/vx_statistics/ens_stats.cc +++ b/met/src/libcode/vx_statistics/ens_stats.cc @@ -522,7 +522,8 @@ void RPSInfo::set(const PairDataEnsemble &pd) { climo_pct.zero_out(); // Derive climatological probabilities - if(cmn_flag) climo_prob = derive_climo_prob(pd.cmn_na, pd.csd_na, + if(cmn_flag) climo_prob = derive_climo_prob(pd.cdf_info, + pd.cmn_na, pd.csd_na, fthresh[i]); // Loop over the observations diff --git a/met/src/tools/core/stat_analysis/aggr_stat_line.cc b/met/src/tools/core/stat_analysis/aggr_stat_line.cc index 3bd72ae766..e8550bc38f 100644 --- a/met/src/tools/core/stat_analysis/aggr_stat_line.cc +++ b/met/src/tools/core/stat_analysis/aggr_stat_line.cc @@ -575,7 +575,22 @@ ConcatString StatHdrInfo::get_shc_str(const ConcatString &cur_case, //////////////////////////////////////////////////////////////////////// // -// Code for AggrTimeSeriesInfo structure. +// Code for AggrENSInfo structure +// +//////////////////////////////////////////////////////////////////////// + +void AggrENSInfo::clear() { + hdr.clear(); + ens_pd.clear(); + me_na.clear(); + mse_na.clear(); + me_oerr_na.clear(); + mse_oerr_na.clear(); +} + +//////////////////////////////////////////////////////////////////////// +// +// Code for AggrTimeSeriesInfo structure // //////////////////////////////////////////////////////////////////////// @@ -2552,8 +2567,7 @@ void aggr_ecnt_lines(LineDataFile &f, STATAnalysisJob &job, // Add a new map entry, if necessary // if(m.count(key) == 0) { - aggr.ens_pd.clear(); - aggr.hdr.clear(); + aggr.clear(); m[key] = aggr; } @@ -2775,8 +2789,7 @@ void aggr_rhist_lines(LineDataFile &f, STATAnalysisJob &job, // Add a new map entry, if necessary // if(m.count(key) == 0) { - aggr.ens_pd.clear(); - aggr.hdr.clear(); + aggr.clear(); for(i=0; i::iterator it; @@ -3045,7 +3058,9 @@ void aggr_orank_lines(LineDataFile &f, STATAnalysisJob &job, // Add a new map entry, if necessary // if(m.count(key) == 0) { - aggr.ens_pd.clear(); + aggr.clear(); + bool center = false; + aggr.ens_pd.cdf_info.set_cdf_ta(nint(1.0/job.out_bin_size), center); aggr.ens_pd.obs_error_flag = !is_bad_data(cur.ens_mean_oerr); aggr.ens_pd.set_ens_size(cur.n_ens); for(i=0; i " - << "the \"N_ENS\" column must remain constant. " + << "the \"N_ENS\" column must remain constant. " << "Try setting \"-column_eq N_ENS n\".\n\n"; throw(1); } @@ -3099,12 +3111,12 @@ void aggr_orank_lines(LineDataFile &f, STATAnalysisJob &job, m[key].ens_pd.v_na.add(n_valid); // Derive ensemble from climo mean and standard deviation - cur_clm = derive_climo_cdf_inv(m[key].ens_pd.cdf_info, - cur.climo_mean, cur.climo_stdev); + derive_climo_vals(m[key].ens_pd.cdf_info, + cur.climo_mean, cur.climo_stdev, climo_vals); // Store empirical CRPS stats m[key].ens_pd.crps_emp_na.add(compute_crps_emp(cur.obs, cur.ens_na)); - m[key].ens_pd.crpscl_emp_na.add(compute_crps_emp(cur.obs, cur_clm)); + m[key].ens_pd.crpscl_emp_na.add(compute_crps_emp(cur.obs, climo_vals)); // Store Gaussian CRPS stats m[key].ens_pd.crps_gaus_na.add(compute_crps_gaus(cur.obs, cur.ens_mean, cur.spread)); diff --git a/met/src/tools/core/stat_analysis/aggr_stat_line.h b/met/src/tools/core/stat_analysis/aggr_stat_line.h index 2e6ab5b72e..e8ed7809f9 100644 --- a/met/src/tools/core/stat_analysis/aggr_stat_line.h +++ b/met/src/tools/core/stat_analysis/aggr_stat_line.h @@ -152,6 +152,7 @@ struct AggrENSInfo { StatHdrInfo hdr; PairDataEnsemble ens_pd; NumArray me_na, mse_na, me_oerr_na, mse_oerr_na; + void clear(); }; struct AggrRPSInfo { From 7d19d06760c2f8c98ffd688aa3712251a55d6eb3 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Mon, 1 Mar 2021 11:05:17 -0700 Subject: [PATCH 05/18] Per #1684, since cdf_info is a member of PairBase class, need to handle it in the PairDataPoint and PairDataEnsemble assignment and subsetting logic. --- met/src/libcode/vx_statistics/pair_base.cc | 7 ++++--- met/src/libcode/vx_statistics/pair_data_ensemble.cc | 3 +++ met/src/libcode/vx_statistics/pair_data_point.cc | 6 ++++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/met/src/libcode/vx_statistics/pair_base.cc b/met/src/libcode/vx_statistics/pair_base.cc index 73ee637f86..b9e16346f4 100644 --- a/met/src/libcode/vx_statistics/pair_base.cc +++ b/met/src/libcode/vx_statistics/pair_base.cc @@ -1043,7 +1043,7 @@ void derive_climo_vals(const ClimoCDFInfo &cdf_info, for(int i=1; i 0 && n_sd > 0) { - mlog << Debug(2) + // The first (>=0.0) and last (>=1.0) climo thresholds are omitted + mlog << Debug(4) << "Deriving climatological probabilities for threshold " - << othresh.get_str() << " by sampling " << cdf_info.cdf_ta.n() + << othresh.get_str() << " by sampling " << cdf_info.cdf_ta.n()-2 << " values from the normal climatological distribution.\n"; // Compute the probability by sampling from the climo distribution diff --git a/met/src/libcode/vx_statistics/pair_data_ensemble.cc b/met/src/libcode/vx_statistics/pair_data_ensemble.cc index 5d6bc00820..df97c8bf23 100644 --- a/met/src/libcode/vx_statistics/pair_data_ensemble.cc +++ b/met/src/libcode/vx_statistics/pair_data_ensemble.cc @@ -206,6 +206,8 @@ void PairDataEnsemble::assign(const PairDataEnsemble &pd) { o_na = pd.o_na; o_qc_sa = pd.o_qc_sa; + cdf_info = pd.cdf_info; + cmn_na = pd.cmn_na; csd_na = pd.csd_na; cdf_na = pd.cdf_na; @@ -751,6 +753,7 @@ PairDataEnsemble PairDataEnsemble::subset_pairs(const SingleThresh &ot) const { pd.ssvar_bin_size = ssvar_bin_size; pd.obs_error_entry = obs_error_entry; pd.obs_error_flag = obs_error_flag; + pd.cdf_info = cdf_info; bool cmn_flag = set_climo_flag(o_na, cmn_na); bool csd_flag = set_climo_flag(o_na, csd_na); diff --git a/met/src/libcode/vx_statistics/pair_data_point.cc b/met/src/libcode/vx_statistics/pair_data_point.cc index bb553f18f1..a8e1203eda 100644 --- a/met/src/libcode/vx_statistics/pair_data_point.cc +++ b/met/src/libcode/vx_statistics/pair_data_point.cc @@ -116,6 +116,8 @@ void PairDataPoint::assign(const PairDataPoint &pd) { // Allocate memory for output pairs extend(pd.n_obs); + cdf_info = pd.cdf_info; + set_mask_name(pd.mask_name.c_str()); set_mask_area_ptr(pd.mask_area_ptr); set_msg_typ(pd.msg_typ.c_str()); @@ -1313,6 +1315,7 @@ PairDataPoint subset_pairs(const PairDataPoint &pd, // Allocate memory for output pairs out_pd.extend(pd.n_obs); + out_pd.set_climo_cdf_info(pd.cdf_info); bool cmn_flag = set_climo_flag(pd.f_na, pd.cmn_na); bool csd_flag = set_climo_flag(pd.f_na, pd.csd_na); @@ -1380,6 +1383,8 @@ void subset_wind_pairs(const PairDataPoint &pd_u, const PairDataPoint &pd_v, out_pd_v.erase(); out_pd_u.extend(pd_u.n_obs); out_pd_v.extend(pd_v.n_obs); + out_pd_u.set_climo_cdf_info(pd_u.cdf_info); + out_pd_v.set_climo_cdf_info(pd_v.cdf_info); bool cmn_flag = set_climo_flag(pd_u.f_na, pd_u.cmn_na) && set_climo_flag(pd_v.f_na, pd_v.cmn_na); @@ -1467,6 +1472,7 @@ PairDataPoint subset_climo_cdf_bin(const PairDataPoint &pd, // Allocate memory for output pairs out_pd.extend(pd.n_obs); + out_pd.set_climo_cdf_info(pd.cdf_info); bool cmn_flag = set_climo_flag(pd.f_na, pd.cmn_na); bool csd_flag = set_climo_flag(pd.f_na, pd.csd_na); From 687b00aaecc992a48b78a9a464a89ced003316eb Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Mon, 1 Mar 2021 12:13:39 -0700 Subject: [PATCH 06/18] Per #1684, during development, I ran across and then updated this log message. --- met/src/libcode/vx_statistics/ens_stats.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/met/src/libcode/vx_statistics/ens_stats.cc b/met/src/libcode/vx_statistics/ens_stats.cc index becf1976cd..ebfe4b5e28 100644 --- a/met/src/libcode/vx_statistics/ens_stats.cc +++ b/met/src/libcode/vx_statistics/ens_stats.cc @@ -484,10 +484,10 @@ void RPSInfo::set(const PairDataEnsemble &pd) { // Check that thresholds are actually defined if(fthresh.n() == 0) { mlog << Error << "\nRPSInfo::set(const PairDataEnsemble &) -> " - << "no thresholds provided to compute the RPS line type! " - << "Specify thresholds using the \"" - << conf_key_prob_cat_thresh - << "\" configuration file option.\n\n"; + << "no thresholds provided to compute the RPS line type!\n" + << "Specify thresholds using the \"" << conf_key_prob_cat_thresh + << "\" configuration file option or by providing climatological " + << "mean and standard deviation data.\n\n"; exit(1); } From 9abfbcc3dbc6b3cfde48f729e1006ed8b03d1762 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Mon, 1 Mar 2021 12:14:14 -0700 Subject: [PATCH 07/18] Per #1684, working on log messages and figured that the regridding climo data should be moved from Debug(1) to at least Debug(2). --- met/src/libcode/vx_statistics/read_climo.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/met/src/libcode/vx_statistics/read_climo.cc b/met/src/libcode/vx_statistics/read_climo.cc index e292a381b3..27d79cbb42 100644 --- a/met/src/libcode/vx_statistics/read_climo.cc +++ b/met/src/libcode/vx_statistics/read_climo.cc @@ -245,7 +245,7 @@ void read_climo_file(const char *climo_file, GrdFileType ctype, // Regrid, if needed if(!(mtddf->grid() == vx_grid)) { - mlog << Debug(1) + mlog << Debug(2) << "Regridding the " << cur_ut_cs << " \"" << info->magic_str() << "\" climatology field to the verification grid.\n"; From a759c1779e1311d154bf658b022b20213d02c8ed Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Mon, 1 Mar 2021 12:15:39 -0700 Subject: [PATCH 08/18] Per #1684 and #1685, update the logic for the derive_climo_vals() utility function. If only a single climo bin is requested, just return the climo mean. Otherwise, sample the requested number of values. --- met/src/libcode/vx_statistics/pair_base.cc | 29 +++++++++++++++++----- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/met/src/libcode/vx_statistics/pair_base.cc b/met/src/libcode/vx_statistics/pair_base.cc index b9e16346f4..d558b2498f 100644 --- a/met/src/libcode/vx_statistics/pair_base.cc +++ b/met/src/libcode/vx_statistics/pair_base.cc @@ -1036,14 +1036,31 @@ void derive_climo_vals(const ClimoCDFInfo &cdf_info, // Initialize climo_vals.erase(); - // Check for bad data - if(is_bad_data(m) || is_bad_data(s)) return; + // cdf_info.cdf_ta starts with >=0.0 and ends with >=1.0. + // The number of bins is the number of thresholds minus 1. - // Skip the first (>=0.0) and last (>=1.0) climo CDF thresholds - for(int i=1; i Date: Mon, 1 Mar 2021 12:59:15 -0700 Subject: [PATCH 09/18] Per #1684, just fixing the format of this log message. --- met/src/tools/core/stat_analysis/stat_analysis.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/met/src/tools/core/stat_analysis/stat_analysis.cc b/met/src/tools/core/stat_analysis/stat_analysis.cc index 08be28c29c..c3d6788b71 100644 --- a/met/src/tools/core/stat_analysis/stat_analysis.cc +++ b/met/src/tools/core/stat_analysis/stat_analysis.cc @@ -635,8 +635,8 @@ void process_job(const char * jobstring, int n_job) { ConcatString full_jobstring; MetConfig go_conf; - mlog << Debug(4) << "process_job(jobstring):" - << jobstring << "\"\n"; + mlog << Debug(4) << "process_job(jobstring): " + << jobstring << "\n"; // // Initialize to the default job From 0737877172dcdd23c7b846605c55f270280f66b6 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Mon, 1 Mar 2021 12:59:51 -0700 Subject: [PATCH 10/18] Per #1684, add a STATLine::get_offset() member function. --- met/src/libcode/vx_analysis_util/stat_line.cc | 16 ++++++++++++++-- met/src/libcode/vx_analysis_util/stat_line.h | 9 +++++---- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/met/src/libcode/vx_analysis_util/stat_line.cc b/met/src/libcode/vx_analysis_util/stat_line.cc index b1d66871e0..9c2dadb7e8 100644 --- a/met/src/libcode/vx_analysis_util/stat_line.cc +++ b/met/src/libcode/vx_analysis_util/stat_line.cc @@ -327,6 +327,18 @@ bool STATLine::has(const char *col_str) const { +return ( !is_bad_data(get_offset(col_str)) ); + +} + + +//////////////////////////////////////////////////////////////////////// + + +int STATLine::get_offset(const char *col_str) const + +{ + int offset = bad_data_int; int dim = bad_data_int; @@ -353,10 +365,10 @@ if ( is_bad_data(offset) ) { } // - // Return whether a valid offset value was found + // Return the offset value // -return ( !is_bad_data(offset) ); +return ( offset ); } diff --git a/met/src/libcode/vx_analysis_util/stat_line.h b/met/src/libcode/vx_analysis_util/stat_line.h index ed52829950..6362031d58 100644 --- a/met/src/libcode/vx_analysis_util/stat_line.h +++ b/met/src/libcode/vx_analysis_util/stat_line.h @@ -61,10 +61,11 @@ class STATLine : public DataLine { // retrieve values of the header columns // - bool has (const char *) const; - ConcatString get (const char *, bool check_na = true) const; - const char * get_item (const char *, bool check_na = true) const; - const char * get_item (int, bool check_na = true) const; + bool has (const char *) const; + int get_offset(const char *) const; + ConcatString get (const char *, bool check_na = true) const; + const char * get_item (const char *, bool check_na = true) const; + const char * get_item (int, bool check_na = true) const; const char * version () const; const char * model () const; From dc6a8aff542fa851a6057a038ecbd74d2d1521e5 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Mon, 1 Mar 2021 13:01:44 -0700 Subject: [PATCH 11/18] Per #1684, update parse_orank_line() logic. Rather than calling NumArray::clear() call NumArray::erase() to preserve allocated memory. Also, instead of parsing ensemble member values by column name, parse them by offset number. --- met/src/tools/core/stat_analysis/parse_stat_line.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/met/src/tools/core/stat_analysis/parse_stat_line.cc b/met/src/tools/core/stat_analysis/parse_stat_line.cc index 2f79ae4c3a..14bf981ea6 100644 --- a/met/src/tools/core/stat_analysis/parse_stat_line.cc +++ b/met/src/tools/core/stat_analysis/parse_stat_line.cc @@ -461,8 +461,7 @@ void parse_relp_line(STATLine &l, RELPData &r_data) { //////////////////////////////////////////////////////////////////////// void parse_orank_line(STATLine &l, ORANKData &o_data) { - int i; - char col_str[max_str_len]; + int i, ens1; o_data.total = atoi(l.get_item("TOTAL")); o_data.index = atoi(l.get_item("INDEX")); @@ -480,10 +479,10 @@ void parse_orank_line(STATLine &l, ORANKData &o_data) { o_data.n_ens = atoi(l.get_item("N_ENS")); // Parse out ENS_i - o_data.ens_na.clear(); + o_data.ens_na.erase(); + ens1 = l.get_offset("ENS_1"); for(i=0; i Date: Mon, 1 Mar 2021 13:02:39 -0700 Subject: [PATCH 12/18] Per #1684, call EnsemblePairData::extend() when parsing ORANK data to allocate one block of memory instead of bunches of litte ones. --- met/src/tools/core/stat_analysis/aggr_stat_line.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/met/src/tools/core/stat_analysis/aggr_stat_line.cc b/met/src/tools/core/stat_analysis/aggr_stat_line.cc index e8550bc38f..f87c4875ed 100644 --- a/met/src/tools/core/stat_analysis/aggr_stat_line.cc +++ b/met/src/tools/core/stat_analysis/aggr_stat_line.cc @@ -3063,6 +3063,7 @@ void aggr_orank_lines(LineDataFile &f, STATAnalysisJob &job, aggr.ens_pd.cdf_info.set_cdf_ta(nint(1.0/job.out_bin_size), center); aggr.ens_pd.obs_error_flag = !is_bad_data(cur.ens_mean_oerr); aggr.ens_pd.set_ens_size(cur.n_ens); + aggr.ens_pd.extend(cur.total); for(i=0; i Date: Mon, 1 Mar 2021 13:37:09 -0700 Subject: [PATCH 13/18] Per #1684 and #1685, add another call to Ensemble-Stat to test computing the CRPSCL_EMP from a single climo mean instead of using the full climo distribution. --- test/config/EnsembleStatConfig_one_cdf_bin | 237 +++++++++++++++++++++ test/xml/unit_climatology.xml | 29 +++ 2 files changed, 266 insertions(+) create mode 100644 test/config/EnsembleStatConfig_one_cdf_bin diff --git a/test/config/EnsembleStatConfig_one_cdf_bin b/test/config/EnsembleStatConfig_one_cdf_bin new file mode 100644 index 0000000000..5e838940a9 --- /dev/null +++ b/test/config/EnsembleStatConfig_one_cdf_bin @@ -0,0 +1,237 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Ensemble-Stat configuration file. +// +// For additional information, please see the MET User's Guide. +// +//////////////////////////////////////////////////////////////////////////////// + +// +// Output model name to be written +// +model = "WRF"; + +// +// Output description to be written +// May be set separately in each "obs.field" entry +// +desc = "NA"; + +// +// Output observation type to be written +// +obtype = "ANALYS"; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Verification grid +// +regrid = { + to_grid = NONE; + method = NEAREST; + width = 1; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Ensemble product fields to be processed +// +ens = { + ens_thresh = 0.75; + vld_thresh = 1.0; + + field = [ + { name = "TMP"; level = "Z2"; }, + { name = "TMP"; level = "P850"; } + ]; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Neighborhood ensemble probabilities +// +nbrhd_prob = { + width = [ 5 ]; + shape = CIRCLE; + vld_thresh = 0.0; +} + +// +// NMEP smoothing methods +// +nmep_smooth = { + vld_thresh = 0.0; + shape = CIRCLE; + gaussian_dx = 81.27; + gaussian_radius = 120; + type = [ + { + method = GAUSSIAN; + width = 1; + } + ]; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Forecast and observation fields to be verified +// +fcst = { + field = [ + { name = "TMP"; level = "Z2"; message_type = [ "ADPSFC" ]; }, + { name = "TMP"; level = "P850"; message_type = [ "ADPUPA" ]; } + ]; +} +obs = fcst; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Climatology data +// +climo_mean = fcst; +climo_mean = { + + file_name = [ ${CLIMO_MEAN_FILE_LIST} ]; + regrid = { + method = BILIN; + width = 2; + vld_thresh = 0.5; + } + + time_interp_method = DW_MEAN; + day_interval = 1; + hour_interval = 6; +} + +// +// May be set separately in each "obs.field" entry +// +climo_cdf = { + cdf_bins = 1; + center_bins = FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Point observation filtering options +// May be set separately in each "obs.field" entry +// +obs_thresh = [ NA ]; +obs_quality = []; +duplicate_flag = NONE; +obs_summary = NONE; +obs_perc_value = 50; +skip_const = FALSE; + +// +// Observation error options +// Set dist_type to NONE to use the observation error table instead +// May be set separately in each "obs.field" entry +// +obs_error = { + flag = FALSE; + dist_type = NONE; + dist_parm = []; + inst_bias_scale = 1.0; + inst_bias_offset = 0.0; + min = NA; + max = NA; +} + +// +// Ensemble bin sizes +// May be set separately in each "obs.field" entry +// +ens_ssvar_bin_size = 1.0; +ens_phist_bin_size = 0.05; + +// +// Categorical thresholds to define ensemble probabilities +// May be set separately in each "fcst.field" entry +// +prob_cat_thresh = []; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Point observation time window +// +obs_window = { + beg = -5400; + end = 5400; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Verification masking regions +// +mask = { + grid = [ "FULL" ]; + poly = []; + sid = []; + llpnt = []; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Interpolation methods +// +interp = { + field = BOTH; + vld_thresh = 1.0; + + type = [ + { + method = NEAREST; + width = 1; + } + ]; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Statistical output types +// +output_flag = { + ecnt = BOTH; + rps = NONE; + rhist = NONE; + phist = NONE; + orank = NONE; + ssvar = NONE; + relp = NONE; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Ensemble product output types +// +ensemble_flag = false; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Random number generator +// +rng = { + type = "mt19937"; + seed = "1"; +} + +//////////////////////////////////////////////////////////////////////////////// + +grid_weight_flag = NONE; +output_prefix = "${OUTPUT_PREFIX}"; +version = "V10.0.0"; + +//////////////////////////////////////////////////////////////////////////////// diff --git a/test/xml/unit_climatology.xml b/test/xml/unit_climatology.xml index 03eb303d41..c3a946072e 100644 --- a/test/xml/unit_climatology.xml +++ b/test/xml/unit_climatology.xml @@ -328,4 +328,33 @@ + + + + echo "&DATA_DIR_MODEL;/grib1/arw-fer-gep1/arw-fer-gep1_2012040912_F024.grib \ + &DATA_DIR_MODEL;/grib1/arw-fer-gep5/arw-fer-gep5_2012040912_F024.grib \ + &DATA_DIR_MODEL;/grib1/arw-sch-gep2/arw-sch-gep2_2012040912_F024.grib \ + &DATA_DIR_MODEL;/grib1/arw-sch-gep6/arw-sch-gep6_2012040912_F024.grib \ + &DATA_DIR_MODEL;/grib1/arw-tom-gep3/arw-tom-gep3_2012040912_F024.grib \ + &DATA_DIR_MODEL;/grib1/arw-tom-gep7/arw-tom-gep7_2012040912_F024.grib" \ + > &OUTPUT_DIR;/climatology/ensemble_stat_input_file_list; \ + &MET_BIN;/ensemble_stat + + OUTPUT_PREFIX ONE_CDF_BIN + CLIMO_MEAN_FILE_LIST "&DATA_DIR_CLIMO;/NCEP_NCAR_40YR_1.0deg/cmean_1d.19590410" + + \ + &OUTPUT_DIR;/climatology/ensemble_stat_input_file_list \ + &CONFIG_DIR;/EnsembleStatConfig_one_cdf_bin \ + -point_obs &OUTPUT_DIR;/pb2nc/ndas.20120410.t12z.prepbufr.tm00.nc \ + -grid_obs &DATA_DIR_OBS;/laps/laps_2012041012_F000.grib \ + -outdir &OUTPUT_DIR;/climatology + + + &OUTPUT_DIR;/climatology/ensemble_stat_ONE_CDF_BIN_20120410_120000V.stat + &OUTPUT_DIR;/climatology/ensemble_stat_ONE_CDF_BIN_20120410_120000V_ecnt.txt + &OUTPUT_DIR;/climatology/ensemble_stat_ONE_CDF_BIN_20120410_120000V_ens.nc + + + From 716f7773247646f8140d326af6e21f6ed8a53885 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Mon, 1 Mar 2021 13:54:29 -0700 Subject: [PATCH 14/18] Per #1684 and #1685, update ensemble-stat docs about computing CRPSS_EMP relative to a single reference model. --- met/docs/Users_Guide/ensemble-stat.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/met/docs/Users_Guide/ensemble-stat.rst b/met/docs/Users_Guide/ensemble-stat.rst index 9a4b8f476e..cfe920c0e6 100644 --- a/met/docs/Users_Guide/ensemble-stat.rst +++ b/met/docs/Users_Guide/ensemble-stat.rst @@ -36,7 +36,11 @@ The ranked probability score (RPS) is included in the Ranked Probability Score ( Climatology data ~~~~~~~~~~~~~~~~ -The Ensemble-Stat output includes at least three statistics computed relative to external climatology data. The climatology is defined by mean and standard deviation fields, and both are required in the computation of ensemble skill score statistics. MET assumes that the climatology follows a normal distribution, defined by the mean and standard deviation at each point. When computing the CRPS skill score for (:ref:`Gneiting et al., 2004 `) the reference CRPS statistic is computed using the climatological mean and standard deviation directly. When computing the CRPS skill score for (:ref:`Hersbach, 2000 `) the reference CRPS statistic is computed by selecting equal-area-spaced values from the assumed normal climatological distribution. The number of points selected is determined by the *cdf_bins* setting in the *climo_cdf* dictionary. The reference CRPS is computed empirically from this ensemble of climatology values. The climatological distribution is also used for the RPSS. The forecast RPS statistic is computed from a probabilistic contingency table in which the probabilities are derived from the ensemble member values. In a simliar fashion, the climatogical probability for each observed value is derived from the climatological distribution. The area of the distribution to the left of the observed value is interpreted as the climatological probability. These climatological probabilities are also evaluated using a probabilistic contingency table from which the reference RPS score is computed. The skill scores are derived by comparing the forecast statistic to the reference climatology statistic. +The Ensemble-Stat output includes at least three statistics computed relative to external climatology data. The climatology is defined by mean and standard deviation fields, and typically both are required in the computation of ensemble skill score statistics. MET assumes that the climatology follows a normal distribution, defined by the mean and standard deviation at each point. + +When computing the CRPS skill score for (:ref:`Gneiting et al., 2004 `) the reference CRPS statistic is computed using the climatological mean and standard deviation directly. When computing the CRPS skill score for (:ref:`Hersbach, 2000 `) the reference CRPS statistic is computed by selecting equal-area-spaced values from the assumed normal climatological distribution. The number of points selected is determined by the *cdf_bins* setting in the *climo_cdf* dictionary. The reference CRPS is computed empirically from this ensemble of climatology values. If the number bins is set to 1, the climatological CRPS is computed using only the climatological mean value. In this way, the empirical CRPSS may be computed relative to a single model rather than a climatological distribution. + +The climatological distribution is also used for the RPSS. The forecast RPS statistic is computed from a probabilistic contingency table in which the probabilities are derived from the ensemble member values. In a simliar fashion, the climatogical probability for each observed value is derived from the climatological distribution. The area of the distribution to the left of the observed value is interpreted as the climatological probability. These climatological probabilities are also evaluated using a probabilistic contingency table from which the reference RPS score is computed. The skill scores are derived by comparing the forecast statistic to the reference climatology statistic. Ensemble observation error ~~~~~~~~~~~~~~~~~~~~~~~~~~ From d2497aec84097b780a6a27acd9e6702ce3fef63d Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Mon, 1 Mar 2021 14:47:12 -0700 Subject: [PATCH 15/18] Per #1684, need to update Grid-Stat to store the climo cdf info in the PairDataPoint objects. --- met/src/tools/core/grid_stat/grid_stat.cc | 77 ++++++++++++++--------- 1 file changed, 49 insertions(+), 28 deletions(-) diff --git a/met/src/tools/core/grid_stat/grid_stat.cc b/met/src/tools/core/grid_stat/grid_stat.cc index 5a90a6464f..2301ff2c29 100644 --- a/met/src/tools/core/grid_stat/grid_stat.cc +++ b/met/src/tools/core/grid_stat/grid_stat.cc @@ -145,7 +145,8 @@ static void build_outfile_name(unixtime, int, const char *, static void process_scores(); -static void get_mask_points(const MaskPlane &, const DataPlane *, +static void get_mask_points(const GridStatVxOpt &, + const MaskPlane &, const DataPlane *, const DataPlane *, const DataPlane *, const DataPlane *, const DataPlane *, PairDataPoint &); @@ -797,7 +798,8 @@ void process_scores() { } // Apply the current mask to the current fields - get_mask_points(mask_mp, &fcst_dp_smooth, &obs_dp_smooth, + get_mask_points(conf_info.vx_opt[i], mask_mp, + &fcst_dp_smooth, &obs_dp_smooth, &cmn_dp, &csd_dp, &wgt_dp, pd); // Set the mask name @@ -981,7 +983,8 @@ void process_scores() { } // Apply the current mask to the U-wind fields - get_mask_points(mask_mp, &fu_dp_smooth, &ou_dp_smooth, + get_mask_points(conf_info.vx_opt[i], mask_mp, + &fu_dp_smooth, &ou_dp_smooth, &cmnu_dp, &csdu_dp, &wgt_dp, pd_u); // Compute VL1L2 @@ -1136,9 +1139,11 @@ void process_scores() { mask_bad_data(mask_mp, ogy_dp); // Apply the current mask to the current fields - get_mask_points(mask_mp, &fgx_dp, &ogx_dp, + get_mask_points(conf_info.vx_opt[i], mask_mp, + &fgx_dp, &ogx_dp, 0, 0, &wgt_dp, pd_gx); - get_mask_points(mask_mp, &fgy_dp, &ogy_dp, + get_mask_points(conf_info.vx_opt[i], mask_mp, + &fgy_dp, &ogy_dp, 0, 0, &wgt_dp, pd_gy); // Set the mask name @@ -1217,7 +1222,8 @@ void process_scores() { conf_info.vx_opt[i].ocat_ta.need_perc()) { // Apply the current mask - get_mask_points(mask_mp, &fcst_dp, &obs_dp, + get_mask_points(conf_info.vx_opt[i], mask_mp, + &fcst_dp, &obs_dp, &cmn_dp, 0, 0, pd); // Process percentile thresholds @@ -1271,9 +1277,11 @@ void process_scores() { // Apply the current mask to the distance map and // thresholded fields - get_mask_points(mask_mp, &fcst_dp_dmap, &obs_dp_dmap, + get_mask_points(conf_info.vx_opt[i], mask_mp, + &fcst_dp_dmap, &obs_dp_dmap, 0, 0, 0, pd); - get_mask_points(mask_mp, &fcst_dp_thresh, &obs_dp_thresh, + get_mask_points(conf_info.vx_opt[i], mask_mp, + &fcst_dp_thresh, &obs_dp_thresh, 0, 0, 0, pd_thr); dmap_info.set_options( @@ -1346,7 +1354,8 @@ void process_scores() { conf_info.vx_opt[i].ocat_ta.need_perc()) { // Apply the current mask - get_mask_points(mask_mp, &fcst_dp, &obs_dp, + get_mask_points(conf_info.vx_opt[i], mask_mp, + &fcst_dp, &obs_dp, &cmn_dp, 0, 0, pd); // Process percentile thresholds @@ -1445,9 +1454,11 @@ void process_scores() { // Apply the current mask to the fractional coverage // and thresholded fields - get_mask_points(mask_mp, &fcst_dp_smooth, &obs_dp_smooth, + get_mask_points(conf_info.vx_opt[i], mask_mp, + &fcst_dp_smooth, &obs_dp_smooth, 0, 0, &wgt_dp, pd); - get_mask_points(mask_mp, &fcst_dp_thresh, &obs_dp_thresh, + get_mask_points(conf_info.vx_opt[i], mask_mp, + &fcst_dp_thresh, &obs_dp_thresh, 0, 0, 0, pd_thr); // Store climatology values as bad data @@ -1618,7 +1629,8 @@ void process_scores() { } // Apply the current mask to the current fields - get_mask_points(mask_mp, &fcst_dp_smooth, &obs_dp_smooth, + get_mask_points(conf_info.vx_opt[i], mask_mp, + &fcst_dp_smooth, &obs_dp_smooth, &cmn_dp_smooth, &csd_dp, &wgt_dp, pd); // Set the mask name @@ -1706,7 +1718,8 @@ void process_scores() { } // Apply the current mask to the U-wind fields - get_mask_points(mask_mp, &fu_dp_smooth, &ou_dp_smooth, + get_mask_points(conf_info.vx_opt[i], mask_mp, + &fu_dp_smooth, &ou_dp_smooth, &cmnu_dp_smooth, 0, &wgt_dp, pd_u); // Compute VL1L2 @@ -1790,29 +1803,33 @@ void process_scores() { //////////////////////////////////////////////////////////////////////// -void get_mask_points(const MaskPlane &mask_mp, +void get_mask_points(const GridStatVxOpt &vx_opt, + const MaskPlane &mask_mp, const DataPlane *fcst_ptr, const DataPlane *obs_ptr, const DataPlane *cmn_ptr, const DataPlane *csd_ptr, const DataPlane *wgt_ptr, PairDataPoint &pd) { - // Initialize - pd.erase(); + // Initialize + pd.erase(); - // Apply the mask the data fields or fill with default values - apply_mask(*fcst_ptr, mask_mp, pd.f_na); - apply_mask(*obs_ptr, mask_mp, pd.o_na); - pd.n_obs = pd.o_na.n(); + // Store the climo CDF info + pd.set_climo_cdf_info(vx_opt.cdf_info); + + // Apply the mask the data fields or fill with default values + apply_mask(*fcst_ptr, mask_mp, pd.f_na); + apply_mask(*obs_ptr, mask_mp, pd.o_na); + pd.n_obs = pd.o_na.n(); - if(cmn_ptr) apply_mask(*cmn_ptr, mask_mp, pd.cmn_na); - else pd.cmn_na.add_const(bad_data_double, pd.n_obs); - if(csd_ptr) apply_mask(*csd_ptr, mask_mp, pd.csd_na); - else pd.csd_na.add_const(bad_data_double, pd.n_obs); - if(wgt_ptr) apply_mask(*wgt_ptr, mask_mp, pd.wgt_na); - else pd.wgt_na.add_const(default_grid_weight, pd.n_obs); + if(cmn_ptr) apply_mask(*cmn_ptr, mask_mp, pd.cmn_na); + else pd.cmn_na.add_const(bad_data_double, pd.n_obs); + if(csd_ptr) apply_mask(*csd_ptr, mask_mp, pd.csd_na); + else pd.csd_na.add_const(bad_data_double, pd.n_obs); + if(wgt_ptr) apply_mask(*wgt_ptr, mask_mp, pd.wgt_na); + else pd.wgt_na.add_const(default_grid_weight, pd.n_obs); - if(cmn_ptr && csd_ptr) pd.add_climo_cdf(); + if(cmn_ptr && csd_ptr) pd.add_climo_cdf(); - return; + return; } //////////////////////////////////////////////////////////////////////// @@ -2172,6 +2189,10 @@ void do_pct(const GridStatVxOpt &vx_opt, const PairDataPoint *pd_ptr) { vx_opt.cdf_info.cdf_ta, j); else pd = *pd_ptr; + mlog << Warning << "JHG: grid_stat pd.cdf_info.cdf_ta:\n"; + pd.cdf_info.cdf_ta.dump(cout); + pd_ptr->cdf_info.cdf_ta.dump(cout); + // Store thresholds pct_info[j].fthresh = vx_opt.fcat_ta; pct_info[j].othresh = vx_opt.ocat_ta[i]; From 719017904c188c50617874e6f26be04134b6313a Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Mon, 1 Mar 2021 14:49:08 -0700 Subject: [PATCH 16/18] Per #1684, remove debug print statements. --- met/src/tools/core/grid_stat/grid_stat.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/met/src/tools/core/grid_stat/grid_stat.cc b/met/src/tools/core/grid_stat/grid_stat.cc index 2301ff2c29..14b09c6d5a 100644 --- a/met/src/tools/core/grid_stat/grid_stat.cc +++ b/met/src/tools/core/grid_stat/grid_stat.cc @@ -2189,10 +2189,6 @@ void do_pct(const GridStatVxOpt &vx_opt, const PairDataPoint *pd_ptr) { vx_opt.cdf_info.cdf_ta, j); else pd = *pd_ptr; - mlog << Warning << "JHG: grid_stat pd.cdf_info.cdf_ta:\n"; - pd.cdf_info.cdf_ta.dump(cout); - pd_ptr->cdf_info.cdf_ta.dump(cout); - // Store thresholds pct_info[j].fthresh = vx_opt.fcat_ta; pct_info[j].othresh = vx_opt.ocat_ta[i]; From 82b5898ee9480bd6ea907745199da1039ea429c8 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Mon, 1 Mar 2021 15:17:22 -0700 Subject: [PATCH 17/18] Per #1684, need to set cdf_info when aggregating MPR lines in Stat-Analysis. --- met/src/tools/core/stat_analysis/aggr_stat_line.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/met/src/tools/core/stat_analysis/aggr_stat_line.cc b/met/src/tools/core/stat_analysis/aggr_stat_line.cc index f87c4875ed..db7cd98ba9 100644 --- a/met/src/tools/core/stat_analysis/aggr_stat_line.cc +++ b/met/src/tools/core/stat_analysis/aggr_stat_line.cc @@ -2205,6 +2205,9 @@ void aggr_mpr_lines(LineDataFile &f, STATAnalysisJob &job, // if(m.count(key) == 0) { + bool center = false; + aggr.pd.cdf_info.set_cdf_ta(nint(1.0/job.out_bin_size), center); + aggr.pd.f_na.clear(); aggr.pd.o_na.clear(); aggr.pd.cmn_na.clear(); @@ -2223,6 +2226,7 @@ void aggr_mpr_lines(LineDataFile &f, STATAnalysisJob &job, aggr.fcst_var = cur.fcst_var; aggr.obs_var = cur.obs_var; aggr.hdr.clear(); + m[key] = aggr; } // From 9a792c553e2005750a2b00586c198e80be2bc3bd Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Mon, 1 Mar 2021 17:11:42 -0700 Subject: [PATCH 18/18] Per #1684 and #1685, update PairDataEnsemble::compute_pair_vals() to print a log message indicating the climo data being used as reference: For a climo distribution defined by mean and stdev: DEBUG 3: Computing ensemble statistics relative to a 9-member climatological ensemble. For a single deterministic reference: DEBUG 3: Computing ensemble statistics relative to the climatological mean. --- .../vx_statistics/pair_data_ensemble.cc | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/met/src/libcode/vx_statistics/pair_data_ensemble.cc b/met/src/libcode/vx_statistics/pair_data_ensemble.cc index df97c8bf23..bc27df220c 100644 --- a/met/src/libcode/vx_statistics/pair_data_ensemble.cc +++ b/met/src/libcode/vx_statistics/pair_data_ensemble.cc @@ -334,6 +334,26 @@ void PairDataEnsemble::compute_pair_vals(const gsl_rng *rng_ptr) { // Check if the ranks have already been computed if(r_na.n() == o_na.n()) return; + // Print the climo data being used + bool cmn_flag = set_climo_flag(o_na, cmn_na); + bool csd_flag = set_climo_flag(o_na, csd_na); + + if(cmn_flag && cdf_info.cdf_ta.n() == 2) { + mlog << Debug(3) + << "Computing ensemble statistics relative to the " + << "climatological mean.\n"; + } + else if(cmn_flag && csd_flag && cdf_info.cdf_ta.n() > 2) { + mlog << Debug(3) + << "Computing ensemble statistics relative to a " + << cdf_info.cdf_ta.n() - 2 + << "-member climatological ensemble.\n"; + } + else { + mlog << Debug(3) + << "No reference climatology data provided.\n"; + } + // Compute the rank for each observation for(i=0, n_pair=0, n_skip_const=0, n_skip_vld=0; i