From 285eeb2e67db20ea0843cb9f1779e5921b1eefa2 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 3 Sep 2024 14:53:44 -0600 Subject: [PATCH 01/22] Per #2924, remove GenEnsProd config file comment about parsing desc separately from each obs.field entry because the obs dictionary does not exist in the GenEnsProd config file. --- data/config/GenEnsProdConfig_default | 1 - internal/test_unit/config/GenEnsProdConfig | 1 - .../test_unit/config/GenEnsProdConfig_climo_anom_ens_member_id | 1 - internal/test_unit/config/GenEnsProdConfig_normalize | 1 - internal/test_unit/config/GenEnsProdConfig_single_file_grib | 1 - internal/test_unit/config/GenEnsProdConfig_single_file_nc | 1 - scripts/config/GenEnsProdConfig | 1 - 7 files changed, 7 deletions(-) diff --git a/data/config/GenEnsProdConfig_default b/data/config/GenEnsProdConfig_default index c650ec8b24..16a36f9833 100644 --- a/data/config/GenEnsProdConfig_default +++ b/data/config/GenEnsProdConfig_default @@ -13,7 +13,6 @@ model = "FCST"; // // Output description to be written -// May be set separately in each "obs.field" entry // desc = "NA"; diff --git a/internal/test_unit/config/GenEnsProdConfig b/internal/test_unit/config/GenEnsProdConfig index 813272dc14..9841006614 100644 --- a/internal/test_unit/config/GenEnsProdConfig +++ b/internal/test_unit/config/GenEnsProdConfig @@ -13,7 +13,6 @@ model = "FCST"; // // Output description to be written -// May be set separately in each "obs.field" entry // desc = "NA"; diff --git a/internal/test_unit/config/GenEnsProdConfig_climo_anom_ens_member_id b/internal/test_unit/config/GenEnsProdConfig_climo_anom_ens_member_id index adebdb2528..440b528326 100644 --- a/internal/test_unit/config/GenEnsProdConfig_climo_anom_ens_member_id +++ b/internal/test_unit/config/GenEnsProdConfig_climo_anom_ens_member_id @@ -13,7 +13,6 @@ model = "CFSv2"; // // Output description to be written -// May be set separately in each "obs.field" entry // desc = "NA"; diff --git a/internal/test_unit/config/GenEnsProdConfig_normalize b/internal/test_unit/config/GenEnsProdConfig_normalize index b23708ab46..192c75cb5b 100644 --- a/internal/test_unit/config/GenEnsProdConfig_normalize +++ b/internal/test_unit/config/GenEnsProdConfig_normalize @@ -13,7 +13,6 @@ model = "FCST"; // // Output description to be written -// May be set separately in each "obs.field" entry // desc = "NA"; diff --git a/internal/test_unit/config/GenEnsProdConfig_single_file_grib b/internal/test_unit/config/GenEnsProdConfig_single_file_grib index b1f2bb3315..82f31da619 100644 --- a/internal/test_unit/config/GenEnsProdConfig_single_file_grib +++ b/internal/test_unit/config/GenEnsProdConfig_single_file_grib @@ -13,7 +13,6 @@ model = "GEFS"; // // Output description to be written -// May be set separately in each "obs.field" entry // desc = "NA"; diff --git a/internal/test_unit/config/GenEnsProdConfig_single_file_nc b/internal/test_unit/config/GenEnsProdConfig_single_file_nc index 2b4be6e12b..9d84b2bcbc 100644 --- a/internal/test_unit/config/GenEnsProdConfig_single_file_nc +++ b/internal/test_unit/config/GenEnsProdConfig_single_file_nc @@ -13,7 +13,6 @@ model = "CFSv2"; // // Output description to be written -// May be set separately in each "obs.field" entry // desc = "NA"; diff --git a/scripts/config/GenEnsProdConfig b/scripts/config/GenEnsProdConfig index 74350a328d..65d13aadbd 100644 --- a/scripts/config/GenEnsProdConfig +++ b/scripts/config/GenEnsProdConfig @@ -13,7 +13,6 @@ model = "FCST"; // // Output description to be written -// May be set separately in each "obs.field" entry // desc = "NA"; From e9ce34f6a6a0588b9dd2e1cd70f4d4f9f909402e Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 5 Sep 2024 09:23:30 -0600 Subject: [PATCH 02/22] Per #2924, update list of needed config entry names --- src/basic/vx_config/config_constants.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/basic/vx_config/config_constants.h b/src/basic/vx_config/config_constants.h index e1a18aeb1a..4900bb79b8 100644 --- a/src/basic/vx_config/config_constants.h +++ b/src/basic/vx_config/config_constants.h @@ -725,12 +725,10 @@ static const char conf_key_is_prob[] = "is_prob"; // // Climatology data parameter key names // -static const char conf_key_climo_mean_field[] = "climo_mean.field"; -static const char conf_key_fcst_climo_mean_field[] = "fcst.climo_mean.field"; -static const char conf_key_obs_climo_mean_field[] = "obs.climo_mean.field"; -static const char conf_key_climo_stdev_field[] = "climo_stdev.field"; -static const char conf_key_fcst_climo_stdev_field[] = "fcst.climo_stdev.field"; -static const char conf_key_obs_climo_stdev_field[] = "obs.climo_stdev.field"; +static const char conf_key_climo_mean[] = "climo_mean"; +static const char conf_key_climo_mean_field[] = "climo_mean.field"; +static const char conf_key_climo_stdev[] = "climo_stdev"; +static const char conf_key_climo_stdev_field[] = "climo_stdev.field"; // // Climatology distribution parameter key names From c1c4f9bf8aa75bd9be7061f31faffb78e2c42f8b Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 5 Sep 2024 09:24:28 -0600 Subject: [PATCH 03/22] Per #2924, remove const from the parent() member function so that we can perform lookups for the parent. --- src/basic/vx_config/dictionary.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/basic/vx_config/dictionary.h b/src/basic/vx_config/dictionary.h index 97faa4e3dc..bcb4a7f34b 100644 --- a/src/basic/vx_config/dictionary.h +++ b/src/basic/vx_config/dictionary.h @@ -243,7 +243,7 @@ class Dictionary { virtual const DictionaryEntry * operator[](int) const; - virtual const Dictionary * parent() const; + virtual Dictionary * parent() const; virtual bool is_array() const; @@ -346,7 +346,7 @@ class Dictionary { inline int Dictionary::n_entries() const { return Nentries; } -inline const Dictionary * Dictionary::parent() const { return Parent; } +inline Dictionary * Dictionary::parent() const { return Parent; } inline void Dictionary::set_is_array(bool __tf) { IsArray = __tf; return; } From d0ac39aafb143750e1d2ba83468839de48f6756f Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 5 Sep 2024 09:26:45 -0600 Subject: [PATCH 04/22] Per #2924, update the signature for and logic of the utility functions that retrieve the climatology data. Rather than requiring all the climo_mean and climo_stdev dictionary entries to be defined at the same config file context level, parse each one individually. This enables the METplus wrappers to only partially override this dictionary and still rely on the default values provided in MET's default configuration files. --- src/libcode/vx_statistics/read_climo.cc | 119 ++++++++++++++++-------- src/libcode/vx_statistics/read_climo.h | 16 ++-- 2 files changed, 91 insertions(+), 44 deletions(-) diff --git a/src/libcode/vx_statistics/read_climo.cc b/src/libcode/vx_statistics/read_climo.cc index f5a0f2db71..072588aff1 100644 --- a/src/libcode/vx_statistics/read_climo.cc +++ b/src/libcode/vx_statistics/read_climo.cc @@ -39,8 +39,11 @@ static DataPlane climo_hms_interp( //////////////////////////////////////////////////////////////////////// -DataPlane read_climo_data_plane(Dictionary *dict, int i_vx, - unixtime vld_ut, const Grid &vx_grid, +DataPlane read_climo_data_plane(Dictionary *dict, + const char *entry_name, + int i_vx, + unixtime vld_ut, + const Grid &vx_grid, const char *desc) { DataPlane dp; DataPlaneArray dpa; @@ -49,7 +52,8 @@ DataPlane read_climo_data_plane(Dictionary *dict, int i_vx, if(!dict) return dp; // Read array of climatology fields - dpa = read_climo_data_plane_array(dict, i_vx, vld_ut, vx_grid, desc); + dpa = read_climo_data_plane_array(dict, entry_name, i_vx, + vld_ut, vx_grid, desc); // Check for multiple matches if(dpa.n_planes() > 1) { @@ -66,82 +70,123 @@ DataPlane read_climo_data_plane(Dictionary *dict, int i_vx, //////////////////////////////////////////////////////////////////////// -DataPlaneArray read_climo_data_plane_array(Dictionary *dict, int i_vx, +DataPlaneArray read_climo_data_plane_array(Dictionary *dict, + const char *climo_name, + int i_vx, unixtime vld_ut, const Grid &vx_grid, const char *desc) { + + const char *method_name = "read_climo_data_plane_array() -> "; + + // + // Parse each of the climatology configuration entries separately + // using the "climo_name.entry_name" scope notation. Use the value + // from the specified dictionary (e.g. "fcst.climo_mean") if found, + // or use the value from the parent dictionary (e.g. top-level config + // "climo_mean") if not found. + // DataPlaneArray dpa; - StringArray climo_files; - RegridInfo regrid_info; - InterpMthd time_interp; - GrdFileType ctype; - double day_interval, hour_interval; - int i, day_ts, hour_ts; + ConcatString cs; // Check for null if(!dict) return dpa; - // Get the i-th array entry - Dictionary i_dict = parse_conf_i_vx_dict(dict, i_vx); - - // Climatology mean and standard deviation files - climo_files = i_dict.lookup_string_array(conf_key_file_name, false); + // Parse the "file_name" array entry + cs << cs_erase << climo_name << "." << conf_key_file_name; + StringArray climo_files(dict->lookup_string_array(cs.c_str())); - // Check for at least one file + // Check for at least one input file if(climo_files.n() == 0) return dpa; - // Regrid info - regrid_info = parse_conf_regrid(&i_dict); + // Parse the "field" array entry + cs << cs_erase << climo_name << "." << conf_key_field; + Dictionary *field_dict = dict->lookup_array(cs.c_str(), false); + + // Get the i-th array entry + Dictionary i_dict = parse_conf_i_vx_dict(field_dict, i_vx); + + // Parse the "regrid" dictionary + RegridInfo regrid_info; + cs << cs_erase << climo_name << "." << conf_key_regrid; + + if(dict->lookup(cs.c_str(), false)) { + Dictionary *climo_dict = dict->lookup_dictionary(climo_name); + regrid_info = parse_conf_regrid(climo_dict); + } + else { + Dictionary *climo_dict = dict->parent()->lookup_dictionary(climo_name); + regrid_info = parse_conf_regrid(climo_dict); + } - // Time interpolation - time_interp = int_to_interpmthd(i_dict.lookup_int(conf_key_time_interp_method)); + // Parse the "time_interp_method" + cs << cs_erase << climo_name << "." << conf_key_time_interp_method; + InterpMthd time_interp = int_to_interpmthd(dict->lookup_int(cs.c_str())); - // Day interval - day_interval = i_dict.lookup_double(conf_key_day_interval); + // Parse the "day_interval" value + cs << cs_erase << climo_name << "." << conf_key_day_interval; + double day_interval = dict->lookup_double(cs.c_str()); - // Range check day_interval + // Range check day_interval value if(!is_bad_data(day_interval) && day_interval < 1) { - mlog << Error << "\nread_climo_data_plane_array() -> " + mlog << Error << "\n" << method_name << "The " << conf_key_day_interval << " entry (" << day_interval << ") can be set to " << na_str << " or a value of at least 1.\n\n"; exit(1); } - // Hour interval - hour_interval = i_dict.lookup_double(conf_key_hour_interval); + // Parse the "hour_interval" value + cs << cs_erase << climo_name << "." << conf_key_hour_interval; + double hour_interval = dict->lookup_double(cs.c_str()); // Range check hour_interval if(!is_bad_data(hour_interval) && (hour_interval <= 0 || hour_interval > 24)) { - mlog << Error << "\nread_climo_data_plane_array() -> " + mlog << Error << "\n" << method_name << "The " << conf_key_hour_interval << " entry (" << hour_interval << ") can be set to " << na_str << " or a value between 0 and 24.\n\n"; exit(1); } - // Check if file_type was specified - ctype = parse_conf_file_type(&i_dict); + // Log search criteria + if(mlog.verbosity_level() >= 5) { + mlog << Debug(5) + << "Searching " << climo_files.n() + << " file(s) for " << desc + << " data using climo_name = " << climo_name + << ", i_vx = " << i_vx + << ", valid time = " << unix_to_yyyymmdd_hhmmss(vld_ut) + << ", regrid_info = " << interpmthd_to_string(regrid_info.method) + << "(" << regrid_info.width << ")" + << ", time_interp = " << interpmthd_to_string(time_interp) + << ", day_interval = " << day_interval + << ", hour_interval = " << hour_interval + << "\n"; + } // Store the time steps in seconds - day_ts = (is_bad_data(day_interval) ? bad_data_int : - nint(day_interval * 24.0 * sec_per_hour)); - hour_ts = (is_bad_data(hour_interval) ? bad_data_int : - nint(hour_interval * sec_per_hour)); - + int day_ts = (is_bad_data(day_interval) ? bad_data_int : + nint(day_interval * 24.0 * sec_per_hour)); + int hour_ts = (is_bad_data(hour_interval) ? bad_data_int : + nint(hour_interval * sec_per_hour)); + + // Check if file_type was specified + GrdFileType ctype = parse_conf_file_type(&i_dict); + // Search the files for the requested records - for(i=0; i Date: Thu, 5 Sep 2024 09:27:59 -0600 Subject: [PATCH 05/22] Per #2924, update all calls to the climatology utility functions based on the new function signature. Also update the tools to check the number of climo fields separately for the forecast and observation climos. --- src/tools/core/ensemble_stat/ensemble_stat.cc | 24 ++++++++++----- .../ensemble_stat/ensemble_stat_conf_info.cc | 5 ++-- src/tools/core/grid_stat/grid_stat.cc | 30 ++++++++++++------- .../core/grid_stat/grid_stat_conf_info.cc | 3 +- src/tools/core/point_stat/point_stat.cc | 12 +++++--- .../core/point_stat/point_stat_conf_info.cc | 3 +- .../core/series_analysis/series_analysis.cc | 12 +++++--- .../series_analysis_conf_info.cc | 5 ++-- src/tools/other/gen_ens_prod/gen_ens_prod.cc | 10 ++++--- 9 files changed, 68 insertions(+), 36 deletions(-) diff --git a/src/tools/core/ensemble_stat/ensemble_stat.cc b/src/tools/core/ensemble_stat/ensemble_stat.cc index 826b8eaf7a..14a089430d 100644 --- a/src/tools/core/ensemble_stat/ensemble_stat.cc +++ b/src/tools/core/ensemble_stat/ensemble_stat.cc @@ -783,21 +783,25 @@ void process_point_vx() { // Read forecast climatology data fcmn_dpa = read_climo_data_plane_array( - conf_info.conf.lookup_array(conf_key_fcst_climo_mean_field, false), + conf_info.conf.lookup_dictionary(conf_key_fcst), + conf_key_climo_mean, i, ens_valid_ut, grid, "forecast climatology mean"); fcsd_dpa = read_climo_data_plane_array( - conf_info.conf.lookup_array(conf_key_fcst_climo_stdev_field, false), + conf_info.conf.lookup_dictionary(conf_key_fcst), + conf_key_climo_stdev, i, ens_valid_ut, grid, "forecast climatology standard deviation"); // Read observation climatology data ocmn_dpa = read_climo_data_plane_array( - conf_info.conf.lookup_array(conf_key_obs_climo_mean_field, false), + conf_info.conf.lookup_dictionary(conf_key_obs), + conf_key_climo_mean, i, ens_valid_ut, grid, "observation climatology mean"); ocsd_dpa = read_climo_data_plane_array( - conf_info.conf.lookup_array(conf_key_obs_climo_stdev_field, false), + conf_info.conf.lookup_dictionary(conf_key_obs), + conf_key_climo_stdev, i, ens_valid_ut, grid, "observation climatology standard deviation"); @@ -1427,21 +1431,25 @@ void process_grid_vx() { // Read forecast climatology data fcmn_dp = read_climo_data_plane( - conf_info.conf.lookup_array(conf_key_fcst_climo_mean_field, false), + conf_info.conf.lookup_dictionary(conf_key_fcst), + conf_key_climo_mean, i, ens_valid_ut, grid, "forecast climatology mean"); fcsd_dp = read_climo_data_plane( - conf_info.conf.lookup_array(conf_key_fcst_climo_stdev_field, false), + conf_info.conf.lookup_dictionary(conf_key_fcst), + conf_key_climo_stdev, i, ens_valid_ut, grid, "forecast climatology standard deviation"); // Read observation climatology data ocmn_dp = read_climo_data_plane( - conf_info.conf.lookup_array(conf_key_obs_climo_mean_field, false), + conf_info.conf.lookup_dictionary(conf_key_obs), + conf_key_climo_mean, i, ens_valid_ut, grid, "observation climatology mean"); ocsd_dp = read_climo_data_plane( - conf_info.conf.lookup_array(conf_key_obs_climo_stdev_field, false), + conf_info.conf.lookup_dictionary(conf_key_obs), + conf_key_climo_stdev, i, ens_valid_ut, grid, "observation climatology standard deviation"); diff --git a/src/tools/core/ensemble_stat/ensemble_stat_conf_info.cc b/src/tools/core/ensemble_stat/ensemble_stat_conf_info.cc index d248124cbd..de3af1256b 100644 --- a/src/tools/core/ensemble_stat/ensemble_stat_conf_info.cc +++ b/src/tools/core/ensemble_stat/ensemble_stat_conf_info.cc @@ -261,8 +261,9 @@ void EnsembleStatConfInfo::process_config(GrdFileType etype, n_vx = n_fvx; vx_opt = new EnsembleStatVxOpt [n_vx]; - // Check climatology fields - check_climo_n_vx(&conf, n_vx); + // Check for consistent number of climatology fields + check_climo_n_vx(fdict, n_vx); + check_climo_n_vx(odict, n_vx); // Parse settings for each verification task for(i=0,max_hira_size=0; iget_var_info(i_ens)->magic_str() << "\".\n"; cmn_dp = read_climo_data_plane( - conf_info.conf.lookup_array(conf_key_climo_mean_field, false), + conf_info.conf.lookup_dictionary(conf_key_ens), + conf_key_climo_mean, i_var, ens_valid_ut, grid, - "climatology mean"); + "ensemble climatology mean"); mlog << Debug(4) << "Reading climatology standard deviation data for ensemble field \"" << ens_info->get_var_info(i_ens)->magic_str() << "\".\n"; csd_dp = read_climo_data_plane( - conf_info.conf.lookup_array(conf_key_climo_stdev_field, false), + conf_info.conf.lookup_dictionary(conf_key_ens), + conf_key_climo_stdev, i_var, ens_valid_ut, grid, - "climatology standard deviation"); + "ensemble climatology standard deviation"); // Unset the MET_ENS_MEMBER_ID environment variable if(set_ens_mem_id) { From 0e21fa69ba8463498cc01b9a8184b691ffe9ffa2 Mon Sep 17 00:00:00 2001 From: MET Tools Test Account Date: Thu, 5 Sep 2024 19:38:41 +0000 Subject: [PATCH 06/22] Per #2924, update the parsing logic for the climatology regrid dictionary. Use config.fcst.climo_mean.regrid first, config.fcst.regrid second, and config.climo_mean.regrid third. Notably, DO NOT use config.regrid. This is definitely the problem with having regrid specified at mutliple config file context levels. It makes the logic for which to use when very messy. --- ...nfig_climo_FCST_NCEP_1.0DEG_OBS_WMO_1.5DEG | 14 +++++++++++++ src/libcode/vx_statistics/read_climo.cc | 21 ++++++++++++------- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/internal/test_unit/config/GridStatConfig_climo_FCST_NCEP_1.0DEG_OBS_WMO_1.5DEG b/internal/test_unit/config/GridStatConfig_climo_FCST_NCEP_1.0DEG_OBS_WMO_1.5DEG index ab1cdd8362..3eca135c6d 100644 --- a/internal/test_unit/config/GridStatConfig_climo_FCST_NCEP_1.0DEG_OBS_WMO_1.5DEG +++ b/internal/test_unit/config/GridStatConfig_climo_FCST_NCEP_1.0DEG_OBS_WMO_1.5DEG @@ -82,6 +82,13 @@ fcst = { file_name = [ "${FCST_CLIMO_DIR}/cstdv_1d.19590410" ]; }; + regrid = { + method = BILIN; + width = 2; + vld_thresh = 0.5; + shape = SQUARE; + } + time_interp_method = DW_MEAN; day_interval = 1; hour_interval = 6; @@ -108,6 +115,13 @@ obs = { "${OBS_CLIMO_DIR}/v850hPa_stdev.grib" ]; }; + regrid = { + method = BILIN; + width = 2; + vld_thresh = 0.5; + shape = SQUARE; + } + time_interp_method = DW_MEAN; day_interval = 1; hour_interval = 12; diff --git a/src/libcode/vx_statistics/read_climo.cc b/src/libcode/vx_statistics/read_climo.cc index 072588aff1..50882aac51 100644 --- a/src/libcode/vx_statistics/read_climo.cc +++ b/src/libcode/vx_statistics/read_climo.cc @@ -106,19 +106,26 @@ DataPlaneArray read_climo_data_plane_array(Dictionary *dict, // Get the i-th array entry Dictionary i_dict = parse_conf_i_vx_dict(field_dict, i_vx); - // Parse the "regrid" dictionary - RegridInfo regrid_info; + // Find the correct "regrid" config file context + Dictionary *regrid_parent_dict = nullptr; cs << cs_erase << climo_name << "." << conf_key_regrid; + // First choice e.g. "config.fcst.climo_mean.regrid" if(dict->lookup(cs.c_str(), false)) { - Dictionary *climo_dict = dict->lookup_dictionary(climo_name); - regrid_info = parse_conf_regrid(climo_dict); + regrid_parent_dict = dict->lookup_dictionary(climo_name); + } + // Second choice e.g. "config.fcst.regrid" + else if(dict->lookup(conf_key_regrid)) { + regrid_parent_dict = dict; } - else { - Dictionary *climo_dict = dict->parent()->lookup_dictionary(climo_name); - regrid_info = parse_conf_regrid(climo_dict); + // Third choice e.g. default "config.climo_mean.regrid" + else if(dict->parent()->lookup(cs.c_str(), false)) { + regrid_parent_dict = dict->parent()->lookup_dictionary(climo_name); } + // Parse the "regrid" dictionary + RegridInfo regrid_info = parse_conf_regrid(regrid_parent_dict); + // Parse the "time_interp_method" cs << cs_erase << climo_name << "." << conf_key_time_interp_method; InterpMthd time_interp = int_to_interpmthd(dict->lookup_int(cs.c_str())); From f256940426b2b060698320a5ddc227cb1b4336d8 Mon Sep 17 00:00:00 2001 From: MET Tools Test Account Date: Thu, 5 Sep 2024 19:43:18 +0000 Subject: [PATCH 07/22] Per #2924, forgot to add an else to print an error --- src/libcode/vx_statistics/read_climo.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libcode/vx_statistics/read_climo.cc b/src/libcode/vx_statistics/read_climo.cc index 50882aac51..f5ec38e33e 100644 --- a/src/libcode/vx_statistics/read_climo.cc +++ b/src/libcode/vx_statistics/read_climo.cc @@ -122,6 +122,11 @@ DataPlaneArray read_climo_data_plane_array(Dictionary *dict, else if(dict->parent()->lookup(cs.c_str(), false)) { regrid_parent_dict = dict->parent()->lookup_dictionary(climo_name); } + else { + mlog << Error << "\n" << method_name + << "Trouble parsing configuration entry: " << cs << "\n"; + exit(1); + } // Parse the "regrid" dictionary RegridInfo regrid_info = parse_conf_regrid(regrid_parent_dict); From 347c6443e3e40a696e14e85c58de1943d28af6ee Mon Sep 17 00:00:00 2001 From: MET Tools Test Account Date: Thu, 5 Sep 2024 19:49:00 +0000 Subject: [PATCH 08/22] Per #2924, remove extraneous semicolon --- src/tools/core/grid_stat/grid_stat_conf_info.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/core/grid_stat/grid_stat_conf_info.cc b/src/tools/core/grid_stat/grid_stat_conf_info.cc index f56ba15617..7c0f8ada2e 100644 --- a/src/tools/core/grid_stat/grid_stat_conf_info.cc +++ b/src/tools/core/grid_stat/grid_stat_conf_info.cc @@ -212,7 +212,7 @@ void GridStatConfInfo::process_config(GrdFileType ftype, // Check for consistent number of climatology fields check_climo_n_vx(fdict, n_vx); - check_climo_n_vx(odict, n_vx);; + check_climo_n_vx(odict, n_vx); // Parse settings for each verification task for(i=0; i Date: Thu, 5 Sep 2024 17:01:08 -0600 Subject: [PATCH 09/22] Per #2924, move 'fcst.regrid' into 'fcst.climo_mean.regrid'. Defining the climatology regridding logic inside fcst is problematic because it applies to the forecast data as well and you end up with the verification grid being undefined. So the climo regridding logic must be defined in 'climo_mean.regrid' either within the 'fcst' and 'obs' dictionaries or at the top-level config context. --- ...nfig_climo_FCST_NCEP_1.0DEG_OBS_WMO_1.5DEG | 46 +++++++++---------- src/libcode/vx_statistics/read_climo.cc | 25 ++++------ 2 files changed, 32 insertions(+), 39 deletions(-) diff --git a/internal/test_unit/config/GridStatConfig_climo_FCST_NCEP_1.0DEG_OBS_WMO_1.5DEG b/internal/test_unit/config/GridStatConfig_climo_FCST_NCEP_1.0DEG_OBS_WMO_1.5DEG index 3eca135c6d..8783cbd9e1 100644 --- a/internal/test_unit/config/GridStatConfig_climo_FCST_NCEP_1.0DEG_OBS_WMO_1.5DEG +++ b/internal/test_unit/config/GridStatConfig_climo_FCST_NCEP_1.0DEG_OBS_WMO_1.5DEG @@ -75,23 +75,24 @@ fcst = { climo_mean = { field = field_list; file_name = [ "${FCST_CLIMO_DIR}/cmean_1d.19590410" ]; + + regrid = { + method = BILIN; + width = 2; + vld_thresh = 0.5; + shape = SQUARE; + } + + time_interp_method = DW_MEAN; + day_interval = 1; + hour_interval = 6; }; + climo_stdev = climo_mean; climo_stdev = { - field = field_list; file_name = [ "${FCST_CLIMO_DIR}/cstdv_1d.19590410" ]; }; - regrid = { - method = BILIN; - width = 2; - vld_thresh = 0.5; - shape = SQUARE; - } - - time_interp_method = DW_MEAN; - day_interval = 1; - hour_interval = 6; } obs = { @@ -106,25 +107,24 @@ obs = { "${OBS_CLIMO_DIR}/u850hPa_mean.grib", "${OBS_CLIMO_DIR}/v500hPa_mean.grib", "${OBS_CLIMO_DIR}/v850hPa_mean.grib" ]; + regrid = { + method = BILIN; + width = 2; + vld_thresh = 0.5; + shape = SQUARE; + } + + time_interp_method = DW_MEAN; + day_interval = 1; + hour_interval = 12; }; + climo_stdev = climo_mean; climo_stdev = { - field = field_list; file_name = [ "${OBS_CLIMO_DIR}/t850hPa_stdev.grib", "${OBS_CLIMO_DIR}/u850hPa_stdev.grib", "${OBS_CLIMO_DIR}/v850hPa_stdev.grib" ]; }; - - regrid = { - method = BILIN; - width = 2; - vld_thresh = 0.5; - shape = SQUARE; - } - - time_interp_method = DW_MEAN; - day_interval = 1; - hour_interval = 12; } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_statistics/read_climo.cc b/src/libcode/vx_statistics/read_climo.cc index f5ec38e33e..6f22713164 100644 --- a/src/libcode/vx_statistics/read_climo.cc +++ b/src/libcode/vx_statistics/read_climo.cc @@ -106,30 +106,23 @@ DataPlaneArray read_climo_data_plane_array(Dictionary *dict, // Get the i-th array entry Dictionary i_dict = parse_conf_i_vx_dict(field_dict, i_vx); - // Find the correct "regrid" config file context - Dictionary *regrid_parent_dict = nullptr; + // Find the "climo_name.regrid" setting + Dictionary *climo_dict = nullptr; cs << cs_erase << climo_name << "." << conf_key_regrid; - // First choice e.g. "config.fcst.climo_mean.regrid" + // Try the current climo_name.regrid setting + // e.g. "config.fcst.climo_mean.regrid" if(dict->lookup(cs.c_str(), false)) { - regrid_parent_dict = dict->lookup_dictionary(climo_name); - } - // Second choice e.g. "config.fcst.regrid" - else if(dict->lookup(conf_key_regrid)) { - regrid_parent_dict = dict; - } - // Third choice e.g. default "config.climo_mean.regrid" - else if(dict->parent()->lookup(cs.c_str(), false)) { - regrid_parent_dict = dict->parent()->lookup_dictionary(climo_name); + climo_dict = dict->lookup_dictionary(climo_name); } + // Try the default climo_name.regrid setting + // e.g. "config.climo_mean.regrid" else { - mlog << Error << "\n" << method_name - << "Trouble parsing configuration entry: " << cs << "\n"; - exit(1); + climo_dict = dict->parent()->lookup_dictionary(climo_name); } // Parse the "regrid" dictionary - RegridInfo regrid_info = parse_conf_regrid(regrid_parent_dict); + RegridInfo regrid_info = parse_conf_regrid(climo_dict); // Parse the "time_interp_method" cs << cs_erase << climo_name << "." << conf_key_time_interp_method; From 7849d5dd3fdc56176ed2735966bc5d204ef2714c Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 12 Sep 2024 08:31:51 -0600 Subject: [PATCH 10/22] Per #2924, based on PR feedback from @georgemccabe, add the Upper_Left, Upper_Right, Lower_Right, and Lower_Left interpolation methods to the list of valid options for regridding, as already indicated in the MET User's Guide. --- src/libcode/vx_regrid/vx_regrid.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libcode/vx_regrid/vx_regrid.cc b/src/libcode/vx_regrid/vx_regrid.cc index 5fcc970601..3914c83004 100644 --- a/src/libcode/vx_regrid/vx_regrid.cc +++ b/src/libcode/vx_regrid/vx_regrid.cc @@ -40,6 +40,10 @@ switch ( info.method ) { case InterpMthd::LS_Fit: case InterpMthd::Bilin: case InterpMthd::Nearest: + case InterpMthd::Upper_Left: + case InterpMthd::Upper_Right: + case InterpMthd::Lower_Right: + case InterpMthd::Lower_Left: out = met_regrid_generic (in, from_grid, to_grid, info); break; From 1563d97bb87c78e863255ec9a1d0c4214cb18afc Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 12 Sep 2024 11:01:32 -0600 Subject: [PATCH 11/22] Per #2924, update the logic of parse_conf_regrid() to (hopefully) make it work the way @georgemccabe expects it to. It now uses pointers to both the primary and default dictionaries and parses each entry individually. --- src/basic/vx_config/config_util.cc | 175 ++++++++++++++++++------ src/basic/vx_config/config_util.h | 63 ++++++--- src/libcode/vx_data2d/var_info.cc | 2 +- src/libcode/vx_statistics/read_climo.cc | 23 +--- 4 files changed, 188 insertions(+), 75 deletions(-) diff --git a/src/basic/vx_config/config_util.cc b/src/basic/vx_config/config_util.cc index 344f997bea..0ec4a6e038 100644 --- a/src/basic/vx_config/config_util.cc +++ b/src/basic/vx_config/config_util.cc @@ -14,6 +14,7 @@ #include "config_util.h" #include "enum_as_int.hpp" +#include "configobjecttype_to_string.h" #include "vx_math.h" #include "vx_util.h" @@ -1334,10 +1335,10 @@ BootInfo parse_conf_boot(Dictionary *dict) { /////////////////////////////////////////////////////////////////////////////// -RegridInfo parse_conf_regrid(Dictionary *dict, bool error_out) { - Dictionary *regrid_dict = (Dictionary *) nullptr; +RegridInfo parse_conf_regrid(Dictionary *dict, Dictionary *default_dict, bool error_out) { + Dictionary *regrid_dict = nullptr; + Dictionary *regrid_default = nullptr; RegridInfo info; - int v; if(!dict) { mlog << Error << "\nparse_conf_regrid() -> " @@ -1348,8 +1349,13 @@ RegridInfo parse_conf_regrid(Dictionary *dict, bool error_out) { // Conf: regrid regrid_dict = dict->lookup_dictionary(conf_key_regrid, false); + // Dictionary with default settings + if(default_dict) { + regrid_default = default_dict->lookup_dictionary(conf_key_regrid, false); + } + // Check that the regrid dictionary is present - if(!regrid_dict) { + if(!regrid_dict && !regrid_default) { if(error_out) { mlog << Error << "\nparse_conf_regrid() -> " << "can't find the \"regrid\" dictionary!\n\n"; @@ -1360,61 +1366,148 @@ RegridInfo parse_conf_regrid(Dictionary *dict, bool error_out) { } } - // Parse to_grid as an integer - v = regrid_dict->lookup_int(conf_key_to_grid, false, false); + // Conf: to_grid (optional) as an integer or string + const DictionaryEntry * entry = regrid_dict->lookup(conf_key_to_grid, false); + if(!entry) entry = regrid_default->lookup(conf_key_to_grid, false); - // If integer lookup successful, convert to FieldType. - if(regrid_dict->last_lookup_status()) { - info.field = int_to_fieldtype(v); - info.enable = (info.field == FieldType::Fcst || - info.field == FieldType::Obs); + // to_grid found + if(entry) { + + // Convert integer to FieldType + if(entry->type() == IntegerType) { + info.field = int_to_fieldtype(entry->i_value()); + info.enable = (info.field == FieldType::Fcst || + info.field == FieldType::Obs); + } + // Store grid name string + else if(entry->type() == StringType) { + info.name = entry->string_value(); + info.enable = true; + } + else { + mlog << Error << "\nparse_conf_regrid() -> " + << "Unexpected type (" + << configobjecttype_to_string(entry->type()) + << ") for \"" << conf_key_to_grid + << "\" configuration entry.\n\n"; + exit(1); + } } - // If integer lookup unsuccessful, parse vx_grid as a string. - // Do not error out since to_grid isn't specified for climo.regrid. + // to_grid not found else { - info.name = regrid_dict->lookup_string(conf_key_to_grid, false); + info.name = ""; info.enable = true; } - // Conf: vld_thresh - double thr = regrid_dict->lookup_double(conf_key_vld_thresh, false); - info.vld_thresh = (is_bad_data(thr) ? default_vld_thresh : thr); + // Conf: vld_thresh (required) + double v_dbl = bad_data_double; + if(regrid_dict && regrid_dict->lookup(conf_key_vld_thresh, false)) { + v_dbl = regrid_dict->lookup_double(conf_key_vld_thresh); + } + else if(regrid_default && regrid_default->lookup(conf_key_vld_thresh, false)) { + v_dbl = regrid_default->lookup_double(conf_key_vld_thresh); + } + info.vld_thresh = (is_bad_data(v_dbl) ? default_vld_thresh : v_dbl); - // Parse the method and width - info.method = int_to_interpmthd(regrid_dict->lookup_int(conf_key_method)); - info.width = regrid_dict->lookup_int(conf_key_width); + // Conf: method (required) + int v_int = bad_data_int; + if(regrid_dict && regrid_dict->lookup(conf_key_method, false)) { + v_int = regrid_dict->lookup_int(conf_key_method); + } + else if(regrid_default && regrid_default->lookup(conf_key_method, false)) { + v_int = regrid_default->lookup_int(conf_key_method); + } + info.method = int_to_interpmthd(v_int); - // Conf: shape - v = regrid_dict->lookup_int(conf_key_shape, false); - if (regrid_dict->last_lookup_status()) { - info.shape = int_to_gridtemplate(v); + // Conf: width (required) + v_int = bad_data_int; + if(regrid_dict && regrid_dict->lookup(conf_key_width, false)) { + v_int = regrid_dict->lookup_int(conf_key_width); } - else { - // If not specified, use the default square shape - info.shape = GridTemplateFactory::GridTemplates::Square; + else if(regrid_default && regrid_default->lookup(conf_key_width, false)) { + v_int = regrid_default->lookup_int(conf_key_width); } + info.width = v_int; - // Conf: gaussian dx and radius - double conf_value = regrid_dict->lookup_double(conf_key_gaussian_dx, false); - info.gaussian.dx = (is_bad_data(conf_value) ? default_gaussian_dx : conf_value); - conf_value = regrid_dict->lookup_double(conf_key_gaussian_radius, false); - info.gaussian.radius = (is_bad_data(conf_value) ? default_gaussian_radius : conf_value); - conf_value = regrid_dict->lookup_double(conf_key_trunc_factor, false); - info.gaussian.trunc_factor = (is_bad_data(conf_value) ? default_trunc_factor : conf_value); - if (info.method == InterpMthd::Gaussian || info.method == InterpMthd::MaxGauss) info.gaussian.compute(); + // Conf: shape (optional) + v_int = bad_data_int; + if(regrid_dict && regrid_dict->lookup(conf_key_shape, false)) { + v_int = regrid_dict->lookup_int(conf_key_shape); + } + else if(regrid_default && regrid_default->lookup(conf_key_shape, false)) { + v_int = regrid_default->lookup_int(conf_key_shape); + } + // Default is square + info.shape = (is_bad_data(v_int) ? + GridTemplateFactory::GridTemplates::Square : + int_to_gridtemplate(v_int)); + + // Conf: gaussian_dx (optional) + v_dbl = bad_data_double; + if(regrid_dict && regrid_dict->lookup(conf_key_gaussian_dx, false)) { + v_dbl = regrid_dict->lookup_double(conf_key_gaussian_dx); + } + else if(regrid_default && regrid_default->lookup(conf_key_gaussian_dx, false)) { + v_dbl = regrid_default->lookup_double(conf_key_gaussian_dx); + } + info.gaussian.dx = (is_bad_data(v_dbl) ? default_gaussian_dx : v_dbl); + + // Conf: gaussian_radius (optional) + v_dbl = bad_data_double; + if(regrid_dict && regrid_dict->lookup(conf_key_gaussian_radius, false)) { + v_dbl = regrid_dict->lookup_double(conf_key_gaussian_radius); + } + else if(regrid_default && regrid_default->lookup(conf_key_gaussian_radius, false)) { + v_dbl = regrid_default->lookup_double(conf_key_gaussian_radius); + } + info.gaussian.radius = (is_bad_data(v_dbl) ? + default_gaussian_radius : + v_dbl); + + // Conf: gaussian_trunc_factor (optional) + v_dbl = bad_data_double; + if(regrid_dict && regrid_dict->lookup(conf_key_trunc_factor, false)) { + v_dbl = regrid_dict->lookup_double(conf_key_trunc_factor); + } + else if(regrid_default && regrid_default->lookup(conf_key_trunc_factor, false)) { + v_dbl = regrid_default->lookup_double(conf_key_trunc_factor); + } + info.gaussian.trunc_factor = (is_bad_data(v_dbl) ? + default_trunc_factor : + v_dbl); + + if(info.method == InterpMthd::Gaussian || + info.method == InterpMthd::MaxGauss) { + info.gaussian.compute(); + } // MET#2437 Do not search the higher levels of config file context for convert, // censor_thresh, and censor_val. They must be specified within the // regrid dictionary itself. - // Conf: convert - info.convert_fx.set(regrid_dict->lookup(conf_key_convert, false)); + // Conf: convert (optional) + if(regrid_dict && regrid_dict->lookup(conf_key_convert, false)) { + info.convert_fx.set(regrid_dict->lookup(conf_key_convert)); + } + else if(regrid_default && regrid_default->lookup(conf_key_convert, false)) { + info.convert_fx.set(regrid_default->lookup(conf_key_convert)); + } - // Conf: censor_thresh - info.censor_thresh = regrid_dict->lookup_thresh_array(conf_key_censor_thresh, false, true, false); + // Conf: censor_thresh (optional) + if(regrid_dict && regrid_dict->lookup(conf_key_censor_thresh, false)) { + info.censor_thresh = regrid_dict->lookup_thresh_array(conf_key_censor_thresh); + } + else if(regrid_default && regrid_default->lookup(conf_key_censor_thresh, false)) { + info.censor_thresh = regrid_default->lookup_thresh_array(conf_key_censor_thresh); + } - // Conf: censor_val - info.censor_val = regrid_dict->lookup_num_array(conf_key_censor_val, false, true, false); + // Conf: censor_val (optional) + if(regrid_dict && regrid_dict->lookup(conf_key_censor_val, false)) { + info.censor_val = regrid_dict->lookup_num_array(conf_key_censor_val); + } + else if(regrid_default && regrid_default->lookup(conf_key_censor_val, false)) { + info.censor_val = regrid_default->lookup_num_array(conf_key_censor_val); + } // Validate the settings info.validate(); diff --git a/src/basic/vx_config/config_util.h b/src/basic/vx_config/config_util.h index 3dae869b2b..97a446b493 100644 --- a/src/basic/vx_config/config_util.h +++ b/src/basic/vx_config/config_util.h @@ -31,18 +31,34 @@ static const char conf_key_old_prepbufr_map[] = "obs_prefbufr_map"; // for ba //////////////////////////////////////////////////////////////////////// extern ConcatString parse_conf_version(Dictionary *dict); -extern ConcatString parse_conf_string(Dictionary *dict, const char *, bool check_empty = true); +extern ConcatString parse_conf_string( + Dictionary *dict, + const char *, + bool check_empty=true); extern GrdFileType parse_conf_file_type(Dictionary *dict); extern std::map - parse_conf_output_flag(Dictionary *dict, const STATLineType *, int); + parse_conf_output_flag( + Dictionary *dict, + const STATLineType *, int); extern std::map parse_conf_output_stats(Dictionary *dict); extern int parse_conf_n_vx(Dictionary *dict); -extern Dictionary parse_conf_i_vx_dict(Dictionary *dict, int index); -extern StringArray parse_conf_tc_model(Dictionary *dict, bool error_out = default_dictionary_error_out); -extern StringArray parse_conf_message_type(Dictionary *dict, bool error_out = default_dictionary_error_out); -extern StringArray parse_conf_sid_list(Dictionary *dict, const char *); -extern void parse_sid_mask(const ConcatString &, StringArray &, ConcatString &); +extern Dictionary parse_conf_i_vx_dict( + Dictionary *dict, + int index); +extern StringArray parse_conf_tc_model( + Dictionary *dict, + bool error_out=default_dictionary_error_out); +extern StringArray parse_conf_message_type( + Dictionary *dict, + bool error_out=default_dictionary_error_out); +extern StringArray parse_conf_sid_list( + Dictionary *dict, + const char *); +extern void parse_sid_mask( + const ConcatString &, + StringArray &, + ConcatString &); extern std::vector parse_conf_llpnt_mask(Dictionary *dict); extern StringArray parse_conf_obs_qty_inc(Dictionary *dict); @@ -51,27 +67,40 @@ extern NumArray parse_conf_ci_alpha(Dictionary *dict); extern NumArray parse_conf_eclv_points(Dictionary *dict); extern ClimoCDFInfo parse_conf_climo_cdf(Dictionary *dict); extern TimeSummaryInfo parse_conf_time_summary(Dictionary *dict); -extern std::map parse_conf_key_value_map( - Dictionary *dict, const char *conf_key_map_name, const char *caller=nullptr); +extern std::map + parse_conf_key_value_map( + Dictionary *dict, + const char *conf_key_map_name, + const char *caller=nullptr); extern void parse_add_conf_key_value_map( - Dictionary *dict, const char *conf_key_map_name, std::map *m); + Dictionary *dict, + const char *conf_key_map_name, + std::map *m); extern void parse_add_conf_key_values_map( - Dictionary *dict, const char *conf_key_map_name, - std::map *m, const char *caller=nullptr); + Dictionary *dict, + const char *conf_key_map_name, + std::map *m, + const char *caller=nullptr); extern std::map parse_conf_message_type_map(Dictionary *dict); extern std::map parse_conf_message_type_group_map(Dictionary *dict); -extern std::map parse_conf_metadata_map(Dictionary *dict); +extern std::map + parse_conf_metadata_map(Dictionary *dict); extern std::map parse_conf_obs_name_map(Dictionary *dict); extern std::map parse_conf_obs_to_qc_map(Dictionary *dict); extern std::map parse_conf_key_convert_map( - Dictionary *dict, const char *conf_key_map_name, const char *caller=nullptr); + Dictionary *dict, + const char *conf_key_map_name, + const char *caller=nullptr); extern BootInfo parse_conf_boot(Dictionary *dict); -extern RegridInfo parse_conf_regrid(Dictionary *dict, bool error_out = default_dictionary_error_out); +extern RegridInfo parse_conf_regrid( + Dictionary *dict, + Dictionary *default_dict=nullptr, + bool error_out=default_dictionary_error_out); extern InterpInfo parse_conf_interp(Dictionary *dict, const char *); extern NbrhdInfo parse_conf_nbrhd(Dictionary *dict, const char *); extern HiRAInfo parse_conf_hira(Dictionary *dict); @@ -92,7 +121,9 @@ extern ConcatString parse_conf_ugrid_coordinates_file(Dictionary *dict); extern ConcatString parse_conf_ugrid_dataset(Dictionary *dict); extern ConcatString parse_conf_ugrid_map_config(Dictionary *dict); extern double parse_conf_ugrid_max_distance_km(Dictionary *dict); -extern void parse_add_conf_ugrid_metadata_map(Dictionary *dict, std::map *m); +extern void parse_add_conf_ugrid_metadata_map( + Dictionary *dict, + std::map *m); extern void check_mask_names(const StringArray &); diff --git a/src/libcode/vx_data2d/var_info.cc b/src/libcode/vx_data2d/var_info.cc index 2c92c6bf69..89514c222b 100644 --- a/src/libcode/vx_data2d/var_info.cc +++ b/src/libcode/vx_data2d/var_info.cc @@ -528,7 +528,7 @@ void VarInfo::set_dict(Dictionary &dict) { if(dict.last_lookup_status()) set_range(na); // Parse regrid, if present - Regrid = parse_conf_regrid(&dict, false); + Regrid = parse_conf_regrid(&dict, nullptr, false); // Parse set_attr strings SetAttrName = diff --git a/src/libcode/vx_statistics/read_climo.cc b/src/libcode/vx_statistics/read_climo.cc index 6f22713164..b4f9cd447e 100644 --- a/src/libcode/vx_statistics/read_climo.cc +++ b/src/libcode/vx_statistics/read_climo.cc @@ -106,23 +106,12 @@ DataPlaneArray read_climo_data_plane_array(Dictionary *dict, // Get the i-th array entry Dictionary i_dict = parse_conf_i_vx_dict(field_dict, i_vx); - // Find the "climo_name.regrid" setting - Dictionary *climo_dict = nullptr; - cs << cs_erase << climo_name << "." << conf_key_regrid; - - // Try the current climo_name.regrid setting - // e.g. "config.fcst.climo_mean.regrid" - if(dict->lookup(cs.c_str(), false)) { - climo_dict = dict->lookup_dictionary(climo_name); - } - // Try the default climo_name.regrid setting - // e.g. "config.climo_mean.regrid" - else { - climo_dict = dict->parent()->lookup_dictionary(climo_name); - } - - // Parse the "regrid" dictionary - RegridInfo regrid_info = parse_conf_regrid(climo_dict); + // Parse the "regrid" dictionary from the current location + // (e.g. "config.fcst.climo_mean.regrid") or default + // location (e.g. "config.climo_mean.regrid") + RegridInfo regrid_info = parse_conf_regrid( + dict->lookup_dictionary(climo_name, false, false, false), + dict->parent()->lookup_dictionary(climo_name, false, false, false)); // Parse the "time_interp_method" cs << cs_erase << climo_name << "." << conf_key_time_interp_method; From 364ec6d7dfa09f9cac0cce349af9383c4a825ec3 Mon Sep 17 00:00:00 2001 From: MET Tools Test Account Date: Thu, 12 Sep 2024 17:34:09 +0000 Subject: [PATCH 12/22] Per #2924, need to check for non-null pointer before using it --- src/basic/vx_config/config_util.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/basic/vx_config/config_util.cc b/src/basic/vx_config/config_util.cc index 0ec4a6e038..41dfa9caef 100644 --- a/src/basic/vx_config/config_util.cc +++ b/src/basic/vx_config/config_util.cc @@ -1367,8 +1367,10 @@ RegridInfo parse_conf_regrid(Dictionary *dict, Dictionary *default_dict, bool er } // Conf: to_grid (optional) as an integer or string - const DictionaryEntry * entry = regrid_dict->lookup(conf_key_to_grid, false); - if(!entry) entry = regrid_default->lookup(conf_key_to_grid, false); + const DictionaryEntry * entry = nullptr; + + if(regrid_dict) entry = regrid_dict->lookup(conf_key_to_grid, false); + if(!entry && regrid_default) entry = regrid_default->lookup(conf_key_to_grid, false); // to_grid found if(entry) { From c71c72e13e597ec33979dedcdf821dbcd225edd7 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 13 Sep 2024 10:15:54 -0600 Subject: [PATCH 13/22] Per #2924, revise the climo_name dictionary lookup logic when parsing the regrid dictionary. --- src/libcode/vx_statistics/read_climo.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcode/vx_statistics/read_climo.cc b/src/libcode/vx_statistics/read_climo.cc index b4f9cd447e..48b2f785bc 100644 --- a/src/libcode/vx_statistics/read_climo.cc +++ b/src/libcode/vx_statistics/read_climo.cc @@ -110,8 +110,8 @@ DataPlaneArray read_climo_data_plane_array(Dictionary *dict, // (e.g. "config.fcst.climo_mean.regrid") or default // location (e.g. "config.climo_mean.regrid") RegridInfo regrid_info = parse_conf_regrid( - dict->lookup_dictionary(climo_name, false, false, false), - dict->parent()->lookup_dictionary(climo_name, false, false, false)); + dict->lookup_dictionary(climo_name, false), + dict->parent()->lookup_dictionary(climo_name, false)); // Parse the "time_interp_method" cs << cs_erase << climo_name << "." << conf_key_time_interp_method; From fa719a168b2e78b39ba260845638334d1bd82e56 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Mon, 16 Sep 2024 15:58:23 -0600 Subject: [PATCH 14/22] Per #2924, update logic for handling RegridInfo --- src/basic/vx_config/config_constants.h | 3 +- src/basic/vx_config/config_util.cc | 123 ++++++++++-------- src/basic/vx_config/config_util.h | 2 +- src/libcode/vx_data2d/var_info.cc | 54 +++++--- src/libcode/vx_data2d/var_info.h | 4 +- src/libcode/vx_statistics/apply_mask.cc | 3 +- src/libcode/vx_statistics/read_climo.cc | 25 ++-- src/tools/core/ensemble_stat/ensemble_stat.cc | 6 +- src/tools/core/grid_stat/grid_stat.cc | 3 +- .../core/grid_stat/grid_stat_conf_info.cc | 5 + src/tools/core/mode/mode_exec.cc | 12 +- src/tools/core/point_stat/point_stat.cc | 3 +- .../core/series_analysis/series_analysis.cc | 6 +- src/tools/core/wavelet_stat/wavelet_stat.cc | 6 +- src/tools/other/gen_ens_prod/gen_ens_prod.cc | 3 +- src/tools/other/grid_diag/grid_diag.cc | 3 +- .../plot_point_obs_conf_info.cc | 3 +- src/tools/tc_utils/tc_diag/tc_diag.cc | 5 +- 18 files changed, 158 insertions(+), 111 deletions(-) diff --git a/src/basic/vx_config/config_constants.h b/src/basic/vx_config/config_constants.h index 4900bb79b8..7bba9e759e 100644 --- a/src/basic/vx_config/config_constants.h +++ b/src/basic/vx_config/config_constants.h @@ -297,7 +297,7 @@ struct InterpInfo { void clear(); void validate(); // Ensure that width and method are accordant bool operator==(const InterpInfo &) const; - InterpInfo &operator=(const InterpInfo &a) noexcept; // SoanrQube findings + InterpInfo &operator=(const InterpInfo &a) noexcept; // SonarQube findings }; //////////////////////////////////////////////////////////////////////// @@ -329,6 +329,7 @@ struct RegridInfo { void validate(); // ensure that width and method are accordant void validate_point(); // ensure that width and method are accordant RegridInfo &operator=(const RegridInfo &a) noexcept; // SoanrQube findings + ConcatString get_str() const; }; //////////////////////////////////////////////////////////////////////// diff --git a/src/basic/vx_config/config_util.cc b/src/basic/vx_config/config_util.cc index 41dfa9caef..b5ebfde54e 100644 --- a/src/basic/vx_config/config_util.cc +++ b/src/basic/vx_config/config_util.cc @@ -266,6 +266,13 @@ RegridInfo &RegridInfo::operator=(const RegridInfo &a) noexcept { return *this; } +/////////////////////////////////////////////////////////////////////////////// + +ConcatString RegridInfo::get_str() const { + ConcatString cs(interpmthd_to_string(method)); + cs << "(" << width << ")"; + return cs; +} /////////////////////////////////////////////////////////////////////////////// @@ -1332,12 +1339,9 @@ BootInfo parse_conf_boot(Dictionary *dict) { return info; } - /////////////////////////////////////////////////////////////////////////////// -RegridInfo parse_conf_regrid(Dictionary *dict, Dictionary *default_dict, bool error_out) { - Dictionary *regrid_dict = nullptr; - Dictionary *regrid_default = nullptr; +RegridInfo parse_conf_regrid(Dictionary *dict, RegridInfo *default_info, bool error_out) { RegridInfo info; if(!dict) { @@ -1347,15 +1351,10 @@ RegridInfo parse_conf_regrid(Dictionary *dict, Dictionary *default_dict, bool er } // Conf: regrid - regrid_dict = dict->lookup_dictionary(conf_key_regrid, false); - - // Dictionary with default settings - if(default_dict) { - regrid_default = default_dict->lookup_dictionary(conf_key_regrid, false); - } + Dictionary *regrid_dict = dict->lookup_dictionary(conf_key_regrid, false); // Check that the regrid dictionary is present - if(!regrid_dict && !regrid_default) { + if(!regrid_dict && !default_info) { if(error_out) { mlog << Error << "\nparse_conf_regrid() -> " << "can't find the \"regrid\" dictionary!\n\n"; @@ -1369,8 +1368,7 @@ RegridInfo parse_conf_regrid(Dictionary *dict, Dictionary *default_dict, bool er // Conf: to_grid (optional) as an integer or string const DictionaryEntry * entry = nullptr; - if(regrid_dict) entry = regrid_dict->lookup(conf_key_to_grid, false); - if(!entry && regrid_default) entry = regrid_default->lookup(conf_key_to_grid, false); + if(regrid_dict) entry = regrid_dict->lookup(conf_key_to_grid, false); // to_grid found if(entry) { @@ -1395,6 +1393,11 @@ RegridInfo parse_conf_regrid(Dictionary *dict, Dictionary *default_dict, bool er exit(1); } } + // Use default RegridInfo + else if(default_info){ + info.name = default_info->name; + info.enable = default_info->enable; + } // to_grid not found else { info.name = ""; @@ -1406,77 +1409,82 @@ RegridInfo parse_conf_regrid(Dictionary *dict, Dictionary *default_dict, bool er if(regrid_dict && regrid_dict->lookup(conf_key_vld_thresh, false)) { v_dbl = regrid_dict->lookup_double(conf_key_vld_thresh); } - else if(regrid_default && regrid_default->lookup(conf_key_vld_thresh, false)) { - v_dbl = regrid_default->lookup_double(conf_key_vld_thresh); + // Use default RegridInfo + else if(default_info) { + v_dbl = default_info->vld_thresh; } info.vld_thresh = (is_bad_data(v_dbl) ? default_vld_thresh : v_dbl); // Conf: method (required) - int v_int = bad_data_int; if(regrid_dict && regrid_dict->lookup(conf_key_method, false)) { - v_int = regrid_dict->lookup_int(conf_key_method); + info.method = int_to_interpmthd(regrid_dict->lookup_int(conf_key_method)); } - else if(regrid_default && regrid_default->lookup(conf_key_method, false)) { - v_int = regrid_default->lookup_int(conf_key_method); + // Use default RegridInfo + else if(default_info) { + info.method = default_info->method; } - info.method = int_to_interpmthd(v_int); // Conf: width (required) - v_int = bad_data_int; if(regrid_dict && regrid_dict->lookup(conf_key_width, false)) { - v_int = regrid_dict->lookup_int(conf_key_width); + info.width = regrid_dict->lookup_int(conf_key_width); } - else if(regrid_default && regrid_default->lookup(conf_key_width, false)) { - v_int = regrid_default->lookup_int(conf_key_width); + // Use default RegridInfo + else if(default_info) { + info.width = default_info->width; } - info.width = v_int; // Conf: shape (optional) - v_int = bad_data_int; if(regrid_dict && regrid_dict->lookup(conf_key_shape, false)) { - v_int = regrid_dict->lookup_int(conf_key_shape); + info.shape = int_to_gridtemplate(regrid_dict->lookup_int(conf_key_shape)); } - else if(regrid_default && regrid_default->lookup(conf_key_shape, false)) { - v_int = regrid_default->lookup_int(conf_key_shape); + // Use default RegridInfo + else if(default_info) { + info.shape = default_info->shape; + } + // Use global default + else { + info.shape = GridTemplateFactory::GridTemplates::Square; } - // Default is square - info.shape = (is_bad_data(v_int) ? - GridTemplateFactory::GridTemplates::Square : - int_to_gridtemplate(v_int)); // Conf: gaussian_dx (optional) - v_dbl = bad_data_double; if(regrid_dict && regrid_dict->lookup(conf_key_gaussian_dx, false)) { - v_dbl = regrid_dict->lookup_double(conf_key_gaussian_dx); + info.gaussian.dx = regrid_dict->lookup_double(conf_key_gaussian_dx); } - else if(regrid_default && regrid_default->lookup(conf_key_gaussian_dx, false)) { - v_dbl = regrid_default->lookup_double(conf_key_gaussian_dx); + // Use default RegridInfo + else if(default_info) { + info.gaussian.dx = default_info->gaussian.dx; + } + // Use global default + else { + info.gaussian.dx = default_gaussian_dx; } - info.gaussian.dx = (is_bad_data(v_dbl) ? default_gaussian_dx : v_dbl); // Conf: gaussian_radius (optional) - v_dbl = bad_data_double; if(regrid_dict && regrid_dict->lookup(conf_key_gaussian_radius, false)) { - v_dbl = regrid_dict->lookup_double(conf_key_gaussian_radius); + info.gaussian.radius = regrid_dict->lookup_double(conf_key_gaussian_radius); } - else if(regrid_default && regrid_default->lookup(conf_key_gaussian_radius, false)) { - v_dbl = regrid_default->lookup_double(conf_key_gaussian_radius); + // Use default RegridInfo + else if(default_info) { + info.gaussian.radius = default_info->gaussian.radius; + } + // Use global default + else { + info.gaussian.radius = default_gaussian_radius; } - info.gaussian.radius = (is_bad_data(v_dbl) ? - default_gaussian_radius : - v_dbl); // Conf: gaussian_trunc_factor (optional) v_dbl = bad_data_double; if(regrid_dict && regrid_dict->lookup(conf_key_trunc_factor, false)) { v_dbl = regrid_dict->lookup_double(conf_key_trunc_factor); } - else if(regrid_default && regrid_default->lookup(conf_key_trunc_factor, false)) { - v_dbl = regrid_default->lookup_double(conf_key_trunc_factor); + // Use default RegridInfo + else if(default_info) { + info.gaussian.trunc_factor = default_info->gaussian.trunc_factor; + } + // Use global default + else { + info.gaussian.trunc_factor = default_trunc_factor; } - info.gaussian.trunc_factor = (is_bad_data(v_dbl) ? - default_trunc_factor : - v_dbl); if(info.method == InterpMthd::Gaussian || info.method == InterpMthd::MaxGauss) { @@ -1491,24 +1499,27 @@ RegridInfo parse_conf_regrid(Dictionary *dict, Dictionary *default_dict, bool er if(regrid_dict && regrid_dict->lookup(conf_key_convert, false)) { info.convert_fx.set(regrid_dict->lookup(conf_key_convert)); } - else if(regrid_default && regrid_default->lookup(conf_key_convert, false)) { - info.convert_fx.set(regrid_default->lookup(conf_key_convert)); + // Use default RegridInfo + else if(default_info) { + info.convert_fx = default_info->convert_fx; } // Conf: censor_thresh (optional) if(regrid_dict && regrid_dict->lookup(conf_key_censor_thresh, false)) { info.censor_thresh = regrid_dict->lookup_thresh_array(conf_key_censor_thresh); } - else if(regrid_default && regrid_default->lookup(conf_key_censor_thresh, false)) { - info.censor_thresh = regrid_default->lookup_thresh_array(conf_key_censor_thresh); + // Use default RegridInfo + else if(default_info) { + info.censor_thresh = default_info->censor_thresh; } // Conf: censor_val (optional) if(regrid_dict && regrid_dict->lookup(conf_key_censor_val, false)) { info.censor_val = regrid_dict->lookup_num_array(conf_key_censor_val); } - else if(regrid_default && regrid_default->lookup(conf_key_censor_val, false)) { - info.censor_val = regrid_default->lookup_num_array(conf_key_censor_val); + // Use default RegridInfo + else if(default_info) { + info.censor_val = default_info->censor_val; } // Validate the settings diff --git a/src/basic/vx_config/config_util.h b/src/basic/vx_config/config_util.h index 97a446b493..15de1e00f0 100644 --- a/src/basic/vx_config/config_util.h +++ b/src/basic/vx_config/config_util.h @@ -99,7 +99,7 @@ extern std::map extern BootInfo parse_conf_boot(Dictionary *dict); extern RegridInfo parse_conf_regrid( Dictionary *dict, - Dictionary *default_dict=nullptr, + RegridInfo *default_info=nullptr, bool error_out=default_dictionary_error_out); extern InterpInfo parse_conf_interp(Dictionary *dict, const char *); extern NbrhdInfo parse_conf_nbrhd(Dictionary *dict, const char *); diff --git a/src/libcode/vx_data2d/var_info.cc b/src/libcode/vx_data2d/var_info.cc index 89514c222b..ac12513e76 100644 --- a/src/libcode/vx_data2d/var_info.cc +++ b/src/libcode/vx_data2d/var_info.cc @@ -116,6 +116,7 @@ void VarInfo::assign(const VarInfo &v) { nBins = v.nBins; Range = v.Range; + DefaultRegrid = v.DefaultRegrid; Regrid = v.Regrid; SetAttrName = v.SetAttrName; @@ -176,6 +177,7 @@ void VarInfo::clear() { nBins = 0; Range.clear(); + DefaultRegrid.clear(); Regrid.clear(); SetAttrName.clear(); @@ -215,26 +217,29 @@ void VarInfo::dump(ostream &out) const { // Dump out the contents out << "VarInfo::dump():\n" - << " MagicStr = " << MagicStr.contents() << "\n" - << " ReqName = " << ReqName.contents() << "\n" - << " Name = " << Name.contents() << "\n" - << " LongName = " << LongName.contents() << "\n" - << " Units = " << Units.contents() << "\n" - << " PFlag = " << PFlag << "\n" - << " PName = " << PName.contents() << "\n" - << " PUnits = " << PUnits.contents() << "\n" - << " PAsScalar = " << PAsScalar << "\n" - << " UVIndex = " << UVIndex << "\n" - << " Init = " << init_str << " (" << Init << ")\n" - << " Valid = " << valid_str << " (" << Valid << ")\n" - << " Ensemble = " << Ensemble.contents() << "\n" - << " Lead = " << lead_str << " (" << Lead << ")\n" - << " ConvertFx = " << (ConvertFx.is_set() ? "IsSet" : "(nul)") << "\n" - << " CensorThresh = " << CensorThresh.get_str() << "\n" - << " CensorVal = " << CensorVal.serialize() << "\n" - << " nBins = " << nBins << "\n" - << " Range = " << Range.serialize() << "\n" - << " Regrid = " << interpmthd_to_string(Regrid.method) << "\n"; + << " MagicStr = " << MagicStr.contents() << "\n" + << " ReqName = " << ReqName.contents() << "\n" + << " Name = " << Name.contents() << "\n" + << " LongName = " << LongName.contents() << "\n" + << " Units = " << Units.contents() << "\n" + << " PFlag = " << PFlag << "\n" + << " PName = " << PName.contents() << "\n" + << " PUnits = " << PUnits.contents() << "\n" + << " PAsScalar = " << PAsScalar << "\n" + << " UVIndex = " << UVIndex << "\n" + << " Init = " << init_str << " (" << Init << ")\n" + << " Valid = " << valid_str << " (" << Valid << ")\n" + << " Ensemble = " << Ensemble.contents() << "\n" + << " Lead = " << lead_str << " (" << Lead << ")\n" + << " ConvertFx = " << (ConvertFx.is_set() ? "IsSet" : "(nul)") << "\n" + << " CensorThresh = " << CensorThresh.get_str() << "\n" + << " CensorVal = " << CensorVal.serialize() << "\n" + << " nBins = " << nBins << "\n" + << " Range = " << Range.serialize() << "\n" + << " DefaultRegrid = " << interpmthd_to_string(DefaultRegrid.method) + << "(" << DefaultRegrid.width << ")\n" + << " Regrid = " << interpmthd_to_string(Regrid.method) + << "(" << Regrid.width << ")\n"; Level.dump(out); @@ -425,6 +430,13 @@ void VarInfo::set_range(const NumArray &a) { /////////////////////////////////////////////////////////////////////////////// +void VarInfo::set_default_regrid(const RegridInfo &ri) { + DefaultRegrid = ri; + return; +} + +/////////////////////////////////////////////////////////////////////////////// + void VarInfo::set_regrid(const RegridInfo &ri) { Regrid = ri; return; @@ -528,7 +540,7 @@ void VarInfo::set_dict(Dictionary &dict) { if(dict.last_lookup_status()) set_range(na); // Parse regrid, if present - Regrid = parse_conf_regrid(&dict, nullptr, false); + Regrid = parse_conf_regrid(&dict, &DefaultRegrid, false); // Parse set_attr strings SetAttrName = diff --git a/src/libcode/vx_data2d/var_info.h b/src/libcode/vx_data2d/var_info.h index 3271376816..eba7551b67 100644 --- a/src/libcode/vx_data2d/var_info.h +++ b/src/libcode/vx_data2d/var_info.h @@ -57,7 +57,8 @@ class VarInfo int nBins; // Number of pdf bins NumArray Range; // Range of pdf bins - RegridInfo Regrid; // Regridding logic + RegridInfo DefaultRegrid; // Default regridding logic + RegridInfo Regrid; // Regridding logic // Options to override metadata ConcatString SetAttrName; @@ -189,6 +190,7 @@ class VarInfo void set_n_bins(const int &); void set_range(const NumArray &); + void set_default_regrid(const RegridInfo &); void set_regrid(const RegridInfo &); void set_level_info_grib(Dictionary & dict); diff --git a/src/libcode/vx_statistics/apply_mask.cc b/src/libcode/vx_statistics/apply_mask.cc index bd12b1a25b..01c696243c 100644 --- a/src/libcode/vx_statistics/apply_mask.cc +++ b/src/libcode/vx_statistics/apply_mask.cc @@ -633,7 +633,8 @@ DataPlane parse_geog_data(Dictionary *dict, const Grid &vx_grid, regrid_info = parse_conf_regrid(dict); mlog << Debug(2) << "Regridding geography mask data " << info->magic_str() - << " to the verification grid.\n"; + << " to the verification grid using " + << regrid_info.get_str() << ".\n"; dp = met_regrid(dp, mtddf->grid(), vx_grid, regrid_info); } } diff --git a/src/libcode/vx_statistics/read_climo.cc b/src/libcode/vx_statistics/read_climo.cc index 48b2f785bc..fe0cb79a84 100644 --- a/src/libcode/vx_statistics/read_climo.cc +++ b/src/libcode/vx_statistics/read_climo.cc @@ -106,12 +106,11 @@ DataPlaneArray read_climo_data_plane_array(Dictionary *dict, // Get the i-th array entry Dictionary i_dict = parse_conf_i_vx_dict(field_dict, i_vx); - // Parse the "regrid" dictionary from the current location - // (e.g. "config.fcst.climo_mean.regrid") or default - // location (e.g. "config.climo_mean.regrid") - RegridInfo regrid_info = parse_conf_regrid( - dict->lookup_dictionary(climo_name, false), - dict->parent()->lookup_dictionary(climo_name, false)); + // Parse the "regrid" dictionary from the top-level + // config file context (e.g. "config.climo_mean.regrid") + // to serve as the default. + RegridInfo regrid_default = parse_conf_regrid( + dict->parent()->lookup_dictionary(climo_name, false)); // Parse the "time_interp_method" cs << cs_erase << climo_name << "." << conf_key_time_interp_method; @@ -152,8 +151,8 @@ DataPlaneArray read_climo_data_plane_array(Dictionary *dict, << " data using climo_name = " << climo_name << ", i_vx = " << i_vx << ", valid time = " << unix_to_yyyymmdd_hhmmss(vld_ut) - << ", regrid_info = " << interpmthd_to_string(regrid_info.method) - << "(" << regrid_info.width << ")" + << ", regrid_default = " << interpmthd_to_string(regrid_default.method) + << "(" << regrid_default.width << ")" << ", time_interp = " << interpmthd_to_string(time_interp) << ", day_interval = " << day_interval << ", hour_interval = " << hour_interval @@ -172,7 +171,7 @@ DataPlaneArray read_climo_data_plane_array(Dictionary *dict, // Search the files for the requested records for(int i=0; ifile_type()); + info->set_default_regrid(regrid_default); info->set_dict(*dict); // Read data planes @@ -265,9 +265,10 @@ void read_climo_file(const char *climo_file, GrdFileType ctype, if(!(mtddf->grid() == vx_grid)) { mlog << Debug(2) << "Regridding " << clm_ut_cs << " " << desc << " field " << info->magic_str() - << " to the verification grid.\n"; + << " to the verification grid using " + << info->regrid().get_str() << ".\n"; dp = met_regrid(clm_dpa[i], mtddf->grid(), vx_grid, - regrid_info); + info->regrid()); } else { dp = clm_dpa[i]; diff --git a/src/tools/core/ensemble_stat/ensemble_stat.cc b/src/tools/core/ensemble_stat/ensemble_stat.cc index 14a089430d..8a92272d75 100644 --- a/src/tools/core/ensemble_stat/ensemble_stat.cc +++ b/src/tools/core/ensemble_stat/ensemble_stat.cc @@ -633,7 +633,8 @@ bool get_data_plane(const char *infile, GrdFileType ftype, if(do_regrid && !(mtddf->grid() == grid)) { mlog << Debug(1) << "Regridding field \"" << info->magic_str() - << "\" to the verification grid.\n"; + << "\" to the verification grid using " + << info->regrid().get_str() << ".\n"; dp = met_regrid(dp, mtddf->grid(), grid, info->regrid()); } @@ -691,7 +692,8 @@ bool get_data_plane_array(const char *infile, GrdFileType ftype, mlog << Debug(1) << "Regridding " << dpa.n_planes() << " field(s) \"" << info->magic_str() - << "\" to the verification grid.\n"; + << "\" to the verification grid using " + << info->regrid().get_str() << ".\n"; // Loop through the forecast fields for(i=0; imagic_str() - << " to the verification grid.\n"; + << " to the verification grid using " + << info->regrid().get_str() << ".\n"; dp = met_regrid(dp, mtddf->grid(), grid, info->regrid()); } diff --git a/src/tools/core/grid_stat/grid_stat_conf_info.cc b/src/tools/core/grid_stat/grid_stat_conf_info.cc index 7c0f8ada2e..19c5a48e83 100644 --- a/src/tools/core/grid_stat/grid_stat_conf_info.cc +++ b/src/tools/core/grid_stat/grid_stat_conf_info.cc @@ -656,6 +656,11 @@ void GridStatVxOpt::process_config( fcst_info = info_factory.new_var_info(ftype); obs_info = info_factory.new_var_info(otype); + // Set the top-level regrid as the default + RegridInfo regrid_info = parse_conf_regrid(fdict.parent()); + fcst_info->set_default_regrid(regrid_info); + obs_info->set_default_regrid(regrid_info); + // Set the VarInfo objects fcst_info->set_dict(fdict); obs_info->set_dict(odict); diff --git a/src/tools/core/mode/mode_exec.cc b/src/tools/core/mode/mode_exec.cc index 578c92acb7..2ee853f30b 100644 --- a/src/tools/core/mode/mode_exec.cc +++ b/src/tools/core/mode/mode_exec.cc @@ -292,7 +292,8 @@ void ModeExecutive::setup_traditional_fcst_obs_data() if ( !(fcst_mtddf->grid() == grid) ) { mlog << Debug(1) << "Regridding forecast " << engine.conf_info.Fcst->var_info->magic_str() - << " to the verification grid.\n"; + << " to the verification grid using " + << engine.conf_info.Fcst->var_info->regrid().get_str() << ".\n"; Fcst_sd.data = met_regrid(Fcst_sd.data, fcst_mtddf->grid(), grid, engine.conf_info.Fcst->var_info->regrid()); } @@ -302,7 +303,8 @@ void ModeExecutive::setup_traditional_fcst_obs_data() if ( !(obs_mtddf->grid() == grid) ) { mlog << Debug(1) << "Regridding observation " << engine.conf_info.Obs->var_info->magic_str() - << " to the verification grid.\n"; + << " to the verification grid using " + << engine.conf_info.Obs->var_info->regrid().get_str() << ".\n"; Obs_sd.data = met_regrid(Obs_sd.data, obs_mtddf->grid(), grid, engine.conf_info.Obs->var_info->regrid()); } @@ -454,7 +456,8 @@ void ModeExecutive::setup_multivar_fcst_data(const Grid &verification_grid, if ( !(input._grid == grid) ) { mlog << Debug(1) << "Regridding forecast " << engine.conf_info.Fcst->var_info->magic_str() - << " to the verification grid.\n"; + << " to the verification grid using " + << engine.conf_info.Fcst->var_info->regrid().get_str() << ".\n"; Fcst_sd.data = met_regrid(Fcst_sd.data, input._grid, grid, engine.conf_info.Fcst->var_info->regrid()); } @@ -520,7 +523,8 @@ void ModeExecutive::setup_multivar_obs_data(const Grid &verification_grid, if ( !(input._grid == grid) ) { mlog << Debug(1) << "Regridding observation " << engine.conf_info.Obs->var_info->magic_str() - << " to the verification grid.\n"; + << " to the verification grid using " + << engine.conf_info.Obs->var_info->regrid().get_str() << ".\n"; Obs_sd.data = met_regrid(Obs_sd.data, input._grid, grid, engine.conf_info.Obs->var_info->regrid()); } diff --git a/src/tools/core/point_stat/point_stat.cc b/src/tools/core/point_stat/point_stat.cc index 2e6a232e26..9e47b3181e 100644 --- a/src/tools/core/point_stat/point_stat.cc +++ b/src/tools/core/point_stat/point_stat.cc @@ -649,7 +649,8 @@ void process_fcst_climo_files() { mlog << Debug(1) << "Regridding " << fcst_dpa.n_planes() << " forecast field(s) for " << fcst_info->magic_str() - << " to the verification grid.\n"; + << " to the verification grid using " + << fcst_info->regrid().get_str() << ".\n"; // Loop through the forecast fields for(j=0; jmagic_str() - << " to the verification grid.\n"; + << " to the verification grid using " + << fcst_info->regrid().get_str() << ".\n"; fcst_dp = met_regrid(fcst_dp, fcst_grid, grid, fcst_info->regrid()); } @@ -582,7 +583,8 @@ void get_series_data(int i_series, mlog << Debug(2) << "Regridding observation " << obs_info->magic_str() - << " to the verification grid.\n"; + << " to the verification grid using " + << obs_info->regrid().get_str() << ".\n"; obs_dp = met_regrid(obs_dp, obs_grid, grid, obs_info->regrid()); } diff --git a/src/tools/core/wavelet_stat/wavelet_stat.cc b/src/tools/core/wavelet_stat/wavelet_stat.cc index 27d868d78b..648d5fd9b6 100644 --- a/src/tools/core/wavelet_stat/wavelet_stat.cc +++ b/src/tools/core/wavelet_stat/wavelet_stat.cc @@ -300,7 +300,8 @@ void process_scores() { if(!(fcst_mtddf->grid() == grid)) { mlog << Debug(1) << "Regridding forecast " << conf_info.fcst_info[i]->magic_str() - << " to the verification grid.\n"; + << " to the verification grid using " + << conf_info.fcst_info[i]->regrid().get_str() << ".\n"; fcst_dp = met_regrid(fcst_dp, fcst_mtddf->grid(), grid, conf_info.fcst_info[i]->regrid()); } @@ -326,7 +327,8 @@ void process_scores() { if(!(obs_mtddf->grid() == grid)) { mlog << Debug(1) << "Regridding observation " << conf_info.obs_info[i]->magic_str() - << " to the verification grid.\n"; + << " to the verification grid using " + << conf_info.obs_info[i]->regrid().get_str() << ".\n"; obs_dp = met_regrid(obs_dp, obs_mtddf->grid(), grid, conf_info.obs_info[i]->regrid()); } diff --git a/src/tools/other/gen_ens_prod/gen_ens_prod.cc b/src/tools/other/gen_ens_prod/gen_ens_prod.cc index cd82cf1d83..9f36c55ad3 100644 --- a/src/tools/other/gen_ens_prod/gen_ens_prod.cc +++ b/src/tools/other/gen_ens_prod/gen_ens_prod.cc @@ -649,7 +649,8 @@ bool get_data_plane(const char *infile, GrdFileType ftype, if(!(mtddf->grid() == grid)) { mlog << Debug(1) << "Regridding field \"" << info->magic_str() - << "\" to the verification grid.\n"; + << "\" to the verification grid using " + << info->regrid().get_str() << ".\n"; dp = met_regrid(dp, mtddf->grid(), grid, info->regrid()); } diff --git a/src/tools/other/grid_diag/grid_diag.cc b/src/tools/other/grid_diag/grid_diag.cc index bb444f2061..cd5ddc843b 100644 --- a/src/tools/other/grid_diag/grid_diag.cc +++ b/src/tools/other/grid_diag/grid_diag.cc @@ -291,7 +291,8 @@ void process_series(void) { if(!(cur_grid == grid)) { mlog << Debug(2) << "Regridding field " << data_info->magic_str_attr() - << " to the verification grid.\n"; + << " to the verification grid using " + << data_info->regrid().get_str() << ".\n"; data_dp[i_var] = met_regrid(data_dp[i_var], cur_grid, grid, data_info->regrid()); diff --git a/src/tools/other/plot_point_obs/plot_point_obs_conf_info.cc b/src/tools/other/plot_point_obs/plot_point_obs_conf_info.cc index 23311d2e3c..4a06fd3e89 100644 --- a/src/tools/other/plot_point_obs/plot_point_obs_conf_info.cc +++ b/src/tools/other/plot_point_obs/plot_point_obs_conf_info.cc @@ -486,7 +486,8 @@ void PlotPointObsConfInfo::process_config( // Regrid, if requested if(grid_data_info->regrid().enable) { mlog << Debug(1) << "Regridding field " - << grid_data_info->magic_str() << ".\n"; + << grid_data_info->magic_str() << " using " + << grid_data_info->regrid().get_str() << ".\n"; Grid to_grid(parse_vx_grid(grid_data_info->regrid(), &grid, &grid)); grid_data = met_regrid(grid_data, grid, to_grid, diff --git a/src/tools/tc_utils/tc_diag/tc_diag.cc b/src/tools/tc_utils/tc_diag/tc_diag.cc index 0b551fd1f2..c4b76a7cdd 100644 --- a/src/tools/tc_utils/tc_diag/tc_diag.cc +++ b/src/tools/tc_utils/tc_diag/tc_diag.cc @@ -2286,9 +2286,8 @@ void TmpFileInfo::write_nc_data(const VarInfo *vi, const DataPlane &dp_in, RegridInfo ri = vi->regrid(); mlog << Debug(4) << "Regridding \"" << vi->magic_str() - << "\" to the \"" << domain << "\" domain using the " - << interpmthd_to_string(ri.method) << "(" << ri.width - << ") interpolation method.\n"; + << "\" to the \"" << domain << "\" domain using " + << ri.get_str() << ".\n"; // Do the cylindrical coordinate transformation if(dp_in.nxy() > 0) { From d47d4f766bcd885349f804b50d148fb60a005dcf Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 17 Sep 2024 09:20:27 -0600 Subject: [PATCH 15/22] Per #2924, remove the default regridding information from the 'Searching' log message to avoid confusion. --- src/basic/vx_config/config_util.cc | 16 +++++++++------- src/libcode/vx_statistics/read_climo.cc | 2 -- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/basic/vx_config/config_util.cc b/src/basic/vx_config/config_util.cc index b5ebfde54e..244b2d9b2e 100644 --- a/src/basic/vx_config/config_util.cc +++ b/src/basic/vx_config/config_util.cc @@ -1398,22 +1398,24 @@ RegridInfo parse_conf_regrid(Dictionary *dict, RegridInfo *default_info, bool er info.name = default_info->name; info.enable = default_info->enable; } - // to_grid not found + // Use global default else { info.name = ""; info.enable = true; } // Conf: vld_thresh (required) - double v_dbl = bad_data_double; if(regrid_dict && regrid_dict->lookup(conf_key_vld_thresh, false)) { - v_dbl = regrid_dict->lookup_double(conf_key_vld_thresh); + info.vld_thresh = regrid_dict->lookup_double(conf_key_vld_thresh); } // Use default RegridInfo else if(default_info) { - v_dbl = default_info->vld_thresh; + info.vld_thresh = default_info->vld_thresh; + } + // Use global default + else { + info.vld_thresh = default_vld_thresh; } - info.vld_thresh = (is_bad_data(v_dbl) ? default_vld_thresh : v_dbl); // Conf: method (required) if(regrid_dict && regrid_dict->lookup(conf_key_method, false)) { @@ -1473,9 +1475,8 @@ RegridInfo parse_conf_regrid(Dictionary *dict, RegridInfo *default_info, bool er } // Conf: gaussian_trunc_factor (optional) - v_dbl = bad_data_double; if(regrid_dict && regrid_dict->lookup(conf_key_trunc_factor, false)) { - v_dbl = regrid_dict->lookup_double(conf_key_trunc_factor); + info.gaussian.trunc_factor = regrid_dict->lookup_double(conf_key_trunc_factor); } // Use default RegridInfo else if(default_info) { @@ -1486,6 +1487,7 @@ RegridInfo parse_conf_regrid(Dictionary *dict, RegridInfo *default_info, bool er info.gaussian.trunc_factor = default_trunc_factor; } + // Compute Guassian parameters if(info.method == InterpMthd::Gaussian || info.method == InterpMthd::MaxGauss) { info.gaussian.compute(); diff --git a/src/libcode/vx_statistics/read_climo.cc b/src/libcode/vx_statistics/read_climo.cc index fe0cb79a84..9559e4c4a2 100644 --- a/src/libcode/vx_statistics/read_climo.cc +++ b/src/libcode/vx_statistics/read_climo.cc @@ -151,8 +151,6 @@ DataPlaneArray read_climo_data_plane_array(Dictionary *dict, << " data using climo_name = " << climo_name << ", i_vx = " << i_vx << ", valid time = " << unix_to_yyyymmdd_hhmmss(vld_ut) - << ", regrid_default = " << interpmthd_to_string(regrid_default.method) - << "(" << regrid_default.width << ")" << ", time_interp = " << interpmthd_to_string(time_interp) << ", day_interval = " << day_interval << ", hour_interval = " << hour_interval From 372016ee76a4a27a69a1cd27b3f8e380c87068a2 Mon Sep 17 00:00:00 2001 From: MET Tools Test Account Date: Wed, 18 Sep 2024 18:11:23 +0000 Subject: [PATCH 16/22] Per #2924, escape sequences, like \n, cannot be used inside R-string literals. --- src/basic/vx_config/threshold.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/basic/vx_config/threshold.cc b/src/basic/vx_config/threshold.cc index cbf0a3cb7d..ef650ef2c0 100644 --- a/src/basic/vx_config/threshold.cc +++ b/src/basic/vx_config/threshold.cc @@ -114,7 +114,7 @@ if ( !match && mlog << Debug(2) << R"(Please replace the deprecated "SCP" and "CDP" )" << R"(threshold types with "SOCP" and "OCDP", respectively, in the ")" - << str << R"(" threshold string.\n)"; + << str << R"(" threshold string.)" << "\n"; print_climo_perc_thresh_log_message = false; From ea0c70a1ee7288292d76640f7f86c54c7ab9cce7 Mon Sep 17 00:00:00 2001 From: MET Tools Test Account Date: Wed, 18 Sep 2024 19:47:50 +0000 Subject: [PATCH 17/22] Per #2924, update the logic of check_climo_n_vx() --- src/basic/vx_config/config_util.cc | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/basic/vx_config/config_util.cc b/src/basic/vx_config/config_util.cc index 244b2d9b2e..a3dba81367 100644 --- a/src/basic/vx_config/config_util.cc +++ b/src/basic/vx_config/config_util.cc @@ -2622,28 +2622,28 @@ void check_mask_names(const StringArray &sa) { /////////////////////////////////////////////////////////////////////////////// -void check_climo_n_vx(Dictionary *dict, const int n_vx) { - int n; +void check_climo_n_vx(Dictionary *dict, const int n_input) { + int n_climo; // Check for a valid number of climatology mean fields - n = parse_conf_n_vx(dict->lookup_array(conf_key_climo_mean_field, false)); - if(n != 0 && n != n_vx) { + n_climo = parse_conf_n_vx(dict->lookup_array(conf_key_climo_mean_field, false)); + if(n_climo != 0 && n_climo != 1 && n_climo != n_input) { mlog << Error << "\ncheck_climo_n_vx() -> " << "The number of climatology mean fields in \"" - << conf_key_climo_mean_field - << "\" must be zero or match the number (" << n_vx - << ") in \"" << conf_key_fcst_field << "\".\n\n"; + << conf_key_climo_mean_field << "\" (" << n_climo + << ") must be 0, 1, or match the number of input fields (" + << n_input << ").\n\n"; exit(1); } // Check for a valid number of climatology standard deviation fields - n = parse_conf_n_vx(dict->lookup_array(conf_key_climo_stdev_field, false)); - if(n != 0 && n != n_vx) { + n_climo = parse_conf_n_vx(dict->lookup_array(conf_key_climo_stdev_field, false)); + if(n_climo != 0 && n_climo != 1 && n_climo != n_input) { mlog << Error << "\ncheck_climo_n_vx() -> " << "The number of climatology standard deviation fields in \"" - << conf_key_climo_stdev_field - << "\" must be zero or match the number (" - << n_vx << ") in \"" << conf_key_fcst_field << "\".\n\n"; + << conf_key_climo_stdev_field << "\" (" << n_climo + << ") must be 0, 1, or match the number of input fields (" + << n_input << ").\n\n"; exit(1); } From 227a552166565c4fc4db223047431df0423cb5a7 Mon Sep 17 00:00:00 2001 From: MET Tools Test Account Date: Wed, 18 Sep 2024 20:43:04 +0000 Subject: [PATCH 18/22] Per #2924, revise logic in read_climo_data_plane_array(). Check the number of climo fields provided. If there's 0, just return since no data has been requested. If there's 1, use it regardless of the number of input fields. If there's more than 1, just use the requested i_vx index value. --- src/libcode/vx_statistics/read_climo.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/libcode/vx_statistics/read_climo.cc b/src/libcode/vx_statistics/read_climo.cc index 9559e4c4a2..8f8ddd8e9b 100644 --- a/src/libcode/vx_statistics/read_climo.cc +++ b/src/libcode/vx_statistics/read_climo.cc @@ -103,8 +103,14 @@ DataPlaneArray read_climo_data_plane_array(Dictionary *dict, cs << cs_erase << climo_name << "." << conf_key_field; Dictionary *field_dict = dict->lookup_array(cs.c_str(), false); - // Get the i-th array entry - Dictionary i_dict = parse_conf_i_vx_dict(field_dict, i_vx); + // Determine which climo array entry to use + int i_climo_field = bad_data_int; + if(field_dict->n_entries() == 0) return dpa; + else if(field_dict->n_entries() == 1) i_climo_field = 0; + else i_climo_field = i_vx; + + // Parse the climo dictionary + Dictionary i_dict = parse_conf_i_vx_dict(field_dict, i_climo_field); // Parse the "regrid" dictionary from the top-level // config file context (e.g. "config.climo_mean.regrid") From ecbb7b1496915f5d9f431187d6e66ebfa2a1b97c Mon Sep 17 00:00:00 2001 From: MET Tools Test Account Date: Wed, 18 Sep 2024 20:44:11 +0000 Subject: [PATCH 19/22] Per #2924, update Series-Analysis to set both i_fcst and i_obs when looping over the series entries. --- src/tools/core/series_analysis/series_analysis.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/tools/core/series_analysis/series_analysis.cc b/src/tools/core/series_analysis/series_analysis.cc index 51dd74364f..a43cb78807 100644 --- a/src/tools/core/series_analysis/series_analysis.cc +++ b/src/tools/core/series_analysis/series_analysis.cc @@ -861,11 +861,14 @@ void process_scores() { // Loop over the series variable for(int i_series=0; i_series 1 ? i_series : 0); + int i_obs = (conf_info.get_n_obs() > 1 ? i_series : 0); // Store the current VarInfo objects - fcst_info = conf_info.fcst_info[i_fcst]; + fcst_info = (conf_info.get_n_fcst() > 1 ? + conf_info.fcst_info[i_series] : + conf_info.fcst_info[0]); obs_info = (conf_info.get_n_obs() > 1 ? conf_info.obs_info[i_series] : conf_info.obs_info[0]); @@ -914,12 +917,12 @@ void process_scores() { ocmn_dp = read_climo_data_plane( conf_info.conf.lookup_dictionary(conf_key_obs), conf_key_climo_mean, - i_fcst, fcst_dp.valid(), grid, + i_obs, fcst_dp.valid(), grid, "observation climatology mean"); ocsd_dp = read_climo_data_plane( conf_info.conf.lookup_dictionary(conf_key_obs), conf_key_climo_stdev, - i_fcst, fcst_dp.valid(), grid, + i_obs, fcst_dp.valid(), grid, "observation climatology standard deviation"); bool fcmn_flag = !fcmn_dp.is_empty(); From cc9c78da9e3a472e33c0870e99727f289a15349e Mon Sep 17 00:00:00 2001 From: MET Tools Test Account Date: Wed, 18 Sep 2024 21:19:01 +0000 Subject: [PATCH 20/22] Per #2924, no real change. Just whitespace. --- src/basic/vx_config/config_util.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/basic/vx_config/config_util.cc b/src/basic/vx_config/config_util.cc index a3dba81367..5cce67dfcb 100644 --- a/src/basic/vx_config/config_util.cc +++ b/src/basic/vx_config/config_util.cc @@ -2632,7 +2632,7 @@ void check_climo_n_vx(Dictionary *dict, const int n_input) { << "The number of climatology mean fields in \"" << conf_key_climo_mean_field << "\" (" << n_climo << ") must be 0, 1, or match the number of input fields (" - << n_input << ").\n\n"; + << n_input << ").\n\n"; exit(1); } From 394fb8d7ff7503d08bbe8afb45c39980f53e7102 Mon Sep 17 00:00:00 2001 From: MET Tools Test Account Date: Thu, 19 Sep 2024 15:39:28 +0000 Subject: [PATCH 21/22] Unrelated to #2924, superficial changes to formatting of method_name strings for consistency. --- src/basic/vx_cal/is_leap_year.cc | 4 ++-- src/libcode/vx_data2d_nc_cf/nc_cf_file.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/basic/vx_cal/is_leap_year.cc b/src/basic/vx_cal/is_leap_year.cc index d37854d690..a383041475 100644 --- a/src/basic/vx_cal/is_leap_year.cc +++ b/src/basic/vx_cal/is_leap_year.cc @@ -102,7 +102,7 @@ void adjuste_day_for_month_year_units(int &day, int &month, int &year, double mo // Compute remaining days from the month fraction bool day_adjusted = false; const int day_offset = (int)(month_fraction * DAYS_PER_MONTH + 0.5); - const char *method_name = "adjuste_day() --> "; + const char *method_name = "adjuste_day_for_month_year_units() -> "; day += day_offset; if (day == 1 && abs(month_fraction-0.5) < DAY_EPSILON) { @@ -162,7 +162,7 @@ unixtime add_to_unixtime(unixtime base_unixtime, int sec_per_unit, unixtime ut; auto time_value_ut = (unixtime)time_value; double time_fraction = time_value - (double)time_value_ut; - const char *method_name = "add_to_unixtime() -->"; + const char *method_name = "add_to_unixtime() -> "; if (sec_per_unit == SEC_MONTH || sec_per_unit == SEC_YEAR) { if (time_value < 0) { diff --git a/src/libcode/vx_data2d_nc_cf/nc_cf_file.cc b/src/libcode/vx_data2d_nc_cf/nc_cf_file.cc index e985870169..41c8106f31 100644 --- a/src/libcode/vx_data2d_nc_cf/nc_cf_file.cc +++ b/src/libcode/vx_data2d_nc_cf/nc_cf_file.cc @@ -2299,7 +2299,7 @@ void NcCfFile::get_grid_mapping_polar_stereographic(const NcVar *grid_mapping_va { double x_coord_to_m_cf = 1.0; double y_coord_to_m_cf = 1.0; - static const string method_name = "NcCfFile::get_grid_mapping_polar_stereographic() --> "; + static const string method_name = "NcCfFile::get_grid_mapping_polar_stereographic() -> "; // Get projection attributes // proj_origin_lat: either 90.0 or -90.0, to decide the northern/southern hemisphere From 0f722eea18c81e6910fc374fa11e04b7213f18dd Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 19 Sep 2024 11:22:27 -0600 Subject: [PATCH 22/22] Per #2924, add a new series_analysis test that ERRORS OUT prior to this PR but works after the changes in this PR. --- .../config/SeriesAnalysisConfig_const_climo | 162 ++++++++++++++++++ .../test_unit/xml/unit_climatology_1.0deg.xml | 28 +++ .../core/series_analysis/series_analysis.cc | 2 +- 3 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 internal/test_unit/config/SeriesAnalysisConfig_const_climo diff --git a/internal/test_unit/config/SeriesAnalysisConfig_const_climo b/internal/test_unit/config/SeriesAnalysisConfig_const_climo new file mode 100644 index 0000000000..df991f208e --- /dev/null +++ b/internal/test_unit/config/SeriesAnalysisConfig_const_climo @@ -0,0 +1,162 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Series-Analysis configuration file. +// +// For additional information, please see the MET User's Guide. +// +//////////////////////////////////////////////////////////////////////////////// + +// +// Output model name to be written +// +model = "GFS"; + +// +// Output description to be written +// +desc = "NA"; + +// +// Output observation type to be written +// +obtype = "GFSANL"; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Verification grid +// +regrid = { + to_grid = NONE; + method = NEAREST; + width = 1; + vld_thresh = 0.5; +} + +//////////////////////////////////////////////////////////////////////////////// + +censor_thresh = []; +censor_val = []; +cat_thresh = []; +cnt_thresh = [ NA ]; +cnt_logic = UNION; + +// +// Forecast and observation fields to be verified +// +fcst = { + field = [ + { name = "TMP"; level = "P850"; valid_time = "20120409_12"; }, + { name = "TMP"; level = "P850"; valid_time = "20120410_00"; }, + { name = "TMP"; level = "P850"; valid_time = "20120410_12"; } + ]; +} +obs = { + field = [ + { name = "TMP"; level = "P850"; valid_time = "20120409_12"; }, + { name = "TMP"; level = "P850"; valid_time = "20120410_00"; }, + { name = "TMP"; level = "P850"; valid_time = "20120410_12"; } + ]; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Climatology data +// +climo_mean = fcst; +climo_mean = { + + file_name = [ ${CLIMO_MEAN_FILE_LIST} ]; + + field = [ + { name = "TMP"; level = "P850"; valid_time = "19590409_00"; } + ]; + + regrid = { + method = BILIN; + width = 2; + vld_thresh = 0.5; + } + + time_interp_method = NEAREST; + day_interval = NA; + hour_interval = NA; +} + +climo_stdev = climo_mean; +climo_stdev = { + file_name = [ ${CLIMO_STDEV_FILE_LIST} ]; +} + +climo_cdf = { + cdf_bins = 1; + center_bins = FALSE; + direct_prob = FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Confidence interval settings +// +ci_alpha = [ 0.05 ]; + +boot = { + interval = PCTILE; + rep_prop = 1.0; + n_rep = 0; + rng = "mt19937"; + seed = "1"; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Verification masking regions +// +mask = { + grid = ""; + poly = ""; +} + +// +// Number of grid points to be processed concurrently. Set smaller to use less +// memory but increase the number of passes through the data. If set <= 0, all +// grid points are processed concurrently. +// +block_size = 0; + +// +// Ratio of valid matched pairs to compute statistics for a grid point +// +vld_thresh = 0.5; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Statistical output types +// +output_stats = { + fho = [ ]; + ctc = [ ]; + cts = [ ]; + mctc = [ ]; + mcts = [ ]; + cnt = [ "TOTAL", "RMSE", "ANOM_CORR" ]; + sl1l2 = [ ]; + sal1l2 = [ ]; + pct = [ ]; + pstd = [ ]; + pjc = [ ]; + prc = [ ]; +} + +//////////////////////////////////////////////////////////////////////////////// + +hss_ec_value = NA; +rank_corr_flag = FALSE; +tmp_dir = "/tmp"; +version = "V12.0.0"; + +//////////////////////////////////////////////////////////////////////////////// diff --git a/internal/test_unit/xml/unit_climatology_1.0deg.xml b/internal/test_unit/xml/unit_climatology_1.0deg.xml index fcd6b59668..699026825e 100644 --- a/internal/test_unit/xml/unit_climatology_1.0deg.xml +++ b/internal/test_unit/xml/unit_climatology_1.0deg.xml @@ -186,6 +186,34 @@ + + &MET_BIN;/series_analysis + + CLIMO_MEAN_FILE_LIST + "&DATA_DIR_CLIMO;/NCEP_NCAR_40YR_1.0deg/cmean_1d.19590409" + + + CLIMO_STDEV_FILE_LIST + "&DATA_DIR_CLIMO;/NCEP_NCAR_40YR_1.0deg/cstdv_1d.19590409" + + + + \ + -fcst &DATA_DIR_MODEL;/grib2/gfs/gfs_2012040900_F012.grib2 \ + &DATA_DIR_MODEL;/grib2/gfs/gfs_2012040900_F024.grib2 \ + &DATA_DIR_MODEL;/grib2/gfs/gfs_2012040900_F036.grib2 \ + -obs &DATA_DIR_MODEL;/grib2/gfsanl/gfsanl_4_20120409_1200_000.grb2 \ + &DATA_DIR_MODEL;/grib2/gfsanl/gfsanl_4_20120410_0000_000.grb2 \ + &DATA_DIR_MODEL;/grib2/gfsanl/gfsanl_4_20120410_1200_000.grb2 \ + -out &OUTPUT_DIR;/climatology_1.0deg/series_analysis_GFS_CLIMO_1.0DEG_CONST_CLIMO.nc \ + -config &CONFIG_DIR;/SeriesAnalysisConfig_const_climo \ + -v 3 + + + &OUTPUT_DIR;/climatology_1.0deg/series_analysis_GFS_CLIMO_1.0DEG_CONST_CLIMO.nc + + + &MET_BIN;/series_analysis diff --git a/src/tools/core/series_analysis/series_analysis.cc b/src/tools/core/series_analysis/series_analysis.cc index a43cb78807..a817768c3a 100644 --- a/src/tools/core/series_analysis/series_analysis.cc +++ b/src/tools/core/series_analysis/series_analysis.cc @@ -363,7 +363,7 @@ void process_command_line(int argc, char **argv) { if(fcst_files.n() != n_series_pair) { mlog << Error << "\nprocess_command_line() -> " << R"(when using the "-paired" command line option, the )" - << "the file list length (" << fcst_files.n() + << "file list length (" << fcst_files.n() << ") and series length (" << n_series_pair << ") must match.\n\n"; usage();