From 4bbe2aecfadeb6bde176c243ed1795a165d3c439 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Wed, 9 Oct 2024 22:38:05 +0000 Subject: [PATCH] Per #2279, add the MaskSID struct to store information about station id names and corresponding weights. --- src/basic/vx_config/config_constants.h | 27 +++ src/basic/vx_config/config_util.cc | 155 ++++++++++++++---- src/basic/vx_config/config_util.h | 5 +- src/libcode/vx_analysis_util/stat_job.cc | 9 +- src/libcode/vx_statistics/pair_base.cc | 26 +-- src/libcode/vx_statistics/pair_base.h | 10 +- .../ensemble_stat/ensemble_stat_conf_info.cc | 7 +- .../ensemble_stat/ensemble_stat_conf_info.h | 2 +- .../core/point_stat/point_stat_conf_info.cc | 7 +- .../core/point_stat/point_stat_conf_info.h | 2 +- src/tools/other/ascii2nc/ascii2nc.cc | 8 +- src/tools/other/ioda2nc/ioda2nc.cc | 8 +- src/tools/other/ioda2nc/ioda2nc_conf_info.cc | 13 +- src/tools/other/madis2nc/madis2nc.cc | 8 +- src/tools/other/pb2nc/pb2nc_conf_info.cc | 13 +- 15 files changed, 206 insertions(+), 94 deletions(-) diff --git a/src/basic/vx_config/config_constants.h b/src/basic/vx_config/config_constants.h index 7bba9e759e..95155ec02a 100644 --- a/src/basic/vx_config/config_constants.h +++ b/src/basic/vx_config/config_constants.h @@ -422,6 +422,33 @@ struct MaskLatLon { //////////////////////////////////////////////////////////////////////// +// +// Struct to store masking station id information +// + +struct MaskSID { + + // Mask name + ConcatString name; + + // Vector of SID name and corresponding weights + std::vector> sid_list; + + void clear(); + bool operator==(const MaskSID &) const; + MaskSID &operator=(const MaskSID &a) noexcept; + + int n() const; + + // Formatted as: station_name(numeric_weight) + void add(const std::string &); + void add_css(const std::string &); + bool has(const std::string &); + void sort(); +}; + +//////////////////////////////////////////////////////////////////////// + // // Enumeration for duplicate_flag configuration parameter // diff --git a/src/basic/vx_config/config_util.cc b/src/basic/vx_config/config_util.cc index 5cce67dfcb..7df287ae66 100644 --- a/src/basic/vx_config/config_util.cc +++ b/src/basic/vx_config/config_util.cc @@ -597,19 +597,115 @@ StringArray parse_conf_message_type(Dictionary *dict, bool error_out) { return sa; } +/////////////////////////////////////////////////////////////////////////////// +// +// Code for MaskSID struct +// +/////////////////////////////////////////////////////////////////////////////// + +void MaskSID::clear() { + name.clear(); + sid_list.clear(); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool MaskSID::operator==(const MaskSID &v) const { + bool match = true; + + if(!(name == v.name ) || + !(sid_list == v.sid_list)) { + match = false; + } + + return match; +} + +/////////////////////////////////////////////////////////////////////////////// + +MaskSID &MaskSID::operator=(const MaskSID &a) noexcept { + if(this != &a) { + name = a.name; + sid_list = a.sid_list; + } + return *this; +} + +/////////////////////////////////////////////////////////////////////////////// + +int MaskSID::n() const { + return sid_list.size(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void MaskSID::add(const string &text) { + size_t pos = 0; + ConcatString sid; + double wgt = 1.0; + + // Parse station id and optional weight + if((pos = text.find("(")) != string::npos) { + sid = text.substr(0, pos); + wgt = stod(text.substr(pos)); + } + // No weight specified + else { + sid = text; + } + + // Store the pair + sid_list.push_back(pair(sid,wgt)); + + return; +} + +/////////////////////////////////////////////////////////////////////////////// + +void MaskSID::add_css(const string &text) { + StringArray sa; + sa.add_css(text); + for(int i=0; i " + mlog << Debug(4) << method_name << "parsing station ID masking file \"" << tmp_file << "\"\n"; // Open the mask station id file specified + ifstream in; in.open(tmp_file.c_str()); if(!in) { - mlog << Error << "\nparse_sid_mask() -> " + mlog << Error << "\n" << method_name << "Can't open the station ID masking file \"" << tmp_file << "\".\n\n"; exit(1); @@ -665,7 +757,7 @@ void parse_sid_mask(const ConcatString &mask_sid_str, // Store the first entry as the name of the mask in >> sid_str; - mask_name = sid_str; + mask_sid.name = sid_str; // Store the rest of the entries as masking station ID's while(in >> sid_str) mask_sid.add(sid_str.c_str()); @@ -673,9 +765,9 @@ void parse_sid_mask(const ConcatString &mask_sid_str, // Close the input file in.close(); - mlog << Debug(4) << "parse_sid_mask() -> " + mlog << Debug(4) << method_name << "parsed " << mask_sid.n() << " station ID's for the \"" - << mask_name << "\" mask from file \"" << tmp_file << "\"\n"; + << mask_sid.name << "\" mask from file \"" << tmp_file << "\"\n"; } // Process list of strings else { @@ -683,19 +775,19 @@ void parse_sid_mask(const ConcatString &mask_sid_str, // Print a warning if the string contains a dot which suggests // the user was trying to specify a file name. if(check_reg_exp("[.]", mask_sid_str.c_str())) { - mlog << Warning << "\nparse_sid_mask() -> " + mlog << Warning << "\n" << method_name << "unable to process \"" << mask_sid_str << "\" as a file name and processing it as a single " << "station ID mask instead.\n\n"; } - mlog << Debug(4) << "parse_sid_mask() -> " + mlog << Debug(4) << method_name << "storing single station ID mask \"" << mask_sid_str << "\"\n"; // Check for embedded whitespace or slashes if(check_reg_exp(ws_reg_exp, mask_sid_str.c_str()) || check_reg_exp("[/]", mask_sid_str.c_str())) { - mlog << Error << "\nparse_sid_mask() -> " + mlog << Error << "\n" << method_name << "masking station ID string can't contain whitespace or " << "slashes \"" << mask_sid_str << "\".\n\n"; exit(1); @@ -708,15 +800,16 @@ void parse_sid_mask(const ConcatString &mask_sid_str, // One elements means no colon was specified if(sa.n() == 1) { mask_sid.add_css(sa[0]); - mask_name = ( mask_sid.n() == 1 ? mask_sid[0] : "MASK_SID" ); + mask_sid.name = (mask_sid.sid_list.size() == 1 ? + mask_sid.sid_list[0].first : "MASK_SID"); } // Two elements means one colon was specified else if(sa.n() == 2) { - mask_name = sa[0]; mask_sid.add_css(sa[1]); + mask_sid.name = sa[0]; } else { - mlog << Error << "\nparse_sid_mask() -> " + mlog << Error << "\n" << method_name << "masking station ID string may contain at most one colon to " << "specify the mask name \"" << mask_sid_str << "\".\n\n"; exit(1); @@ -727,11 +820,14 @@ void parse_sid_mask(const ConcatString &mask_sid_str, // Sort the mask_sid's mask_sid.sort(); - return; + return mask_sid; } /////////////////////////////////////////////////////////////////////////////// - +// +// Code for MaskLatLon struct +// +/////////////////////////////////////////////////////////////////////////////// void MaskLatLon::clear() { name.clear(); @@ -764,7 +860,6 @@ MaskLatLon &MaskLatLon::operator=(const MaskLatLon &a) noexcept { return *this; } - /////////////////////////////////////////////////////////////////////////////// vector parse_conf_llpnt_mask(Dictionary *dict) { diff --git a/src/basic/vx_config/config_util.h b/src/basic/vx_config/config_util.h index 15de1e00f0..f1e66ada2b 100644 --- a/src/basic/vx_config/config_util.h +++ b/src/basic/vx_config/config_util.h @@ -55,10 +55,7 @@ extern StringArray parse_conf_message_type( extern StringArray parse_conf_sid_list( Dictionary *dict, const char *); -extern void parse_sid_mask( - const ConcatString &, - StringArray &, - ConcatString &); +extern MaskSID parse_sid_mask(const ConcatString &); extern std::vector parse_conf_llpnt_mask(Dictionary *dict); extern StringArray parse_conf_obs_qty_inc(Dictionary *dict); diff --git a/src/libcode/vx_analysis_util/stat_job.cc b/src/libcode/vx_analysis_util/stat_job.cc index c10f392b85..dc8c9496ee 100644 --- a/src/libcode/vx_analysis_util/stat_job.cc +++ b/src/libcode/vx_analysis_util/stat_job.cc @@ -1802,20 +1802,19 @@ void STATAnalysisJob::set_mask_sid(const char *c) { if(!c) return; - ConcatString mask_name; - mask_sid_str = c; // List the station ID mask mlog << Debug(1) << "Station ID Mask: " << mask_sid_str << "\n"; - parse_sid_mask(mask_sid_str, mask_sid, mask_name); + MaskSID ms = parse_sid_mask(mask_sid_str); + for(auto item : ms.sid_list) mask_sid.add(item.first); // List the length of the station ID mask mlog << Debug(2) - << "Parsed Station ID Mask: " << mask_name - << " containing " << mask_sid.n() << " points\n"; + << "Parsed Station ID Mask: " << ms.name + << " containing " << mask_sid.n() << " stations\n"; return; } diff --git a/src/libcode/vx_statistics/pair_base.cc b/src/libcode/vx_statistics/pair_base.cc index c26d2d3459..3c5df818cd 100644 --- a/src/libcode/vx_statistics/pair_base.cc +++ b/src/libcode/vx_statistics/pair_base.cc @@ -81,9 +81,9 @@ void PairBase::clear() { IsPointVx = false; mask_name.clear(); - mask_area_ptr = (MaskPlane *) nullptr; // Not allocated - mask_sid_ptr = (StringArray *) nullptr; // Not allocated - mask_llpnt_ptr = (MaskLatLon *) nullptr; // Not allocated + mask_area_ptr = (MaskPlane *) nullptr; // Not allocated + mask_sid_ptr = (MaskSID *) nullptr; // Not allocated + mask_llpnt_ptr = (MaskLatLon *) nullptr; // Not allocated cdf_info_ptr = (const ClimoCDFInfo *) nullptr; // Not allocated @@ -133,9 +133,9 @@ void PairBase::erase() { IsPointVx = false; mask_name.erase(); - mask_area_ptr = (MaskPlane *) nullptr; // Not allocated - mask_sid_ptr = (StringArray *) nullptr; // Not allocated - mask_llpnt_ptr = (MaskLatLon *) nullptr; // Not allocated + mask_area_ptr = (MaskPlane *) nullptr; // Not allocated + mask_sid_ptr = (MaskSID *) nullptr; // Not allocated + mask_llpnt_ptr = (MaskLatLon *) nullptr; // Not allocated cdf_info_ptr = (const ClimoCDFInfo *) nullptr; // Not allocated @@ -205,9 +205,9 @@ void PairBase::extend(int n) { //////////////////////////////////////////////////////////////////////// -void PairBase::set_mask_name(const char *c) { +void PairBase::set_mask_name(const string &s) { - mask_name = c; + mask_name = s; return; } @@ -223,9 +223,9 @@ void PairBase::set_mask_area_ptr(MaskPlane *mp_ptr) { //////////////////////////////////////////////////////////////////////// -void PairBase::set_mask_sid_ptr(StringArray *sid_ptr) { +void PairBase::set_mask_sid_ptr(MaskSID *ms_ptr) { - mask_sid_ptr = sid_ptr; + mask_sid_ptr = ms_ptr; return; } @@ -1293,13 +1293,15 @@ void VxPairBase::set_mask_area(int i_mask, const char *name, //////////////////////////////////////////////////////////////////////// void VxPairBase::set_mask_sid(int i_mask, const char *name, - StringArray *sid_ptr) { + MaskSID *ms_ptr) { + + if(!ms_ptr) return; for(int i_msg_typ=0; i_msg_typset_mask_name(name); - pb_ptr[n]->set_mask_sid_ptr(sid_ptr); + pb_ptr[n]->set_mask_sid_ptr(ms_ptr); } } diff --git a/src/libcode/vx_statistics/pair_base.h b/src/libcode/vx_statistics/pair_base.h index af92385f5c..37a7244635 100644 --- a/src/libcode/vx_statistics/pair_base.h +++ b/src/libcode/vx_statistics/pair_base.h @@ -75,10 +75,10 @@ class PairBase { ////////////////////////////////////////////////////////////////// // Masking area applied to the forecast and climo fields - ConcatString mask_name; + ConcatString mask_name; MaskPlane *mask_area_ptr; // Pointer to the masking MaskPlane // which is not allocated - StringArray *mask_sid_ptr; // Pointer to masking station ID list + MaskSID *mask_sid_ptr; // Pointer to masking station ID list // which is not allocated MaskLatLon *mask_llpnt_ptr; // Pointer to Lat/Lon thresholds // which is not allocated @@ -137,9 +137,9 @@ class PairBase { bool is_point_vx() const; - void set_mask_name(const char *); + void set_mask_name(const std::string &); void set_mask_area_ptr(MaskPlane *); - void set_mask_sid_ptr(StringArray *); + void set_mask_sid_ptr(MaskSID *); void set_mask_llpnt_ptr(MaskLatLon *); void set_climo_cdf_info_ptr(const ClimoCDFInfo *); @@ -349,7 +349,7 @@ class VxPairBase { void set_msg_typ(int, const char *); void set_msg_typ_vals(int, const StringArray &); void set_mask_area(int, const char *, MaskPlane *); - void set_mask_sid(int, const char *, StringArray *); + void set_mask_sid(int, const char *, MaskSID *); void set_mask_llpnt(int, const char *, MaskLatLon *); void set_interp(int i_interp, const char *interp_mthd_str, int width, diff --git a/src/tools/core/ensemble_stat/ensemble_stat_conf_info.cc b/src/tools/core/ensemble_stat/ensemble_stat_conf_info.cc index de3af1256b..2e9086a809 100644 --- a/src/tools/core/ensemble_stat/ensemble_stat_conf_info.cc +++ b/src/tools/core/ensemble_stat/ensemble_stat_conf_info.cc @@ -378,7 +378,6 @@ void EnsembleStatConfInfo::process_flags() { void EnsembleStatConfInfo::process_masks(const Grid &grid) { int i, j; MaskPlane mp; - StringArray sid; ConcatString name; mlog << Debug(2) @@ -447,9 +446,9 @@ void EnsembleStatConfInfo::process_masks(const Grid &grid) { mlog << Debug(3) << "Processing station ID mask: " << vx_opt[i].mask_sid[j] << "\n"; - parse_sid_mask(vx_opt[i].mask_sid[j], sid, name); - sid_map[vx_opt[i].mask_sid[j]] = name; - mask_sid_map[name] = sid; + MaskSID ms = parse_sid_mask(vx_opt[i].mask_sid[j]); + sid_map[vx_opt[i].mask_sid[j]] = ms.name; + mask_sid_map[ms.name] = ms; } // Store the name only for point verification diff --git a/src/tools/core/ensemble_stat/ensemble_stat_conf_info.h b/src/tools/core/ensemble_stat/ensemble_stat_conf_info.h index 9d9177cdab..3b7015b885 100644 --- a/src/tools/core/ensemble_stat/ensemble_stat_conf_info.h +++ b/src/tools/core/ensemble_stat/ensemble_stat_conf_info.h @@ -226,7 +226,7 @@ class EnsembleStatConfInfo { std::map mask_area_map; // Mapping of mask names to Station ID lists - std::map mask_sid_map; + std::map mask_sid_map; gsl_rng *rng_ptr; // GSL random number generator (allocated) diff --git a/src/tools/core/point_stat/point_stat_conf_info.cc b/src/tools/core/point_stat/point_stat_conf_info.cc index c8ea7c4f70..252bbd5fb8 100644 --- a/src/tools/core/point_stat/point_stat_conf_info.cc +++ b/src/tools/core/point_stat/point_stat_conf_info.cc @@ -378,7 +378,6 @@ void PointStatConfInfo::process_flags() { void PointStatConfInfo::process_masks(const Grid &grid) { int i, j; MaskPlane mp; - StringArray sid; ConcatString name; mlog << Debug(2) @@ -444,9 +443,9 @@ void PointStatConfInfo::process_masks(const Grid &grid) { mlog << Debug(3) << "Processing station ID mask: " << vx_opt[i].mask_sid[j] << "\n"; - parse_sid_mask(vx_opt[i].mask_sid[j], sid, name); - sid_map[vx_opt[i].mask_sid[j]] = name; - mask_sid_map[name] = sid; + MaskSID ms = parse_sid_mask(vx_opt[i].mask_sid[j]); + sid_map[vx_opt[i].mask_sid[j]] = ms.name; + mask_sid_map[ms.name] = ms; } // Store the name for the current station ID mask diff --git a/src/tools/core/point_stat/point_stat_conf_info.h b/src/tools/core/point_stat/point_stat_conf_info.h index 95bf59a7a7..8dbddc3453 100644 --- a/src/tools/core/point_stat/point_stat_conf_info.h +++ b/src/tools/core/point_stat/point_stat_conf_info.h @@ -240,7 +240,7 @@ class PointStatConfInfo { std::map mask_area_map; // Mapping of mask names to Station ID lists - std::map mask_sid_map; + std::map mask_sid_map; ConcatString tmp_dir; // Directory for temporary files ConcatString output_prefix; // String to customize output file name diff --git a/src/tools/other/ascii2nc/ascii2nc.cc b/src/tools/other/ascii2nc/ascii2nc.cc index 940e12cedf..a814ffa3e0 100644 --- a/src/tools/other/ascii2nc/ascii2nc.cc +++ b/src/tools/other/ascii2nc/ascii2nc.cc @@ -743,18 +743,18 @@ void set_mask_poly(const StringArray & a) { //////////////////////////////////////////////////////////////////////// void set_mask_sid(const StringArray & a) { - ConcatString mask_name; // List the station ID mask mlog << Debug(1) << "Station ID Mask: " << a[0] << "\n"; - parse_sid_mask(a[0], mask_sid, mask_name); + MaskSID ms = parse_sid_mask(a[0]); + for(auto item : ms.sid_list) mask_sid.add(item.first); // List the length of the station ID mask mlog << Debug(2) - << "Parsed Station ID Mask: " << mask_name - << " containing " << mask_sid.n_elements() << " points\n"; + << "Parsed Station ID Mask: " << ms.name + << " containing " << mask_sid.n() << " stations\n"; } //////////////////////////////////////////////////////////////////////// diff --git a/src/tools/other/ioda2nc/ioda2nc.cc b/src/tools/other/ioda2nc/ioda2nc.cc index da466c79d2..92d61ea788 100644 --- a/src/tools/other/ioda2nc/ioda2nc.cc +++ b/src/tools/other/ioda2nc/ioda2nc.cc @@ -1562,16 +1562,16 @@ void set_mask_poly(const StringArray & a) { //////////////////////////////////////////////////////////////////////// void set_mask_sid(const StringArray & a) { - ConcatString mask_name; // List the station ID mask mlog << Debug(1) << "Station ID Mask: " << a[0] << "\n"; - parse_sid_mask(a[0], mask_sid, mask_name); + MaskSID ms = parse_sid_mask(a[0]); + for(auto item : ms.sid_list) mask_sid.add(item.first); // List the length of the station ID mask - mlog << Debug(2) << "Parsed Station ID Mask: " << mask_name - << " containing " << mask_sid.n_elements() << " points\n"; + mlog << Debug(2) << "Parsed Station ID Mask: " << ms.name + << " containing " << mask_sid.n() << " stations\n"; } //////////////////////////////////////////////////////////////////////// diff --git a/src/tools/other/ioda2nc/ioda2nc_conf_info.cc b/src/tools/other/ioda2nc/ioda2nc_conf_info.cc index 68300c0ac3..d827353ab1 100644 --- a/src/tools/other/ioda2nc/ioda2nc_conf_info.cc +++ b/src/tools/other/ioda2nc/ioda2nc_conf_info.cc @@ -93,9 +93,9 @@ void IODA2NCConfInfo::read_config(const char *default_file_name, void IODA2NCConfInfo::process_config() { int i; - ConcatString s, mask_name; + ConcatString s; + ConcatString mask_name; StringArray sa; - StringArray * sid_list = nullptr; Dictionary *dict = (Dictionary *) nullptr; static const char *method_name = "IODA2NCConfInfo::process_config() -> "; @@ -124,10 +124,9 @@ void IODA2NCConfInfo::process_config() { // Conf: station_id sa = conf.lookup_string_array(conf_key_station_id); - sid_list = new StringArray [sa.n_elements()]; - for(i=0; i