From dbc7d10ec9f82a1a8885c940d0dd5dcb8c8c41d4 Mon Sep 17 00:00:00 2001 From: George McCabe <23407799+georgemccabe@users.noreply.github.com> Date: Wed, 12 Jan 2022 15:30:46 -0700 Subject: [PATCH] Feature 1695 ensemble single file (gen_ens_prod) (#2001) Co-authored-by: johnhg --- met/data/config/GenEnsProdConfig_default | 7 + met/docs/Users_Guide/gen-ens-prod.rst | 46 +++- met/src/basic/vx_config/config_constants.h | 2 + met/src/basic/vx_config/config_file.cc | 2 +- met/src/basic/vx_config/config_util.cc | 16 ++ met/src/basic/vx_config/config_util.h | 1 + met/src/basic/vx_config/dictionary.cc | 29 ++- met/src/basic/vx_config/dictionary.h | 5 +- met/src/basic/vx_log/file_fxns.h | 1 - .../ensemble_stat/ensemble_stat_conf_info.h | 1 + .../tools/other/gen_ens_prod/gen_ens_prod.cc | 212 +++++++++-------- .../tools/other/gen_ens_prod/gen_ens_prod.h | 2 +- .../gen_ens_prod/gen_ens_prod_conf_info.cc | 223 ++++++++++++++++-- .../gen_ens_prod/gen_ens_prod_conf_info.h | 48 +++- .../other/mode_graphics/plot_mode_field.cc | 2 +- scripts/environment/development.seneca | 2 +- test/config/GenEnsProdConfig | 7 + test/config/GenEnsProdConfig_single_file_grib | 149 ++++++++++++ test/config/GenEnsProdConfig_single_file_nc | 149 ++++++++++++ test/xml/unit_gen_ens_prod.xml | 56 ++++- 20 files changed, 819 insertions(+), 141 deletions(-) create mode 100644 test/config/GenEnsProdConfig_single_file_grib create mode 100644 test/config/GenEnsProdConfig_single_file_nc diff --git a/met/data/config/GenEnsProdConfig_default b/met/data/config/GenEnsProdConfig_default index fbe81a00f4..09746b626e 100644 --- a/met/data/config/GenEnsProdConfig_default +++ b/met/data/config/GenEnsProdConfig_default @@ -57,6 +57,13 @@ ens = { ]; } +// +// IDs for ensemble members +// Only set if processing a single file with all ensembles +// +ens_member_ids = []; +control_id = ""; + //////////////////////////////////////////////////////////////////////////////// // diff --git a/met/docs/Users_Guide/gen-ens-prod.rst b/met/docs/Users_Guide/gen-ens-prod.rst index 029d256ad2..459a9778f1 100644 --- a/met/docs/Users_Guide/gen-ens-prod.rst +++ b/met/docs/Users_Guide/gen-ens-prod.rst @@ -67,7 +67,7 @@ Required arguments gen_ens_prod Optional arguments for gen_ens_prod ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -4. The **-ctrl file** option specifies the input file for the ensemble control member. Data for this member is included in the computation of the ensemble mean, but excluded from the spread. The control file should not appear in the **-ens** list of ensemble member files. +4. The **-ctrl file** option specifies the input file for the ensemble control member. Data for this member is included in the computation of the ensemble mean, but excluded from the spread. The control file should not appear in the **-ens** list of ensemble member files (unless processing a single file that contains all ensemble members). 5. The **-log** file outputs log messages to the specified file. @@ -134,6 +134,50 @@ For each dictionary entry in the **field** array, give the name and vertical or _______________________ +.. code-block:: none + + ens_member_ids = []; + control_id = ""; + +The **ens_member_ids** array is only used if reading a single file that contains all ensemble members. +It should contain a list of string identifiers that are substituted into the **ens** dictionary fields +to determine which data to read from the file. +The length of the array determines how many ensemble members will be processed for a given field. +Each value in the array will replace the text **MET_ENS_MEMBER_ID**. + +**NetCDF Example:** + +.. code-block:: none + + ens = { + field = [ + { + name = "fcst"; + level = "(MET_ENS_MEMBER_ID,0,*,*)"; + } + ]; + } + +**GRIB Example:** + +.. code-block:: none + + ens = { + field = [ + { + name = "fcst"; + level = "L0"; + GRIB_ens = "+MET_ENS_MEMBER_ID"; + } + ]; + } + +**control_id** is a string that is substituted in the same way as the **ens_member_ids** values +to read a control member. This value is only used when the **-ctrl** command line argument is +used. The value should not be found in the **ens_member_ids** array. + +_______________________ + .. code-block:: none nbrhd_prob = { diff --git a/met/src/basic/vx_config/config_constants.h b/met/src/basic/vx_config/config_constants.h index 01c598bd72..01f03b3840 100644 --- a/met/src/basic/vx_config/config_constants.h +++ b/met/src/basic/vx_config/config_constants.h @@ -632,6 +632,8 @@ static const char conf_key_eclv_points[] = "eclv_points"; static const char conf_key_var_name_map[] = "var_name_map"; static const char conf_key_metadata_map[] = "metadata_map"; static const char conf_key_missing_thresh[] = "missing_thresh"; +static const char conf_key_control_id[] = "control_id"; +static const char conf_key_ens_member_ids[] = "ens_member_ids"; // // Entries to override file metadata diff --git a/met/src/basic/vx_config/config_file.cc b/met/src/basic/vx_config/config_file.cc index a7b1377405..1e229d5aa9 100644 --- a/met/src/basic/vx_config/config_file.cc +++ b/met/src/basic/vx_config/config_file.cc @@ -252,7 +252,7 @@ ConcatString MetConfig::get_tmp_dir() // Use the MET_TMP_DIR environment variable, if set. if(!get_env("MET_TMP_DIR", tmp_dir)) { const DictionaryEntry * _e = lookup(conf_key_tmp_dir); - if ( LastLookupStatus ) tmp_dir = *(_e->string_value()); + if ( LastLookupStatus ) tmp_dir = _e->string_value(); else tmp_dir = default_tmp_dir; } diff --git a/met/src/basic/vx_config/config_util.cc b/met/src/basic/vx_config/config_util.cc index 934bec72b9..1218e2940d 100644 --- a/met/src/basic/vx_config/config_util.cc +++ b/met/src/basic/vx_config/config_util.cc @@ -2965,3 +2965,19 @@ ConcatString wavelettype_to_string(WaveletType type) { } /////////////////////////////////////////////////////////////////////////////// + +StringArray parse_conf_ens_member_ids(Dictionary *dict) { + const char *method_name = "parse_conf_ens_member_ids() -> "; + + StringArray sa = parse_conf_string_array(dict, conf_key_ens_member_ids, method_name); + + if(sa.n() > 0) { + mlog << Debug(4) << method_name + << "Ensemble Member IDs \"" << conf_key_ens_member_ids << "\" list contains " + << sa.n() << " entries.\n"; + } + + return(sa); +} + +/////////////////////////////////////////////////////////////////////////////// diff --git a/met/src/basic/vx_config/config_util.h b/met/src/basic/vx_config/config_util.h index 5e83b2c6aa..ff9d38e7d4 100644 --- a/met/src/basic/vx_config/config_util.h +++ b/met/src/basic/vx_config/config_util.h @@ -73,6 +73,7 @@ extern map parse_conf_filter_attr_map(Dictionary *dict); extern void parse_conf_range_int(Dictionary *dict, int &beg, int &end); extern void parse_conf_range_double(Dictionary *dict, double &beg, double &end); +extern StringArray parse_conf_ens_member_ids(Dictionary *dict); extern void check_mask_names(const StringArray &); diff --git a/met/src/basic/vx_config/dictionary.cc b/met/src/basic/vx_config/dictionary.cc index 55ef59a0ac..f090916ace 100644 --- a/met/src/basic/vx_config/dictionary.cc +++ b/met/src/basic/vx_config/dictionary.cc @@ -762,21 +762,30 @@ return ( Bval ); //////////////////////////////////////////////////////////////////////// -const ConcatString * DictionaryEntry::string_value() const +const ConcatString DictionaryEntry::string_value() const { -if ( Type != StringType ) { + if ( Type != StringType ) { - mlog << Error - << "\nDictionaryEntry::string_value() -> bad type\n\n"; + mlog << Error + << "\nDictionaryEntry::string_value() -> bad type\n\n"; - exit ( 1 ); + exit ( 1 ); -} + } + + ConcatString sub_text = ConcatString(*Text); + ConcatString cur_env_val; + if ( get_env(met_ens_member_id, cur_env_val) ) { + if(!cur_env_val.empty()) { + sub_text.replace(met_ens_member_id, cur_env_val.c_str(), false); + } + + } -return ( Text ); + return ( sub_text ); } @@ -1816,7 +1825,7 @@ if ( !Entry || !is_correct_type ) { } -return ( *(Entry->string_value()) ); +return ( Entry->string_value() ); } @@ -1874,7 +1883,7 @@ if ( !Entry || !is_correct_type ) { if ( Entry->type() == StringType ) { - array.add( *(Entry->string_value()) ); + array.add( Entry->string_value() ); return ( array ); @@ -1911,7 +1920,7 @@ if ( Dict->n_entries() > 0 ) { for (int i=0; in_entries(); i++) { - array.add(*(*Dict)[i]->string_value()); + array.add((*Dict)[i]->string_value()); } diff --git a/met/src/basic/vx_config/dictionary.h b/met/src/basic/vx_config/dictionary.h index a39949be04..3a90e047e5 100644 --- a/met/src/basic/vx_config/dictionary.h +++ b/met/src/basic/vx_config/dictionary.h @@ -40,6 +40,9 @@ class Dictionary; // forward reference //////////////////////////////////////////////////////////////////////// +static const char met_ens_member_id [] = "MET_ENS_MEMBER_ID"; + +//////////////////////////////////////////////////////////////////////// class DictionaryEntry { @@ -122,7 +125,7 @@ class DictionaryEntry { int n_args () const; - const ConcatString * string_value () const; + const ConcatString string_value () const; Dictionary * dict_value () const; diff --git a/met/src/basic/vx_log/file_fxns.h b/met/src/basic/vx_log/file_fxns.h index 4b868bbdbf..f5d571962d 100644 --- a/met/src/basic/vx_log/file_fxns.h +++ b/met/src/basic/vx_log/file_fxns.h @@ -22,7 +22,6 @@ #include #include "concat_string.h" -#include "file_fxns.h" //////////////////////////////////////////////////////////////////////// diff --git a/met/src/tools/core/ensemble_stat/ensemble_stat_conf_info.h b/met/src/tools/core/ensemble_stat/ensemble_stat_conf_info.h index 7148109bba..df46f8ecf7 100644 --- a/met/src/tools/core/ensemble_stat/ensemble_stat_conf_info.h +++ b/met/src/tools/core/ensemble_stat/ensemble_stat_conf_info.h @@ -95,6 +95,7 @@ class EnsembleStatVxOpt { VxPairDataEnsemble vx_pd; // Ensemble pair data ConcatString var_str; // nc_pairs_var_str string + ConcatString control_id; // Control ID int beg_ds; // Begin observation time window offset int end_ds; // End observation time window offset diff --git a/met/src/tools/other/gen_ens_prod/gen_ens_prod.cc b/met/src/tools/other/gen_ens_prod/gen_ens_prod.cc index c7b48a7331..1f634c38b2 100644 --- a/met/src/tools/other/gen_ens_prod/gen_ens_prod.cc +++ b/met/src/tools/other/gen_ens_prod/gen_ens_prod.cc @@ -53,17 +53,17 @@ static void process_ensemble(); static bool get_data_plane(const char *, GrdFileType, VarInfo *, DataPlane &); static void clear_counts(); -static void track_counts(int, const DataPlane &, bool, +static void track_counts(EnsVarInfo *, const DataPlane &, bool, const DataPlane &, const DataPlane &); static void setup_nc_file(); -static void write_ens_nc(int, int, const DataPlane &, +static void write_ens_nc(EnsVarInfo *, int, const DataPlane &, const DataPlane &, const DataPlane &); -static void write_ens_var_float(int, float *, const DataPlane &, +static void write_ens_var_float(EnsVarInfo *, float *, const DataPlane &, const char *, const char *); -static void write_ens_var_int(int, int *, const DataPlane &, +static void write_ens_var_int(EnsVarInfo *, int *, const DataPlane &, const char *, const char *); -static void write_ens_data_plane(int, const DataPlane &, const DataPlane &, +static void write_ens_data_plane(EnsVarInfo *, const DataPlane &, const DataPlane &, const char *, const char *); static void add_var_att_local(VarInfo *, NcVar *, bool is_int, @@ -136,8 +136,8 @@ void process_command_line(int argc, char **argv) { if(cline.n() != 0) usage(); // Check that the required arguments have been set - n_ens = ens_files.n(); - if(ens_files.n() == 0) { + n_ens_files = ens_files.n(); + if(n_ens_files == 0) { mlog << Error << "\nprocess_command_line() -> " << "the ensemble file list must be set using the " << "\"-ens\" option.\n\n"; @@ -181,7 +181,7 @@ void process_command_line(int argc, char **argv) { etype = ens_mtddf->file_type(); // Process the configuration - conf_info.process_config(etype); + conf_info.process_config(etype, &ens_files); // Allocate arrays to store threshold counts thresh_cnt_na = new NumArray [conf_info.get_max_n_cat()]; @@ -193,8 +193,8 @@ void process_command_line(int argc, char **argv) { // List the input ensemble files mlog << Debug(1) << "Ensemble Files[" - << ens_files.n() << "]:\n"; - for(i=0; i " << "the ensemble control file should not appear in the list " << "of ensemble member files:\n" << ctrl_file << "\n\n"; @@ -211,7 +211,7 @@ void process_command_line(int argc, char **argv) { } // Check for missing non-python ensemble files - for(i=0; i " @@ -224,6 +224,12 @@ void process_command_line(int argc, char **argv) { } } + if(conf_info.control_id.nonempty() && ctrl_file.empty()) { + mlog << Warning << "\nprocess_command_line() -> " + << "control_id is set in the config file but " + << "control file is not provided with -ctrl argument\n\n"; + } + // Deallocate memory for data files if(ens_mtddf) { delete ens_mtddf; ens_mtddf = (Met2dDataFile *) 0; } @@ -238,7 +244,7 @@ void process_grid(const Grid &fcst_grid) { // Parse regridding logic RegridInfo ri; if(conf_info.get_n_var() > 0) { - ri = conf_info.ens_info[0]->regrid(); + ri = conf_info.ens_input[0]->get_var_info()->regrid(); } else { mlog << Error << "\nprocess_grid() -> " @@ -308,33 +314,45 @@ bool get_data_plane(const char *infile, GrdFileType ftype, //////////////////////////////////////////////////////////////////////// void process_ensemble() { - int i_var, i_file, n_ens_vld; + int i_var, i_ens, n_ens_vld, n_ens_inputs; bool need_reset; DataPlane ens_dp, ctrl_dp, cmn_dp, csd_dp; unixtime max_init_ut = bad_data_ll; + VarInfo * var_info; + ConcatString ens_file; // Loop through each of the ensemble fields to be processed - for(i_var=0; i_var::const_iterator var_it = conf_info.ens_input.begin(); + for(i_var=0; var_it != conf_info.ens_input.end(); var_it++, i_var++) { + + // Need to reinitialize counts and sums for each ensemble field + need_reset = true; + var_info = (*var_it)->get_var_info(); mlog << Debug(2) << "\n" << sep_str << "\n\n" << "Processing ensemble field: " - << conf_info.ens_info[i_var]->magic_str() << "\n"; + << (*var_it)->raw_magic_str << "\n"; - // Need to reinitialize counts and sums for each ensemble field - need_reset = true; + n_ens_inputs = (*var_it)->inputs_n(); + for(i_ens=n_ens_vld=0; i_ens < n_ens_inputs; i_ens++) { - // Loop through the ensemble member files - for(i_file=0, n_ens_vld=0; i_fileget_file(i_ens); + var_info = (*var_it)->get_var_info(i_ens); // Skip bad data files - if(!ens_file_vld[i_file]) continue; + if(!ens_file_vld[(*var_it)->get_file_index(i_ens)]) continue; + + mlog << Debug(3) << "\n" + << "Reading field: " + << var_info->magic_str() << "\n"; // Read data and track the valid data count - if(!get_data_plane(ens_files[i_file].c_str(), etype, - conf_info.ens_info[i_var], ens_dp)) { + if(!get_data_plane(ens_file.c_str(), etype, + var_info, ens_dp)) { mlog << Warning << "\nprocess_ensemble() -> " - << "ensemble field \"" << conf_info.ens_info[i_var]->magic_str() - << "\" not found in file \"" << ens_files[i_file] << "\"\n\n"; + << "ensemble field \"" << var_info->magic_str() + << "\" not found in file \"" << ens_file << "\"\n\n"; continue; } else { @@ -360,19 +378,24 @@ void process_ensemble() { // Read ensemble control member data, if provided if(ctrl_file.nonempty()) { + VarInfo * ctrl_info = (*var_it)->get_ctrl(i_ens); + + mlog << Debug(3) << "\n" + << "Reading control field: " + << ctrl_info->magic_str() << "\n"; // Error out if missing if(!get_data_plane(ctrl_file.c_str(), etype, - conf_info.ens_info[i_var], ctrl_dp)) { + ctrl_info, ctrl_dp)) { mlog << Error << "\nprocess_ensemble() -> " << "control member ensemble field \"" - << conf_info.ens_info[i_var]->magic_str() + << ctrl_info->magic_str() << "\" not found in file \"" << ctrl_file << "\"\n\n"; exit(1); } // Apply current data to the running sums and counts - track_counts(i_var, ctrl_dp, true, cmn_dp, csd_dp); + track_counts(*var_it, ctrl_dp, true, cmn_dp, csd_dp); } // end if ctrl_file @@ -381,26 +404,27 @@ void process_ensemble() { << " control member, " << (cmn_dp.is_empty() ? 0 : 1) << " climatology mean, and " << (csd_dp.is_empty() ? 0 : 1) << " climatology standard deviation field(s) for \"" - << conf_info.ens_info[i_var]->magic_str() << "\".\n"; + << var_info->magic_str() << "\".\n"; } // end if need_reset // Apply current data to the running sums and counts - track_counts(i_var, ens_dp, false, cmn_dp, csd_dp); + track_counts(*var_it, ens_dp, false, cmn_dp, csd_dp); // Keep track of the maximum initialization time if(is_bad_data(max_init_ut) || ens_dp.init() > max_init_ut) { max_init_ut = ens_dp.init(); } - } // end for i_file + } // end for it // Check for too much missing data - if(((double) n_ens_vld/n_ens) < conf_info.vld_ens_thresh) { + if(((double) n_ens_vld/n_ens_inputs) < conf_info.vld_ens_thresh) { mlog << Error << "\nprocess_ensemble() -> " - << n_ens - n_ens_vld << " of " << n_ens - << " missing fields for \"" << conf_info.ens_info[i_var]->magic_str() - << "\" exceeds the maximum allowable specified by \"" + << n_ens_vld << " of " << n_ens_inputs + << " (" << (double)n_ens_vld/n_ens_inputs << ")" + << " fields found for \"" << (*var_it)->get_var_info()->magic_str() + << "\" does not meet the threshold specified by \"" << conf_key_ens_ens_thresh << "\" (" << conf_info.vld_ens_thresh << ") in the configuration file.\n\n"; exit(1); @@ -408,9 +432,9 @@ void process_ensemble() { // Write out the ensemble information to a NetCDF file ens_dp.set_init(max_init_ut); - write_ens_nc(i_var, n_ens_vld, ens_dp, cmn_dp, csd_dp); + write_ens_nc(*var_it, n_ens_vld, ens_dp, cmn_dp, csd_dp); - } // end for i_var + } // end for var_it return; } @@ -441,14 +465,14 @@ void clear_counts() { //////////////////////////////////////////////////////////////////////// -void track_counts(int i_var, const DataPlane &ens_dp, bool is_ctrl, +void track_counts(EnsVarInfo * ens_info, const DataPlane &ens_dp, bool is_ctrl, const DataPlane &cmn_dp, const DataPlane &csd_dp) { int i, j, k; double ens, cmn, csd; // Ensemble thresholds - const int n_thr = conf_info.cat_ta[i_var].n(); - SingleThresh *thr_buf = conf_info.cat_ta[i_var].buf(); + const int n_thr = ens_info->cat_ta.n(); + SingleThresh *thr_buf = ens_info->cat_ta.buf(); // Increment counts for each grid point for(i=0; i 0 - if(conf_info.nc_info[i_var].do_nmep) { + if(ens_info->nc_info.do_nmep) { DataPlane frac_dp; // Loop over thresholds @@ -543,7 +567,7 @@ void setup_nc_file() { lon_dim = add_dim(nc_out, "lon", (long) grid.nx()); // Add the lat/lon variables - if(conf_info.nc_info[0].do_latlon) { + if(conf_info.ens_input[0]->nc_info.do_latlon) { write_netcdf_latlon(nc_out, &lat_dim, &lon_dim, grid); } @@ -552,7 +576,7 @@ void setup_nc_file() { //////////////////////////////////////////////////////////////////////// -void write_ens_nc(int i_var, int n_ens_vld, +void write_ens_nc(EnsVarInfo * ens_info, int n_ens_vld, const DataPlane &ens_dp, const DataPlane &cmn_dp, const DataPlane &csd_dp) { @@ -605,69 +629,69 @@ void write_ens_nc(int i_var, int n_ens_vld, } // end for i // Add the ensemble mean, if requested - if(conf_info.nc_info[i_var].do_mean) { - write_ens_var_float(i_var, ens_mean, ens_dp, + if(ens_info->nc_info.do_mean) { + write_ens_var_float(ens_info, ens_mean, ens_dp, "ENS_MEAN", "Ensemble Mean"); } // Add the ensemble standard deviation, if requested - if(conf_info.nc_info[i_var].do_stdev) { - write_ens_var_float(i_var, ens_stdev, ens_dp, + if(ens_info->nc_info.do_stdev) { + write_ens_var_float(ens_info, ens_stdev, ens_dp, "ENS_STDEV", "Ensemble Standard Deviation"); } // Add the ensemble mean minus one standard deviation, if requested - if(conf_info.nc_info[i_var].do_minus) { - write_ens_var_float(i_var, ens_minus, ens_dp, + if(ens_info->nc_info.do_minus) { + write_ens_var_float(ens_info, ens_minus, ens_dp, "ENS_MINUS", "Ensemble Mean Minus 1 Standard Deviation"); } // Add the ensemble mean plus one standard deviation, if requested - if(conf_info.nc_info[i_var].do_plus) { - write_ens_var_float(i_var, ens_plus, ens_dp, + if(ens_info->nc_info.do_plus) { + write_ens_var_float(ens_info, ens_plus, ens_dp, "ENS_PLUS", "Ensemble Mean Plus 1 Standard Deviation"); } // Add the ensemble minimum value, if requested - if(conf_info.nc_info[i_var].do_min) { - write_ens_var_float(i_var, ens_min, ens_dp, + if(ens_info->nc_info.do_min) { + write_ens_var_float(ens_info, ens_min, ens_dp, "ENS_MIN", "Ensemble Minimum"); } // Add the ensemble maximum value, if requested - if(conf_info.nc_info[i_var].do_max) { - write_ens_var_float(i_var, ens_max, ens_dp, + if(ens_info->nc_info.do_max) { + write_ens_var_float(ens_info, ens_max, ens_dp, "ENS_MAX", "Ensemble Maximum"); } // Add the ensemble range, if requested - if(conf_info.nc_info[i_var].do_range) { - write_ens_var_float(i_var, ens_range, ens_dp, + if(ens_info->nc_info.do_range) { + write_ens_var_float(ens_info, ens_range, ens_dp, "ENS_RANGE", "Ensemble Range"); } // Add the ensemble valid data count, if requested - if(conf_info.nc_info[i_var].do_vld) { - write_ens_var_int(i_var, ens_vld, ens_dp, + if(ens_info->nc_info.do_vld) { + write_ens_var_int(ens_info, ens_vld, ens_dp, "ENS_VLD", "Ensemble Valid Data Count"); } // Add the ensemble relative frequencies and neighborhood probabilities, if requested - if(conf_info.nc_info[i_var].do_freq || - conf_info.nc_info[i_var].do_nep) { + if(ens_info->nc_info.do_freq || + ens_info->nc_info.do_nep) { prob_dp.set_size(grid.nx(), grid.ny()); // Loop through each threshold - for(i=0; icat_ta.n(); i++) { // Initialize prob_dp.erase(); @@ -680,15 +704,15 @@ void write_ens_nc(int i_var, int n_ens_vld, } // Write ensemble relative frequency - if(conf_info.nc_info[i_var].do_freq) { + if(ens_info->nc_info.do_freq) { snprintf(type_str, sizeof(type_str), "ENS_FREQ_%s", - conf_info.cat_ta[i_var][i].get_abbr_str().contents().c_str()); - write_ens_data_plane(i_var, prob_dp, ens_dp, type_str, + ens_info->cat_ta[i].get_abbr_str().contents().c_str()); + write_ens_data_plane(ens_info, prob_dp, ens_dp, type_str, "Ensemble Relative Frequency"); } // Process the neighborhood ensemble probability - if(conf_info.nc_info[i_var].do_nep) { + if(ens_info->nc_info.do_nep) { GaussianInfo info; // Loop over the neighborhoods @@ -701,10 +725,10 @@ void write_ens_nc(int i_var, int n_ens_vld, // Write neighborhood ensemble probability snprintf(type_str, sizeof(type_str), "ENS_NEP_%s_%s%i", - conf_info.cat_ta[i_var][i].get_abbr_str().contents().c_str(), + ens_info->cat_ta[i].get_abbr_str().contents().c_str(), interpmthd_to_string(InterpMthd_Nbrhd).c_str(), conf_info.nbrhd_prob.width[j]*conf_info.nbrhd_prob.width[j]); - write_ens_data_plane(i_var, nbrhd_dp, ens_dp, type_str, + write_ens_data_plane(ens_info, nbrhd_dp, ens_dp, type_str, "Neighborhood Ensemble Probability"); } // end for k } // end if do_nep @@ -712,12 +736,12 @@ void write_ens_nc(int i_var, int n_ens_vld, } // end if // Add the neighborhood maximum ensemble probabilities, if requested - if(conf_info.nc_info[i_var].do_nmep) { + if(ens_info->nc_info.do_nmep) { prob_dp.set_size(grid.nx(), grid.ny()); // Loop through each threshold - for(i=0; icat_ta.n(); i++) { // Loop through each neigbhorhood size for(j=0; jcat_ta[i].get_abbr_str().contents().c_str(), interpmthd_to_string(InterpMthd_Nbrhd).c_str(), conf_info.nbrhd_prob.width[j]*conf_info.nbrhd_prob.width[j], conf_info.nmep_smooth.method[k].c_str(), conf_info.nmep_smooth.width[k]*conf_info.nmep_smooth.width[k]); - write_ens_data_plane(i_var, nbrhd_dp, ens_dp, type_str, + write_ens_data_plane(ens_info, nbrhd_dp, ens_dp, type_str, "Neighborhood Maximum Ensemble Probability"); } // end for k } // end for j @@ -757,26 +781,26 @@ void write_ens_nc(int i_var, int n_ens_vld, } // end if do_nep // Write the climo mean field, if requested - if(conf_info.nc_info[i_var].do_climo && !cmn_dp.is_empty()) { - write_ens_data_plane(i_var, cmn_dp, ens_dp, + if(ens_info->nc_info.do_climo && !cmn_dp.is_empty()) { + write_ens_data_plane(ens_info, cmn_dp, ens_dp, "CLIMO_MEAN", "Climatology mean"); } // Write the climo stdev field, if requested - if(conf_info.nc_info[i_var].do_climo && !csd_dp.is_empty()) { - write_ens_data_plane(i_var, csd_dp, ens_dp, + if(ens_info->nc_info.do_climo && !csd_dp.is_empty()) { + write_ens_data_plane(ens_info, csd_dp, ens_dp, "CLIMO_STDEV", "Climatology standard deviation"); } // Write the climo distribution percentile thresholds, if requested - if(conf_info.nc_info[i_var].do_climo_cdp && + if(ens_info->nc_info.do_climo_cdp && !cmn_dp.is_empty() && !csd_dp.is_empty()) { DataPlane cdp_dp; vector simp; - conf_info.cat_ta[i_var].get_simple_nodes(simp); + ens_info->cat_ta.get_simple_nodes(simp); // Process all CDP thresholds except 0 and 100 for(vector::iterator it = simp.begin(); @@ -787,7 +811,7 @@ void write_ens_nc(int i_var, int n_ens_vld, snprintf(type_str, sizeof(type_str), "CLIMO_CDP%i", nint(it->pvalue())); cdp_dp = normal_cdf_inv(it->pvalue()/100.0, cmn_dp, csd_dp); - write_ens_data_plane(i_var, cdp_dp, ens_dp, + write_ens_data_plane(ens_info, cdp_dp, ens_dp, type_str, "Climatology distribution percentile"); } @@ -809,20 +833,20 @@ void write_ens_nc(int i_var, int n_ens_vld, //////////////////////////////////////////////////////////////////////// -void write_ens_var_float(int i_var, float *ens_data, const DataPlane &dp, +void write_ens_var_float(EnsVarInfo * ens_info, float *ens_data, const DataPlane &dp, const char *type_str, const char *long_name_str) { NcVar ens_var; ConcatString ens_var_name, var_str, name_str, cs; // Append nc_var_str config file entry - cs = conf_info.nc_var_str[i_var]; + cs = ens_info->nc_var_str; if(cs.length() > 0) var_str << "_" << cs; // Construct the variable name ens_var_name << cs_erase - << conf_info.ens_info[i_var]->name_attr() << "_" - << conf_info.ens_info[i_var]->level_attr() + << ens_info->get_var_info()->name_attr() << "_" + << ens_info->get_var_info()->level_attr() << var_str << "_" << type_str; // Skip variable names that have already been written @@ -840,16 +864,16 @@ void write_ens_var_float(int i_var, float *ens_data, const DataPlane &dp, // if(strcmp(type_str, "ENS_MEAN") == 0) { name_str << cs_erase - << conf_info.ens_info[i_var]->name_attr(); + << ens_info->get_var_info()->name_attr(); } else { name_str << cs_erase - << conf_info.ens_info[i_var]->name_attr() << "_" + << ens_info->get_var_info()->name_attr() << "_" << type_str; } // Add the variable attributes - add_var_att_local(conf_info.ens_info[i_var], &ens_var, false, dp, + add_var_att_local(ens_info->get_var_info(), &ens_var, false, dp, name_str.c_str(), long_name_str); // Write the data @@ -865,20 +889,20 @@ void write_ens_var_float(int i_var, float *ens_data, const DataPlane &dp, //////////////////////////////////////////////////////////////////////// -void write_ens_var_int(int i_var, int *ens_data, const DataPlane &dp, +void write_ens_var_int(EnsVarInfo * ens_info, int *ens_data, const DataPlane &dp, const char *type_str, const char *long_name_str) { NcVar ens_var; ConcatString ens_var_name, var_str, name_str, cs; // Append nc_var_str config file entry - cs = conf_info.nc_var_str[i_var]; + cs = ens_info->nc_var_str; if(cs.length() > 0) var_str << "_" << cs; // Construct the variable name ens_var_name << cs_erase - << conf_info.ens_info[i_var]->name_attr() << "_" - << conf_info.ens_info[i_var]->level_attr() + << ens_info->get_var_info()->name_attr() << "_" + << ens_info->get_var_info()->level_attr() << var_str << "_" << type_str; // Skip variable names that have already been written @@ -892,11 +916,11 @@ void write_ens_var_int(int i_var, int *ens_data, const DataPlane &dp, // Construct the variable name attribute name_str << cs_erase - << conf_info.ens_info[i_var]->name_attr() << "_" + << ens_info->get_var_info()->name_attr() << "_" << type_str; // Add the variable attributes - add_var_att_local(conf_info.ens_info[i_var], &ens_var, true, dp, + add_var_att_local(ens_info->get_var_info(), &ens_var, true, dp, name_str.c_str(), long_name_str); // Write the data @@ -912,7 +936,7 @@ void write_ens_var_int(int i_var, int *ens_data, const DataPlane &dp, //////////////////////////////////////////////////////////////////////// -void write_ens_data_plane(int i_var, const DataPlane &ens_dp, const DataPlane &dp, +void write_ens_data_plane(EnsVarInfo * ens_info, const DataPlane &ens_dp, const DataPlane &dp, const char *type_str, const char *long_name_str) { // Allocate memory for this data @@ -922,7 +946,7 @@ void write_ens_data_plane(int i_var, const DataPlane &ens_dp, const DataPlane &d for(int i=0; i::const_iterator it; + vector::const_iterator var_it = ens_input.begin(); // Clear, erase, and initialize members model.clear(); desc.clear(); - for(it = ens_info.begin(); it != ens_info.end(); it++) { - if(*it) { delete *it; } + + for(; var_it != ens_input.end(); var_it++) { + + if(*var_it) { delete *var_it; } + } - ens_info.clear(); + ens_input.clear(); cdf_info.clear(); - cat_ta.clear(); - nc_var_str.clear(); nbrhd_prob.clear(); nmep_smooth.clear(); vld_ens_thresh = bad_data_double; vld_data_thresh = bad_data_double; - nc_info.clear(); version.clear(); // Reset counts @@ -100,12 +100,18 @@ void GenEnsProdConfInfo::read_config(const ConcatString default_file_name, //////////////////////////////////////////////////////////////////////// -void GenEnsProdConfInfo::process_config(GrdFileType etype) { - int i; +void GenEnsProdConfInfo::process_config(GrdFileType etype, StringArray * ens_files) { + int i, j; VarInfoFactory info_factory; Dictionary *edict = (Dictionary *) 0; Dictionary i_edict; InterpMthd mthd; + VarInfo * next_var; + + int n_ens_files = ens_files->n(); + + // Unset MET_ENS_MEMBER_ID in case it is set by the user + unsetenv(met_ens_member_id); // Dump the contents of the config file if(mlog.verbosity_level() >= 5) conf.dump(cout); @@ -122,6 +128,38 @@ void GenEnsProdConfInfo::process_config(GrdFileType etype) { // Conf: desc desc = parse_conf_string(&conf, conf_key_desc); + // Conf: ens_member_ids + ens_member_ids = parse_conf_ens_member_ids(&conf); + + // Conf: control_id + control_id = parse_conf_string(&conf, conf_key_control_id, false); + + // Error check ens_member_ids and ensemble file list + if(ens_member_ids.n() > 1) { + + // Only a single file should be provided if using ens_member_ids + if(n_ens_files > 1) { + mlog << Error << "\nGenEnsProdConfInfo::process_config() -> " + << "The \"" << conf_key_ens_member_ids << "\" " + << "must be empty if more than " + << "one file is provided.\n\n"; + exit(1); + } + + // If control ID is set, it cannot be found in ens_member_ids + if(!control_id.empty() && ens_member_ids.has(control_id)) { + mlog << Error << "\nGenEnsProdConfInfo::process_config() -> " + << "control_id (" << control_id << ") must not be found " + << "in ens_member_ids\n\n"; + exit(1); + } + } + + // If no ensemble member IDs were provided, add an empty string + if(ens_member_ids.n() == 0) { + ens_member_ids.add(""); + } + // Conf: ens.field edict = conf.lookup_array(conf_key_ens_field); @@ -136,41 +174,87 @@ void GenEnsProdConfInfo::process_config(GrdFileType etype) { // Parse the ensemble field information for(i=0,max_n_cat=0; iset_dict(i_edict); + // get VarInfo magic string without substituted values + ens_info->raw_magic_str = raw_magic_str(i_edict); - // Dump the contents of the current VarInfo - if(mlog.verbosity_level() >= 5) { - mlog << Debug(5) - << "Parsed ensemble field number " << i+1 << ":\n"; - ens_info[i]->dump(cout); + // Loop over ensemble member IDs to substitute + for(j=0; jset_dict(i_edict); + + // Dump the contents of the current VarInfo + if(mlog.verbosity_level() >= 5) { + mlog << Debug(5) + << "Parsed ensemble field number " << i+1 + << " (" << j+1 << "):\n"; + next_var->dump(cout); + } + + InputInfo input_info; + input_info.var_info = next_var; + input_info.file_index = 0; + input_info.file_list = ens_files; + ens_info->add_input(input_info); + + // Add InputInfo to ens info list for each ensemble file provided + // set var_info to NULL to note first VarInfo should be used + for(int k=1; kadd_input(input_info); + } // end for k + + } // end for j + + // Get field info for control member if set + if(!control_id.empty()) { + + // Set environment variable for ens member ID + setenv(met_ens_member_id, control_id.c_str(), 1); + + // Allocate new VarInfo object + next_var = info_factory.new_var_info(etype); + + // Set the current dictionary + next_var->set_dict(i_edict); + + ens_info->set_ctrl(next_var); } // Conf: nc_var_str - nc_var_str.add(parse_conf_string(&i_edict, conf_key_nc_var_str, false)); + ens_info->nc_var_str =parse_conf_string(&i_edict, conf_key_nc_var_str, false); // Conf: cat_thresh - cat_ta.push_back(i_edict.lookup_thresh_array(conf_key_cat_thresh)); + ens_info->cat_ta = i_edict.lookup_thresh_array(conf_key_cat_thresh); // Dump the contents of the current thresholds if(mlog.verbosity_level() >= 5) { mlog << Debug(5) << "Parsed thresholds for ensemble field number " << i+1 << ":\n"; - cat_ta[i].dump(cout); + ens_info->cat_ta.dump(cout); } // Keep track of the maximum number of thresholds - if(cat_ta[i].n() > max_n_cat) max_n_cat = cat_ta[i].n(); + if(ens_info->cat_ta.n() > max_n_cat) max_n_cat = ens_info->cat_ta.n(); // Conf: ensemble_flag - nc_info.push_back(parse_nc_info(&i_edict)); - } + ens_info->nc_info = parse_nc_info(&i_edict); + + ens_input.push_back(ens_info); + } // end for i // Conf: ens.ens_thresh vld_ens_thresh = conf.lookup_double(conf_key_ens_ens_thresh); @@ -360,3 +444,94 @@ void GenEnsProdNcOutInfo::set_all_true() { } //////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////// +// +// Code for class EnsVarInfo +// +//////////////////////////////////////////////////////////////////////// + +EnsVarInfo::EnsVarInfo() { + ctrl_info = NULL; +} + +//////////////////////////////////////////////////////////////////////// + +EnsVarInfo::~EnsVarInfo() { + vector::const_iterator it; + for(it = inputs.begin(); it != inputs.end(); it++) { + if((*it).var_info) { delete (*it).var_info; } + } + + if(ctrl_info) { delete ctrl_info; } +} + +//////////////////////////////////////////////////////////////////////// + +void EnsVarInfo::add_input(InputInfo input) { + inputs.push_back(input); +} + +//////////////////////////////////////////////////////////////////////// + +int EnsVarInfo::inputs_n() { + return inputs.size(); +} + +//////////////////////////////////////////////////////////////////////// + +void EnsVarInfo::set_ctrl(VarInfo * ctrl) { + ctrl_info = ctrl; +} + +//////////////////////////////////////////////////////////////////////// + +VarInfo * EnsVarInfo::get_ctrl(int index) { + if(ctrl_info) { + return ctrl_info; + } + return inputs[index].var_info; +} + +//////////////////////////////////////////////////////////////////////// + +VarInfo * EnsVarInfo::get_var_info(int index) { + if(inputs[index].var_info) { + return inputs[index].var_info; + } + return inputs[0].var_info; +} + +//////////////////////////////////////////////////////////////////////// + +ConcatString EnsVarInfo::get_file(int index) { + int file_index = inputs[index].file_index; + return (*inputs[index].file_list)[file_index]; +} + +//////////////////////////////////////////////////////////////////////// + +int EnsVarInfo::get_file_index(int index) { + return inputs[index].file_index; +} + +//////////////////////////////////////////////////////////////////////// + +ConcatString raw_magic_str(Dictionary i_edict) { + ConcatString magic_str; + + ConcatString name = i_edict.lookup_string("name"); + ConcatString level = i_edict.lookup_string("level"); + + if(level.nonempty() && level[0] != '(') { + magic_str << name << "/" << level; + } else { + magic_str << name << level; + } + + return magic_str; + +} + +//////////////////////////////////////////////////////////////////////// diff --git a/met/src/tools/other/gen_ens_prod/gen_ens_prod_conf_info.h b/met/src/tools/other/gen_ens_prod/gen_ens_prod_conf_info.h index 2ec6014824..d0d5e60bbe 100644 --- a/met/src/tools/other/gen_ens_prod/gen_ens_prod_conf_info.h +++ b/met/src/tools/other/gen_ens_prod/gen_ens_prod_conf_info.h @@ -51,6 +51,43 @@ struct GenEnsProdNcOutInfo { void set_all_true(); }; + +//////////////////////////////////////////////////////////////////////// + +struct InputInfo { + VarInfo * var_info; // Variable information to read + int file_index; // Index in file_list of file to read + StringArray * file_list; // Array of files (unallocated) +}; + +//////////////////////////////////////////////////////////////////////// + +class EnsVarInfo { + + private: + vector inputs; // Vector of InputInfo + VarInfo * ctrl_info; // Field info for control member + public: + EnsVarInfo(); + ~EnsVarInfo(); + + void add_input(InputInfo); + int inputs_n(); + + void set_ctrl(VarInfo *); + VarInfo * get_ctrl(int); + + // Get VarInfo from first InputInfo if requested VarInfo is NULL + VarInfo * get_var_info(int index=0); + ConcatString get_file(int index=0); + int get_file_index(int index=0); + + ConcatString nc_var_str; // Ensemble variable name strings + ThreshArray cat_ta; // Ensemble categorical thresholds + GenEnsProdNcOutInfo nc_info; // Ensemble product outputs + ConcatString raw_magic_str; // Magic string w/o var substitution +}; + //////////////////////////////////////////////////////////////////////// class GenEnsProdConfInfo { @@ -76,12 +113,11 @@ class GenEnsProdConfInfo { // Data parsed from the Gen-Ens-Prod configuration object ConcatString model; // Model name ConcatString desc; // Description + ConcatString control_id; // Control ID - vector ens_info; // Array of VarInfo pointers (allocated) + vector ens_input; // Vector of EnsVarInfo pointers (allocated) vector cdf_info; // Array of climo CDF info objects - vector cat_ta; // Array for ensemble categorical thresholds - StringArray nc_var_str; // Array of ensemble variable name strings - vector nc_info; // Array of ensemble product outputs + StringArray ens_member_ids; // Array of ensemble member ID strings NbrhdInfo nbrhd_prob; // Neighborhood probability definition InterpInfo nmep_smooth; // Neighborhood maximum smoothing information @@ -96,7 +132,7 @@ class GenEnsProdConfInfo { void clear(); void read_config (const ConcatString, const ConcatString); - void process_config(GrdFileType); + void process_config(GrdFileType, StringArray *); GenEnsProdNcOutInfo parse_nc_info(Dictionary *); @@ -116,6 +152,8 @@ inline int GenEnsProdConfInfo::get_compression_level() { return(conf.nc_compress //////////////////////////////////////////////////////////////////////// +ConcatString raw_magic_str(Dictionary i_edict); + #endif /* __GEN_ENS_PROD_CONF_INFO_H__ */ //////////////////////////////////////////////////////////////////////// diff --git a/met/src/tools/other/mode_graphics/plot_mode_field.cc b/met/src/tools/other/mode_graphics/plot_mode_field.cc index 8d0894f154..ab77a6bb4c 100644 --- a/met/src/tools/other/mode_graphics/plot_mode_field.cc +++ b/met/src/tools/other/mode_graphics/plot_mode_field.cc @@ -1111,7 +1111,7 @@ if ( e->type() != StringType ) { } -s = *(e->string_value()); +s = e->string_value(); return ( s ); diff --git a/scripts/environment/development.seneca b/scripts/environment/development.seneca index 325e80ed3b..5b3497c0c1 100644 --- a/scripts/environment/development.seneca +++ b/scripts/environment/development.seneca @@ -48,5 +48,5 @@ export MET_TEST_RSCRIPT=/usr/local/R-4.1.2/bin/Rscript # - NetCDF is for ncdump. export PATH="/usr/local/nco/bin:/usr/local/netcdf/bin:\ /usr/local/sbin:/usr/local/bin:/usr/sbin:\ - /usr/bin:/sbin:/bin:/usr/bin/X11:/opt/bin" + /usr/bin:/sbin:/bin:/usr/bin/X11:/opt/bin:$PATH" diff --git a/test/config/GenEnsProdConfig b/test/config/GenEnsProdConfig index 33fcc2337f..3c4af297ef 100644 --- a/test/config/GenEnsProdConfig +++ b/test/config/GenEnsProdConfig @@ -74,6 +74,13 @@ ens = { ]; } +// +// IDs for ensemble members +// Only set if processing a single file with all ensembles +// +ens_member_ids = []; +control_id = ""; + //////////////////////////////////////////////////////////////////////////////// // diff --git a/test/config/GenEnsProdConfig_single_file_grib b/test/config/GenEnsProdConfig_single_file_grib new file mode 100644 index 0000000000..cc5edda640 --- /dev/null +++ b/test/config/GenEnsProdConfig_single_file_grib @@ -0,0 +1,149 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Gen-Ens-Prod configuration file. +// +// For additional information, please see the MET User's Guide. +// +//////////////////////////////////////////////////////////////////////////////// + +// +// Output model name to be written +// +model = "GEFS"; + +// +// Output description to be written +// May be set separately in each "obs.field" entry +// +desc = "NA"; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Verification grid +// May be set separately in each "field" entry +// +regrid = { + to_grid = NONE; + method = NEAREST; + width = 1; + vld_thresh = 0.5; + shape = SQUARE; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// May be set separately in each "field" entry +// +censor_thresh = []; +censor_val = []; +cat_thresh = []; +nc_var_str = ""; + +// +// Ensemble fields to be processed +// +ens = { + ens_thresh = 1.0; + vld_thresh = 1.0; + + field = [ + { + name = "PRMSL"; + level = "L0"; + lead_time = "06"; + GRIB_ens = "MET_ENS_MEMBER_ID"; + } + ]; +} + +// +// IDs for ensemble members +// Only set if processing a single file with all ensembles +// +ens_member_ids = ["+1", "+2", "+3", "+4", "+5", "+6", "+7", "+8", "+9", "+10", "+11", "+12", "+13", "+14", "+15", "+16", "+17", "+18", "+19", "+20"]; +control_id = "hi_res_ctl"; + +//////////////////////////////////////////////////////////////////////////////// + +// +// 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; + } + ]; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Climatology data +// +climo_mean = { + + file_name = []; + field = []; + + regrid = { + method = NEAREST; + width = 1; + vld_thresh = 0.5; + shape = SQUARE; + } + + time_interp_method = DW_MEAN; + day_interval = 31; + hour_interval = 6; +} + +climo_stdev = climo_mean; +climo_stdev = { + file_name = []; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Ensemble product output types +// May be set separately in each "ens.field" entry +// +ensemble_flag = { + latlon = TRUE; + mean = TRUE; + stdev = TRUE; + minus = TRUE; + plus = TRUE; + min = TRUE; + max = TRUE; + range = TRUE; + vld_count = TRUE; + frequency = TRUE; + nep = FALSE; + nmep = FALSE; + climo = FALSE; + climo_cdp = FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// + +version = "V10.1.0"; + +//////////////////////////////////////////////////////////////////////////////// diff --git a/test/config/GenEnsProdConfig_single_file_nc b/test/config/GenEnsProdConfig_single_file_nc new file mode 100644 index 0000000000..1049dc6a3a --- /dev/null +++ b/test/config/GenEnsProdConfig_single_file_nc @@ -0,0 +1,149 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Gen-Ens-Prod 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"; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Verification grid +// May be set separately in each "field" entry +// +regrid = { + to_grid = NONE; + method = NEAREST; + width = 1; + vld_thresh = 0.5; + shape = SQUARE; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// May be set separately in each "field" entry +// +censor_thresh = []; +censor_val = []; +cat_thresh = []; +nc_var_str = ""; + +// +// Ensemble fields to be processed +// +ens = { + file_type = NETCDF_NCCF; + ens_thresh = 1.0; + vld_thresh = 1.0; + + field = [ + { + name = "fcst"; + level = "(MET_ENS_MEMBER_ID,0,*,*)"; + cat_thresh = [ >0.0, >=5.0 ]; + } + ]; +} + +// +// IDs for ensemble members +// Only set if processing a single file with all ensembles +// +ens_member_ids = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23"]; +control_id = "0"; + +//////////////////////////////////////////////////////////////////////////////// + +// +// 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; + } + ]; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Climatology data +// +climo_mean = ens; +climo_mean = { + + file_name = []; + + regrid = { + method = NEAREST; + width = 1; + vld_thresh = 0.5; + shape = SQUARE; + } + + time_interp_method = DW_MEAN; + day_interval = 31; + hour_interval = 6; +} + +climo_stdev = climo_mean; +climo_stdev = { + file_name = []; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Ensemble product output types +// May be set separately in each "ens.field" entry +// +ensemble_flag = { + latlon = TRUE; + mean = TRUE; + stdev = TRUE; + minus = TRUE; + plus = TRUE; + min = TRUE; + max = TRUE; + range = TRUE; + vld_count = TRUE; + frequency = TRUE; + nep = FALSE; + nmep = FALSE; + climo = FALSE; + climo_cdp = FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// + +version = "V10.1.0"; + +//////////////////////////////////////////////////////////////////////////////// diff --git a/test/xml/unit_gen_ens_prod.xml b/test/xml/unit_gen_ens_prod.xml index 9d3f2b0c75..91f2321431 100644 --- a/test/xml/unit_gen_ens_prod.xml +++ b/test/xml/unit_gen_ens_prod.xml @@ -75,4 +75,58 @@ - + + &MET_BIN;/gen_ens_prod + \ + -ens &DATA_DIR_MODEL;/CPC_NMME/CFSv2.tmp2m.198201.fcst.nc \ + -config &CONFIG_DIR;/GenEnsProdConfig_single_file_nc \ + -out &OUTPUT_DIR;/gen_ens_prod/gen_ens_prod_SINGLE_FILE_NC_NO_CTRL.nc \ + -v 2 + + + &OUTPUT_DIR;/gen_ens_prod/gen_ens_prod_SINGLE_FILE_NC_NO_CTRL.nc + + + + + &MET_BIN;/gen_ens_prod + \ + -ens &DATA_DIR_MODEL;/CPC_NMME/CFSv2.tmp2m.198201.fcst.nc \ + -config &CONFIG_DIR;/GenEnsProdConfig_single_file_nc \ + -ctrl &DATA_DIR_MODEL;/CPC_NMME/CFSv2.tmp2m.198201.fcst.nc \ + -out &OUTPUT_DIR;/gen_ens_prod/gen_ens_prod_SINGLE_FILE_NC_WITH_CTRL.nc \ + -v 2 + + + &OUTPUT_DIR;/gen_ens_prod/gen_ens_prod_SINGLE_FILE_NC_WITH_CTRL.nc + + + + + &MET_BIN;/gen_ens_prod + \ + -ens &DATA_DIR_MODEL;/grib2/gefs/enspost_grb2.t00z.prmsl \ + -config &CONFIG_DIR;/GenEnsProdConfig_single_file_grib \ + -out &OUTPUT_DIR;/gen_ens_prod/gen_ens_prod_SINGLE_FILE_GRIB_NO_CTRL.nc \ + -v 2 + + + &OUTPUT_DIR;/gen_ens_prod/gen_ens_prod_SINGLE_FILE_GRIB_NO_CTRL.nc + + + + + &MET_BIN;/gen_ens_prod + \ + -ens &DATA_DIR_MODEL;/grib2/gefs/enspost_grb2.t00z.prmsl \ + -config &CONFIG_DIR;/GenEnsProdConfig_single_file_grib \ + -ctrl &DATA_DIR_MODEL;/grib2/gefs/enspost_grb2.t00z.prmsl \ + -out &OUTPUT_DIR;/gen_ens_prod/gen_ens_prod_SINGLE_FILE_GRIB_WITH_CTRL.nc \ + -v 2 + + + &OUTPUT_DIR;/gen_ens_prod/gen_ens_prod_SINGLE_FILE_GRIB_WITH_CTRL.nc + + + +