From 4a990ea0f44a629481cfd98e7b00926eaacbb616 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Wed, 22 Sep 2021 15:55:05 -0600 Subject: [PATCH] Per #1904, strip out the logic from Ensemble-Stat that does not apply to Gen-Ens-Prod. --- .../tools/other/gen_ens_prod/gen_ens_prod.cc | 2261 ++--------------- .../tools/other/gen_ens_prod/gen_ens_prod.h | 103 +- .../gen_ens_prod/gen_ens_prod_conf_info.cc | 892 +------ .../gen_ens_prod/gen_ens_prod_conf_info.h | 209 +- 4 files changed, 273 insertions(+), 3192 deletions(-) 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 e4feb58f0d..bc0bb5ea5e 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 @@ -14,51 +14,7 @@ // // Mod# Date Name Description // ---- ---- ---- ----------- -// 000 02/01/10 Halley Gotway New -// 001 09/09/11 Halley Gotway Call set_grid after reading -// gridded observation files. -// 002 10/13/11 Holmes Added use of command line class to -// parse the command line arguments. -// 003 10/18/11 Halley Gotway When the user requests verification -// in the config file, check that obs files have been -// specified on the command line. -// 004 11/14/11 Holmes Added code to enable reading of -// multiple config files. -// 005 12/09/11 Halley Gotway When gridded observations are -// missing, print a warning and continue rather than exiting -// with error status. -// 006 05/08/12 Halley Gotway Switch to using vx_config library. -// 007 05/08/12 Halley Gotway Move -ens_valid, -ens_lead, -// and -obs_lead command line options to config file. -// 008 05/18/12 Halley Gotway Modify logic to better handle -// missing files, fields, and data values. -// 009 08/30/12 Oldenburg Add spread/skill functionality -// 010 06/03/14 Halley Gotway Add PHIST line type -// 011 07/09/14 Halley Gotway Add station id exclusion option. -// 012 11/12/14 Halley Gotway Pass the obtype entry from the -// from the config file to the output files. -// 013 03/02/15 Halley Gotway Add automated regridding. -// 014 09/11/15 Halley Gotway Add climatology. -// 015 05/10/16 Halley Gotway Add grid weighting. -// 016 05/20/16 Prestopnik J Removed -version (now in command_line.cc) -// 017 08/09/16 Halley Gotway Fixed n_ens_vld vs n_vx_vld bug. -// 018 05/15/17 Prestonik P Add shape for regrid and interp. -// 019 05/15/17 Halley Gotway Add RELP line type and skip_const. -// 020 02/21/18 Halley Gotway Restructure config logic to make -// all options settable for each verification task. -// 021 03/21/18 Halley Gotway Add obs_error perturbation. -// 022 04/05/18 Halley Gotway Replace -ssvar_mean with -ens_mean. -// 023 08/15/18 Halley Gotway Add mask.llpnt type. -// 024 04/01/19 Fillmore Add FCST and OBS units. -// 025 04/15/19 Halley Gotway Add percentile thresholds. -// 026 11/26/19 Halley Gotway Add neighborhood probabilities. -// 027 12/11/19 Halley Gotway Reorganize logic to support the use -// of python embedding. -// 028 12/17/19 Halley Gotway Apply climatology bins to ensemble -// continuous statistics. -// 029 01/21/20 Halley Gotway Add RPS output line type. -// 030 02/19/21 Halley Gotway MET #1450, #1451 Overhaul CRPS -// statistics in the ECNT line type. +// 000 09/10/21 Halley Gotway Initial version (MET #1904). // //////////////////////////////////////////////////////////////////////// @@ -94,44 +50,18 @@ static void process_command_line (int, char **); static void process_grid (const Grid &); static void process_n_vld (); static void process_ensemble (); -static void process_vx (); static bool get_data_plane (const char *, GrdFileType, VarInfo *, DataPlane &, bool do_regrid); static bool get_data_plane_array (const char *, GrdFileType, VarInfo *, DataPlaneArray &, bool do_regrid); -static void process_point_vx (); -static void process_point_climo (); -static void process_point_obs (int); -static int process_point_ens (int, int &); -static void process_point_scores (); - -static void process_grid_vx (); -static void process_grid_scores (int, - const DataPlane *, const DataPlane *, - const DataPlane &, const DataPlane &, - const DataPlane &, const DataPlane &, - const DataPlane &, const MaskPlane &, - ObsErrorEntry *, PairDataEnsemble &); - -static void do_ecnt (const GenEnsProdVxOpt &, - const SingleThresh &, - const PairDataEnsemble *); -static void do_rps (const GenEnsProdVxOpt &, - const SingleThresh &, - const PairDataEnsemble *); - static void clear_counts(); static void track_counts(int, const DataPlane &); -static ConcatString get_ens_mn_var_name(int); - static void setup_nc_file (unixtime, const char *); static void setup_txt_files (); static void setup_table (AsciiTable &); -static void build_outfile_name(unixtime, const char *, - ConcatString &); static void write_ens_nc(int, DataPlane &); static void write_ens_var_float(int, float *, DataPlane &, const char *, const char *); @@ -152,13 +82,10 @@ static void clean_up(); static void usage(); -static void set_grid_obs(const StringArray &); -static void set_point_obs(const StringArray &); -static void set_ens_mean(const StringArray & a); -static void set_obs_valid_beg(const StringArray &); -static void set_obs_valid_end(const StringArray &); -static void set_outdir(const StringArray &); -static void set_compress(const StringArray &); +static void set_ens_files (const StringArray &); +static void set_out_file (const StringArray &); +static void set_config_file(const StringArray &); +static void set_ctrl_file (const StringArray &); //////////////////////////////////////////////////////////////////////// @@ -171,14 +98,12 @@ int main(int argc, char *argv[]) { process_command_line(argc, argv); // Check for valid ensemble data + // JHG, this is dumb. This logic should be incorporated into process_ensemble(). process_n_vld(); // Process the ensemble fields process_ensemble(); - // Only perform verification if requested - if(vx_flag) process_vx(); - // Close the text files and deallocate memory clean_up(); @@ -192,120 +117,58 @@ void process_command_line(int argc, char **argv) { CommandLine cline; ConcatString default_config_file; Met2dDataFile *ens_mtddf = (Met2dDataFile *) 0; - Met2dDataFile *obs_mtddf = (Met2dDataFile *) 0; - - // Set default output directory - out_dir = "."; // - // check for zero arguments + // Check for zero arguments // if(argc == 1) usage(); // - // parse the command line into tokens + // Parse the command line into tokens // cline.set(argc, argv); // - // set the usage function + // Set the usage function // cline.set_usage(usage); // - // add the options function calls - // - cline.add(set_grid_obs, "-grid_obs", 1); - cline.add(set_point_obs, "-point_obs", 1); - cline.add(set_ens_mean, "-ens_mean", 1); - cline.add(set_obs_valid_beg, "-obs_valid_beg", 1); - cline.add(set_obs_valid_end, "-obs_valid_end", 1); - cline.add(set_outdir, "-outdir", 1); - cline.add(set_compress, "-compress", 1); - - // - // quietly support deprecated -ssvar_mean option + // Add the options function calls // - cline.add(set_ens_mean, "-ssvar_mean", 1); + cline.add(set_ens_files, "-ens", -1); + cline.add(set_out_file, "-out", 1); + cline.add(set_config_file, "-config", 1); + cline.add(set_ctrl_file, "-ctrl", 1); // - // parse the command line + // Parse the command line // cline.parse(); - // - // Check for error. There should be either a number followed by that - // number of filenames or a single filename and a config filename. - // - if(cline.n() < 2) usage(); - - if(cline.n() == 2) { - - // - // It should be a filename and then a config filename - // - if(is_integer(cline[0].c_str()) == 0) { - ens_file_list = parse_ascii_file_list(cline[0].c_str()); - n_ens = ens_file_list.n(); - } - else { - usage(); - } - } - else { - - // - // More than two arguments. Check that the first is an integer - // followed by that number of filenames and a config filename. - // - if(is_integer(cline[0].c_str()) == 1) { - - n_ens = atoi(cline[0].c_str()); - - if(n_ens <= 0) { - mlog << Error << "\nprocess_command_line() -> " - << "the number of ensemble member files must be >= 1 (" - << n_ens << ")\n\n"; - exit(1); - } - - if((cline.n() - 2) == n_ens) { + // Check for error, there should be zero arguments left + if(cline.n() != 0) usage(); - // - // Add each of the ensemble members to the list of files. - // - for(i=1; i<=n_ens; i++) ens_file_list.add(cline[i]); - } - else { - usage(); - } - } + // Check that the required arguments have been set + if(ens_files.n() == 0) { + mlog << Error << "\nprocess_command_line() -> " + << "the ensemble file list must be set using the " + << "\"-ens\" option.\n\n"; + exit(1); } - - // Check for at least one valid input ensemble file - if(ens_file_list.n() == 0) { + if(config_file.length() == 0) { mlog << Error << "\nprocess_command_line() -> " - << "no valid input ensemble member files specified!\n\n"; + << "the output file must be set using the " + << "\"-out\" option.\n\n"; exit(1); } - - // Check that the end_ut >= beg_ut - if(obs_valid_beg_ut != (unixtime) 0 && - obs_valid_end_ut != (unixtime) 0 && - obs_valid_beg_ut > obs_valid_end_ut) { - + if(config_file.length() == 0) { mlog << Error << "\nprocess_command_line() -> " - << "the ending time (" - << unix_to_yyyymmdd_hhmmss(obs_valid_end_ut) - << ") must be greater than the beginning time (" - << unix_to_yyyymmdd_hhmmss(obs_valid_beg_ut) - << ").\n\n"; + << "the configuration file must be set using the " + << "\"-config\" option.\n\n"; exit(1); } - // Store the config file name - config_file = cline[cline.n() - 1]; - // Create the default config file name default_config_file = replace_path(default_config_filename); @@ -321,93 +184,40 @@ void process_command_line(int argc, char **argv) { etype = parse_conf_file_type(conf_info.conf.lookup_dictionary(conf_key_ens)); // Read the first input ensemble file - if(!(ens_mtddf = mtddf_factory.new_met_2d_data_file(ens_file_list[0].c_str(), etype))) { + if(!(ens_mtddf = mtddf_factory.new_met_2d_data_file(ens_files[0].c_str(), etype))) { mlog << Error << "\nprocess_command_line() -> " - << "trouble reading ensemble file \"" - << ens_file_list[0] << "\"\n\n"; + << "trouble reading ensemble file \"" << ens_files[0] << "\"\n\n"; exit(1); } // Store the input ensemble file type etype = ens_mtddf->file_type(); - // Use a variable index from var_name instead of GRIB code - bool use_var_id = false; - - // Determine the input observation file type - if(point_obs_flag) { - otype = FileType_Gb1; - if(point_obs_file_list.n() > 0) { - use_var_id = is_using_var_id(point_obs_file_list[0].c_str()); - } - } - else if(!grid_obs_flag) { - otype = FileType_None; - } - else { - - // Get the observation file type from config, if present - otype = parse_conf_file_type(conf_info.conf.lookup_dictionary(conf_key_obs)); - - // Read the first gridded observation file - if(!(obs_mtddf = mtddf_factory.new_met_2d_data_file(grid_obs_file_list[0].c_str(), otype))) { - mlog << Error << "\nprocess_command_line() -> " - << "trouble reading gridded observation file \"" - << grid_obs_file_list[0] << "\"\n\n"; - exit(1); - } - - // Store the gridded observation file type - otype = obs_mtddf->file_type(); - } - // Process the configuration - conf_info.process_config(etype, otype, grid_obs_flag, point_obs_flag, use_var_id); - - // Set the model name - shc.set_model(conf_info.model.c_str()); + conf_info.process_config(etype); // Allocate arrays to store threshold counts - thresh_count_na = new NumArray [conf_info.get_max_n_thresh()]; - thresh_nbrhd_count_na = new NumArray * [conf_info.get_max_n_thresh()]; + thresh_count_na = new NumArray [conf_info.get_max_n_cat_ta()]; + thresh_nbrhd_count_na = new NumArray * [conf_info.get_max_n_cat_ta()]; - for(i=0; i 0) { - mlog << Debug(1) << "Gridded Observation Files[" - << grid_obs_file_list.n() << "]:\n" ; - for(i=0; i 0) { - mlog << Debug(1) << "Point Observation Files[" - << point_obs_file_list.n() << "]:\n" ; - for(i=0; i " << "can't open input ensemble file: " - << ens_file_list[i] << "\n\n"; + << ens_files[i] << "\n\n"; ens_file_vld.add(0); } else { @@ -415,62 +225,8 @@ void process_command_line(int argc, char **argv) { } } - // Set flag to indicate whether verification is to be performed - if((point_obs_flag || grid_obs_flag) && - (conf_info.get_n_vx() > 0) && - (conf_info.output_flag[i_ecnt] != STATOutputType_None || - conf_info.output_flag[i_rhist] != STATOutputType_None || - conf_info.output_flag[i_phist] != STATOutputType_None || - conf_info.output_flag[i_ssvar] != STATOutputType_None || - conf_info.output_flag[i_relp] != STATOutputType_None || - conf_info.output_flag[i_orank] != STATOutputType_None)) vx_flag = 1; - else vx_flag = 0; - - // Process ensemble mean information - ens_mean_flag = false; - bool need_ens_mean = ( - conf_info.output_flag[i_ecnt] != STATOutputType_None || - conf_info.output_flag[i_orank] != STATOutputType_None || - conf_info.output_flag[i_ssvar] != STATOutputType_None); - - // User-specified ensemble mean file - if(ens_mean_user.nonempty()) { - - if(!need_ens_mean) { - mlog << Warning << "\nprocess_command_line() -> " - << "ignoring input -ens_mean file because no ensemble " - << "mean is needed.\n\n"; - } - else if(!file_exists(ens_mean_user.c_str())) { - mlog << Warning << "\nprocess_command_line() -> " - << "can't open input ensemble mean file: " - << ens_mean_user << "\n\n"; - ens_mean_user = ""; - } - else if(!vx_flag) { - mlog << Warning << "\nprocess_command_line() -> " - << "ignoring input -ens_mean file because no verification " - << "has been requested\n\n"; - } - else { - ens_mean_flag = true; - } - } - else if(need_ens_mean) { - - ens_mean_flag = true; - - if(!conf_info.nc_info.do_mean) { - mlog << Warning << "\nprocess_command_line() -> " - << "enabling NetCDF ensemble mean computation to be used " - << "in verificaiton.\n\n"; - conf_info.nc_info.do_mean = true; - } - } - // Deallocate memory for data files if(ens_mtddf) { delete ens_mtddf; ens_mtddf = (Met2dDataFile *) 0; } - if(obs_mtddf) { delete obs_mtddf; obs_mtddf = (Met2dDataFile *) 0; } return; } @@ -485,61 +241,16 @@ void process_grid(const Grid &fcst_grid) { if(conf_info.get_n_ens_var() > 0) { ri = conf_info.ens_info[0]->regrid(); } - else if(conf_info.get_n_vx() > 0) { - ri = conf_info.vx_opt[0].vx_pd.fcst_info->regrid(); - } else { mlog << Error << "\nprocess_grid() -> " - << "at least one ensemble field or verification field must " - << "be provided!\n\n"; + << "at least one ensemble field must be specified!\n\n"; exit(1); } - // Read gridded observation data, if necessary - if(ri.field == FieldType_Obs) { - - if(!grid_obs_flag) { - mlog << Error << "\nprocess_grid() -> " - << "attempting to regrid to the observation grid, but no " - << "gridded observations provided!\n\n"; - exit(1); - } - - DataPlane dp; - Met2dDataFile *mtddf = (Met2dDataFile *) 0; - if(!(mtddf = mtddf_factory.new_met_2d_data_file( - grid_obs_file_list[0].c_str(), otype))) { - mlog << Error << "\nprocess_grid() -> " - << "trouble reading file \"" << grid_obs_file_list[0] - << "\"\n\n"; - exit(1); - } - - if(!mtddf->data_plane(*(conf_info.vx_opt[0].vx_pd.obs_info), dp)) { - mlog << Error << "\nprocess_grid() -> " - << "observation field \"" - << conf_info.vx_opt[0].vx_pd.obs_info->magic_str() - << "\" not found in file \"" << grid_obs_file_list[0] - << "\"\n\n"; - exit(1); - } - - // Store the observation grid - obs_grid = mtddf->grid(); - - if(mtddf) { delete mtddf; mtddf = (Met2dDataFile *) 0; } - } - else { - obs_grid = fcst_grid; - } - // Determine the verification grid - grid = parse_vx_grid(ri, &fcst_grid, &obs_grid); + grid = parse_vx_grid(ri, &fcst_grid, &fcst_grid); nxy = grid.nx() * grid.ny(); - // Compute weight for each grid point - parse_grid_weight(grid, conf_info.grid_weight_flag, wgt_dp); - return; } @@ -552,24 +263,23 @@ void process_n_vld() { // Initialize n_ens_vld.clear(); - n_vx_vld.clear(); // Loop through the ensemble fields to be processed for(i=0; i " << "ensemble field \"" << conf_info.ens_info[i]->magic_str() - << "\" not found in file \"" << ens_file_list[j] + << "\" not found in file \"" << ens_files[j] << "\"\n\n"; } else { @@ -593,50 +303,6 @@ void process_n_vld() { } // end for i - // Loop through the verification fields to be processed - for(i=0; i " - << "no data found for forecast field \"" - << conf_info.vx_opt[i].vx_pd.fcst_info->magic_str() - << "\" in file \"" << ens_file_list[j] - << "\"\n\n"; - } - else { - - // Store the lead times for the first verification field - if(i==0) ens_lead_na.add(dpa[0].lead()); - - // Increment the valid counter - n_vld++; - } - } // end for j - - // Check for enough valid data - if((double) n_vld/n_ens < conf_info.vld_ens_thresh) { - mlog << Error << "\nprocess_n_vld() -> " - << n_ens - n_vld << " missing forecast fields exceeds the " - << "maximum allowable specified by \"ens.ens_thresh\" " - << "in the configuration file.\n\n"; - exit(1); - } - - // Store the valid data count - n_vx_vld.add(n_vld); - - } // end for i - return; } @@ -743,1208 +409,68 @@ bool get_data_plane_array(const char *infile, GrdFileType ftype, } // end if found - // Deallocate the data file pointer, if necessary - if(mtddf) { delete mtddf; mtddf = (Met2dDataFile *) 0; } - - return(found); -} - -//////////////////////////////////////////////////////////////////////// - -void process_ensemble() { - int i, j; - bool reset; - DataPlane ens_dp; - unixtime max_init_ut = bad_data_ll; - - // Loop through each of the ensemble fields to be processed - for(i=0; imagic_str() << "\n"; - - // Loop through each of the input forecast files - for(j=0, reset=true; j max_init_ut) { - max_init_ut = ens_dp.init(); - } - - } // end for j - - // Write out the ensemble information to a NetCDF file - ens_dp.set_init(max_init_ut); - write_ens_nc(i, ens_dp); - - // Store the ensemble mean output file - ens_mean_file = - out_nc_file_list[out_nc_file_list.n() - 1]; - - } // end for i - - // Close the output NetCDF file - if(nc_out) { - delete nc_out; - nc_out = (NcFile *) 0; - } - - return; -} - -//////////////////////////////////////////////////////////////////////// - -void process_vx() { - - if(conf_info.get_n_vx() > 0) { - - if(point_obs_file_list.n() == 0 && - grid_obs_file_list.n() == 0) { - mlog << Error << "\nprocess_vx() -> " - << " when \"fcst.field\" is non-empty, you must use " - << "\"-point_obs\" and/or \"-grid_obs\" to specify the " - << "verifying observations.\n\n"; - exit(1); - } - - // Process masks Grids and Polylines in the config file - conf_info.process_masks(grid); - - // Setup the PairDataEnsemble objects - conf_info.set_vx_pd(n_vx_vld); - - // Process the point observations - if(point_obs_flag) process_point_vx(); - - // Process the gridded observations - if(grid_obs_flag) process_grid_vx(); - } - - return; -} - -//////////////////////////////////////////////////////////////////////// - -void process_point_vx() { - int i, n_miss; - unixtime beg_ut, end_ut; - - // Set observation time window for each verification task - for(i=0; i DEF_NC_BUFFER_SIZE) ? DEF_NC_BUFFER_SIZE : (obs_count)); - - int obs_qty_idx_block[buf_size]; - float obs_arr_block[buf_size][OBS_ARRAY_LEN]; - float obs_arr[OBS_ARRAY_LEN], hdr_arr[HDR_ARRAY_LEN]; - int hdr_typ_arr[HDR_TYPE_ARR_LEN]; - ConcatString hdr_typ_str; - ConcatString hdr_sid_str; - ConcatString hdr_vld_str; - ConcatString obs_qty_str; - ConcatString var_name; - StringArray var_names; - StringArray obs_qty_array = nc_point_obs.get_qty_data(); - if(use_var_id) var_names = nc_point_obs.get_var_names(); - - for(int i_start=0; i_start DEF_NC_BUFFER_SIZE) - ? DEF_NC_BUFFER_SIZE : (obs_count-i_start); - - if (!nc_point_obs.read_obs_data(buf_size, i_start, (float *)obs_arr_block, - obs_qty_idx_block, (char *)0)) { - exit(1); - } - // Process each observation in the file - for(int i_offset=0; i_offset= hdr_count) { - mlog << Warning << "\n" << method_name - << "range check error for header index " << headerOffset - << " from observation number " << i_obs - << " of point observation file: " - << point_obs_file_list[i_nc] << "\n\n"; - continue; - } - - // Read the corresponding header array for this observation - // - the corresponding header type, header Station ID, and valid time - nc_point_obs.get_header(headerOffset, hdr_arr, hdr_typ_str, - hdr_sid_str, hdr_vld_str); - - // Read the header integer types - nc_point_obs.get_header_type(headerOffset, hdr_typ_arr); - - // Convert string to a unixtime - hdr_ut = timestring_to_unix(hdr_vld_str.c_str()); - - int grib_code = nc_point_obs.get_grib_code_or_var_index(obs_arr); - if (use_var_id && grib_code < var_names.n()) { - var_name = var_names[grib_code]; - } - else { - var_name = ""; - } - - // Check each conf_info.vx_pd object to see if this observation - // should be added - for(j=0; jfile_type(), info, - fcst_dpa, true)) { - - // Error out if unable to read the ensemble mean - if(is_ens_mean) { - mlog << Error << "\nprocess_point_ens() -> " - << "trouble reading the ensemble mean field \"" - << info->magic_str() << "\" from file \"" - << ens_file << "\"\n\n"; - exit(1); - } - - n_miss++; - continue; - } - - // Dump out the number of levels found - mlog << Debug(2) << "For " << info->magic_str() - << " found " << fcst_dpa.n_planes() << " forecast levels.\n"; - - // Store information for the raw forecast fields - conf_info.vx_opt[i].vx_pd.set_fcst_dpa(fcst_dpa); - - // Compute forecast values for this ensemble member - conf_info.vx_opt[i].vx_pd.add_ens(i_ens-n_miss, is_ens_mean); - - } // end for i - - return(0); -} - -//////////////////////////////////////////////////////////////////////// - -void process_point_scores() { - PairDataEnsemble *pd_ptr = (PairDataEnsemble *) 0; - PairDataEnsemble pd; - ConcatString cs; - int i, j, k, l, m, n; - - mlog << Debug(2) << "\n" << sep_str << "\n\n"; - - // Create output text files as requested in the config file - setup_txt_files(); - - // Store the forecast lead time - shc.set_fcst_lead_sec(nint(ens_lead_na.min())); - - // Store the forecast valid time - shc.set_fcst_valid_beg(ens_valid_ut); - shc.set_fcst_valid_end(ens_valid_ut); - - // Loop through the Ensemble pair data objects, compute the scores - // requested, and write the output. - for(i=0; iname_attr()); - - // Store the forecast variable units - shc.set_fcst_units(conf_info.vx_opt[i].vx_pd.fcst_info->units_attr()); - - // Set the forecast level name - shc.set_fcst_lev(conf_info.vx_opt[i].vx_pd.fcst_info->level_attr().c_str()); - - // Store the observation variable name - shc.set_obs_var(conf_info.vx_opt[i].vx_pd.obs_info->name_attr()); - - // Store the observation variable units - cs = conf_info.vx_opt[i].vx_pd.obs_info->units_attr(); - if(cs.empty()) cs = na_string; - shc.set_obs_units(cs); - - // Set the observation level name - shc.set_obs_lev(conf_info.vx_opt[i].vx_pd.obs_info->level_attr().c_str()); - - // Set the observation lead time - shc.set_obs_lead_sec(0); - - // Set the observation valid time - shc.set_obs_valid_beg(conf_info.vx_opt[i].vx_pd.beg_ut); - shc.set_obs_valid_end(conf_info.vx_opt[i].vx_pd.end_ut); - - // Loop through the message types - for(j=0; jmagic_str() - << " versus " - << conf_info.vx_opt[i].vx_pd.obs_info->magic_str() - << ", for observation type " << pd_ptr->msg_typ - << ", over region " << pd_ptr->mask_name - << ", for interpolation method " - << shc.get_interp_mthd() << "(" - << shc.get_interp_pnts_str() - << "), using " << pd_ptr->n_obs << " matched pairs.\n"; - - // Continue if there are no points - if(pd_ptr->n_obs == 0) continue; - - // Process percentile thresholds - conf_info.vx_opt[i].set_perc_thresh(pd_ptr); - - // Compute observation ranks and pair values - pd_ptr->compute_pair_vals(conf_info.rng_ptr); - - // Process each filtering threshold - for(m=0; msubset_pairs_obs_thresh(conf_info.vx_opt[i].othr_ta[m]); - - // Continue if there are no points - if(pd.n_obs == 0) continue; - - // Compute ECNT scores - if(conf_info.output_flag[i_ecnt] != STATOutputType_None) { - do_ecnt(conf_info.vx_opt[i], - conf_info.vx_opt[i].othr_ta[m], &pd); - } - - // Compute RPS scores - if(conf_info.output_flag[i_rps] != STATOutputType_None) { - do_rps(conf_info.vx_opt[i], - conf_info.vx_opt[i].othr_ta[m], &pd); - } - - // Write RHIST counts - if(conf_info.output_flag[i_rhist] != STATOutputType_None) { - - pd.compute_rhist(); - - if(pd.rhist_na.sum() > 0) { - write_rhist_row(shc, &pd, - conf_info.output_flag[i_rhist], - stat_at, i_stat_row, - txt_at[i_rhist], i_txt_row[i_rhist]); - } - } - - // Write PHIST counts if greater than 0 - if(conf_info.output_flag[i_phist] != STATOutputType_None) { - - pd.compute_phist(); - - if(pd.phist_na.sum() > 0) { - write_phist_row(shc, &pd, - conf_info.output_flag[i_phist], - stat_at, i_stat_row, - txt_at[i_phist], i_txt_row[i_phist]); - } - } - - // Write RELP counts - if(conf_info.output_flag[i_relp] != STATOutputType_None) { - - pd.compute_relp(); - - if(pd.relp_na.sum() > 0) { - write_relp_row(shc, &pd, - conf_info.output_flag[i_relp], - stat_at, i_stat_row, - txt_at[i_relp], i_txt_row[i_relp]); - } - } - - // Write SSVAR scores - if(conf_info.output_flag[i_ssvar] != STATOutputType_None) { - - pd.compute_ssvar(); - - // Make sure there are bins to process - if(pd.ssvar_bins) { - - // Add rows to the output AsciiTables for SSVAR - stat_at.add_rows(pd.ssvar_bins[0].n_bin * - conf_info.vx_opt[i].ci_alpha.n()); - - if(conf_info.output_flag[i_ssvar] == STATOutputType_Both) { - txt_at[i_ssvar].add_rows(pd.ssvar_bins[0].n_bin * - conf_info.vx_opt[i].ci_alpha.n()); - } - - // Write the SSVAR data for each alpha value - for(n=0; nname_attr()); - - // Store the forecast variable units - shc.set_fcst_units(conf_info.vx_opt[i].vx_pd.fcst_info->units_attr()); - - // Set the forecast level name - shc.set_fcst_lev(conf_info.vx_opt[i].vx_pd.fcst_info->level_attr().c_str()); - - // Set the ObsErrorEntry pointer - if(conf_info.vx_opt[i].obs_error.flag) { - - // Use config file setting, if specified - if(conf_info.vx_opt[i].obs_error.entry.dist_type != DistType_None) { - mlog << Debug(3) - << "Observation error for gridded verification is " - << "defined in the configuration file.\n"; - oerr_ptr = &(conf_info.vx_opt[i].obs_error.entry); - } - // Otherwise, do a table lookup - else { - - // Check for table entries for this variable and message type - if(!obs_error_table.has( - conf_info.vx_opt[i].vx_pd.obs_info->name().c_str(), - conf_info.obtype.c_str())) { - mlog << Warning << "\nprocess_grid_vx() -> " - << "Disabling observation error logic since the " - << "obs error table contains no entry for OBS_VAR(" - << conf_info.vx_opt[i].vx_pd.obs_info->name() - << ") and MESSAGE_TYPE(" << conf_info.obtype - << ").\nSpecify a custom obs error table using the " - << "MET_OBS_ERROR_TABLE environment variable.\n\n"; - conf_info.vx_opt[i].obs_error.flag = false; - } - else { - - // Do a lookup for this variable and message type - oerr_ptr = obs_error_table.lookup( - conf_info.vx_opt[i].vx_pd.obs_info->name().c_str(), - conf_info.obtype.c_str()); - - // If match was found and includes a value range setting, - // reset to NULL and lookup separately for grid point - if(oerr_ptr) { - if(oerr_ptr->val_range.n() == 0) { - mlog << Debug(3) - << "Observation error for gridded verification is " - << "defined by a single table entry.\n"; - } - else { - mlog << Debug(3) - << "Observation error for gridded verification is " - << "defined by a table lookup for each point.\n"; - oerr_ptr = (ObsErrorEntry *) 0; - } - } - } - } - } - - // Loop through each of the input ensemble files - for(j=0, n_miss=0; jmagic_str() << ".\n"; - - // If requested in the config file, create a NetCDF file to store - // the verification matched pairs - if(conf_info.nc_info.do_orank && - nc_out == (NcFile *) 0) - setup_nc_file(fcst_dp[j].valid(), "_orank.nc"); - - // Read the observation file - for(j=0, n_miss=0; jmagic_str() - << " from file: " << grid_obs_file_list[j] << "\n"; - break; - } - } - - // Check if the observation field was found - if(n_miss == grid_obs_file_list.n()) { - mlog << Warning << "\nprocess_grid_vx() -> " - << conf_info.vx_opt[i].vx_pd.obs_info->magic_str() - << " not found in observation files.\n\n"; - continue; - } - - // Set the observation variable name - shc.set_obs_var(conf_info.vx_opt[i].vx_pd.obs_info->name_attr()); - - // Store the observation variable units - shc.set_obs_units(conf_info.vx_opt[i].vx_pd.obs_info->units_attr()); - - // Set the observation level name - shc.set_obs_lev(conf_info.vx_opt[i].vx_pd.obs_info->level_attr().c_str()); - - // Set the observation lead time - shc.set_obs_lead_sec(obs_dp.lead()); - - // Set the observation valid time - shc.set_obs_valid_beg(obs_dp.valid()); - shc.set_obs_valid_end(obs_dp.valid()); - - // Process the ensemble mean, if necessary - if(ens_mean_flag) { - VarInfo *info = (VarInfo *) 0; - VarInfoNcMet ens_mean_info; - ConcatString mn_file = (ens_mean_user.empty() ? - ens_mean_file : ens_mean_user); - - mlog << Debug(2) << "\n" << sep_str << "\n\n" - << "Processing ensemble mean file: " << mn_file << "\n"; - - // Use the calculated mean file, in necessary - if(ens_mean_user.empty()) { - ens_mean_info.set_magic(get_ens_mn_var_name(i), - (string)"(*,*)"); - info = &ens_mean_info; - } - else { - info = conf_info.vx_opt[i].vx_pd.fcst_info; - } - - // Read the gridded data from the mean file - found = get_data_plane(mn_file.c_str(), FileType_None, - info, emn_dp, true); - - if(!found) { - mlog << Error << "\nprocess_grid_vx() -> " - << "trouble reading ensemble mean field \"" - << info->magic_str() << "\" from file \"" - << mn_file << "\"\n\n"; - exit(1); - } - } - - // Loop through and apply each of the smoothing operations - for(j=0; j " - << mthd_str << " smoothing option not supported for " - << "gridded observations.\n\n"; - continue; - } - - // Set the interpolation method and width - shc.set_interp_mthd(mthd, shape); - shc.set_interp_wdth(wdth); - - // Smooth the ensemble mean field, if requested - if(ens_mean_flag && - (field == FieldType_Fcst || field == FieldType_Both)) { - emn_dp = smooth_field(emn_dp, mthd, wdth, shape, - vld_thresh, gaussian); - } - - // Smooth the observation field, if requested - if(field == FieldType_Obs || field == FieldType_Both) { - obs_dp = smooth_field(obs_dp, mthd, wdth, shape, - vld_thresh, gaussian); - } - - // Store a copy of the unperturbed observation field - oraw_dp = obs_dp; - - // Apply observation error bias correciton, if requested - if(conf_info.vx_opt[i].obs_error.flag) { - mlog << Debug(3) - << "Applying observation error bias correction to " - << "gridded observation data.\n"; - obs_dp = add_obs_error_bc(conf_info.rng_ptr, - FieldType_Obs, oerr_ptr, oraw_dp, oraw_dp, - conf_info.vx_opt[i].vx_pd.obs_info->name().c_str(), - conf_info.obtype.c_str()); - } - - // Looop through the ensemble members - for(k=0; kname().c_str(), - conf_info.obtype.c_str()); - } - } // end for k - - // Loop through the masks to be applied - for(k=0; kmagic_str() - << " versus " - << conf_info.vx_opt[i].vx_pd.obs_info->magic_str() - << ", for observation type " << shc.get_obtype() - << ", over region " << shc.get_mask() - << ", for interpolation method " - << shc.get_interp_mthd() << "(" - << shc.get_interp_pnts_str() - << "), using " << pd_all.n_obs << " matched pairs.\n"; - - // Continue if there are no points - if(pd_all.n_obs == 0) continue; - - // Process percentile thresholds - conf_info.vx_opt[i].set_perc_thresh(&pd_all); - - // Compute observation ranks and pair values - pd_all.compute_pair_vals(conf_info.rng_ptr); - - // Write out the unfiltered observation rank field. - if(conf_info.nc_info.do_orank) { - write_orank_nc(pd_all, obs_dp, i, j, k); - } - - // Process each filtering threshold - for(l=0; l 0) { - write_rhist_row(shc, &pd, - conf_info.output_flag[i_rhist], - stat_at, i_stat_row, - txt_at[i_rhist], i_txt_row[i_rhist]); - } - } - - // Write PHIST counts if greater than 0 - if(conf_info.output_flag[i_phist] != STATOutputType_None) { - - pd.phist_bin_size = conf_info.vx_opt[i].vx_pd.pd[0][0][0].phist_bin_size; - pd.compute_phist(); - - if(pd.phist_na.sum() > 0) { - write_phist_row(shc, &pd, - conf_info.output_flag[i_phist], - stat_at, i_stat_row, - txt_at[i_phist], i_txt_row[i_phist]); - } - } - - // Write RELP counts - if(conf_info.output_flag[i_relp] != STATOutputType_None) { - - pd.compute_relp(); - - if(pd.relp_na.sum() > 0) { - write_relp_row(shc, &pd, - conf_info.output_flag[i_relp], - stat_at, i_stat_row, - txt_at[i_relp], i_txt_row[i_relp]); - } - } - - // Write SSVAR scores - if(conf_info.output_flag[i_ssvar] != STATOutputType_None) { - - pd.ssvar_bin_size = conf_info.vx_opt[i].vx_pd.pd[0][0][0].ssvar_bin_size; - pd.compute_ssvar(); - - // Make sure there are bins to process - if(pd.ssvar_bins) { - - // Add rows to the output AsciiTables for SSVAR - stat_at.add_rows(pd.ssvar_bins[0].n_bin * - conf_info.vx_opt[i].ci_alpha.n()); - - if(conf_info.output_flag[i_ssvar] == STATOutputType_Both) { - txt_at[i_ssvar].add_rows(pd.ssvar_bins[0].n_bin * - conf_info.vx_opt[i].ci_alpha.n()); - } - - // Write the SSVAR data for each alpha value - for(m=0; mname().c_str(), - conf_info.obtype.c_str(), oraw_dp(x,y)); - } - else { - e = (ObsErrorEntry *) 0; - } - - // Store the observation error entry pointer - pd.add_obs_error_entry(e); +void process_ensemble() { + int i, j; + bool reset; + DataPlane ens_dp; + unixtime max_init_ut = bad_data_ll; - // Add the ensemble mean value for this point - pd.mn_na.add((emn_flag ? emn_dp(x, y) : bad_data_double)); + // Loop through each of the ensemble fields to be processed + for(i=0; imagic_str() << "\n"; - // Loop through the observation points - for(i=0; i 0) { - write_ecnt_row(shc, ecnt_info, vx_opt.output_flag[i_ecnt], - stat_at, i_stat_row, - txt_at[i_ecnt], i_txt_row[i_ecnt]); - } - - return; -} + // 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 j -void do_rps(const GenEnsProdVxOpt &vx_opt, - const SingleThresh &othresh, - const PairDataEnsemble *pd_ptr) { - RPSInfo rps_info; - - // Check for valid pointer - if(!pd_ptr) return; - - // Store observation filering threshold - rps_info.othresh = othresh; - rps_info.set_prob_cat_thresh(vx_opt.prob_cat_ta); - - // If prob_cat_thresh is empty and climo data is available, - // use climo_cdf thresholds instead - if(rps_info.fthresh.n() == 0 && - pd_ptr->cmn_na.n_valid() > 0 && - pd_ptr->csd_na.n_valid() > 0 && - vx_opt.cdf_info.cdf_ta.n() > 0) { - rps_info.set_cdp_thresh(vx_opt.cdf_info.cdf_ta); - } + // Write out the ensemble information to a NetCDF file + ens_dp.set_init(max_init_ut); + write_ens_nc(i, ens_dp); - // Compute ensemble RPS statistics - rps_info.set(*pd_ptr); + } // end for i - // Write out RPS - if(vx_opt.output_flag[i_rps] != STATOutputType_None && - rps_info.n_pair > 0) { - write_rps_row(shc, rps_info, vx_opt.output_flag[i_rps], - stat_at, i_stat_row, - txt_at[i_rps], i_txt_row[i_rps]); + // Close the output NetCDF file + if(nc_out) { + delete nc_out; + nc_out = (NcFile *) 0; } return; @@ -1961,7 +487,7 @@ void clear_counts() { max_na.extend(nxy); sum_na.extend(nxy); sum_sq_na.extend(nxy); - for(i=0; i 0 - if(conf_info.nc_info.do_nmep) { + if(conf_info.nc_info[i_vx].do_nmep) { DataPlane frac_dp; // Loop over thresholds @@ -2075,40 +601,21 @@ void track_counts(int i_vx, const DataPlane &dp) { //////////////////////////////////////////////////////////////////////// -ConcatString get_ens_mn_var_name(int i_vx) { - ConcatString cs; - - cs << conf_info.vx_opt[i_vx].vx_pd.fcst_info->name_attr() << "_" - << conf_info.vx_opt[i_vx].vx_pd.fcst_info->level_attr() - << "_ENS_MEAN"; - cs.replace(",", "_", false); - cs.replace("*", "all", false); - mlog << Debug(4) << "Generated mean field: " << cs << "\n"; - - return(cs); -} - -//////////////////////////////////////////////////////////////////////// - void setup_nc_file(unixtime valid_ut, const char *suffix) { - ConcatString out_nc_file; - - // Create output NetCDF file name - build_outfile_name(ens_valid_ut, suffix, out_nc_file); // Create a new NetCDF file and open it - nc_out = open_ncfile(out_nc_file.c_str(), true); + nc_out = open_ncfile(out_file.c_str(), true); if(IS_INVALID_NC_P(nc_out)) { mlog << Error << "\nsetup_nc_file() -> " << "trouble opening output NetCDF file " - << out_nc_file << "\n\n"; + << out_file << "\n\n"; exit(1); } // Add global attributes - write_netcdf_global(nc_out, out_nc_file.text(), program_name, - conf_info.model.c_str(), conf_info.obtype.c_str()); + write_netcdf_global(nc_out, out_file.text(), program_name, + conf_info.model.c_str()); // Add the projection information write_netcdf_proj(nc_out, grid); @@ -2118,211 +625,10 @@ void setup_nc_file(unixtime valid_ut, const char *suffix) { lon_dim = add_dim(nc_out, "lon", (long) grid.nx()); // Add the lat/lon variables - if(conf_info.nc_info.do_latlon) { + if(conf_info.nc_info[0].do_latlon) { write_netcdf_latlon(nc_out, &lat_dim, &lon_dim, grid); } - // Add grid weight variable - if(conf_info.nc_info.do_weight) { - write_netcdf_grid_weight(nc_out, &lat_dim, &lon_dim, - conf_info.grid_weight_flag, wgt_dp); - } - - // Append to the list of output files - out_nc_file_list.add(out_nc_file); - - return; -} - -//////////////////////////////////////////////////////////////////////// - -void setup_txt_files() { - int i, n, n_phist_bin, n_vld, max_col; - ConcatString tmp_str; - - // Check to see if the text files have already been set up - if(stat_at.nrows() > 0 || stat_at.ncols() > 0) return; - - // Create output file names for the stat file and optional text files - build_outfile_name(ens_valid_ut, "", tmp_str); - - ///////////////////////////////////////////////////////////////////// - // - // Setup the output STAT file - // - ///////////////////////////////////////////////////////////////////// - - // Compute the number of PHIST bins - for(i=n_phist_bin=0; i n_phist_bin ? n : n_phist_bin); - } - - // Store the maximum number of valid verification fields - n_vld = n_vx_vld.max(); - - // Get the maximum number of data columns - max_col = max(get_n_orank_columns(n_vld+1), - get_n_rhist_columns(n_vld)); - max_col = max(max_col, get_n_phist_columns(n_phist_bin)); - max_col = max(max_col, n_ecnt_columns); - max_col = max(max_col, n_ssvar_columns); - max_col = max(max_col, get_n_relp_columns(n_vld)); - max_col += n_header_columns; - - // Initialize file stream - stat_out = (ofstream *) 0; - - // Build the file name - stat_file << tmp_str << stat_file_ext; - - // Create the output STAT file - open_txt_file(stat_out, stat_file.c_str()); - - // Setup the STAT AsciiTable - stat_at.set_size(conf_info.n_stat_row() + 1, max_col); - setup_table(stat_at); - - // Write the text header row - write_header_row((const char **) 0, 0, 1, stat_at, 0, 0); - - // Initialize the row index to 1 to account for the header - i_stat_row = 1; - - ///////////////////////////////////////////////////////////////////// - // - // Setup each of the optional output text files - // - ///////////////////////////////////////////////////////////////////// - - // Loop through output line type - for(i=0; i 0) { - var_str << "_" << conf_info.vx_opt[i_vx].var_str; - } - - // Get the interpolation method string and width - mthd_str = conf_info.vx_opt[i_vx].interp_info.method[i_interp]; - wdth = conf_info.vx_opt[i_vx].interp_info.width[i_interp]; - - // Build the orank variable name - var_name << cs_erase - << conf_info.vx_opt[i_vx].vx_pd.obs_info->name_attr() << "_" - << conf_info.vx_opt[i_vx].vx_pd.obs_info->level_attr() - << var_str << "_" << type_str << "_" - << conf_info.vx_opt[i_vx].mask_name_area[i_mask]; - - // Construct the variable name attribute - name_str << cs_erase - << conf_info.vx_opt[i_vx].vx_pd.obs_info->name_attr() << "_" - << type_str << "_" - << conf_info.vx_opt[i_vx].mask_name_area[i_mask]; - - // Append smoothing information, except for the raw observations - ConcatString type_cs(type_str); - if(wdth > 1 && - (type_cs != "OBS" || - conf_info.vx_opt[i_vx].interp_info.field == FieldType_Obs || - conf_info.vx_opt[i_vx].interp_info.field == FieldType_Both)) { - var_name << "_" << mthd_str << "_" << wdth*wdth; - name_str << "_" << mthd_str << "_" << wdth*wdth; - } - - // Skip variable names that have already been written - if(nc_orank_var_sa.has(var_name)) return; - - // Otherwise, add to the list of previously defined variables - nc_orank_var_sa.add(var_name); - - // Define the variable - nc_var = add_var(nc_out, (string)var_name, ncFloat, lat_dim, lon_dim); - - // Add the variable attributes - add_var_att_local(conf_info.vx_opt[i_vx].vx_pd.fcst_info, &nc_var, false, dp, - name_str.c_str(), long_name_str); - - // Write the data - if(!put_nc_data_with_dims(&nc_var, &data[0], grid.ny(), grid.nx())) { - mlog << Error << "\nwrite_orank_var_float() -> " - << "error in nc_var->put for the " << var_name - << " field.\n\n"; - exit(1); - } - - return; -} - -//////////////////////////////////////////////////////////////////////// - -void write_orank_var_int(int i_vx, int i_interp, int i_mask, - int *data, DataPlane &dp, - const char *type_str, - const char *long_name_str) { - NcVar nc_var; - int wdth; - ConcatString mthd_str, var_name, var_str, name_str; - - // Append nc_var_str config file entry - if(conf_info.vx_opt[i_vx].var_str.length() > 0) { - var_str << "_" << conf_info.vx_opt[i_vx].var_str; - } - - // Get the interpolation method string and width - mthd_str = conf_info.vx_opt[i_vx].interp_info.method[i_interp]; - wdth = conf_info.vx_opt[i_vx].interp_info.width[i_interp]; - - // Build the orank variable name - var_name << cs_erase - << conf_info.vx_opt[i_vx].vx_pd.obs_info->name_attr() << "_" - << conf_info.vx_opt[i_vx].vx_pd.obs_info->level_attr() - << var_str << "_" << type_str << "_" - << conf_info.vx_opt[i_vx].mask_name_area[i_mask]; - - // Construct the variable name attribute - name_str << cs_erase - << conf_info.vx_opt[i_vx].vx_pd.obs_info->name_attr() << "_" - << type_str << "_" - << conf_info.vx_opt[i_vx].mask_name_area[i_mask]; - - // Append smoothing information - if(wdth > 1) { - var_name << "_" << mthd_str << "_" << wdth*wdth; - name_str << "_" << mthd_str << "_" << wdth*wdth; - } - - // Skip variable names that have already been written - if(nc_orank_var_sa.has(var_name)) return; - - // Otherwise, add to the list of previously defined variables - nc_orank_var_sa.add(var_name); - - // Define the variable - nc_var = add_var(nc_out, (string)var_name, ncInt, lat_dim, lon_dim); - - // Add the variable attributes - add_var_att_local(conf_info.vx_opt[i_vx].vx_pd.fcst_info, &nc_var, true, dp, - name_str.c_str(), long_name_str); - - // Write the data - if(!put_nc_data_with_dims(&nc_var, &data[0], grid.ny(), grid.nx())) { - mlog << Error << "\nwrite_orank_var_int() -> " - << "error in nc_var->put for the " << var_name - << " field.\n\n"; - exit(1); - } - - return; -} - -//////////////////////////////////////////////////////////////////////// - void add_var_att_local(VarInfo *info, NcVar *nc_var, bool is_int, DataPlane &dp, const char *name_str, const char *long_name_str) { ConcatString att_str; @@ -2916,59 +1024,24 @@ void add_var_att_local(VarInfo *info, NcVar *nc_var, bool is_int, DataPlane &dp, //////////////////////////////////////////////////////////////////////// -void finish_txt_files() { - int i; - - // Write out the contents of the STAT AsciiTable and - // close the STAT output files - if(stat_out) { - *stat_out << stat_at; - close_txt_file(stat_out, stat_file.c_str()); - } - - // Finish up each of the optional text files - for(i=0; i::const_iterator it; - // Initialize values - ens_var_str.clear(); + // Clear, erase, and initialize members model.clear(); - obtype.clear(); - vld_ens_thresh = bad_data_double; - vld_data_thresh = bad_data_double; + desc.clear(); + for(it = ens_info.begin(); it != ens_info.end(); it++) { + if(*it) { delete *it; } + } + ens_info.clear(); + cdf_info.clear(); + ens_cat_ta.clear(); + ens_var_str.clear(); nbrhd_prob.clear(); nmep_smooth.clear(); - msg_typ_group_map.clear(); - msg_typ_sfc.clear(); - mask_area_map.clear(); - mask_sid_map.clear(); - grid_weight_flag = GridWeightType_None; + vld_ens_thresh = bad_data_double; + vld_data_thresh = bad_data_double; + nc_info.clear(); tmp_dir.clear(); - output_prefix.clear(); version.clear(); - // Deallocate memory for the random number generator - if(rng_ptr) rng_free(rng_ptr); - - for(i=0; ioutput_map; - Dictionary *edict = (Dictionary *) 0; - Dictionary *fdict = (Dictionary *) 0; - Dictionary *odict = (Dictionary *) 0; - Dictionary i_edict, i_fdict, i_odict; + Dictionary *edict = (Dictionary *) 0; + Dictionary i_edict; InterpMthd mthd; // Dump the contents of the config file @@ -152,8 +124,8 @@ void GenEnsProdConfInfo::process_config(GrdFileType etype, // Conf: model model = parse_conf_string(&conf, conf_key_model); - // Conf: obtype - obtype = parse_conf_string(&conf, conf_key_obtype, grid_vx); + // Conf: desc + desc = parse_conf_string(&conf, conf_key_desc); // Conf: rng_type and rng_seed ConcatString rng_type, rng_seed; @@ -163,50 +135,22 @@ void GenEnsProdConfInfo::process_config(GrdFileType etype, // Set the random number generator and seed value rng_set(rng_ptr, rng_type.c_str(), rng_seed.c_str()); - // Conf: grid_weight_flag - grid_weight_flag = parse_conf_grid_weight_flag(&conf); - - // Conf: output_prefix - output_prefix = conf.lookup_string(conf_key_output_prefix); - - // Conf: message_type_group_map - msg_typ_group_map = parse_conf_message_type_group_map(&conf); - - // Conf: message_type_group_map(SURFACE) - if(msg_typ_group_map.count((string)surface_msg_typ_group_str) == 0) { - mlog << Error << "\nGenEnsProdConfInfo::process_config() -> " - << "\"" << conf_key_message_type_group_map - << "\" must contain an entry for \"" - << surface_msg_typ_group_str << "\".\n\n"; - exit(1); - } - else { - msg_typ_sfc = msg_typ_group_map[(string)surface_msg_typ_group_str]; - } - - // Conf: ensemble_flag - parse_nc_info(); - // Conf: ens.field edict = conf.lookup_array(conf_key_ens_field); // Determine the number of ensemble fields to be processed - n_ens_var = parse_conf_n_vx(edict); - - // Allocate space based on the number of ensemble fields - if(n_ens_var > 0) { - ens_info = new VarInfo * [n_ens_var]; - ens_ta = new ThreshArray [n_ens_var]; + if((n_ens_var = parse_conf_n_vx(edict)) == 0) { + mlog << Error << "\nGenEnsProdConfInfo::process_config() -> " + << "At least one field must be specified in the \"" + << conf_key_ens_field << "\" dictionary!\n\n"; + exit(1); } - // Initialize pointers - for(i=0; i= 5) { + mlog << Debug(5) + << "Parsed thresholds for ensemble field number " << i+1 << ":\n"; + ens_cat_ta[i].dump(cout); + } - // Dump the contents of the current thresholds - if(mlog.verbosity_level() >= 5) { - mlog << Debug(5) - << "Parsed thresholds for ensemble field number " << i+1 << ":\n"; - ens_ta[i].dump(cout); - } + // Keep track of the maximum number of thresholds + if(ens_cat_ta[i].n() > max_n_cat_ta) max_n_cat_ta = ens_cat_ta[i].n(); - // Keep track of the maximum number of thresholds - if(ens_ta[i].n_elements() > max_n_thresh) { - max_n_thresh = ens_ta[i].n_elements(); - } - } + // Conf: ensemble_flag + nc_info.push_back(parse_nc_info(&i_edict)); } // Conf: ens.ens_thresh @@ -269,7 +209,7 @@ void GenEnsProdConfInfo::process_config(GrdFileType etype, // Conf: nbrhd_prob nbrhd_prob = parse_conf_nbrhd(edict, conf_key_nbrhd_prob); - n_nbrhd = nbrhd_prob.width.n(); + n_nbrhd = nbrhd_prob.width.n(); // Conf: nmep_smooth nmep_smooth = parse_conf_interp(edict, conf_key_nmep_smooth); @@ -301,72 +241,21 @@ void GenEnsProdConfInfo::process_config(GrdFileType etype, } } // end for i - // Conf: fcst.field and obs.field - fdict = conf.lookup_array(conf_key_fcst_field); - odict = conf.lookup_array(conf_key_obs_field); - - // Determine the number of fields to be verified - n_vx = parse_conf_n_vx(fdict); - - // Check for a valid number of verification tasks - if(parse_conf_n_vx(odict) != n_vx) { - mlog << Error << "\nGenEnsProdConfInfo::process_config() -> " - << "The number of verification tasks in \"" - << conf_key_obs_field - << "\" must match the number in \"" - << conf_key_fcst_field << "\".\n\n"; - exit(1); - } - - if(n_vx > 0) { - - // Allocate memory for the verification task options - vx_opt = new GenEnsProdVxOpt [n_vx]; - +// JHG work here to parse the climo_mean and climo_stdev info! +/* // Check climatology fields check_climo_n_vx(&conf, n_vx); - - // Check to make sure the observation file type is defined - if(otype == FileType_None) { - mlog << Error << "\nGenEnsProdConfInfo::process_config() -> " - << "When \"fcst.field\" is non-empty, you must use " - << "\"-point_obs\" and/or \"-grid_obs\" to specify the " - << "verifying observations.\n\n"; - exit(1); - } - - // Parse settings for each verification task - for(i=0; ilookup(conf_key_ensemble_flag); if(!e) { mlog << Error @@ -376,656 +265,40 @@ void GenEnsProdConfInfo::parse_nc_info() { exit(1); } - const ConfigObjectType type = e->type(); - - if(type == BooleanType) { - bool value = e->b_value(); - - if(!value) nc_info.set_all_false(); - - return; - } - - // It should be a dictionary - if(type != DictionaryType) { - mlog << Error - << "\nGenEnsProdConfInfo::parse_nc_info() -> " - << "bad type (" << configobjecttype_to_string(type) - << ") for key \"" << conf_key_ensemble_flag << "\"\n\n"; - exit(1); - } - - // Parse the various entries - Dictionary * d = e->dict_value(); - - nc_info.do_latlon = d->lookup_bool(conf_key_latlon_flag); - nc_info.do_mean = d->lookup_bool(conf_key_mean_flag); - nc_info.do_stdev = d->lookup_bool(conf_key_stdev_flag); - nc_info.do_minus = d->lookup_bool(conf_key_minus_flag); - nc_info.do_plus = d->lookup_bool(conf_key_plus_flag); - nc_info.do_min = d->lookup_bool(conf_key_min_flag); - nc_info.do_max = d->lookup_bool(conf_key_max_flag); - nc_info.do_range = d->lookup_bool(conf_key_range_flag); - nc_info.do_vld = d->lookup_bool(conf_key_vld_count_flag); - nc_info.do_freq = d->lookup_bool(conf_key_frequency_flag); - nc_info.do_nep = d->lookup_bool(conf_key_nep_flag); - nc_info.do_nmep = d->lookup_bool(conf_key_nmep_flag); - nc_info.do_orank = d->lookup_bool(conf_key_rank_flag); - nc_info.do_weight = d->lookup_bool(conf_key_weight); - - return; -} - -//////////////////////////////////////////////////////////////////////// - -void GenEnsProdConfInfo::process_flags() { - int i, j; - bool output_ascii_flag = false; - - // Initialize - for(i=0; itype() == BooleanType) { + if(e->b_value()) cur.set_all_true(); + else cur.set_all_false(); } + // Dictionary type + else { - return; -} - -//////////////////////////////////////////////////////////////////////// - -void GenEnsProdConfInfo::process_masks(const Grid &grid) { - int i, j; - MaskPlane mp; - StringArray sid; - ConcatString name; - - mlog << Debug(2) - << "Processing masking regions.\n"; - - // Mapping of grid definition strings to mask names - map grid_map; - map poly_map; - map sid_map; - map point_map; - - // Initialize - mask_area_map.clear(); - mask_sid_map.clear(); - - // Process the masks for each vx task - for(i=0; i " - << "At least one grid, polyline or station ID masking " - << "region must be provided for verification task number " - << i+1 << ".\n\n"; + // Check the type + if(e->type() != DictionaryType) { + mlog << Error << "\nGenEnsProdConfInfo::parse_nc_info() -> " + << "bad type (" << configobjecttype_to_string(e->type()) + << ") for key \"" << conf_key_ensemble_flag << "\"\n\n"; exit(1); } - } // end for i - - return; -} - -//////////////////////////////////////////////////////////////////////// - -int GenEnsProdConfInfo::n_txt_row(int i_txt_row) const { - int i, n; - - // Loop over the tasks and sum the line counts for this line type - for(i=0, n=0; idict_value(); + cur.do_latlon = d->lookup_bool(conf_key_latlon_flag); + cur.do_mean = d->lookup_bool(conf_key_mean_flag); + cur.do_stdev = d->lookup_bool(conf_key_stdev_flag); + cur.do_minus = d->lookup_bool(conf_key_minus_flag); + cur.do_plus = d->lookup_bool(conf_key_plus_flag); + cur.do_min = d->lookup_bool(conf_key_min_flag); + cur.do_max = d->lookup_bool(conf_key_max_flag); + cur.do_range = d->lookup_bool(conf_key_range_flag); + cur.do_vld = d->lookup_bool(conf_key_vld_count_flag); + cur.do_freq = d->lookup_bool(conf_key_frequency_flag); + cur.do_nep = d->lookup_bool(conf_key_nep_flag); + cur.do_nmep = d->lookup_bool(conf_key_nmep_flag); } - return; -} - -//////////////////////////////////////////////////////////////////////// -// -// Code for class GenEnsProdVxOpt -// -//////////////////////////////////////////////////////////////////////// - -GenEnsProdVxOpt::GenEnsProdVxOpt() { - - init_from_scratch(); -} - -//////////////////////////////////////////////////////////////////////// - -GenEnsProdVxOpt::~GenEnsProdVxOpt() { - - clear(); -} - -//////////////////////////////////////////////////////////////////////// - -void GenEnsProdVxOpt::init_from_scratch() { - - clear(); - - return; -} - -//////////////////////////////////////////////////////////////////////// - -void GenEnsProdVxOpt::clear() { - int i; - - // Initialize values - vx_pd.clear(); - var_str.clear(); - beg_ds = end_ds = bad_data_int; - mask_grid.clear(); - mask_poly.clear(); - mask_sid.clear(); - mask_llpnt.clear(); - mask_name.clear(); - mask_name_area.clear(); - msg_typ.clear(); - othr_ta.clear(); - cdf_info.clear(); - ci_alpha.clear(); - interp_info.clear(); - - ssvar_bin_size = bad_data_double; - phist_bin_size = bad_data_double; - prob_cat_ta.clear(); - - duplicate_flag = DuplicateType_None; - obs_summary = ObsSummary_None; - obs_perc = bad_data_int; - skip_const = false; - obs_error.clear(); - - for(i=0; ioutput_map; - Dictionary *dict; - - // Initialize - clear(); - - // Allocate new VarInfo objects - vx_pd.fcst_info = info_factory.new_var_info(ftype); - vx_pd.obs_info = info_factory.new_var_info(otype); - - // Set the VarInfo objects - vx_pd.fcst_info->set_dict(fdict); - vx_pd.obs_info->set_dict(odict); - - // Set the GRIB code for point observations - if(point_vx && !use_var_id) vx_pd.obs_info->add_grib_code(odict); - - // Dump the contents of the current VarInfo - if(mlog.verbosity_level() >= 5) { - mlog << Debug(5) - << "Parsed forecast field:\n"; - vx_pd.fcst_info->dump(cout); - mlog << Debug(5) - << "Parsed observation field:\n"; - vx_pd.obs_info->dump(cout); - } - - // Check the levels for the forecast and observation fields. If the - // forecast field is a range of pressure levels, check to see if the - // range of observation field pressure levels is wholly contained in the - // fcst levels. If not, print a warning message. - if(vx_pd.fcst_info->level().type() == LevelType_Pres && - !is_eq(vx_pd.fcst_info->level().lower(), vx_pd.fcst_info->level().upper()) && - (vx_pd.obs_info->level().lower() < vx_pd.fcst_info->level().lower() || - vx_pd.obs_info->level().upper() > vx_pd.fcst_info->level().upper())) { - - mlog << Warning - << "\nGenEnsProdVxOpt::process_config() -> " - << "The range of requested observation pressure levels " - << "is not contained within the range of requested " - << "forecast pressure levels. No vertical interpolation " - << "will be performed for observations falling outside " - << "the range of forecast levels. Instead, they will be " - << "matched to the single nearest forecast level.\n\n"; - } - - // No support for wind direction - if(vx_pd.fcst_info->is_wind_direction() || - vx_pd.obs_info->is_wind_direction()) { - mlog << Error << "\nGenEnsProdVxOpt::process_config() -> " - << "wind direction may not be verified using grid_stat.\n\n"; - exit(1); - } - - // Check that the observation field does not contain probabilities - if(vx_pd.obs_info->is_prob()) { - mlog << Error << "\nGenEnsProdVxOpt::process_config() -> " - << "the observation field cannot contain probabilities.\n\n"; - exit(1); - } - - // Conf: nc_var_str - var_str = parse_conf_string(&odict, conf_key_nc_var_str, false); - - // Conf: beg_ds and end_ds - dict = odict.lookup_dictionary(conf_key_obs_window); - parse_conf_range_int(dict, beg_ds, end_ds); - - // Conf: mask_grid - mask_grid = odict.lookup_string_array(conf_key_mask_grid); - - // Conf: mask_poly - mask_poly = odict.lookup_string_array(conf_key_mask_poly); - - // Conf: mask_sid - mask_sid = odict.lookup_string_array(conf_key_mask_sid); - - // Conf: mask_llpnt - mask_llpnt = parse_conf_llpnt_mask(&odict); - - // Conf: message_type - msg_typ = parse_conf_message_type(&odict, point_vx); - - // Conf: othr_thresh - othr_ta = process_perc_thresh_bins( - odict.lookup_thresh_array(conf_key_obs_thresh)); - - // Conf: climo_cdf - cdf_info = parse_conf_climo_cdf(&odict); - - // Conf: ci_alpha - ci_alpha = parse_conf_ci_alpha(&odict); - - // Conf: interp - interp_info = parse_conf_interp(&odict, conf_key_interp); - - // Conf: output_flag - output_map = parse_conf_output_flag(&odict, txt_file_type, n_txt); - - // Populate the output_flag array with map values - for(i=0; i " - << "At least one output message type must be requested in \"" - << conf_key_message_type << "\".\n\n"; - exit(1); - } - - // Check for at least one masking region - if(n_mask == 0) { - mlog << Error << "\nGenEnsProdVxOpt::set_vx_pd() -> " - << "At least one output masking region must be requested in \"" - << conf_key_mask_grid << "\", \"" - << conf_key_mask_poly << "\", \"" - << conf_key_mask_sid << "\", or \"" - << conf_key_mask_llpnt << "\".\n\n"; - exit(1); - } - - // Check for at least one interpolation method - if(n_interp == 0) { - mlog << Error << "\nGenEnsProdVxOpt::set_vx_pd() -> " - << "At least one interpolation method must be requested in \"" - << conf_key_interp << "\".\n\n"; - exit(1); - } - - // Define the dimensions - vx_pd.set_pd_size(n_msg_typ, n_mask, n_interp); - - // Store the climo CDF info - vx_pd.set_climo_cdf_info(cdf_info); - - // Store the list of surface message types - vx_pd.set_msg_typ_sfc(conf_info->msg_typ_sfc); - - // Define the verifying message type name and values - for(i=0; imsg_typ_group_map[msg_typ[i]]; - if(sa.n_elements() == 0) sa.add(msg_typ[i]); - vx_pd.set_msg_typ_vals(i, sa); - } - - // Define the masking information: grid, poly, sid - - // Define the grid masks - for(i=0; imask_area_map[mask_name[n]])); - } - - // Define the poly masks - for(i=0; imask_area_map[mask_name[n]])); - } - - // Define the station ID masks - for(i=0; imask_sid_map[mask_name[n]])); - } - - // Define the Lat/Lon point masks - for(i=0; i<(int) mask_llpnt.size(); i++) { - n = i + mask_grid.n_elements() + mask_poly.n_elements() + mask_sid.n_elements(); - vx_pd.set_mask_llpnt(n, mask_name[n].c_str(), &mask_llpnt[i]); - } - - // Define the interpolation methods - for(i=0; in_ens; i++) fsort.add(pd_ptr->e_na[i]); - NumArray osort = pd_ptr->o_na; - NumArray csort = pd_ptr->cmn_na; - fsort.sort_array(); - osort.sort_array(); - csort.sort_array(); - - // - // Compute percentiles, passing the observation thresholds in for - // the fcst and obs slots. - // - othr_ta.set_perc(&fsort, &osort, &csort, &othr_ta, &othr_ta); - - return; -} - -//////////////////////////////////////////////////////////////////////// - -int GenEnsProdVxOpt::n_txt_row(int i_txt_row) const { - int n = 0; - - // Range check - if(i_txt_row < 0 || i_txt_row >= n_txt) { - mlog << Error << "\nGenEnsProdVxOpt::n_txt_row(int) -> " - << "range check error for " << i_txt_row << "\n\n"; - exit(1); - } - - // Check if this output line type is requested - if(output_flag[i_txt_row] == STATOutputType_None) return(0); - - // Switch on the index of the line type - switch(i_txt_row) { - - case(i_ecnt): - case(i_rps): - - // Maximum number of ECNT and RPS lines possible = - // Point Vx: Message Types * Masks * Interpolations * - // Obs Thresholds - // Grid Vx: Masks * Interpolations * - // Obs Thresholds - n = (get_n_msg_typ() + 1) * get_n_mask() * get_n_interp() * - get_n_o_thresh(); - break; - - case(i_rhist): - case(i_phist): - case(i_relp): - - // Maximum number of RHIST, PHIST, and RELP lines possible = - // Point Vx: Message Types * Masks * Interpolations * Obs Thresholds - // Grid Vx: Masks * Interpolations * Obs Thresholds - n = (get_n_msg_typ() + 1) * get_n_mask() * get_n_interp() * - get_n_o_thresh(); - break; - - case(i_orank): - - // Compute the maximum number of matched pairs to be written - // out by summing the number for each VxPairDataEnsemble object - n = vx_pd.get_n_pair() * get_n_o_thresh(); - break; - - case(i_ssvar): - - // Just return zero since we'll resize the output AsciiTables - // to accomodate the SSVAR output - n = 0; - break; - - default: - mlog << Error << "\nGenEnsProdVxOpt::n_txt_row(int) -> " - << "unexpected output type index value: " << i_txt_row - << "\n\n"; - exit(1); - } - - return(n); + return(cur); } //////////////////////////////////////////////////////////////////////// @@ -1053,14 +326,19 @@ bool GenEnsProdNcOutInfo::all_false() const { bool status = do_latlon || do_mean || do_stdev || do_minus || do_plus || do_min || do_max || do_range || - do_vld || do_freq || do_nep || do_nmep || - do_orank || do_weight; + do_vld || do_freq || do_nep || do_nmep; return(!status); } //////////////////////////////////////////////////////////////////////// +bool GenEnsProdNcOutInfo::need_cat_thresh() const { + return(do_freq || do_nep || do_nmep); +} + +//////////////////////////////////////////////////////////////////////// + void GenEnsProdNcOutInfo::set_all_false() { do_latlon = false; @@ -1075,13 +353,10 @@ void GenEnsProdNcOutInfo::set_all_false() { do_freq = false; do_nep = false; do_nmep = false; - do_orank = false; - do_weight = false; return; } - //////////////////////////////////////////////////////////////////////// void GenEnsProdNcOutInfo::set_all_true() { @@ -1098,11 +373,8 @@ void GenEnsProdNcOutInfo::set_all_true() { do_freq = true; do_nep = true; do_nmep = true; - do_orank = true; - do_weight = true; return; } //////////////////////////////////////////////////////////////////////// - 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 628c8995ef..e65cec32e0 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 @@ -22,25 +22,6 @@ #include "vx_cal.h" #include "vx_math.h" #include "vx_gsl_prob.h" -#include "vx_statistics.h" - -//////////////////////////////////////////////////////////////////////// - -// Indices for the output flag types in the configuration file -static const int i_ecnt = 0; -static const int i_rps = 1; -static const int i_rhist = 2; -static const int i_phist = 3; -static const int i_orank = 4; -static const int i_ssvar = 5; -static const int i_relp = 6; -static const int n_txt = 7; - -// Text file type -static const STATLineType txt_file_type[n_txt] = { - stat_ecnt, stat_rps, stat_rhist, stat_phist, - stat_orank, stat_ssvar, stat_relp -}; //////////////////////////////////////////////////////////////////////// @@ -58,16 +39,13 @@ struct GenEnsProdNcOutInfo { bool do_freq; bool do_nep; bool do_nmep; - bool do_orank; - bool do_weight; - - ////////////////////////////////////////////////////////////////// GenEnsProdNcOutInfo(); - void clear(); // sets everything to true + void clear(); bool all_false() const; + bool need_cat_thresh() const; void set_all_false(); void set_all_true(); @@ -75,99 +53,6 @@ struct GenEnsProdNcOutInfo { //////////////////////////////////////////////////////////////////////// -class GenEnsProdConfInfo; // forward reference - -//////////////////////////////////////////////////////////////////////// - -class GenEnsProdVxOpt { - - private: - - void init_from_scratch(); - - public: - - GenEnsProdVxOpt(); - ~GenEnsProdVxOpt(); - - ////////////////////////////////////////////////////////////////// - - VxPairDataEnsemble vx_pd; // Ensemble pair data - - ConcatString var_str; // nc_pairs_var_str string - - int beg_ds; // Begin observation time window offset - int end_ds; // End observation time window offset - - StringArray mask_grid; // Masking grid strings - StringArray mask_poly; // Masking polyline strings - StringArray mask_sid; // Masking station ID's - - // Vector of MaskLatLon objects defining Lat/Lon Point masks - vector mask_llpnt; - - StringArray mask_name; // Masking region names - StringArray mask_name_area; // Masking area (grid + poly) region names - - StringArray msg_typ; // Verifying message types - - ThreshArray othr_ta; // Observation filetering thresholds - - ClimoCDFInfo cdf_info; // Climo CDF info - - NumArray ci_alpha; // Alpha value for confidence intervals - - InterpInfo interp_info; // Interpolation (smoothing) information - - double ssvar_bin_size; // SSVAR bin size - double phist_bin_size; // PHIST bin size - ThreshArray prob_cat_ta; // Categorical thresholds for probabilities - - DuplicateType duplicate_flag; // Duplicate observations - ObsSummary obs_summary; // Summarize observations - int obs_perc; // Summary percentile value - bool skip_const; // Skip points with constant data values - ObsErrorInfo obs_error; // Observation error handling - - // Output file options - STATOutputType output_flag[n_txt]; // Flag for each output line type - - ////////////////////////////////////////////////////////////////// - - void clear(); - - void process_config(GrdFileType, Dictionary &, - GrdFileType, Dictionary &, - gsl_rng *, bool, bool, bool); - void set_vx_pd(GenEnsProdConfInfo *); - - void set_perc_thresh(const PairDataEnsemble *); - - // Compute the number of output lines for this task - int n_txt_row(int i) const; - - int get_n_msg_typ() const; - int get_n_interp() const; - int get_n_mask() const; - int get_n_mask_area() const; - - int get_n_o_thresh() const; - int get_n_cdf_bin() const; - int get_n_ci_alpha() const; -}; - -//////////////////////////////////////////////////////////////////////// - -inline int GenEnsProdVxOpt::get_n_msg_typ() const { return(msg_typ.n()); } -inline int GenEnsProdVxOpt::get_n_interp() const { return(interp_info.n_interp); } -inline int GenEnsProdVxOpt::get_n_mask() const { return(mask_name.n()); } -inline int GenEnsProdVxOpt::get_n_mask_area() const { return(mask_name_area.n()); } -inline int GenEnsProdVxOpt::get_n_o_thresh() const { return(othr_ta.n()); } -inline int GenEnsProdVxOpt::get_n_cdf_bin() const { return(cdf_info.n_bin); } -inline int GenEnsProdVxOpt::get_n_ci_alpha() const { return(ci_alpha.n()); } - -//////////////////////////////////////////////////////////////////////// - class GenEnsProdConfInfo { private: @@ -176,10 +61,8 @@ class GenEnsProdConfInfo { // Ensemble processing int n_ens_var; // Number of ensemble fields to be processed - int max_n_thresh; // Maximum number of ensemble thresholds - - // Ensemble verification - int n_vx; // Number of ensemble fields to be verified + int max_n_cat_ta; // Maximum number of ensemble thresholds + int n_nbrhd; // Number of neighborhood sizes public: @@ -188,78 +71,52 @@ class GenEnsProdConfInfo { ////////////////////////////////////////////////////////////////// - // Ensemble-Stat configuration object + // Gen-Ens-Prod configuration object MetConfig conf; - // Store data parsed from the Ensemble-Stat configuration object - ConcatString model; // Model name - ConcatString obtype; // Observation type - - VarInfo ** ens_info; // Array of pointers for ensemble [n_ens_var] (allocated) - ThreshArray * ens_ta; // Array for ensemble thresholds [n_ens_var] (allocated) - StringArray ens_var_str; // Array for ensemble variable name strings [n_ens_var] + // Data parsed from the Gen-Ens-Prod configuration object + ConcatString model; // Model name + ConcatString desc; // Description - NbrhdInfo nbrhd_prob; // Neighborhood probability definition - int n_nbrhd; // Number of neighborhood sizes - InterpInfo nmep_smooth; // Neighborhood maximum smoothing information + vector ens_info; // Array of var info pointers (allocated) + vector cdf_info; // Array of climo CDF info objects + vector ens_cat_ta; // Array for ensemble categorical thresholds + StringArray ens_var_str; // Array of ensemble variable name strings + vector nc_info; // Array of ensemble product outputs - GenEnsProdVxOpt * vx_opt; // Array of vx task options [n_vx] (allocated) + NbrhdInfo nbrhd_prob; // Neighborhood probability definition + InterpInfo nmep_smooth; // Neighborhood maximum smoothing information - double vld_ens_thresh; // Required ratio of valid input files - double vld_data_thresh; // Required ratio of valid data for each point + double vld_ens_thresh; // Required ratio of valid input files + double vld_data_thresh; // Required ratio of valid data for each point - // Message type groups that should be processed together - map msg_typ_group_map; - StringArray msg_typ_sfc; + gsl_rng * rng_ptr; // GSL random number generator (allocated) - // Mapping of mask names to MaskPlanes - map mask_area_map; - - // Mapping of mask names to Station ID lists - map mask_sid_map; - - gsl_rng *rng_ptr; // GSL random number generator (allocated) - - GridWeightType grid_weight_flag; // Grid weighting flag - ConcatString tmp_dir; // Directory for temporary files - ConcatString output_prefix; // String to customize output file name - ConcatString version; // Config file version - - STATOutputType output_flag[n_txt]; // Summary of output_flag options - - GenEnsProdNcOutInfo nc_info; // Output NetCDF file contents + ConcatString tmp_dir; // Directory for temporary files + ConcatString version; // Config file version ////////////////////////////////////////////////////////////////// void clear(); - void read_config (const ConcatString , const ConcatString); - void process_config(GrdFileType, GrdFileType, bool, bool, bool); - void process_flags (); - void parse_nc_info (); - void process_masks (const Grid &); - void set_vx_pd (const IntArray &); - - // Dump out the counts - int get_n_ens_var() const; - int get_max_n_thresh() const; - int get_n_nbrhd() const; - int get_n_vx() const; - - // Compute the maximum number of output lines possible based - // on the contents of the configuration file - int n_txt_row(int i) const; - int n_stat_row() const; + void read_config (const ConcatString, const ConcatString); + void process_config(GrdFileType); + + GenEnsProdNcOutInfo parse_nc_info(Dictionary *); + + // Accessor functions + int get_n_ens_var() const; + int get_max_n_cat_ta() const; + int get_n_nbrhd() const; int get_compression_level(); }; //////////////////////////////////////////////////////////////////////// -inline int GenEnsProdConfInfo::get_n_ens_var() const { return(n_ens_var); } -inline int GenEnsProdConfInfo::get_max_n_thresh() const { return(max_n_thresh); } -inline int GenEnsProdConfInfo::get_n_nbrhd() const { return(n_nbrhd); } -inline int GenEnsProdConfInfo::get_n_vx() const { return(n_vx); } -inline int GenEnsProdConfInfo::get_compression_level() { return(conf.nc_compression()); } +inline int GenEnsProdConfInfo::get_n_ens_var() const { return(n_ens_var); } +inline int GenEnsProdConfInfo::get_max_n_cat_ta() const { return(max_n_cat_ta); } +inline int GenEnsProdConfInfo::get_n_nbrhd() const { return(n_nbrhd); } +inline int GenEnsProdConfInfo::get_compression_level() { return(conf.nc_compression()); } ////////////////////////////////////////////////////////////////////////