From e2f77e44518877aaf75682ad4cfb78a730af0044 Mon Sep 17 00:00:00 2001 From: johnhg Date: Mon, 29 Mar 2021 10:33:31 -0600 Subject: [PATCH 1/4] Feature 1733 exc (#1734) * Per #1733, add column_exc_name, column_exc_val, init_exc_name, and init_exc_val options to the TCStat config files. * Per #1733, enhance tc_stat to support the column_exc and init_exc config file and job command filtering options. * Per #1733, update stat_analysis to support the -column_exc job filtering option. Still need to update docuementation and add unit tests. * Per #1773, update the user's guide with the new config and job command options. * Per #1733, add call to stat_analysis to exercise -column_str and -column_exc options. * Per #1733, I ran into a namespace conflict in tc_stat where -init_exc was used for to filter by time AND my string value. So I switched to using -init_str_exc instead. And made the corresponding change to -column_str_exc in stat_analysis and tc_stat. Also changed internal variable names to use IncMap and ExcMap to keep the logic clear. * Per #1733, tc_stat config file updates to switch from column_exc and init_exc to column_str_exc and init_str_exc. * Per #1733, add tc_stat and stat_analysis jobs to exercise the string filtering options. --- met/data/config/TCStatConfig_default | 12 + met/docs/Users_Guide/config_options.rst | 16 +- met/docs/Users_Guide/config_options_tc.rst | 52 ++- met/docs/Users_Guide/gsi-tools.rst | 4 +- met/docs/Users_Guide/stat-analysis.rst | 15 +- met/docs/Users_Guide/tc-stat.rst | 24 +- met/src/basic/vx_config/config_constants.h | 4 + met/src/libcode/vx_analysis_util/stat_job.cc | 77 +++- met/src/libcode/vx_analysis_util/stat_job.h | 3 +- .../tc_utils/tc_stat/tc_stat_conf_info.cc | 219 +++++----- met/src/tools/tc_utils/tc_stat/tc_stat_job.cc | 379 +++++++++++------- met/src/tools/tc_utils/tc_stat/tc_stat_job.h | 6 +- test/config/TCStatConfig_ALAL2010 | 12 + test/config/TCStatConfig_PROBRIRW | 12 + test/xml/unit_stat_analysis.xml | 15 + test/xml/unit_tc_stat.xml | 15 +- 16 files changed, 562 insertions(+), 303 deletions(-) diff --git a/met/data/config/TCStatConfig_default b/met/data/config/TCStatConfig_default index 3fc882f0f2..d385b01353 100644 --- a/met/data/config/TCStatConfig_default +++ b/met/data/config/TCStatConfig_default @@ -111,6 +111,12 @@ column_thresh_val = []; column_str_name = []; column_str_val = []; +// +// Stratify by excluding strings in non-numeric data columns. +// +column_str_exc_name = []; +column_str_exc_val = []; + // // Similar to the column_thresh options above // @@ -123,6 +129,12 @@ init_thresh_val = []; init_str_name = []; init_str_val = []; +// +// Similar to the column_str_exc options above +// +init_str_exc_name = []; +init_str_exc_val = []; + // // Stratify by the ADECK and BDECK distances to land. // diff --git a/met/docs/Users_Guide/config_options.rst b/met/docs/Users_Guide/config_options.rst index d8acbab286..e1f65cc7b4 100644 --- a/met/docs/Users_Guide/config_options.rst +++ b/met/docs/Users_Guide/config_options.rst @@ -3748,17 +3748,19 @@ Where "job_name" is set to one of the following: Job command FILTERING options that may be used only when -line_type has been listed once. These options take two arguments: the name of the data column to be used and the min, max, or exact value for that column. - If multiple column eq/min/max/str options are listed, the job will be + If multiple column eq/min/max/str/exc options are listed, the job will be performed on their intersection: .. code-block:: none - "-column_min col_name value" e.g. -column_min BASER 0.02 - "-column_max col_name value" - "-column_eq col_name value" - "-column_thresh col_name threshold" e.g. -column_thresh FCST '>273' - "-column_str col_name string" separate multiple filtering strings - with commas + "-column_min col_name value" e.g. -column_min BASER 0.02 + "-column_max col_name value" + "-column_eq col_name value" + "-column_thresh col_name threshold" e.g. -column_thresh FCST '>273' + "-column_str col_name string" separate multiple filtering strings + with commas + "-column_str_exc col_name string" separate multiple filtering strings + with commas Job command options to DEFINE the analysis job. Unless otherwise noted, diff --git a/met/docs/Users_Guide/config_options_tc.rst b/met/docs/Users_Guide/config_options_tc.rst index 155a394ed0..11f7330b4b 100644 --- a/met/docs/Users_Guide/config_options_tc.rst +++ b/met/docs/Users_Guide/config_options_tc.rst @@ -517,8 +517,8 @@ For example: Stratify by performing string matching on non-numeric data columns. Specify a comma-separated list of columns names and values -to be checked. May add using the "-column_str name string" job command -options. +to be included in the analysis. +May add using the "-column_str name string" job command options. For example: @@ -531,6 +531,23 @@ For example: column_str_name = []; column_str_val = []; +**column_str_exc_name, column_str_exc_val** + +Stratify by performing string matching on non-numeric data columns. +Specify a comma-separated list of columns names and values +to be excluded from the analysis. +May add using the "-column_str_exc name string" job command options. + +For example: + +| column_str_exc_name = [ "LEVEL" ]; +| column_str_exc_val = [ "TD" ]; +| + +.. code-block:: none + + column_str_exc_name = []; + column_str_exc_val = []; **init_thresh_name, init_thresh_val** @@ -567,6 +584,23 @@ For example: init_str_name = []; init_str_val = []; +**init_str_exc_name, init_str_exc_val** + +Just like the column_str_exc options above, but apply the string matching only +when lead = 0. If lead = 0 string does match, discard the entire track. +May add using the "-init_str_exc name thresh" job command options. + +For example: + +| init_str_exc_name = [ "LEVEL" ]; +| init_str_exc_val = [ "HU" ]; +| + +.. code-block:: none + + init_str_exc_name = []; + init_str_exc_val = []; + **water_only** Stratify by the ADECK and BDECK distances to land. Once either the ADECK or @@ -747,8 +781,10 @@ Where "job_name" is set to one of the following: "-track_watch_warn name" "-column_thresh name thresh" "-column_str name string" + "-column_str_exc name string" "-init_thresh name thresh" "-init_str name string" + "-init_str_exc name string" Additional filtering options that may be used only when -line_type has been listed only once. These options take two arguments: the name @@ -758,11 +794,13 @@ Where "job_name" is set to one of the following: .. code-block:: none - "-column_min col_name value" For example: -column_min TK_ERR 100.00 - "-column_max col_name value" - "-column_eq col_name value" - "-column_str col_name string" separate multiple filtering strings - with commas + "-column_min col_name value" For example: -column_min TK_ERR 100.00 + "-column_max col_name value" + "-column_eq col_name value" + "-column_str col_name string" separate multiple filtering strings + with commas + "-column_str_exc col_name string" separate multiple filtering strings + with commas Required Args: -dump_row diff --git a/met/docs/Users_Guide/gsi-tools.rst b/met/docs/Users_Guide/gsi-tools.rst index 0e7a6fb92a..019e5c3f7b 100644 --- a/met/docs/Users_Guide/gsi-tools.rst +++ b/met/docs/Users_Guide/gsi-tools.rst @@ -230,7 +230,7 @@ The GSID2MPR tool writes the same set of MPR output columns for the conventional - PRS_MAX_WGT - Pressure of the maximum weighing function -The gsid2mpr output may be passed to the Stat-Analysis tool to derive additional statistics. In particular, users should consider running the **aggregate_stat** job type to read MPR lines and compute partial sums (SL1L2), continuous statistics (CNT), contingency table counts (CTC), or contingency table statistics (CTS). Stat-Analysis has been enhanced to parse any extra columns found at the end of the input lines. Users can filter the values in those extra columns using the **-column_thresh** and **-column_str** job command options. +The gsid2mpr output may be passed to the Stat-Analysis tool to derive additional statistics. In particular, users should consider running the **aggregate_stat** job type to read MPR lines and compute partial sums (SL1L2), continuous statistics (CNT), contingency table counts (CTC), or contingency table statistics (CTS). Stat-Analysis has been enhanced to parse any extra columns found at the end of the input lines. Users can filter the values in those extra columns using the **-column_thresh**, **-column_str**, and **-column_str_exc** job command options. An example of the Stat-Analysis calling sequence is shown below: @@ -425,7 +425,7 @@ The GSID2MPR tool writes the same set of ORANK output columns for the convention - TZFND - d(Tz)/d(Tr) -The gsidens2orank output may be passed to the Stat-Analysis tool to derive additional statistics. In particular, users should consider running the **aggregate_stat** job type to read ORANK lines and ranked histograms (RHIST), probability integral transform histograms (PHIST), and spread-skill variance output (SSVAR). Stat-Analysis has been enhanced to parse any extra columns found at the end of the input lines. Users can filter the values in those extra columns using the **-column_thresh** and **-column_str** job command options. +The gsidens2orank output may be passed to the Stat-Analysis tool to derive additional statistics. In particular, users should consider running the **aggregate_stat** job type to read ORANK lines and ranked histograms (RHIST), probability integral transform histograms (PHIST), and spread-skill variance output (SSVAR). Stat-Analysis has been enhanced to parse any extra columns found at the end of the input lines. Users can filter the values in those extra columns using the **-column_thresh**, **-column_str**, and **-column_str_exc** job command options. An example of the Stat-Analysis calling sequence is shown below: diff --git a/met/docs/Users_Guide/stat-analysis.rst b/met/docs/Users_Guide/stat-analysis.rst index 50655fc573..ce2d8c7654 100644 --- a/met/docs/Users_Guide/stat-analysis.rst +++ b/met/docs/Users_Guide/stat-analysis.rst @@ -522,13 +522,14 @@ This job command option is extremely useful. It can be used multiple times to sp .. code-block:: none - -column_min col_name value - -column_max col_name value - -column_eq col_name value - -column_thresh col_name thresh - -column_str col_name string - -The column filtering options may be used when the **-line_type** has been set to a single value. These options take two arguments, the name of the data column to be used followed by a value, string, or threshold to be applied. If multiple column_min/max/eq/thresh/str options are listed, the job will be performed on their intersection. Each input line is only retained if its value meets the numeric filtering criteria defined or matches one of the strings defined by the **-column_str** option. Multiple filtering strings may be listed using commas. Defining thresholds in MET is described in :numref:`config_options`. + -column_min col_name value + -column_max col_name value + -column_eq col_name value + -column_thresh col_name thresh + -column_str col_name string + -column_str_exc col_name string + +The column filtering options may be used when the **-line_type** has been set to a single value. These options take two arguments, the name of the data column to be used followed by a value, string, or threshold to be applied. If multiple column_min/max/eq/thresh/str options are listed, the job will be performed on their intersection. Each input line is only retained if its value meets the numeric filtering criteria defined, matches one of the strings defined by the **-column_str** option, or does not match any of the string defined by the **-column_str_exc** option. Multiple filtering strings may be listed using commas. Defining thresholds in MET is described in :numref:`config_options`. .. code-block:: none diff --git a/met/docs/Users_Guide/tc-stat.rst b/met/docs/Users_Guide/tc-stat.rst index f1ddfbeb7d..c66a6f6894 100644 --- a/met/docs/Users_Guide/tc-stat.rst +++ b/met/docs/Users_Guide/tc-stat.rst @@ -251,7 +251,16 @@ _________________________ column_str_name = []; column_str_val = []; -The **column_str_name** and **column_str_val** fields stratify by performing string matching on non-numeric data columns. Specify a comma-separated list of columns names and values to be checked. The length of the **column_str_val** should match that of the **column_str_name**. Using the **-column_str name val** option within the job command lines may further refine these selections. +The **column_str_name** and **column_str_val** fields stratify by performing string matching on non-numeric data columns. Specify a comma-separated list of columns names and values to be **included** in the analysis. The length of the **column_str_val** should match that of the **column_str_name**. Using the **-column_str name val** option within the job command lines may further refine these selections. + +_________________________ + +.. code-block:: none + + column_str_exc_name = []; + column_str_exc_val = []; + +The **column_str_exc_name** and **column_str_exc_val** fields stratify by performing string matching on non-numeric data columns. Specify a comma-separated list of columns names and values to be **excluded** from the analysis. The length of the **column_str_exc_val** should match that of the **column_str_exc_name**. Using the **-column_str_exc name val** option within the job command lines may further refine these selections. _________________________ @@ -260,7 +269,7 @@ _________________________ init_thresh_name = []; init_thresh_val = []; -The **init_thresh_name** and **init_thresh_val** fields stratify by applying thresholds to numeric data columns only when lead = 0. If lead =0, but the value does not meet the threshold, discard the entire track. The length of the **init_thresh_val** should match that of the **init_thresh_name**. Using the **-init_thresh name val** option within the job command lines may further refine these selections. +The **init_thresh_name** and **init_thresh_val** fields stratify by applying thresholds to numeric data columns only when lead = 0. If lead = 0, but the value does not meet the threshold, discard the entire track. The length of the **init_thresh_val** should match that of the **init_thresh_name**. Using the **-init_thresh name val** option within the job command lines may further refine these selections. _________________________ @@ -269,7 +278,16 @@ _________________________ init_str_name = []; init_str_val = []; -The **init_str_name** and **init_str_val** fields stratify by performing string matching on non-numeric data columns only when lead = 0. If lead =0, but the string does not match, discard the entire track. The length of the **init_str_val** should match that of the **init_str_name**. Using the **-init_str name val** option within the job command lines may further refine these selections. +The **init_str_name** and **init_str_val** fields stratify by performing string matching on non-numeric data columns only when lead = 0. If lead = 0, but the string **does not** match, discard the entire track. The length of the **init_str_val** should match that of the **init_str_name**. Using the **-init_str name val** option within the job command lines may further refine these selections. + +_________________________ + +.. code-block:: none + + init_str_exc_name = []; + init_str_exc_val = []; + +The **init_str_exc_name** and **init_str_exc_val** fields stratify by performing string matching on non-numeric data columns only when lead = 0. If lead = 0, and the string **does** match, discard the entire track. The length of the **init_str_exc_val** should match that of the **init_str_exc_name**. Using the **-init_str_exc name val** option within the job command lines may further refine these selections. _________________________ diff --git a/met/src/basic/vx_config/config_constants.h b/met/src/basic/vx_config/config_constants.h index 1ae8d5d90d..e63a6935f0 100644 --- a/met/src/basic/vx_config/config_constants.h +++ b/met/src/basic/vx_config/config_constants.h @@ -1037,10 +1037,14 @@ static const char conf_key_column_thresh_name[] = "column_thresh_name"; static const char conf_key_column_thresh_val[] = "column_thresh_val"; static const char conf_key_column_str_name[] = "column_str_name"; static const char conf_key_column_str_val[] = "column_str_val"; +static const char conf_key_column_str_exc_name[] = "column_str_exc_name"; +static const char conf_key_column_str_exc_val[] = "column_str_exc_val"; static const char conf_key_init_thresh_name[] = "init_thresh_name"; static const char conf_key_init_thresh_val[] = "init_thresh_val"; static const char conf_key_init_str_name[] = "init_str_name"; static const char conf_key_init_str_val[] = "init_str_val"; +static const char conf_key_init_str_exc_name[] = "init_str_exc_name"; +static const char conf_key_init_str_exc_val[] = "init_str_exc_val"; static const char conf_key_water_only[] = "water_only"; static const char conf_key_rirw_track[] = "rirw.track"; static const char conf_key_rirw_time_adeck[] = "rirw.adeck.time"; diff --git a/met/src/libcode/vx_analysis_util/stat_job.cc b/met/src/libcode/vx_analysis_util/stat_job.cc index 346ba9e03f..870d5cac1d 100644 --- a/met/src/libcode/vx_analysis_util/stat_job.cc +++ b/met/src/libcode/vx_analysis_util/stat_job.cc @@ -172,7 +172,8 @@ void STATAnalysisJob::clear() { wmo_fisher_stats.clear(); column_thresh_map.clear(); - column_str_map.clear(); + column_str_inc_map.clear(); + column_str_exc_map.clear(); by_column.clear(); @@ -306,7 +307,8 @@ void STATAnalysisJob::assign(const STATAnalysisJob & aj) { wmo_fisher_stats = aj.wmo_fisher_stats; column_thresh_map = aj.column_thresh_map; - column_str_map = aj.column_str_map; + column_str_inc_map = aj.column_str_inc_map; + column_str_exc_map = aj.column_str_exc_map; by_column = aj.by_column; @@ -507,9 +509,16 @@ void STATAnalysisJob::dump(ostream & out, int depth) const { thr_it->second.dump(out, depth + 1); } - out << prefix << "column_str_map ...\n"; - for(map::const_iterator str_it = column_str_map.begin(); - str_it != column_str_map.end(); str_it++) { + out << prefix << "column_str_inc_map ...\n"; + for(map::const_iterator str_it = column_str_inc_map.begin(); + str_it != column_str_inc_map.end(); str_it++) { + out << prefix << str_it->first << ": \n"; + str_it->second.dump(out, depth + 1); + } + + out << prefix << "column_str_exc_map ...\n"; + for(map::const_iterator str_it = column_str_exc_map.begin(); + str_it != column_str_exc_map.end(); str_it++) { out << prefix << str_it->first << ": \n"; str_it->second.dump(out, depth + 1); } @@ -948,8 +957,8 @@ int STATAnalysisJob::is_keeper(const STATLine & L) const { // // column_str // - for(map::const_iterator str_it = column_str_map.begin(); - str_it != column_str_map.end(); str_it++) { + for(map::const_iterator str_it = column_str_inc_map.begin(); + str_it != column_str_inc_map.end(); str_it++) { // // Check if the current value is in the list for the column @@ -957,6 +966,18 @@ int STATAnalysisJob::is_keeper(const STATLine & L) const { if(!str_it->second.has(L.get_item(str_it->first.c_str(), false))) return(0); } + // + // column_str_exc + // + for(map::const_iterator str_it = column_str_exc_map.begin(); + str_it != column_str_exc_map.end(); str_it++) { + + // + // Check if the current value is not in the list for the column + // + if(str_it->second.has(L.get_item(str_it->first.c_str(), false))) return(0); + } + // // For MPR lines, check mask_grid, mask_poly, and mask_sid // @@ -1125,7 +1146,10 @@ void STATAnalysisJob::parse_job_command(const char *jobstring) { column_thresh_map.clear(); } else if(jc_array[i] == "-column_str" ) { - column_str_map.clear(); + column_str_inc_map.clear(); + } + else if(jc_array[i] == "-column_str_exc" ) { + column_str_exc_map.clear(); } else if(jc_array[i] == "-set_hdr" ) { hdr_name.clear(); @@ -1376,12 +1400,30 @@ void STATAnalysisJob::parse_job_command(const char *jobstring) { col_value.add_css(jc_array[i+2]); // If the column name is already present in the map, add to it - if(column_str_map.count(col_name) > 0) { - column_str_map[col_name].add(col_value); + if(column_str_inc_map.count(col_name) > 0) { + column_str_inc_map[col_name].add(col_value); } // Otherwise, add a new map entry else { - column_str_map.insert(pair(col_name, col_value)); + column_str_inc_map.insert(pair(col_name, col_value)); + } + i+=2; + } + else if(jc_array[i] == "-column_str_exc") { + + // Parse the column name and value + col_name = to_upper((string)jc_array[i+1]); + col_value.clear(); + col_value.set_ignore_case(1); + col_value.add_css(jc_array[i+2]); + + // If the column name is already present in the map, add to it + if(column_str_exc_map.count(col_name) > 0) { + column_str_exc_map[col_name].add(col_value); + } + // Otherwise, add a new map entry + else { + column_str_exc_map.insert(pair(col_name, col_value)); } i+=2; } @@ -2461,14 +2503,23 @@ ConcatString STATAnalysisJob::get_jobstring() const { } // column_str - for(map::const_iterator str_it = column_str_map.begin(); - str_it != column_str_map.end(); str_it++) { + for(map::const_iterator str_it = column_str_inc_map.begin(); + str_it != column_str_inc_map.end(); str_it++) { for(i=0; isecond.n(); i++) { js << "-column_str " << str_it->first << " " << str_it->second[i] << " "; } } + // column_str_exc + for(map::const_iterator str_it = column_str_exc_map.begin(); + str_it != column_str_exc_map.end(); str_it++) { + + for(i=0; isecond.n(); i++) { + js << "-column_str_exc " << str_it->first << " " << str_it->second[i] << " "; + } + } + // by_column if(by_column.n() > 0) { for(i=0; i column_thresh_map; // ASCII column string matching - map column_str_map; + map column_str_inc_map; + map column_str_exc_map; StringArray hdr_name; StringArray hdr_value; diff --git a/met/src/tools/tc_utils/tc_stat/tc_stat_conf_info.cc b/met/src/tools/tc_utils/tc_stat/tc_stat_conf_info.cc index 3b21161363..1bdc3af262 100644 --- a/met/src/tools/tc_utils/tc_stat/tc_stat_conf_info.cc +++ b/met/src/tools/tc_utils/tc_stat/tc_stat_conf_info.cc @@ -22,6 +22,16 @@ using namespace std; #include "vx_log.h" +//////////////////////////////////////////////////////////////////////// + +// Functions for parsing config entries +static void parse_conf_thresh_map(MetConfig &, + const char *, const char *, + map &); +static void parse_conf_string_map(MetConfig &, + const char *, const char *, + map &); + //////////////////////////////////////////////////////////////////////// // // Code for class TCStatConfInfo @@ -63,7 +73,7 @@ void TCStatConfInfo::clear() { //////////////////////////////////////////////////////////////////////// void TCStatConfInfo::read_config(const char *default_file_name, - const char *user_file_name) { + const char *user_file_name) { // Read the config file constants Conf.read(replace_path(config_const_filename).c_str()); @@ -84,8 +94,7 @@ void TCStatConfInfo::read_config(const char *default_file_name, void TCStatConfInfo::process_config() { int i; - StringArray sa, sa_val, sa_new; - ThreshArray ta_val, ta_new; + StringArray sa; ConcatString poly_file; // Conf: Version @@ -119,12 +128,12 @@ void TCStatConfInfo::process_config() { // Conf: TCStatJob::InitInc sa = Conf.lookup_string_array(conf_key_init_inc); - for(i=0; i " - << "the \"column_thresh_name\" and \"column_thresh_val\" " - << "entries must have the same length.\n\n"; - exit(1); - } + parse_conf_thresh_map(Conf, + conf_key_column_thresh_name, conf_key_column_thresh_val, + Filter.ColumnThreshMap); - // Add entries to the map - for(i=0; i 0) { - Filter.ColumnThreshMap[sa[i]].add(ta_val[i]); - } - else { - ta_new.clear(); - ta_new.add(ta_val[i]); - Filter.ColumnThreshMap.insert(pair(sa[i], ta_new)); - } - } // end for i - - // Conf: TCStatJob::ColumnStrName, TCStatJob::ColumnStrVal - sa = Conf.lookup_string_array(conf_key_column_str_name); - sa_val = Conf.lookup_string_array(conf_key_column_str_val); - - // Check that they are the same length - if(sa.n_elements() != sa_val.n_elements()) { - mlog << Error - << "\nTCStatConfInfo::process_config() -> " - << "the \"column_str_name\" and \"column_str_val\" " - << "entries must have the same length.\n\n"; - exit(1); - } + // Conf: TCStatJob::ColumnStrIncName, TCStatJob::ColumnStrIncVal + parse_conf_string_map(Conf, + conf_key_column_str_name, conf_key_column_str_val, + Filter.ColumnStrIncMap); - // Add entries to the map - for(i=0; i 0) { - Filter.ColumnStrMap[sa[i]].add(sa_val[i]); - } - else { - sa_new.clear(); - sa_new.set_ignore_case(1); - sa_new.add(sa_val[i]); - Filter.ColumnStrMap.insert(pair(sa[i], sa_new)); - } - } // end for i + // Conf: TCStatJob::ColumnStrExcName, TCStatJob::ColumnStrExcVal + parse_conf_string_map(Conf, + conf_key_column_str_exc_name, conf_key_column_str_exc_val, + Filter.ColumnStrExcMap); // Conf: TCStatJob::InitThreshName, TCStatJob::InitThreshVal - sa = Conf.lookup_string_array(conf_key_init_thresh_name); - ta_val = Conf.lookup_thresh_array(conf_key_init_thresh_val); + parse_conf_thresh_map(Conf, + conf_key_init_thresh_name, conf_key_init_thresh_val, + Filter.InitThreshMap); - // Check that they are the same length - if(sa.n_elements() != ta_val.n_elements()) { - mlog << Error - << "\nTCStatConfInfo::process_config() -> " - << "the \"init_thresh_name\" and \"init_thresh_val\" " - << "entries must have the same length.\n\n"; - exit(1); - } - - // Add entries to the map - for(i=0; i 0) { - Filter.InitThreshMap[sa[i]].add(ta_val[i]); - } - else { - ta_new.clear(); - ta_new.add(ta_val[i]); - Filter.InitThreshMap.insert(pair(sa[i], ta_new)); - } - } // end for i - - // Conf: TCStatJob::InitStrName, TCStatJob::InitStrVal - sa = Conf.lookup_string_array(conf_key_init_str_name); - sa_val = Conf.lookup_string_array(conf_key_init_str_val); - - // Check that they are the same length - if(sa.n_elements() != sa_val.n_elements()) { - mlog << Error - << "\nTCStatConfInfo::process_config() -> " - << "the \"init_str_name\" and \"init_str_val\" " - << "entries must have the same length.\n\n"; - exit(1); - } + // Conf: TCStatJob::InitStrIncName, TCStatJob::InitStrIncVal + parse_conf_string_map(Conf, + conf_key_init_str_name, conf_key_init_str_val, + Filter.InitStrIncMap); - // Add entries to the map - for(i=0; i 0) { - Filter.InitStrMap[sa[i]].add(sa_val[i]); - } - else { - sa_new.clear(); - sa_new.set_ignore_case(1); - sa_new.add(sa_val[i]); - Filter.InitStrMap.insert(pair(sa[i], sa_new)); - } - } // end for i + // Conf: TCStatJob::InitStrExcName, TCStatJob::InitStrExcVal + parse_conf_string_map(Conf, + conf_key_init_str_exc_name, conf_key_init_str_exc_val, + Filter.InitStrExcMap); // Conf: TCStatJob::WaterOnly Filter.WaterOnly = Conf.lookup_bool(conf_key_water_only); @@ -311,7 +248,7 @@ void TCStatConfInfo::process_config() { // Conf: Jobs Jobs = Conf.lookup_string_array(conf_key_jobs); - if(Jobs.n_elements() == 0) { + if(Jobs.n() == 0) { mlog << Error << "\nTCStatConfInfo::process_config() -> " << "must specify at least one entry in \"jobs\".\n\n"; @@ -322,3 +259,73 @@ void TCStatConfInfo::process_config() { } //////////////////////////////////////////////////////////////////////// + +void parse_conf_thresh_map(MetConfig &conf, + const char *conf_key_name, const char *conf_key_val, + map &m) { + StringArray sa; + ThreshArray ta_val, ta_new; + + sa = conf.lookup_string_array(conf_key_name); + ta_val = conf.lookup_thresh_array(conf_key_val); + + // Check that they are the same length + if(sa.n() != ta_val.n()) { + mlog << Error + << "\nTCStatConfInfo::parse_conf_thresh_map() -> " + << "the \"" << conf_key_name << "\" and \"" << conf_key_val << "\" " + << "entries must have the same length.\n\n"; + exit(1); + } + + // Add entries to the map + for(int i=0; i 0) { + m[sa[i]].add(ta_val[i]); + } + else { + ta_new.clear(); + ta_new.add(ta_val[i]); + m.insert(pair(sa[i], ta_new)); + } + } // end for i + + return; +} + +//////////////////////////////////////////////////////////////////////// + +void parse_conf_string_map(MetConfig &conf, + const char *conf_key_name, const char *conf_key_val, + map &m) { + StringArray sa, sa_val, sa_new; + + sa = conf.lookup_string_array(conf_key_name); + sa_val = conf.lookup_string_array(conf_key_val); + + // Check that they are the same length + if(sa.n() != sa_val.n()) { + mlog << Error + << "\nTCStatConfInfo::parse_conf_string_map() -> " + << "the \"" << conf_key_name << "\" and \"" << conf_key_val << "\" " + << "entries must have the same length.\n\n"; + exit(1); + } + + // Add entries to the map + for(int i=0; i 0) { + m[sa[i]].add(sa_val[i]); + } + else { + sa_new.clear(); + sa_new.set_ignore_case(1); + sa_new.add(sa_val[i]); + m.insert(pair(sa[i], sa_new)); + } + } // end for i + + return; +} + +//////////////////////////////////////////////////////////////////////// diff --git a/met/src/tools/tc_utils/tc_stat/tc_stat_job.cc b/met/src/tools/tc_utils/tc_stat/tc_stat_job.cc index e472af405b..6f6f812878 100644 --- a/met/src/tools/tc_utils/tc_stat/tc_stat_job.cc +++ b/met/src/tools/tc_utils/tc_stat/tc_stat_job.cc @@ -112,11 +112,11 @@ TCStatJob *TCStatJobFactory::new_tc_stat_job(const char *jobstring) { a = job->parse_job_command(jobstring); // Check for unused arguments - if(a.n_elements() > 0) { + if(a.n() > 0) { // Build list of unknown args - for(i=0; i " @@ -220,9 +220,11 @@ void TCStatJob::clear() { LineType.clear(); TrackWatchWarn.clear(); ColumnThreshMap.clear(); - ColumnStrMap.clear(); + ColumnStrIncMap.clear(); + ColumnStrExcMap.clear(); InitThreshMap.clear(); - InitStrMap.clear(); + InitStrIncMap.clear(); + InitStrExcMap.clear(); EventEqualLead.clear(); EventEqualCases.clear(); @@ -301,9 +303,11 @@ void TCStatJob::assign(const TCStatJob & j) { LineType = j.LineType; TrackWatchWarn = j.TrackWatchWarn; ColumnThreshMap = j.ColumnThreshMap; - ColumnStrMap = j.ColumnStrMap; + ColumnStrIncMap = j.ColumnStrIncMap; + ColumnStrExcMap = j.ColumnStrExcMap; InitThreshMap = j.InitThreshMap; - InitStrMap = j.InitStrMap; + InitStrIncMap = j.InitStrIncMap; + InitStrExcMap = j.InitStrExcMap; DumpFile = j.DumpFile; open_dump_file(); @@ -423,8 +427,14 @@ void TCStatJob::dump(ostream & out, int depth) const { thr_it->second.dump(out, depth + 1); } - out << prefix << "ColumnStrMap ...\n"; - for(str_it=ColumnStrMap.begin(); str_it!= ColumnStrMap.end(); str_it++) { + out << prefix << "ColumnStrIncMap ...\n"; + for(str_it=ColumnStrIncMap.begin(); str_it!= ColumnStrIncMap.end(); str_it++) { + out << prefix << str_it->first << ": \n"; + str_it->second.dump(out, depth + 1); + } + + out << prefix << "ColumnStrExcMap ...\n"; + for(str_it=ColumnStrExcMap.begin(); str_it!= ColumnStrExcMap.end(); str_it++) { out << prefix << str_it->first << ": \n"; str_it->second.dump(out, depth + 1); } @@ -435,8 +445,14 @@ void TCStatJob::dump(ostream & out, int depth) const { thr_it->second.dump(out, depth + 1); } - out << prefix << "InitStrMap ...\n"; - for(str_it=InitStrMap.begin(); str_it!= InitStrMap.end(); str_it++) { + out << prefix << "InitStrIncMap ...\n"; + for(str_it=InitStrIncMap.begin(); str_it!= InitStrIncMap.end(); str_it++) { + out << prefix << str_it->first << ": \n"; + str_it->second.dump(out, depth + 1); + } + + out << prefix << "InitStrExcMap ...\n"; + for(str_it=InitStrExcMap.begin(); str_it!= InitStrExcMap.end(); str_it++) { out << prefix << str_it->first << ": \n"; str_it->second.dump(out, depth + 1); } @@ -501,7 +517,7 @@ bool TCStatJob::is_keeper_track(const TrackPairInfo &pair, map::const_iterator str_it; // Check TrackWatchWarn for each TrackPoint - if(TrackWatchWarn.n_elements() > 0) { + if(TrackWatchWarn.n() > 0) { // Assume track will not be kept keep = false; @@ -539,7 +555,11 @@ bool TCStatJob::is_keeper_track(const TrackPairInfo &pair, keep = false; n.RejInitThresh += pair.n_points(); } - else if(InitStrMap.size() > 0) { + else if(InitStrIncMap.size() > 0) { + keep = false; + n.RejInitStr += pair.n_points(); + } + else if(InitStrExcMap.size() > 0) { keep = false; n.RejInitStr += pair.n_points(); } @@ -567,10 +587,10 @@ bool TCStatJob::is_keeper_track(const TrackPairInfo &pair, } } - // Check InitStr + // Check InitStrInc if(keep == true) { - for(str_it=InitStrMap.begin(); str_it!= InitStrMap.end(); str_it++) { + for(str_it=InitStrIncMap.begin(); str_it!= InitStrIncMap.end(); str_it++) { // Retrieve the column value v_str = pair.line(i_init)->get_item(str_it->first.c_str()); @@ -584,6 +604,23 @@ bool TCStatJob::is_keeper_track(const TrackPairInfo &pair, } } + // Check InitStrExc + if(keep == true) { + + for(str_it=InitStrExcMap.begin(); str_it!= InitStrExcMap.end(); str_it++) { + + // Retrieve the column value + v_str = pair.line(i_init)->get_item(str_it->first.c_str()); + + // Check the string value + if(str_it->second.has(v_str)) { + keep = false; + n.RejInitStr += pair.n_points(); + break; + } + } + } + // Check OutInitMask if(keep == true) { @@ -606,11 +643,11 @@ bool TCStatJob::is_keeper_track(const TrackPairInfo &pair, // MET-667 Check this track for required lead times // If no required lead times were defined, do nothing. - if(keep == true && LeadReq.n_elements() > 0){ + if(keep == true && LeadReq.n() > 0){ // Loop through the points and see if any of the // lead times are in the list of required lead times // defined in the configuration file. - for(int j=0; j::const_iterator str_it; // Check TC-STAT header columns - if(AModel.n_elements() > 0 && + if(AModel.n() > 0 && !AModel.has(line.amodel())) { keep = false; n.RejAModel++; } - else if(BModel.n_elements() > 0 && + else if(BModel.n() > 0 && !BModel.has(line.bmodel())) { keep = false; n.RejBModel++; } - else if(Desc.n_elements() > 0 && + else if(Desc.n() > 0 && !Desc.has(line.desc())) { keep = false; n.RejDesc++; } - else if(StormId.n_elements() > 0 && + else if(StormId.n() > 0 && !has_storm_id(StormId, (string)line.basin(), (string)line.cyclone(), line.init())) { keep = false; n.RejStormId++; } - else if(Basin.n_elements() > 0 && + else if(Basin.n() > 0 && !Basin.has(line.basin())) { keep = false; n.RejBasin++; } - else if(Cyclone.n_elements() > 0 && + else if(Cyclone.n() > 0 && !Cyclone.has(line.cyclone())) { keep = false; n.RejCyclone++; } - else if(StormName.n_elements() > 0 && + else if(StormName.n() > 0 && !StormName.has(line.storm_name())) { keep = false; n.RejStormName++; } else if(InitBeg > 0 && line.init() < InitBeg) { keep = false; n.RejInit++; } else if(InitEnd > 0 && line.init() > InitEnd) { keep = false; n.RejInit++; } - else if(InitInc.n_elements() > 0 && + else if(InitInc.n() > 0 && !InitInc.has(line.init())) { keep = false; n.RejInit++; } - else if(InitExc.n_elements() > 0 && + else if(InitExc.n() > 0 && InitExc.has(line.init())) { keep = false; n.RejInit++; } - else if(InitHour.n_elements() > 0 && + else if(InitHour.n() > 0 && !InitHour.has(line.init_hour())) { keep = false; n.RejInitHour++; } - else if(Lead.n_elements() > 0 && + else if(Lead.n() > 0 && !Lead.has(line.lead())) { keep = false; n.RejLead++; } else if(ValidBeg > 0 && line.valid() < ValidBeg) { keep = false; n.RejValid++; } else if(ValidEnd > 0 && line.valid() > ValidEnd) { keep = false; n.RejValid++; } - else if(ValidInc.n_elements() > 0 && + else if(ValidInc.n() > 0 && !ValidInc.has(line.valid())) { keep = false; n.RejValid++; } - else if(ValidExc.n_elements() > 0 && + else if(ValidExc.n() > 0 && ValidExc.has(line.valid())) { keep = false; n.RejValid++; } - else if(ValidHour.n_elements() > 0 && + else if(ValidHour.n() > 0 && !ValidHour.has(line.valid_hour())) { keep = false; n.RejValidHour++; } - else if(InitMask.n_elements() > 0 && + else if(InitMask.n() > 0 && !InitMask.has(line.init_mask())) { keep = false; n.RejInitMask++; } - else if(ValidMask.n_elements() > 0 && + else if(ValidMask.n() > 0 && !ValidMask.has(line.valid_mask())) { keep = false; n.RejValidMask++; } - else if(LineType.n_elements() > 0 && + else if(LineType.n() > 0 && !LineType.has(line.line_type())) { keep = false; n.RejLineType++; } // Check that PROBRIRW lines include the requested probability type @@ -701,27 +738,45 @@ bool TCStatJob::is_keeper_line(const TCStatLine &line, // Check the column threshold if(!thr_it->second.check_dbl(v_dbl)) { - keep = false; - n.RejColumnThresh++; - break; + keep = false; + n.RejColumnThresh++; + break; } } } - // Check ColumnStrMap + // Check ColumnStrIncMap if(keep == true) { // Loop through the column string matching - for(str_it=ColumnStrMap.begin(); str_it!= ColumnStrMap.end(); str_it++) { + for(str_it=ColumnStrIncMap.begin(); str_it!= ColumnStrIncMap.end(); str_it++) { // Retrieve the column value v_str = line.get_item(str_it->first.c_str()); // Check the string value if(!str_it->second.has(v_str)) { - keep = false; - n.RejColumnStr++; - break; + keep = false; + n.RejColumnStr++; + break; + } + } + } + + // Check ColumnStrExcMap + if(keep == true) { + + // Loop through the column string matching + for(str_it=ColumnStrExcMap.begin(); str_it!= ColumnStrExcMap.end(); str_it++) { + + // Retrieve the column value + v_str = line.get_item(str_it->first.c_str()); + + // Check the string value + if(str_it->second.has(v_str)) { + keep = false; + n.RejColumnStr++; + break; } } } @@ -805,10 +860,10 @@ double TCStatJob::get_column_double(const TCStatLine &line, v = atof(line.get_item(sa[0].c_str())); // If multiple columns, compute the requested difference - if(sa.n_elements() > 1) { + if(sa.n() > 1) { // Loop through the column - for(i=1; i 0) s << "-init_beg " << unix_to_yyyymmdd_hhmmss(InitBeg) << " "; if(InitEnd > 0) s << "-init_end " << unix_to_yyyymmdd_hhmmss(InitEnd) << " "; - for(i=0; i 0) s << "-valid_beg " << unix_to_yyyymmdd_hhmmss(ValidBeg) << " "; if(ValidEnd > 0) s << "-valid_end " << unix_to_yyyymmdd_hhmmss(ValidEnd) << " "; - for(i=0; isecond.n_elements(); i++) { + for(i=0; isecond.n(); i++) { s << "-column_thresh " << thr_it->first << " " << thr_it->second[i].get_str() << " "; } } - for(str_it=ColumnStrMap.begin(); str_it!= ColumnStrMap.end(); str_it++) { - for(i=0; isecond.n_elements(); i++) { + for(str_it=ColumnStrIncMap.begin(); str_it!= ColumnStrIncMap.end(); str_it++) { + for(i=0; isecond.n(); i++) { s << "-column_str " << str_it->first << " " << str_it->second[i] << " "; } } + for(str_it=ColumnStrExcMap.begin(); str_it!= ColumnStrExcMap.end(); str_it++) { + for(i=0; isecond.n(); i++) { + s << "-column_str_exc " << str_it->first << " " + << str_it->second[i] << " "; + } + } for(thr_it=InitThreshMap.begin(); thr_it!= InitThreshMap.end(); thr_it++) { - for(i=0; isecond.n_elements(); i++) { + for(i=0; isecond.n(); i++) { s << "-init_thresh " << thr_it->first << " " << thr_it->second[i].get_str() << " "; } } - for(str_it=InitStrMap.begin(); str_it!= InitStrMap.end(); str_it++) { - for(i=0; isecond.n_elements(); i++) { + for(str_it=InitStrIncMap.begin(); str_it!= InitStrIncMap.end(); str_it++) { + for(i=0; isecond.n(); i++) { s << "-init_str " << str_it->first << " " << str_it->second[i] << " "; } } + for(str_it=InitStrExcMap.begin(); str_it!= InitStrExcMap.end(); str_it++) { + for(i=0; isecond.n(); i++) { + s << "-init_str_exc " << str_it->first << " " + << str_it->second[i] << " "; + } + } if(WaterOnly != default_water_only) s << "-water_only " << bool_to_string(WaterOnly) << " "; if(RIRWTrack != default_rirw_track) { @@ -1223,7 +1294,7 @@ ConcatString TCStatJob::serialize() const { s << "-match_points " << bool_to_string(MatchPoints) << " "; if(EventEqual != default_event_equal) s << "-event_equal " << bool_to_string(EventEqual) << " "; - for(i=0; i " << "the track-based " << TCStatLineType_TCMPR_Str @@ -1611,7 +1682,7 @@ void TCStatJobFilter::filter_tracks(TCLineCounts &n) { if(EventEqual == true) event_equalize_tracks(); // Check for no common cases - if(EventEqualSet == true && EventEqualCases.n_elements() == 0) { + if(EventEqualSet == true && EventEqualCases.n() == 0) { mlog << Debug(1) << "Event equalization of tracks found no common cases.\n"; } @@ -1650,7 +1721,7 @@ void TCStatJobFilter::filter_lines(TCLineCounts &n) { if(EventEqual == true) event_equalize_lines(); // Check for no common cases - if(EventEqualSet == true && EventEqualCases.n_elements() == 0) { + if(EventEqualSet == true && EventEqualCases.n() == 0) { mlog << Debug(1) << "Event equalization of lines found no common cases.\n"; } @@ -1793,7 +1864,7 @@ StringArray TCStatJobSummary::parse_job_command(const char *jobstring) { a = TCStatJob::parse_job_command(jobstring); // Loop over the StringArray elements - for(i=0; i " << "this function may only be called when using the " << "-column option in the job command line:\n" @@ -1904,7 +1975,7 @@ void TCStatJobSummary::do_job(const StringArray &file_list, // // If not specified, assume TCMPR by adding it to the LineType - if(LineType.n_elements() == 0) LineType.add(TCStatLineType_TCMPR_Str); + if(LineType.n() == 0) LineType.add(TCStatLineType_TCMPR_Str); // Add the input file list TCSTFiles.add_files(file_list); @@ -1913,7 +1984,7 @@ void TCStatJobSummary::do_job(const StringArray &file_list, if(LineType.has(TCStatLineType_TCMPR_Str)) { // TCMPR and non-TCMPR LineTypes cannot be mixed - for(i=0; i " << "the track-based " << TCStatLineType_TCMPR_Str @@ -1950,7 +2021,7 @@ void TCStatJobSummary::summarize_tracks(TCLineCounts &n) { if(EventEqual == true) event_equalize_tracks(); // Check for no common cases - if(EventEqualSet == true && EventEqualCases.n_elements() == 0) { + if(EventEqualSet == true && EventEqualCases.n() == 0) { mlog << Debug(1) << "Event equalization of tracks found no common cases.\n"; } @@ -1992,7 +2063,7 @@ void TCStatJobSummary::summarize_lines(TCLineCounts &n) { if(EventEqual == true) event_equalize_lines(); // Check for no common cases - if(EventEqualSet == true && EventEqualCases.n_elements() == 0) { + if(EventEqualSet == true && EventEqualCases.n() == 0) { mlog << Debug(1) << "Event equalization of lines found no common cases.\n"; } @@ -2039,7 +2110,7 @@ void TCStatJobSummary::process_pair(TrackPairInfo &pair) { for(i=0; i&m) { mlog << Debug(5) << "Summary Map Insert (" << it->first << ") " - << it->second.Val.n_elements() << " values: " + << it->second.Val.n() << " values: " << it->second.Val.serialize() << "\n"; // Add the pair to the map @@ -2132,7 +2203,7 @@ void TCStatJobSummary::add_map(map&m) { mlog << Debug(5) << "Summary Map Add (" << it->first << ") " - << it->second.Val.n_elements() << " values: " + << it->second.Val.n() << " values: " << it->second.Val.serialize() << "\n"; // Add the value for the existing key @@ -2165,11 +2236,11 @@ void TCStatJobSummary::do_output(ostream &out) { // Setup the output table out_at.set_size((int) SummaryMap.size() + 1, - ByColumn.n_elements() + 24); + ByColumn.n() + 24); // Left-justify case info and right-justify summary output for(i=0; isecond.Val.n_elements(); i++) { + for(i=0; isecond.Val.n(); i++) { if(!is_bad_data(it->second.Val[i])) { v.add(it->second.Val[i]); init.add(it->second.Init[i]); @@ -2244,7 +2315,7 @@ void TCStatJobSummary::do_output(ostream &out) { // Build index array index.clear(); - for(i=0; isecond.Val.n_elements()); - out_at.set_entry(r, c++, v.n_elements()); + out_at.set_entry(r, c++, it->second.Val.n()); + out_at.set_entry(r, c++, v.n()); out_at.set_entry(r, c++, mean_ci.v); out_at.set_entry(r, c++, mean_ci.v_ncl[0]); out_at.set_entry(r, c++, mean_ci.v_ncu[0]); @@ -2352,11 +2423,11 @@ void TCStatJobSummary::compute_fsp(NumArray &total, NumArray &best, mlog << Debug(4) << "Computing frequency of superior performance for " - << Column.n_elements() << " columns and " - << case_list.n_elements() << " cases.\n"; + << Column.n() << " columns and " + << case_list.n() << " cases.\n"; // Loop over the columns being summarized - for(i=0; isecond.Hdr.n_elements(); k++) { + for(k=0; ksecond.Hdr.n(); k++) { // Check if entry matches the current case if(strncasecmp(Column[i].c_str(), it->first.c_str(), @@ -2498,9 +2569,9 @@ bool is_time_series(const TimeArray &init, const NumArray &lead, dsec = bad_data_int; // The arrays should all be of the same length > 1 - if(init.n_elements() != lead.n_elements() || - init.n_elements() != valid.n_elements() || - init.n_elements() < 2) { + if(init.n() != lead.n() || + init.n() != valid.n() || + init.n() < 2) { mlog << Debug(4) << "Skipping time-series computations since the array " << "lengths differ.\n"; @@ -2513,7 +2584,7 @@ bool is_time_series(const TimeArray &init, const NumArray &lead, dvalid = valid[1] - valid[0]; // Loop over the entries to determine the time spacing - for(i=0; i= mean); @@ -2609,8 +2680,8 @@ int compute_time_to_indep(const NumArray &val, int ds) { exp_runs = 1.0 + 2.0*(n_abv * n_bel)/(n_abv + n_bel); // Calculate effective sample size, time to independence - eff_size = val.n_elements()*(n_run_abv + n_run_bel)/exp_runs; - tind = ds*val.n_elements()/eff_size; + eff_size = val.n()*(n_run_abv + n_run_bel)/exp_runs; + tind = ds*val.n()/eff_size; return(nint(tind)); } @@ -2622,7 +2693,7 @@ StringArray intersection(const StringArray &s1, const StringArray &s2) { int i; // Add elements common to both list - for(i=0; isecond.Hdr.n_elements(); + r += it->second.Hdr.n(); } // Format the output table out_at.set_size(r + 1, - 9 + ByColumn.n_elements() + 15); - setup_table(out_at, 9 + ByColumn.n_elements(), get_precision()); + 9 + ByColumn.n() + 15); + setup_table(out_at, 9 + ByColumn.n(), get_precision()); // Initialize row and column indices r = c = 0; @@ -3339,7 +3410,7 @@ void TCStatJobRIRW::do_mpr_output(ostream &out) { out_at.set_entry(r, c++, "WINDOW_END"); // Write case column names - for(i=0; isecond.Hdr.n_elements(); i++,r++) { + for(i=0; isecond.Hdr.n(); i++,r++) { // Initialize column counter c = 0; @@ -3384,14 +3455,14 @@ void TCStatJobRIRW::do_mpr_output(ostream &out) { // Write case column values sa = it->first.split(":"); - for(j=1; jsecond.Hdr[i]; sa = cs.split(":"); - for(j=0; j 0) { if(!mask_poly.latlon_is_inside_dege(lat, lon)) { @@ -3967,7 +4038,7 @@ bool check_masks(const MaskPoly &mask_poly, const Grid &mask_grid, } // - // Check grid masking. + // Check grid masking // if(mask_grid.nx() > 0 || mask_grid.ny() > 0) { mask_grid.latlon_to_xy(lat, -1.0*lon, grid_x, grid_y); @@ -3977,7 +4048,7 @@ bool check_masks(const MaskPoly &mask_poly, const Grid &mask_grid, } // - // Check area mask. + // Check area mask // if(mask_area.nx() > 0 || mask_area.ny() > 0) { if(!mask_area.s_is_on(nint(grid_x), nint(grid_y))) { diff --git a/met/src/tools/tc_utils/tc_stat/tc_stat_job.h b/met/src/tools/tc_utils/tc_stat/tc_stat_job.h index f97d5ae581..4ad98be987 100644 --- a/met/src/tools/tc_utils/tc_stat/tc_stat_job.h +++ b/met/src/tools/tc_utils/tc_stat/tc_stat_job.h @@ -286,13 +286,15 @@ class TCStatJob { map ColumnThreshMap; // ASCII column string matching - map ColumnStrMap; + map ColumnStrIncMap; + map ColumnStrExcMap; // Numeric column thresholds map InitThreshMap; // ASCII column string matching - map InitStrMap; + map InitStrIncMap; + map InitStrExcMap; // Variables to the store the analysis job specification ConcatString DumpFile; // Dump TrackPairInfo used to a file diff --git a/test/config/TCStatConfig_ALAL2010 b/test/config/TCStatConfig_ALAL2010 index 714029745f..8f59d36f5b 100644 --- a/test/config/TCStatConfig_ALAL2010 +++ b/test/config/TCStatConfig_ALAL2010 @@ -112,6 +112,12 @@ column_thresh_val = []; column_str_name = []; column_str_val = []; +// +// Stratify by excluding strings in non-numeric data columns. +// +column_str_exc_name = []; +column_str_exc_val = []; + // // Similar to the column_thresh options above // @@ -124,6 +130,12 @@ init_thresh_val = []; init_str_name = []; init_str_val = []; +// +// Similar to the column_str_exc options above +// +init_str_exc_name = []; +init_str_exc_val = []; + // // Stratify by the ADECK and BDECK distances to land. // diff --git a/test/config/TCStatConfig_PROBRIRW b/test/config/TCStatConfig_PROBRIRW index 9843408d2a..bf443a9e66 100644 --- a/test/config/TCStatConfig_PROBRIRW +++ b/test/config/TCStatConfig_PROBRIRW @@ -112,6 +112,12 @@ column_thresh_val = []; column_str_name = []; column_str_val = []; +// +// Stratify by excluding strings in non-numeric data columns. +// +column_str_exc_name = []; +column_str_exc_val = []; + // // Similar to the column_thresh options above // @@ -124,6 +130,12 @@ init_thresh_val = []; init_str_name = []; init_str_val = []; +// +// Similar to the column_str_exc options above +// +init_str_exc_name = []; +init_str_exc_val = []; + // // Stratify by the ADECK and BDECK distances to land. // diff --git a/test/xml/unit_stat_analysis.xml b/test/xml/unit_stat_analysis.xml index 799011f8a6..1558d101fd 100644 --- a/test/xml/unit_stat_analysis.xml +++ b/test/xml/unit_stat_analysis.xml @@ -315,6 +315,21 @@ + + &MET_BIN;/stat_analysis + \ + -lookin &OUTPUT_DIR;/point_stat/point_stat_GRIB1_NAM_GDAS_120000L_20120409_120000V.stat \ + -job filter -line_type MPR -fcst_var TMP -fcst_lev Z2 -vx_mask DTC165 \ + -column_str OBS_SID KDLN,KDHT,KDEN,KDLS,KDMA,KDMN,KDVT,KDEW \ + -column_str_exc OBS_SID KDLN,KDHT \ + -dump_row &OUTPUT_DIR;/stat_analysis/POINT_STAT_FILTER_OBS_SID.stat \ + -v 1 + + + &OUTPUT_DIR;/stat_analysis/POINT_STAT_FILTER_OBS_SID.stat + + + OUTPUT_DIR &OUTPUT_DIR;/stat_analysis diff --git a/test/xml/unit_tc_stat.xml b/test/xml/unit_tc_stat.xml index 8a7891a2fd..7353d72f68 100644 --- a/test/xml/unit_tc_stat.xml +++ b/test/xml/unit_tc_stat.xml @@ -15,7 +15,6 @@ &TEST_DIR; true - &MET_BIN;/tc_stat \ @@ -33,6 +32,20 @@ + + &MET_BIN;/tc_stat + \ + -lookin &OUTPUT_DIR;/tc_pairs/alal2010.tcst \ + -job filter -dump_row &OUTPUT_DIR;/tc_stat/ALAL2010_FILTER_STRINGS.tcst \ + -init_str LEVEL TS,HU -init_str_exc WATCH_WARN HUWARN \ + -column_str LEVEL HU -column_str_exc WATCH_WARN TSWATCH \ + -v 2 + + + &OUTPUT_DIR;/tc_stat/ALAL2010_FILTER_STRINGS.tcst + + + &MET_BIN;/tc_stat \ From 6055600ea746ff8f3317569cb925d5476c102b32 Mon Sep 17 00:00:00 2001 From: johnhg Date: Tue, 30 Mar 2021 16:55:05 -0600 Subject: [PATCH 2/4] Bugfix 1737 develop little_r (#1739) * Per #1737, migrate the same fix from main_v9.1 over to the develop branch. * Per #1737, add another unit test for running ascii2nc with corrupt littl_r records. --- .../tools/other/ascii2nc/little_r_handler.cc | 73 ++++++++++++------- test/xml/unit_ascii2nc.xml | 12 +++ 2 files changed, 60 insertions(+), 25 deletions(-) diff --git a/met/src/tools/other/ascii2nc/little_r_handler.cc b/met/src/tools/other/ascii2nc/little_r_handler.cc index b3d49787ea..a604a96355 100644 --- a/met/src/tools/other/ascii2nc/little_r_handler.cc +++ b/met/src/tools/other/ascii2nc/little_r_handler.cc @@ -66,6 +66,8 @@ static const string lr_grib_names[] = { // Little-R regular expression used to determine file type static const char *lr_rpt_reg_exp = "FM-[0-9]"; +static const char *lr_dtg_reg_exp = "[0-9]\\{14\\}"; + //////////////////////////////////////////////////////////////////////// @@ -137,46 +139,49 @@ bool LittleRHandler::_readObservations(LineDataFile &ascii_file) int n_data_hdr; StringArray mappedTypes; StringArray unmappedTypes; + bool is_bad_header = false; while (ascii_file.read_fwf_line(data_line, lr_rpt_wdth, n_lr_rpt_wdth)) { + // Check for expected header line if (!check_reg_exp(lr_rpt_reg_exp, data_line[4])) { mlog << Error << "\nLittleRHandler::_readObservations() -> " << "the fifth entry of the little_r report on line " - << data_line.line_number() << " does not match \"" + << data_line.line_number() + << " does not match the regular expression \"" << lr_rpt_reg_exp << "\":\n\"" << data_line[4] << "\"\n\n"; return false; } // Store the message type - ConcatString concat_string = (string)data_line[4]; - concat_string.ws_strip(); + ConcatString cs = (string)data_line[4]; + cs.ws_strip(); ConcatString hdr_typ; - if (_messageTypeMap[concat_string] != "") + if (_messageTypeMap.count(cs) > 0) { - hdr_typ = _messageTypeMap[concat_string]; - if (!mappedTypes.has(concat_string)) { + hdr_typ = _messageTypeMap[cs]; + if (!mappedTypes.has(cs)) { mlog << Debug(5) - << "Switching little_r report type \"" << concat_string + << "Switching little_r report type \"" << cs << "\" to message type \"" << hdr_typ << "\".\n"; - mappedTypes.add(concat_string); + mappedTypes.add(cs); } } else { - hdr_typ = concat_string; + hdr_typ = cs; hdr_typ.replace(" ", "_", false); - - if (!unmappedTypes.has(concat_string)) { - mlog << Warning << "\nLittleRHandler::_processObs() -> " + + if (!unmappedTypes.has(cs)) { + mlog << Warning << "\nLittleRHandler::_readObservations() -> " << "Storing message type as \"" << hdr_typ - << "\" for unexpected report type \"" << concat_string << "\".\n\n"; - unmappedTypes.add(concat_string); + << "\" for unexpected report type \"" << cs << "\".\n\n"; + unmappedTypes.add(cs); } } @@ -188,16 +193,29 @@ bool LittleRHandler::_readObservations(LineDataFile &ascii_file) // Store the valid time in YYYYMMDD_HHMMSS format - ConcatString hdr_vld_str; - - concat_string = data_line[17]; - concat_string.ws_strip(); - hdr_vld_str << cs_erase; - hdr_vld_str.format("%.8s_%.6s", - concat_string.text(), concat_string.text()+8); + time_t hdr_vld = 0; - time_t hdr_vld = _getValidTime(hdr_vld_str.text()); + if (check_reg_exp(lr_dtg_reg_exp, data_line[17])) + { + ConcatString hdr_vld_str; + cs = data_line[17]; + cs.ws_strip(); + hdr_vld_str << cs_erase; + hdr_vld_str.format("%.8s_%.6s", cs.text(), cs.text()+8); + hdr_vld = _getValidTime(hdr_vld_str.text()); + is_bad_header = false; + + } else + { + mlog << Warning << "\nLittleRHandler::_readObservations() -> " + << "the 18 entry of the little_r report on line " + << data_line.line_number() + << " does not match the timestring regular expression \"" + << lr_dtg_reg_exp << "\":\n\"" << data_line[17] << "\"\n\n"; + is_bad_header = true; + } + // Store the station location double hdr_lat = atof(data_line[0]); @@ -211,7 +229,8 @@ bool LittleRHandler::_readObservations(LineDataFile &ascii_file) // Observation of sea level pressure in pascals. - if (!is_eq(atof(data_line[18]), lr_missing_value)) + if (!is_eq(atof(data_line[18]), lr_missing_value) && + !is_bad_header) { ConcatString obs_qty = (is_eq(atof(data_line[19]), lr_missing_value) ? na_string : (string)data_line[19]); @@ -237,12 +256,16 @@ bool LittleRHandler::_readObservations(LineDataFile &ascii_file) int i_data = 0; while (ascii_file.read_fwf_line(data_line, lr_meas_wdth, n_lr_meas_wdth)) { + // Check for the end of report if (is_eq(atof(data_line[0]), lr_end_value) && - is_eq(atof(data_line[2]), lr_end_value)) + is_eq(atof(data_line[2]), lr_end_value)) break; + // Skip data lines if the header line is bad + if (is_bad_header) continue; + // Retrieve pressure and height double obs_prs = (is_eq(atof(data_line[0]), lr_missing_value) ? @@ -305,7 +328,7 @@ bool LittleRHandler::_readObservations(LineDataFile &ascii_file) if (n_data_hdr != i_data) { - mlog << Warning << "\nprocess_little_r_obs() -> " + mlog << Warning << "\nLittleRHandler::_readObservations() -> " << "the number of data lines specified in the header (" << n_data_hdr << ") does not match the number found in the data (" diff --git a/test/xml/unit_ascii2nc.xml b/test/xml/unit_ascii2nc.xml index fc1d1c4b86..2edb2bf9b7 100644 --- a/test/xml/unit_ascii2nc.xml +++ b/test/xml/unit_ascii2nc.xml @@ -76,6 +76,18 @@ + + &MET_BIN;/ascii2nc + \ + &DATA_DIR_OBS;/ascii/OBS:2015080700_bad_record \ + &OUTPUT_DIR;/ascii2nc/OBS:2015080700_bad_record.nc \ + -v 1 + + + &OUTPUT_DIR;/ascii2nc/OBS:2015080700_bad_record.nc + + + &MET_BIN;/ascii2nc \ From 804b1ac397ccc78bb19d39e855dbde27dcfaedc7 Mon Sep 17 00:00:00 2001 From: jprestop Date: Thu, 1 Apr 2021 12:14:29 -0600 Subject: [PATCH 3/4] Feature GitHub actions (#1742) * Adding files to build documenation via GitHub Actions * Removing html_theme_options * Removed warnings.log from help section --- .github/workflows/main.yml | 50 ++++++++++++++++++++++++++++++++++++++ met/docs/Makefile | 3 ++- met/docs/conf.py | 2 -- 3 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000000..d959c9e411 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,50 @@ +name: MET CI/CD Workflow +on: + push: + branches: + - develop + - develop-ref + - feature_* + - main_* + - bugfix_* + pull_request: + types: [opened, reopened, synchronize] + +jobs: + documentation: + name: Build Documentation + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: '3.6' + - name: Install dependencies + run: | + python -m pip install --upgrade python-dateutil requests sphinx \ + sphinx-gallery Pillow sphinx_rtd_theme + - name: Build docs + continue-on-error: true + run: | + DOCS_DIR=${GITHUB_WORKSPACE}/met/docs + cd ${DOCS_DIR} + make clean html + cd ${GITHUB_WORKSPACE} + warning_file=${DOCS_DIR}/_build/warnings.log + mkdir -p artifact/documentation + cp -r ${DOCS_DIR}/_build/html/* artifact/documentation + if [ -s $warning_file ]; then + cp -r ${DOCS_DIR}/_build/warnings.log artifact/doc_warnings.log + cp artifact/doc_warnings.log artifact/documentation + else + rm ${warning_file} + fi + - uses: actions/upload-artifact@v2 + with: + name: documentation + path: artifact/documentation + - uses: actions/upload-artifact@v2 + with: + name: documentation_warnings.log + path: artifact/doc_warnings.log + if-no-files-found: ignore diff --git a/met/docs/Makefile b/met/docs/Makefile index 6d88c8d309..81e7849441 100644 --- a/met/docs/Makefile +++ b/met/docs/Makefile @@ -21,4 +21,5 @@ clean: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + [ -d $(BUILDDIR) ] || mkdir -p $(BUILDDIR) + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -w "$(BUILDDIR)/warnings.log" diff --git a/met/docs/conf.py b/met/docs/conf.py index 13f65b1b9d..2a51afe4d7 100644 --- a/met/docs/conf.py +++ b/met/docs/conf.py @@ -53,8 +53,6 @@ html_theme = 'sphinx_rtd_theme' html_theme_path = ["_themes", ] html_js_files = ['pop_ver.js'] -html_theme_options = {'canonical_url': 'https://dtcenter.github.io/MET/latest/'} -html_theme_options['versions'] = {'latest': '../latest', 'develop': '../develop'} html_css_files = ['theme_override.css'] # Add any paths that contain custom static files (such as style sheets) here, From 853ad34b7f8f74bc8a73d2787f3a4da49c59ca71 Mon Sep 17 00:00:00 2001 From: johnhg Date: Thu, 1 Apr 2021 16:56:03 -0600 Subject: [PATCH 4/4] Feature 1575 large_diffs (#1741) * Per #1575, add mpr_column and mpr_thresh entries to all of the Grid-Stat and Point-Stat config files. * Per #1575, define config strings to be parsed from the config files. * Per #1575, store col_name_ptr and col_thresh_ptr in PairBase. They are being used for PairDataPoint to do MPR filtering in Grid-Stat and Point-Stat. But they could be eventually be extended to filter ORANK columns for Ensemble-Stat. * Per #1575, add MPR filtering logic to pair_data_point.cc. Include filtering logic in PairDataPoint instead of VxPairDataPoint since Grid-Stat uses PairDataPoint. * Per #1575, update point_stat to parse the mpr_column and mpr_thresh config file options. Include the MPR rejection reason code counts in the log output. * Per #1575, updated Grid-Stat to parse mpr_column and mpr_thresh options. * Per #1575, update Point-Stat to store mpr_sa and mpr_ta locally and then call set_mpr_filt() after the VxPairDataPoint object has been sized and allocated. * Per #1575, renamed PairDataEnsemble::subset_pairs() to subset_pairs_obs_thresh() to be a little more explicit about things. I'll do the same for PairDataPoint using names subset_pairs_cnt_thresh() and subset_pairs_mpr_thresh(). * Per #1575, some cleanup, moving check_fo_thresh() utility function from vx_config to vx_statistics library. * Per #1575, when implementing this for Grid-Stat, I realized that there isn't much benefit in storing col_name_ptr and col_name_thresh in PairBase. These changes remove that. * Per #1575, updating pair_data_point.h/.cc to handle the subsetting of data based on the MPR thresh. * Per #1575, rename subset_pairs() to subset_pairs_cnt_thresh() to be a bit more explicit with the naming conventions. * Per #1575, no real changes here. Just reorganizing the location of the mpr_sa and mpr_ta members. * Per #1575, make the subset_pairs() utility function a member function of the PairDataPoint class named subset_pairs_cnt_thresh() and update the application code to call it. * Per #1575, need to actually set the mpr_thresh! * Per #1575, update subset_pairs_mpr_thresh() to make sure the StringArray and ThreshArray lengths are the same. * Per #1575, replace PairDataPoint::subset_pairs_mpr_thresh() with a utility function named apply_mpr_thresh_mask(). This is for Grid-Stat to apply the mpr_thresh settings after the DataPlane pairs have been created but prior to applying any smoothing operations. * Per #1575, add documentation about mpr_column and mpr_thresh. * Per #1575, mpr_columns can also include CLIMO_CDF. * Per #1575, add tests for Grid-Stat and Point-Stat to exercise the mpr_column and mpr_thresh config file options. --- met/data/config/GridStatConfig_default | 2 + met/data/config/PointStatConfig_default | 2 + met/docs/Users_Guide/config_options.rst | 25 +- met/docs/Users_Guide/grid-stat.rst | 4 +- met/docs/Users_Guide/point-stat.rst | 4 +- met/scripts/config/GridStatConfig_APCP_12 | 3 +- met/scripts/config/GridStatConfig_APCP_24 | 3 + met/scripts/config/GridStatConfig_POP_12 | 2 + met/scripts/config/GridStatConfig_all | 2 + met/scripts/config/PointStatConfig | 2 + met/src/basic/vx_config/config_constants.h | 6 +- met/src/basic/vx_config/config_util.cc | 40 -- met/src/basic/vx_config/config_util.h | 4 - met/src/libcode/vx_statistics/met_stats.cc | 2 +- met/src/libcode/vx_statistics/pair_base.h | 2 + .../vx_statistics/pair_data_ensemble.cc | 2 +- .../vx_statistics/pair_data_ensemble.h | 2 +- .../libcode/vx_statistics/pair_data_point.cc | 344 +++++++++++++++--- .../libcode/vx_statistics/pair_data_point.h | 32 +- .../tools/core/ensemble_stat/ensemble_stat.cc | 4 +- met/src/tools/core/grid_stat/grid_stat.cc | 14 +- .../core/grid_stat/grid_stat_conf_info.cc | 12 +- .../core/grid_stat/grid_stat_conf_info.h | 3 + met/src/tools/core/point_stat/point_stat.cc | 8 +- .../core/point_stat/point_stat_conf_info.cc | 12 + .../core/point_stat/point_stat_conf_info.h | 3 + .../core/series_analysis/series_analysis.cc | 4 +- test/config/GridStatConfig_APCP_regrid | 2 + test/config/GridStatConfig_GRIB_lvl_typ_val | 2 + test/config/GridStatConfig_GRIB_set_attr | 2 + test/config/GridStatConfig_GTG_latlon | 2 + test/config/GridStatConfig_GTG_lc | 2 + test/config/GridStatConfig_apply_mask | 2 + test/config/GridStatConfig_climo_WMO | 2 + test/config/GridStatConfig_climo_prob | 2 + test/config/GridStatConfig_fourier | 2 + test/config/GridStatConfig_grid_weight | 2 + test/config/GridStatConfig_interp_shape | 2 + test/config/GridStatConfig_mpr_thresh | 274 ++++++++++++++ test/config/GridStatConfig_no_leap | 2 + test/config/GridStatConfig_prob_as_scalar | 2 + test/config/GridStatConfig_python | 2 + test/config/GridStatConfig_python_mixed | 2 + test/config/GridStatConfig_rtma | 2 + test/config/GridStatConfig_rtma_perc_thresh | 2 + test/config/GridStatConfig_st4 | 2 + test/config/GridStatConfig_st4_censor | 2 + test/config/PointStatConfig_APCP | 2 + test/config/PointStatConfig_APCP_HIRA | 2 + test/config/PointStatConfig_GTG_latlon | 2 + test/config/PointStatConfig_GTG_lc | 2 + test/config/PointStatConfig_INTERP_OPTS | 2 + test/config/PointStatConfig_LAND_TOPO_MASK | 2 + test/config/PointStatConfig_MASK_SID | 2 + test/config/PointStatConfig_PHYS | 2 + test/config/PointStatConfig_PHYS_pint | 2 + test/config/PointStatConfig_WINDS | 2 + test/config/PointStatConfig_aeronet | 2 + test/config/PointStatConfig_airnow | 2 + test/config/PointStatConfig_climo | 2 + test/config/PointStatConfig_climo_WMO | 2 + test/config/PointStatConfig_climo_prob | 2 + test/config/PointStatConfig_dup | 2 + test/config/PointStatConfig_mpr_thresh | 221 +++++++++++ test/config/PointStatConfig_obs_summary | 2 + test/config/PointStatConfig_obs_summary_all | 2 + test/config/PointStatConfig_prob | 2 + test/config/PointStatConfig_python | 2 + test/config/PointStatConfig_sid_inc_exc | 2 + test/config/ref_config/GridStatConfig_03h | 2 + test/config/ref_config/GridStatConfig_24h | 3 + test/config/ref_config/PointStatConfig_ADPUPA | 2 + test/config/ref_config/PointStatConfig_ONLYSF | 2 + test/config/ref_config/PointStatConfig_WINDS | 2 + test/xml/unit_grid_stat.xml | 27 ++ test/xml/unit_point_stat.xml | 27 ++ 76 files changed, 1065 insertions(+), 118 deletions(-) create mode 100644 test/config/GridStatConfig_mpr_thresh create mode 100644 test/config/PointStatConfig_mpr_thresh diff --git a/met/data/config/GridStatConfig_default b/met/data/config/GridStatConfig_default index acd3a71051..c32872783a 100644 --- a/met/data/config/GridStatConfig_default +++ b/met/data/config/GridStatConfig_default @@ -43,6 +43,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/met/data/config/PointStatConfig_default b/met/data/config/PointStatConfig_default index ae05370fbc..b0a4981c62 100644 --- a/met/data/config/PointStatConfig_default +++ b/met/data/config/PointStatConfig_default @@ -38,6 +38,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = [ NA ]; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/met/docs/Users_Guide/config_options.rst b/met/docs/Users_Guide/config_options.rst index e1f65cc7b4..1277564934 100644 --- a/met/docs/Users_Guide/config_options.rst +++ b/met/docs/Users_Guide/config_options.rst @@ -640,12 +640,12 @@ to be verified. This dictionary may include the following entries: metadata of any output files, but the user can set the "desc" entry accordingly. - Examples of user-defined conversion functions include: + Examples of user-defined data censoring operations include: .. code-block:: none censor_thresh = [ >12000 ]; - censor_val = [ 12000 ]; + censor_val = [ 12000 ]; * Several configuration options are provided to override and correct the metadata read from the input file. The supported options are listed @@ -678,6 +678,25 @@ to be verified. This dictionary may include the following entries: is_wind_direction = boolean; is_prob = boolean; + * The "mpr_column" and "mpr_thresh" entries are arrays of strings and + thresholds to specify which matched pairs should be included in the + statistics. These options apply to the Point-Stat and Grid-Stat tools. + They are parsed seperately for each "obs.field" array entry. + The "mpr_column" strings specify MPR column names ("FCST", "OBS", + "CLIMO_MEAN", "CLIMO_STDEV", or "CLIMO_CDF"), differences of columns + ("FCST-OBS"), or the absolute value of those differences ("ABS(FCST-OBS)"). + The number of "mpr_thresh" thresholds must match the number of "mpr_column" + entries, and the n-th threshold is applied to the n-th column. Any matched + pairs which do not meet any of the specified thresholds are excluded from + the analysis. For example, the following settings exclude matched pairs + where the observation value differs from the forecast or climatological + mean values by more than 10: + + .. code-block:: none + + mpr_column = [ "ABS(OBS-FCST)", "ABS(OBS-CLIMO_MEAN)" ]; + mpr_thresh = [ <=10, <=10 ]; + * The "cat_thresh" entry is an array of thresholds to be used when computing categorical statistics. @@ -981,6 +1000,8 @@ or obs = { censor_thresh = []; censor_val = []; + mpr_column = []; + mpr_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; wind_thresh = [ NA ]; diff --git a/met/docs/Users_Guide/grid-stat.rst b/met/docs/Users_Guide/grid-stat.rst index a3aac48240..ff5808df9c 100644 --- a/met/docs/Users_Guide/grid-stat.rst +++ b/met/docs/Users_Guide/grid-stat.rst @@ -221,13 +221,15 @@ __________________________ type = [ { method = NEAREST; width = 1; } ]; } censor_thresh = []; censor_val = []; + mpr_column = []; + mpr_thresh = []; eclv_points = 0.05; rank_corr_flag = TRUE; tmp_dir = "/tmp"; output_prefix = ""; version = "VN.N"; -The configuration options listed above are common to many MET tools and are described in :numref:`config_options`. +The configuration options listed above are common to multiple MET tools and are described in :numref:`config_options`. ___________________________ diff --git a/met/docs/Users_Guide/point-stat.rst b/met/docs/Users_Guide/point-stat.rst index 1ec6fdacb9..bfbbc53fba 100644 --- a/met/docs/Users_Guide/point-stat.rst +++ b/met/docs/Users_Guide/point-stat.rst @@ -334,6 +334,8 @@ ________________________ type = [ { method = NEAREST; width = 1; } ]; } censor_thresh = []; censor_val = []; + mpr_column = []; + mpr_thresh = []; eclv_points = 0.05; rank_corr_flag = TRUE; sid_inc = []; @@ -347,7 +349,7 @@ ________________________ output_prefix = ""; version = "VN.N"; -The configuration options listed above are common to many MET tools and are described in :numref:`config_options`. +The configuration options listed above are common to multiple MET tools and are described in :numref:`config_options`. _________________________ diff --git a/met/scripts/config/GridStatConfig_APCP_12 b/met/scripts/config/GridStatConfig_APCP_12 index 9ea99e03bc..f4308d3bca 100644 --- a/met/scripts/config/GridStatConfig_APCP_12 +++ b/met/scripts/config/GridStatConfig_APCP_12 @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; @@ -52,7 +54,6 @@ nc_pairs_var_name = ""; nc_pairs_var_suffix = ""; rank_corr_flag = FALSE; - // // Forecast and observation fields to be verified // diff --git a/met/scripts/config/GridStatConfig_APCP_24 b/met/scripts/config/GridStatConfig_APCP_24 index 9d73b6b21c..af2cf4f003 100644 --- a/met/scripts/config/GridStatConfig_APCP_24 +++ b/met/scripts/config/GridStatConfig_APCP_24 @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; @@ -51,6 +53,7 @@ eclv_points = 0.05; nc_pairs_var_name = ""; nc_pairs_var_suffix = ""; rank_corr_flag = FALSE; + // // Forecast and observation fields to be verified // diff --git a/met/scripts/config/GridStatConfig_POP_12 b/met/scripts/config/GridStatConfig_POP_12 index faff0be7e3..c46f639b94 100644 --- a/met/scripts/config/GridStatConfig_POP_12 +++ b/met/scripts/config/GridStatConfig_POP_12 @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/met/scripts/config/GridStatConfig_all b/met/scripts/config/GridStatConfig_all index 1050ab5920..9360adca0a 100644 --- a/met/scripts/config/GridStatConfig_all +++ b/met/scripts/config/GridStatConfig_all @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/met/scripts/config/PointStatConfig b/met/scripts/config/PointStatConfig index fe007f5f9e..159e9ae1b8 100644 --- a/met/scripts/config/PointStatConfig +++ b/met/scripts/config/PointStatConfig @@ -33,6 +33,8 @@ regrid = { censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; wind_thresh = [ NA ]; diff --git a/met/src/basic/vx_config/config_constants.h b/met/src/basic/vx_config/config_constants.h index e63a6935f0..bc82d55625 100644 --- a/met/src/basic/vx_config/config_constants.h +++ b/met/src/basic/vx_config/config_constants.h @@ -380,7 +380,7 @@ struct MaskLatLon { // enum DuplicateType { - DuplicateType_None, // Apply no logic for duplicate point obs + DuplicateType_None, // Apply no logic for duplicate point obs DuplicateType_Unique // Filter out duplicate observation values }; @@ -394,7 +394,7 @@ enum ObsSummary { ObsSummary_None, // Keep all observations, no statistics ObsSummary_Nearest, // Keep only the observation closest in time ObsSummary_Min, // Keep only smallest value - ObsSummary_Max, // Keep only largest valueXS + ObsSummary_Max, // Keep only largest value ObsSummary_UW_Mean, // Calculate un-weighted mean ObsSummary_DW_Mean, // Calculate time weighted mean ObsSummary_Median, // Calculate median @@ -536,6 +536,8 @@ static const char conf_key_obs_qty[] = "obs_quality"; static const char conf_key_convert[] = "convert"; static const char conf_key_censor_thresh[] = "censor_thresh"; static const char conf_key_censor_val[] = "censor_val"; +static const char conf_key_mpr_column[] = "mpr_column"; +static const char conf_key_mpr_thresh[] = "mpr_thresh"; static const char conf_key_cnt_thresh[] = "cnt_thresh"; static const char conf_key_cnt_logic[] = "cnt_logic"; static const char conf_key_cat_thresh[] = "cat_thresh"; diff --git a/met/src/basic/vx_config/config_util.cc b/met/src/basic/vx_config/config_util.cc index 349eb06081..6eb13ef7a5 100644 --- a/met/src/basic/vx_config/config_util.cc +++ b/met/src/basic/vx_config/config_util.cc @@ -2285,46 +2285,6 @@ void check_mctc_thresh(const ThreshArray &ta) { /////////////////////////////////////////////////////////////////////////////// -bool check_fo_thresh(const double f, const double o, - const double cmn, const double csd, - const SingleThresh &ft, const SingleThresh &ot, - const SetLogic type) { - bool status = true; - bool fcheck = ft.check(f, cmn, csd); - bool ocheck = ot.check(o, cmn, csd); - SetLogic t = type; - - // If either of the thresholds is NA, reset the logic to intersection - // because an NA threshold is always true. - if(ft.get_type() == thresh_na || ot.get_type() == thresh_na) { - t = SetLogic_Intersection; - } - - switch(t) { - case(SetLogic_Union): - if(!fcheck && !ocheck) status = false; - break; - - case(SetLogic_Intersection): - if(!fcheck || !ocheck) status = false; - break; - - case(SetLogic_SymDiff): - if(fcheck == ocheck) status = false; - break; - - default: - mlog << Error << "\ncheck_fo_thresh() -> " - << "Unexpected SetLogic value of " << type << ".\n\n"; - exit(1); - break; - } - - return(status); -} - -/////////////////////////////////////////////////////////////////////////////// - const char * statlinetype_to_string(const STATLineType t) { const char *s = (const char *) 0; diff --git a/met/src/basic/vx_config/config_util.h b/met/src/basic/vx_config/config_util.h index d09a154c4c..ced39afb2d 100644 --- a/met/src/basic/vx_config/config_util.h +++ b/met/src/basic/vx_config/config_util.h @@ -80,10 +80,6 @@ extern void check_climo_n_vx(Dictionary *dict, const int); extern InterpMthd int_to_interpmthd(int); extern void check_mctc_thresh(const ThreshArray &); -extern bool check_fo_thresh(const double, const double, const double, const double, - const SingleThresh &, const SingleThresh &, - const SetLogic); - extern const char * statlinetype_to_string(const STATLineType); extern void statlinetype_to_string(const STATLineType, char *); extern STATLineType string_to_statlinetype(const char *); diff --git a/met/src/libcode/vx_statistics/met_stats.cc b/met/src/libcode/vx_statistics/met_stats.cc index e4074a79a6..27904462d1 100644 --- a/met/src/libcode/vx_statistics/met_stats.cc +++ b/met/src/libcode/vx_statistics/met_stats.cc @@ -1207,7 +1207,7 @@ void SL1L2Info::set(const PairDataPoint &pd_all) { zero_out(); // Apply continuous filtering thresholds to subset pairs - pd = subset_pairs(pd_all, fthresh, othresh, logic); + pd = pd_all.subset_pairs_cnt_thresh(fthresh, othresh, logic); // Check for no matched pairs to process if(pd.n_obs == 0) return; diff --git a/met/src/libcode/vx_statistics/pair_base.h b/met/src/libcode/vx_statistics/pair_base.h index 0c1bec3bd0..db7b63297f 100644 --- a/met/src/libcode/vx_statistics/pair_base.h +++ b/met/src/libcode/vx_statistics/pair_base.h @@ -71,6 +71,8 @@ class PairBase { MaskLatLon *mask_llpnt_ptr; // Pointer to Lat/Lon thresholds // which is not allocated + ////////////////////////////////////////////////////////////////// + ConcatString msg_typ; // Name of the verifying message type StringArray msg_typ_vals; // Message type values to be included diff --git a/met/src/libcode/vx_statistics/pair_data_ensemble.cc b/met/src/libcode/vx_statistics/pair_data_ensemble.cc index bc27df220c..5f21f17fe9 100644 --- a/met/src/libcode/vx_statistics/pair_data_ensemble.cc +++ b/met/src/libcode/vx_statistics/pair_data_ensemble.cc @@ -758,7 +758,7 @@ void PairDataEnsemble::compute_ssvar() { // //////////////////////////////////////////////////////////////////////// -PairDataEnsemble PairDataEnsemble::subset_pairs(const SingleThresh &ot) const { +PairDataEnsemble PairDataEnsemble::subset_pairs_obs_thresh(const SingleThresh &ot) const { // Check for no work to be done if(ot.get_type() == thresh_na) return(*this); diff --git a/met/src/libcode/vx_statistics/pair_data_ensemble.h b/met/src/libcode/vx_statistics/pair_data_ensemble.h index 5bfd4d4300..3d71af984b 100644 --- a/met/src/libcode/vx_statistics/pair_data_ensemble.h +++ b/met/src/libcode/vx_statistics/pair_data_ensemble.h @@ -142,7 +142,7 @@ class PairDataEnsemble : public PairBase { void compute_phist(); void compute_ssvar(); - PairDataEnsemble subset_pairs(const SingleThresh &ot) const; + PairDataEnsemble subset_pairs_obs_thresh(const SingleThresh &ot) const; }; //////////////////////////////////////////////////////////////////////// diff --git a/met/src/libcode/vx_statistics/pair_data_point.cc b/met/src/libcode/vx_statistics/pair_data_point.cc index d728b242cb..0ca19804dd 100644 --- a/met/src/libcode/vx_statistics/pair_data_point.cc +++ b/met/src/libcode/vx_statistics/pair_data_point.cc @@ -174,8 +174,7 @@ void PairDataPoint::set_point_pair(int i_obs, const char *sid, if(i_obs < 0 || i_obs >= n_obs) { mlog << Error << "\nPairDataPoint::set_point_pair() -> " << "range check error: " << i_obs << " not in (0, " - << n_obs << ").\n\n" - ; + << n_obs << ").\n\n"; exit(1); } @@ -232,6 +231,67 @@ bool PairDataPoint::add_grid_pair(const NumArray &f_in, const NumArray &o_in, return(true); } +//////////////////////////////////////////////////////////////////////// + +PairDataPoint PairDataPoint::subset_pairs_cnt_thresh( + const SingleThresh &ft, const SingleThresh &ot, + const SetLogic type) const { + + // Check for no work to be done + if(ft.get_type() == thresh_na && ot.get_type() == thresh_na) { + return(*this); + } + + int i; + PairDataPoint out_pd; + + // Allocate memory for output pairs + out_pd.extend(n_obs); + out_pd.set_climo_cdf_info(cdf_info); + + bool cmn_flag = set_climo_flag(f_na, cmn_na); + bool csd_flag = set_climo_flag(f_na, csd_na); + bool wgt_flag = set_climo_flag(f_na, wgt_na); + + // Loop over the pairs + for(i=0; i " + << "the \"" << conf_key_mpr_column << "\" (" + << write_css(sa) << ") and \"" << conf_key_mpr_thresh + << "\" (" << write_css(ta) + << ") config file entries must have the same length!\n\n"; + exit(1); + } + + mpr_column = sa; + mpr_thresh = ta; + + return; +} + +//////////////////////////////////////////////////////////////////////// + void VxPairDataPoint::set_climo_cdf_info(const ClimoCDFInfo &info) { for(int i=0; imagic_str() << " versus " + << obs_info->magic_str() + << ", skipping observation due to matched pair filter since " + << reason_cs << ":\n" + << point_obs_to_string(hdr_arr, hdr_typ_str, hdr_sid_str, + hdr_ut, obs_qty, obs_arr, var_name) + << "\n"; + inc_count(rej_mpr, i, j, k); + continue; + } + // Compute weight for current point wgt_v = (wgt_dp == (DataPlane *) 0 ? default_grid_weight : wgt_dp->get(x, y)); @@ -1336,64 +1445,199 @@ void VxPairDataPoint::inc_count(int ***&rej, int i, int j, int k) { // //////////////////////////////////////////////////////////////////////// -PairDataPoint subset_pairs(const PairDataPoint &pd, - const SingleThresh &ft, const SingleThresh &ot, - const SetLogic type) { +bool check_fo_thresh(double f, double o, double cmn, double csd, + const SingleThresh &ft, const SingleThresh &ot, + const SetLogic type) { + bool status = true; + bool fcheck = ft.check(f, cmn, csd); + bool ocheck = ot.check(o, cmn, csd); + SetLogic t = type; - // Check for no work to be done - if(ft.get_type() == thresh_na && ot.get_type() == thresh_na) { - return(pd); + // If either of the thresholds is NA, reset the logic to intersection + // because an NA threshold is always true. + if(ft.get_type() == thresh_na || ot.get_type() == thresh_na) { + t = SetLogic_Intersection; } - int i; - PairDataPoint out_pd; + switch(t) { + case(SetLogic_Union): + if(!fcheck && !ocheck) status = false; + break; - // Allocate memory for output pairs - out_pd.extend(pd.n_obs); - out_pd.set_climo_cdf_info(pd.cdf_info); + case(SetLogic_Intersection): + if(!fcheck || !ocheck) status = false; + break; - bool cmn_flag = set_climo_flag(pd.f_na, pd.cmn_na); - bool csd_flag = set_climo_flag(pd.f_na, pd.csd_na); - bool wgt_flag = set_climo_flag(pd.f_na, pd.wgt_na); + case(SetLogic_SymDiff): + if(fcheck == ocheck) status = false; + break; - // Loop over the pairs - for(i=0; i " + << "Unexpected SetLogic value of " << type << ".\n\n"; + exit(1); + break; + } - // Check for bad data - if(is_bad_data(pd.f_na[i]) || - is_bad_data(pd.o_na[i]) || - (cmn_flag && is_bad_data(pd.cmn_na[i])) || - (csd_flag && is_bad_data(pd.csd_na[i])) || - (wgt_flag && is_bad_data(pd.wgt_na[i]))) continue; + return(status); +} - // Keep pairs which meet the threshold criteria - if(check_fo_thresh(pd.f_na[i], pd.o_na[i], - pd.cmn_na[i], pd.csd_na[i], - ft, ot, type)) { +//////////////////////////////////////////////////////////////////////// - // Handle point data - if(pd.is_point_vx()) { - out_pd.add_point_pair(pd.sid_sa[i].c_str(), pd.lat_na[i], - pd.lon_na[i], pd.x_na[i], pd.y_na[i], - pd.vld_ta[i], pd.lvl_na[i], pd.elv_na[i], - pd.f_na[i], pd.o_na[i], pd.o_qc_sa[i].c_str(), - pd.cmn_na[i], pd.csd_na[i], pd.wgt_na[i]); - } - // Handle gridded data - else { - out_pd.add_grid_pair(pd.f_na[i], pd.o_na[i], pd.cmn_na[i], - pd.csd_na[i], pd.wgt_na[i]); +bool check_mpr_thresh(double f, double o, double cmn, double csd, + const StringArray &col_sa, const ThreshArray &col_ta, + ConcatString *reason_ptr) { + // Initialize + if(reason_ptr) reason_ptr->erase(); + + // Check arrays + if(col_sa.n() == 0 || col_ta.n() == 0) return(true); + + bool keep = true; + bool absv = false; + StringArray sa; + ConcatString cs; + double v, v_cur; + int i, j; + + // Loop over all the column filter names + for(i=0; i 1) { + + // Loop through the columns + for(j=1; j " + << "unsupported matched pair column name requested in \"" + << conf_key_mpr_column << "\" (" << s << ")!\n\n"; + exit(1); + } + + return(v); +} + +//////////////////////////////////////////////////////////////////////// + +void apply_mpr_thresh_mask(DataPlane &fcst_dp, DataPlane &obs_dp, + DataPlane &cmn_dp, DataPlane &csd_dp, + const StringArray &col_sa, const ThreshArray &col_ta) { + + // Check for no work to be done + if(col_sa.n() == 0 && col_ta.n() == 0) return; + + // Check for constant length + if(col_sa.n() != col_ta.n()) { + mlog << Error << "\napply_mpr_thresh_mask() -> " + << "the \"" << conf_key_mpr_column << "\" (" + << write_css(col_sa) << ") and \"" << conf_key_mpr_thresh + << "\" (" << write_css(col_ta) + << ") config file entries must have the same length!\n\n"; + exit(1); + } + + int nxy = fcst_dp.nx() * fcst_dp.ny(); + int n_skip = 0; + bool cmn_flag = !(cmn_dp.is_empty()); + bool csd_flag = !(csd_dp.is_empty()); + + // Loop over the pairs + for(int i=0; isubset_pairs(conf_info.vx_opt[i].othr_ta[m]); + pd = pd_ptr->subset_pairs_obs_thresh(conf_info.vx_opt[i].othr_ta[m]); // Continue if there are no points if(pd.n_obs == 0) continue; @@ -1779,7 +1779,7 @@ void process_grid_vx() { shc.set_obs_thresh(conf_info.vx_opt[i].othr_ta[l]); // Subset pairs using the current obs_thresh - pd = pd_all.subset_pairs(conf_info.vx_opt[i].othr_ta[l]); + pd = pd_all.subset_pairs_obs_thresh(conf_info.vx_opt[i].othr_ta[l]); // Continue if there are no points if(pd.n_obs == 0) continue; diff --git a/met/src/tools/core/grid_stat/grid_stat.cc b/met/src/tools/core/grid_stat/grid_stat.cc index 14b09c6d5a..cf30bd282f 100644 --- a/met/src/tools/core/grid_stat/grid_stat.cc +++ b/met/src/tools/core/grid_stat/grid_stat.cc @@ -106,6 +106,8 @@ // continuous and probabilistic statistics. // 050 03/02/20 Halley Gotway Add nc_pairs_var_name and rename // nc_pairs_var_str to nc_pairs_var_suffix. +// 051 03/28/21 Halley Gotway Add mpr_column and mpr_thresh +// filtering options. // //////////////////////////////////////////////////////////////////////// @@ -711,6 +713,13 @@ void process_scores() { << " climatology standard deviation field(s) for forecast " << conf_info.vx_opt[i].fcst_info->magic_str() << ".\n"; + // Apply MPR threshold filters + if(conf_info.vx_opt[i].mpr_sa.n() > 0) { + apply_mpr_thresh_mask(fcst_dp, obs_dp, cmn_dp, csd_dp, + conf_info.vx_opt[i].mpr_sa, + conf_info.vx_opt[i].mpr_ta); + } + // Setup the first pass through the data if(is_first_pass) setup_first_pass(fcst_dp); @@ -1961,8 +1970,9 @@ void do_cnt_sl1l2(const GridStatVxOpt &vx_opt, const PairDataPoint *pd_ptr) { for(i=0; isubset_pairs_cnt_thresh(vx_opt.fcnt_ta[i], + vx_opt.ocnt_ta[i], + vx_opt.cnt_logic); // Check for no matched pairs to process if(pd_thr.n_obs == 0) continue; diff --git a/met/src/tools/core/grid_stat/grid_stat_conf_info.cc b/met/src/tools/core/grid_stat/grid_stat_conf_info.cc index a5702ca06f..8b2b572eca 100644 --- a/met/src/tools/core/grid_stat/grid_stat_conf_info.cc +++ b/met/src/tools/core/grid_stat/grid_stat_conf_info.cc @@ -275,7 +275,7 @@ void GridStatConfInfo::process_flags() { // Check for at least one output data type if(!output_ascii_flag && !output_nc_flag) { - mlog << Error << "\nGridStatVxOpt::process_config() -> " + mlog << Error << "\nGridStatConfInfo::process_flags() -> " << "At least one output STAT or NetCDF type must be " << " requested in \"" << conf_key_output_flag << "\" or \"" << conf_key_nc_pairs_flag << "\".\n\n"; @@ -495,6 +495,9 @@ void GridStatVxOpt::clear() { var_name.clear(); var_suffix.clear(); + mpr_sa.clear(); + mpr_ta.clear(); + fcat_ta.clear(); ocat_ta.clear(); @@ -614,6 +617,10 @@ void GridStatVxOpt::process_config( // Populate the output_flag array with map values for(i=0; i= 5) { mlog << Debug(5) << "Parsed thresholds:\n" + << "Matched pair filter columns: " << write_css(mpr_sa) << "\n" + << "Matched pair filter thresholds: " << mpr_ta.get_str() << "\n" << "Forecast categorical thresholds: " << fcat_ta.get_str() << "\n" << "Observed categorical thresholds: " << ocat_ta.get_str() << "\n" << "Forecast continuous thresholds: " << fcnt_ta.get_str() << "\n" @@ -875,6 +884,7 @@ bool GridStatVxOpt::is_uv_match(const GridStatVxOpt &v) const { // // The following do not impact matched pairs: // desc, var_name, var_suffix, + // mpr_sa, mpr_ta, // fcat_ta, ocat_ta, // fcnt_ta, ocnt_ta, cnt_logic, // fwind_ta, owind_ta, wind_logic, diff --git a/met/src/tools/core/grid_stat/grid_stat_conf_info.h b/met/src/tools/core/grid_stat/grid_stat_conf_info.h index 3b92c5be06..e03b657488 100644 --- a/met/src/tools/core/grid_stat/grid_stat_conf_info.h +++ b/met/src/tools/core/grid_stat/grid_stat_conf_info.h @@ -145,6 +145,9 @@ class GridStatVxOpt { ConcatString var_suffix; // nc_pairs_var_suffix string // nc_pairs_var_str is deprecated + StringArray mpr_sa; // MPR filtering columns + ThreshArray mpr_ta; // MPR filtering thresholds + ThreshArray fcat_ta; // fcst categorical thresholds ThreshArray ocat_ta; // obs categorical thresholds diff --git a/met/src/tools/core/point_stat/point_stat.cc b/met/src/tools/core/point_stat/point_stat.cc index d1edfdb935..ba28097e6a 100644 --- a/met/src/tools/core/point_stat/point_stat.cc +++ b/met/src/tools/core/point_stat/point_stat.cc @@ -92,6 +92,8 @@ // 043 11/15/19 Halley Gotway Apply climatology bins to // continuous and probabilistic statistics. // 044 01/24/20 Halley Gotway Add HiRA RPS output. +// 045 03/28/21 Halley Gotway Add mpr_column and mpr_thresh +// filtering options. // //////////////////////////////////////////////////////////////////////// @@ -1016,6 +1018,7 @@ void process_scores() { << "Rejected: bad fcst value = " << conf_info.vx_opt[i].vx_pd.rej_fcst[j][k][l] << "\n" << "Rejected: bad climo mean = " << conf_info.vx_opt[i].vx_pd.rej_cmn[j][k][l] << "\n" << "Rejected: bad climo stdev = " << conf_info.vx_opt[i].vx_pd.rej_csd[j][k][l] << "\n" + << "Rejected: mpr filter = " << conf_info.vx_opt[i].vx_pd.rej_mpr[j][k][l] << "\n" << "Rejected: duplicates = " << conf_info.vx_opt[i].vx_pd.rej_dup[j][k][l] << "\n"; // Print report based on the number of matched pairs @@ -1421,8 +1424,9 @@ void do_cnt_sl1l2(const PointStatVxOpt &vx_opt, const PairDataPoint *pd_ptr) { for(i=0; isubset_pairs_cnt_thresh(vx_opt.fcnt_ta[i], + vx_opt.ocnt_ta[i], + vx_opt.cnt_logic); // Check for no matched pairs to process if(pd_thr.n_obs == 0) continue; diff --git a/met/src/tools/core/point_stat/point_stat_conf_info.cc b/met/src/tools/core/point_stat/point_stat_conf_info.cc index ecd6b8b3dc..5a039e1bae 100644 --- a/met/src/tools/core/point_stat/point_stat_conf_info.cc +++ b/met/src/tools/core/point_stat/point_stat_conf_info.cc @@ -606,6 +606,9 @@ void PointStatVxOpt::clear() { mask_sid.clear(); mask_llpnt.clear(); + mpr_sa.clear(); + mpr_ta.clear(); + mask_name.clear(); eclv_points.clear(); @@ -774,10 +777,16 @@ void PointStatVxOpt::process_config(GrdFileType ftype, int_to_setlogic(fdict.lookup_int(conf_key_wind_logic)), int_to_setlogic(odict.lookup_int(conf_key_wind_logic))); + // Conf: mpr_column and mpr_thresh + mpr_sa = odict.lookup_string_array(conf_key_mpr_column); + mpr_ta = odict.lookup_thresh_array(conf_key_mpr_thresh); + // Dump the contents of the current thresholds if(mlog.verbosity_level() >= 5) { mlog << Debug(5) << "Parsed thresholds:\n" + << "Matched pair filter columns: " << write_css(mpr_sa) << "\n" + << "Matched pair filter thresholds: " << mpr_ta.get_str() << "\n" << "Forecast categorical thresholds: " << fcat_ta.get_str() << "\n" << "Observed categorical thresholds: " << ocat_ta.get_str() << "\n" << "Forecast continuous thresholds: " << fcnt_ta.get_str() << "\n" @@ -932,6 +941,9 @@ void PointStatVxOpt::set_vx_pd(PointStatConfInfo *conf_info) { // Define the dimensions vx_pd.set_pd_size(n_msg_typ, n_mask, n_interp); + // Store the MPR filter threshold + vx_pd.set_mpr_thresh(mpr_sa, mpr_ta); + // Store the climo CDF info vx_pd.set_climo_cdf_info(cdf_info); diff --git a/met/src/tools/core/point_stat/point_stat_conf_info.h b/met/src/tools/core/point_stat/point_stat_conf_info.h index d849dcc113..dd1d787dfa 100644 --- a/met/src/tools/core/point_stat/point_stat_conf_info.h +++ b/met/src/tools/core/point_stat/point_stat_conf_info.h @@ -123,6 +123,9 @@ class PointStatVxOpt { StringArray mask_poly; // Masking polyline strings StringArray mask_sid; // Masking station ID's + StringArray mpr_sa; // MPR column names + ThreshArray mpr_ta; // MPR column thresholds + // Vector of MaskLatLon objects defining Lat/Lon Point masks vector mask_llpnt; diff --git a/met/src/tools/core/series_analysis/series_analysis.cc b/met/src/tools/core/series_analysis/series_analysis.cc index 5a17f62ff7..acc347aff0 100644 --- a/met/src/tools/core/series_analysis/series_analysis.cc +++ b/met/src/tools/core/series_analysis/series_analysis.cc @@ -1008,8 +1008,8 @@ void do_cnt(int n, const PairDataPoint *pd_ptr) { } // Apply continuous filtering thresholds to subset pairs - pd = subset_pairs(*pd_ptr, cnt_info.fthresh, cnt_info.othresh, - cnt_info.logic); + pd = pd_ptr->subset_pairs_cnt_thresh(cnt_info.fthresh, cnt_info.othresh, + cnt_info.logic); // Check for no matched pairs to process if(pd.n_obs == 0) continue; diff --git a/test/config/GridStatConfig_APCP_regrid b/test/config/GridStatConfig_APCP_regrid index 445ff414e9..7696febce9 100644 --- a/test/config/GridStatConfig_APCP_regrid +++ b/test/config/GridStatConfig_APCP_regrid @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/GridStatConfig_GRIB_lvl_typ_val b/test/config/GridStatConfig_GRIB_lvl_typ_val index ceadb05264..5e0f64d6a7 100644 --- a/test/config/GridStatConfig_GRIB_lvl_typ_val +++ b/test/config/GridStatConfig_GRIB_lvl_typ_val @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/GridStatConfig_GRIB_set_attr b/test/config/GridStatConfig_GRIB_set_attr index 88703198c1..d1d5dbc30d 100644 --- a/test/config/GridStatConfig_GRIB_set_attr +++ b/test/config/GridStatConfig_GRIB_set_attr @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/GridStatConfig_GTG_latlon b/test/config/GridStatConfig_GTG_latlon index 86419f863c..648863688e 100644 --- a/test/config/GridStatConfig_GTG_latlon +++ b/test/config/GridStatConfig_GTG_latlon @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/GridStatConfig_GTG_lc b/test/config/GridStatConfig_GTG_lc index 290756e91e..846f5a2e6e 100644 --- a/test/config/GridStatConfig_GTG_lc +++ b/test/config/GridStatConfig_GTG_lc @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/GridStatConfig_apply_mask b/test/config/GridStatConfig_apply_mask index fef335f064..1bb34bb9f1 100644 --- a/test/config/GridStatConfig_apply_mask +++ b/test/config/GridStatConfig_apply_mask @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/GridStatConfig_climo_WMO b/test/config/GridStatConfig_climo_WMO index 6974d71937..a9f4c120cf 100644 --- a/test/config/GridStatConfig_climo_WMO +++ b/test/config/GridStatConfig_climo_WMO @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/GridStatConfig_climo_prob b/test/config/GridStatConfig_climo_prob index 4d652daa12..7b91e8da0f 100644 --- a/test/config/GridStatConfig_climo_prob +++ b/test/config/GridStatConfig_climo_prob @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/GridStatConfig_fourier b/test/config/GridStatConfig_fourier index e978c99f8c..a441acd51f 100644 --- a/test/config/GridStatConfig_fourier +++ b/test/config/GridStatConfig_fourier @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/GridStatConfig_grid_weight b/test/config/GridStatConfig_grid_weight index c5cf23cef6..5ea4b6df87 100644 --- a/test/config/GridStatConfig_grid_weight +++ b/test/config/GridStatConfig_grid_weight @@ -41,6 +41,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/GridStatConfig_interp_shape b/test/config/GridStatConfig_interp_shape index cc212d77f8..af303ec165 100644 --- a/test/config/GridStatConfig_interp_shape +++ b/test/config/GridStatConfig_interp_shape @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/GridStatConfig_mpr_thresh b/test/config/GridStatConfig_mpr_thresh new file mode 100644 index 0000000000..bd28d883f2 --- /dev/null +++ b/test/config/GridStatConfig_mpr_thresh @@ -0,0 +1,274 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Grid-Stat configuration file. +// +// For additional information, please see the MET User's Guide. +// +//////////////////////////////////////////////////////////////////////////////// + +// +// Output model name to be written +// +model = "GFS"; + +// +// Output description to be written +// May be set separately in each "obs.field" entry +// +desc = "NA"; + +// +// Output observation type to be written +// +obtype = "GFSANL"; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Verification grid +// +regrid = { + to_grid = NONE; + method = NEAREST; + width = 1; + vld_thresh = 0.5; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// May be set separately in each "field" entry +// +censor_thresh = []; +censor_val = []; +mpr_column = []; +mpr_thresh = []; +cat_thresh = []; +cnt_thresh = [ NA ]; +cnt_logic = UNION; +wind_thresh = [ NA ]; +wind_logic = UNION; +eclv_points = 0.05; +nc_pairs_var_name = ""; +nc_pairs_var_suffix = ""; +rank_corr_flag = FALSE; + +// +// Forecast and observation fields to be verified +// +fcst = { + + name = "TMP"; + level = "Z2"; + + field = [ + { + desc = "NO_MPR_THRESH"; + nc_pairs_var_suffix = desc; + }, + { + mpr_column = [ "OBS-FCST" ]; + mpr_thresh = [ >=-5&&<=5 ]; + desc = "OBS_FCST_DIFF"; + nc_pairs_var_suffix = desc; + }, + { + mpr_column = [ "ABS(OBS-FCST)" ]; + mpr_thresh = [ <=5 ]; + desc = "ABS_OBS_FCST_DIFF"; + nc_pairs_var_suffix = desc; + }, + { + mpr_column = [ "ABS(OBS-CLIMO_MEAN)" ]; + mpr_thresh = [ <=5 ]; + desc = "ABS_OBS_CLIMO_MEAN_DIFF"; + nc_pairs_var_suffix = desc; + }, + { + mpr_column = [ "CLIMO_CDF" ]; + mpr_thresh = [ >=0.25&&<=0.75 ]; + desc = "CLIMO_CDF_IQR"; + nc_pairs_var_suffix = desc; + } + ]; +} +obs = fcst; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Climatology mean data +// +climo_mean = fcst; +climo_mean = { + + file_name = [ ${CLIMO_MEAN_FILE_LIST} ]; + + regrid = { + method = BILIN; + width = 2; + vld_thresh = 0.5; + } + + time_interp_method = DW_MEAN; + day_interval = ${DAY_INTERVAL}; + hour_interval = ${HOUR_INTERVAL}; +} + +climo_stdev = climo_mean; +climo_stdev = { + file_name = [ ${CLIMO_STDEV_FILE_LIST} ]; +} + +// +// May be set separately in each "obs.field" entry +// +climo_cdf = { + cdf_bins = 1; + center_bins = FALSE; + write_bins = TRUE; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Verification masking regions +// +mask = { + grid = [ "FULL" ]; + poly = []; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Confidence interval settings +// +ci_alpha = [ 0.05 ]; + +boot = { + interval = PCTILE; + rep_prop = 1.0; + n_rep = 0; + rng = "mt19937"; + seed = ""; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Data smoothing methods +// +interp = { + field = BOTH; + vld_thresh = 1.0; + shape = SQUARE; + + type = [ + { + method = NEAREST; + width = 1; + } + ]; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Neighborhood methods +// +nbrhd = { + width = [ 1 ]; + cov_thresh = [ >=0.5 ]; + vld_thresh = 1.0; + shape = SQUARE; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Fourier decomposition +// +fourier = { + wave_1d_beg = []; + wave_1d_end = []; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Gradient statistics +// May be set separately in each "obs.field" entry +// +gradient = { + dx = [ 1 ]; + dy = [ 1 ]; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Distance Map statistics +// May be set separately in each "obs.field" entry +// +distance_map = { + baddeley_p = 2; + baddeley_max_dist = NA; + fom_alpha = 0.1; + zhu_weight = 0.5; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Statistical output types +// +output_flag = { + fho = NONE; + ctc = NONE; + cts = NONE; + mctc = NONE; + mcts = NONE; + cnt = NONE; + sl1l2 = STAT; + sal1l2 = NONE; + vl1l2 = NONE; + val1l2 = NONE; + vcnt = NONE; + pct = NONE; + pstd = NONE; + pjc = NONE; + prc = NONE; + eclv = NONE; + nbrctc = NONE; + nbrcts = NONE; + nbrcnt = NONE; + grad = NONE; + dmap = NONE; +} + +// +// NetCDF matched pairs output file +// +nc_pairs_flag = { + latlon = FALSE; + raw = FALSE; + diff = TRUE; + climo = FALSE; + climo_cdp = FALSE; + weight = FALSE; + nbrhd = FALSE; + fourier = FALSE; + gradient = FALSE; + distance_map = FALSE; + apply_mask = FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// + +grid_weight_flag = COS_LAT; +tmp_dir = "/tmp"; +output_prefix = "${OUTPUT_PREFIX}"; +version = "V10.0.0"; + +//////////////////////////////////////////////////////////////////////////////// diff --git a/test/config/GridStatConfig_no_leap b/test/config/GridStatConfig_no_leap index e415640c07..47ab1f474b 100644 --- a/test/config/GridStatConfig_no_leap +++ b/test/config/GridStatConfig_no_leap @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/GridStatConfig_prob_as_scalar b/test/config/GridStatConfig_prob_as_scalar index 2c63950004..13c6143438 100644 --- a/test/config/GridStatConfig_prob_as_scalar +++ b/test/config/GridStatConfig_prob_as_scalar @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/GridStatConfig_python b/test/config/GridStatConfig_python index 85dd871c5e..0d5e908266 100644 --- a/test/config/GridStatConfig_python +++ b/test/config/GridStatConfig_python @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/GridStatConfig_python_mixed b/test/config/GridStatConfig_python_mixed index 367c0e1118..b3a6c2ea2b 100644 --- a/test/config/GridStatConfig_python_mixed +++ b/test/config/GridStatConfig_python_mixed @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/GridStatConfig_rtma b/test/config/GridStatConfig_rtma index 4d88b8e6c7..77d491e5b5 100644 --- a/test/config/GridStatConfig_rtma +++ b/test/config/GridStatConfig_rtma @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/GridStatConfig_rtma_perc_thresh b/test/config/GridStatConfig_rtma_perc_thresh index 0f96a179f4..cabb9c13df 100644 --- a/test/config/GridStatConfig_rtma_perc_thresh +++ b/test/config/GridStatConfig_rtma_perc_thresh @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/GridStatConfig_st4 b/test/config/GridStatConfig_st4 index abb1c4079f..7ad113c13f 100644 --- a/test/config/GridStatConfig_st4 +++ b/test/config/GridStatConfig_st4 @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/GridStatConfig_st4_censor b/test/config/GridStatConfig_st4_censor index fd9debdcdf..8f088b7a6d 100644 --- a/test/config/GridStatConfig_st4_censor +++ b/test/config/GridStatConfig_st4_censor @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/PointStatConfig_APCP b/test/config/PointStatConfig_APCP index 3923198689..920034bc27 100644 --- a/test/config/PointStatConfig_APCP +++ b/test/config/PointStatConfig_APCP @@ -31,6 +31,8 @@ obs_window = { //////////////////////////////////////////////////////////////////////////////// +mpr_column = []; +mpr_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; wind_thresh = [ NA ]; diff --git a/test/config/PointStatConfig_APCP_HIRA b/test/config/PointStatConfig_APCP_HIRA index 4941473a82..e39d21863c 100644 --- a/test/config/PointStatConfig_APCP_HIRA +++ b/test/config/PointStatConfig_APCP_HIRA @@ -31,6 +31,8 @@ obs_window = { //////////////////////////////////////////////////////////////////////////////// +mpr_column = []; +mpr_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; wind_thresh = [ NA ]; diff --git a/test/config/PointStatConfig_GTG_latlon b/test/config/PointStatConfig_GTG_latlon index 4a33c23102..fc5fa1eef9 100644 --- a/test/config/PointStatConfig_GTG_latlon +++ b/test/config/PointStatConfig_GTG_latlon @@ -31,6 +31,8 @@ obs_window = { //////////////////////////////////////////////////////////////////////////////// +mpr_column = []; +mpr_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; wind_thresh = [ NA ]; diff --git a/test/config/PointStatConfig_GTG_lc b/test/config/PointStatConfig_GTG_lc index 0a08acdf19..e1c5f89ab2 100644 --- a/test/config/PointStatConfig_GTG_lc +++ b/test/config/PointStatConfig_GTG_lc @@ -31,6 +31,8 @@ obs_window = { //////////////////////////////////////////////////////////////////////////////// +mpr_column = []; +mpr_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; wind_thresh = [ NA ]; diff --git a/test/config/PointStatConfig_INTERP_OPTS b/test/config/PointStatConfig_INTERP_OPTS index 902138d916..1538ce4bf9 100644 --- a/test/config/PointStatConfig_INTERP_OPTS +++ b/test/config/PointStatConfig_INTERP_OPTS @@ -31,6 +31,8 @@ obs_window = { //////////////////////////////////////////////////////////////////////////////// +mpr_column = []; +mpr_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; wind_thresh = [ NA ]; diff --git a/test/config/PointStatConfig_LAND_TOPO_MASK b/test/config/PointStatConfig_LAND_TOPO_MASK index a98c163ff1..9d9e77564e 100644 --- a/test/config/PointStatConfig_LAND_TOPO_MASK +++ b/test/config/PointStatConfig_LAND_TOPO_MASK @@ -31,6 +31,8 @@ obs_window = { //////////////////////////////////////////////////////////////////////////////// +mpr_column = []; +mpr_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; wind_thresh = [ NA ]; diff --git a/test/config/PointStatConfig_MASK_SID b/test/config/PointStatConfig_MASK_SID index 6333358fac..b9afca5389 100644 --- a/test/config/PointStatConfig_MASK_SID +++ b/test/config/PointStatConfig_MASK_SID @@ -31,6 +31,8 @@ obs_window = { //////////////////////////////////////////////////////////////////////////////// +mpr_column = []; +mpr_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; wind_thresh = [ NA ]; diff --git a/test/config/PointStatConfig_PHYS b/test/config/PointStatConfig_PHYS index 03a67ca8b4..aea79c4b19 100644 --- a/test/config/PointStatConfig_PHYS +++ b/test/config/PointStatConfig_PHYS @@ -31,6 +31,8 @@ obs_window = { //////////////////////////////////////////////////////////////////////////////// +mpr_column = []; +mpr_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; wind_thresh = [ NA ]; diff --git a/test/config/PointStatConfig_PHYS_pint b/test/config/PointStatConfig_PHYS_pint index 951d936320..be5abaaf6f 100644 --- a/test/config/PointStatConfig_PHYS_pint +++ b/test/config/PointStatConfig_PHYS_pint @@ -31,6 +31,8 @@ obs_window = { //////////////////////////////////////////////////////////////////////////////// +mpr_column = []; +mpr_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; wind_thresh = [ NA ]; diff --git a/test/config/PointStatConfig_WINDS b/test/config/PointStatConfig_WINDS index 66257da5fa..3dc709d48c 100644 --- a/test/config/PointStatConfig_WINDS +++ b/test/config/PointStatConfig_WINDS @@ -31,6 +31,8 @@ obs_window = { //////////////////////////////////////////////////////////////////////////////// +mpr_column = []; +mpr_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; wind_thresh = [ NA ]; diff --git a/test/config/PointStatConfig_aeronet b/test/config/PointStatConfig_aeronet index 7423d57bba..a1405e9424 100644 --- a/test/config/PointStatConfig_aeronet +++ b/test/config/PointStatConfig_aeronet @@ -31,6 +31,8 @@ regrid = { //////////////////////////////////////////////////////////////////////////////// +mpr_column = []; +mpr_thresh = []; cat_thresh = [ NA ]; cnt_thresh = [ NA ]; //cnt_logic = UNION; diff --git a/test/config/PointStatConfig_airnow b/test/config/PointStatConfig_airnow index 89a1b22252..eb18e2000f 100644 --- a/test/config/PointStatConfig_airnow +++ b/test/config/PointStatConfig_airnow @@ -38,6 +38,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = [ NA ]; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/PointStatConfig_climo b/test/config/PointStatConfig_climo index 843c927614..17005f9979 100644 --- a/test/config/PointStatConfig_climo +++ b/test/config/PointStatConfig_climo @@ -31,6 +31,8 @@ regrid = { //////////////////////////////////////////////////////////////////////////////// +mpr_column = []; +mpr_thresh = []; cat_thresh = [ NA ]; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/PointStatConfig_climo_WMO b/test/config/PointStatConfig_climo_WMO index fe2eedd6e9..722edd4881 100644 --- a/test/config/PointStatConfig_climo_WMO +++ b/test/config/PointStatConfig_climo_WMO @@ -31,6 +31,8 @@ regrid = { //////////////////////////////////////////////////////////////////////////////// +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/PointStatConfig_climo_prob b/test/config/PointStatConfig_climo_prob index 2d59e5712b..53a754b87c 100644 --- a/test/config/PointStatConfig_climo_prob +++ b/test/config/PointStatConfig_climo_prob @@ -32,6 +32,8 @@ regrid = { //////////////////////////////////////////////////////////////////////////////// +mpr_column = []; +mpr_thresh = []; cat_thresh = [ NA ]; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/PointStatConfig_dup b/test/config/PointStatConfig_dup index 9f0c2992ad..e67fb84089 100644 --- a/test/config/PointStatConfig_dup +++ b/test/config/PointStatConfig_dup @@ -30,6 +30,8 @@ regrid = { //////////////////////////////////////////////////////////////////////////////// +mpr_column = []; +mpr_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; wind_thresh = [ NA ]; diff --git a/test/config/PointStatConfig_mpr_thresh b/test/config/PointStatConfig_mpr_thresh new file mode 100644 index 0000000000..6a33eebf2a --- /dev/null +++ b/test/config/PointStatConfig_mpr_thresh @@ -0,0 +1,221 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Point-Stat configuration file. +// +// For additional information, please see the MET User's Guide. +// +//////////////////////////////////////////////////////////////////////////////// + +// +// Output model name to be written +// +model = "GFS"; + +// +// Output description to be written +// May be set separately in each "obs.field" entry +// +desc = "NA"; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Verification grid +// +regrid = { + to_grid = NONE; + method = NEAREST; + width = 1; + vld_thresh = 0.5; +} + +//////////////////////////////////////////////////////////////////////////////// + +mpr_column = []; +mpr_thresh = []; +cat_thresh = [ NA ]; +cnt_thresh = [ NA ]; +cnt_logic = UNION; +wind_thresh = [ NA ]; +wind_logic = UNION; +eclv_points = 0.05; + +// +// Forecast and observation fields to be verified +// +fcst = { + sid_inc = []; + sid_exc = []; + cat_thresh = []; + message_type = [ "ADPSFC" ]; + + name = "TMP"; + level = "Z2"; + + field = [ + { + desc = "NO_MPR_THRESH"; + }, + { + mpr_column = [ "OBS-FCST" ]; + mpr_thresh = [ >=-5&&<=5 ]; + desc = "OBS_FCST_DIFF"; + }, + { + mpr_column = [ "ABS(OBS-FCST)" ]; + mpr_thresh = [ <=5 ]; + desc = "ABS_OBS_FCST_DIFF"; + }, + { + mpr_column = [ "ABS(OBS-CLIMO_MEAN)" ]; + mpr_thresh = [ <=5 ]; + desc = "ABS_OBS_CLIMO_MEAN_DIFF"; + }, + { + mpr_column = [ "CLIMO_CDF" ]; + mpr_thresh = [ >=0.25&&<=0.75 ]; + desc = "CLIMO_CDF_IQR"; + } + ]; +} +obs = fcst; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Climatology mean data +// +climo_mean = fcst; +climo_mean = { + + file_name = [ ${CLIMO_MEAN_FILE_LIST} ]; + + regrid = { + method = BILIN; + width = 2; + vld_thresh = 0.5; + } + + time_interp_method = DW_MEAN; + day_interval = ${DAY_INTERVAL}; + hour_interval = ${HOUR_INTERVAL}; +} + +climo_stdev = climo_mean; +climo_stdev = { + file_name = [ ${CLIMO_STDEV_FILE_LIST} ]; +} + +// +// May be set separately in each "obs.field" entry +// +climo_cdf = { + cdf_bins = 1; + center_bins = FALSE; + write_bins = TRUE; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Point observation time window +// +obs_window = { + beg = -5400; + end = 5400; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Verification masking regions +// +mask = { + grid = [ "FULL" ]; + poly = []; + sid = []; + llpnt = []; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Confidence interval settings +// +ci_alpha = [ 0.05 ]; + +boot = { + interval = PCTILE; + rep_prop = 1.0; + n_rep = 1000; + rng = "mt19937"; + seed = "1"; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Interpolation methods +// +interp = { + vld_thresh = 1.0; + + type = [ + { + method = NEAREST; + width = 1; + } + ]; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// HiRA verification method +// +hira = { + flag = FALSE; + width = [ 2, 3, 4, 5 ]; + vld_thresh = 1.0; + cov_thresh = [ ==0.25 ]; + shape = SQUARE; + prob_cat_thresh = []; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Statistical output types +// +output_flag = { + fho = NONE; + ctc = NONE; + cts = NONE; + mctc = NONE; + mcts = NONE; + cnt = NONE; + sl1l2 = STAT; + sal1l2 = NONE; + vl1l2 = NONE; + val1l2 = NONE; + vcnt = NONE; + pct = NONE; + pstd = NONE; + pjc = NONE; + prc = NONE; + ecnt = NONE; + rps = NONE; + eclv = NONE; + mpr = NONE; +} + +//////////////////////////////////////////////////////////////////////////////// + +obs_quality = []; +duplicate_flag = NONE; +rank_corr_flag = TRUE; +tmp_dir = "/tmp"; +output_prefix = "${OUTPUT_PREFIX}"; +version = "V10.0.0"; + +//////////////////////////////////////////////////////////////////////////////// diff --git a/test/config/PointStatConfig_obs_summary b/test/config/PointStatConfig_obs_summary index 1bce341f5e..03b00e3438 100644 --- a/test/config/PointStatConfig_obs_summary +++ b/test/config/PointStatConfig_obs_summary @@ -30,6 +30,8 @@ regrid = { //////////////////////////////////////////////////////////////////////////////// +mpr_column = []; +mpr_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; wind_thresh = [ NA ]; diff --git a/test/config/PointStatConfig_obs_summary_all b/test/config/PointStatConfig_obs_summary_all index 4bbe7821b3..329a3bd05f 100644 --- a/test/config/PointStatConfig_obs_summary_all +++ b/test/config/PointStatConfig_obs_summary_all @@ -30,6 +30,8 @@ regrid = { //////////////////////////////////////////////////////////////////////////////// +mpr_column = []; +mpr_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; wind_thresh = [ NA ]; diff --git a/test/config/PointStatConfig_prob b/test/config/PointStatConfig_prob index 3c26b54ec0..c1d7f8d58f 100644 --- a/test/config/PointStatConfig_prob +++ b/test/config/PointStatConfig_prob @@ -31,6 +31,8 @@ obs_window = { //////////////////////////////////////////////////////////////////////////////// +mpr_column = []; +mpr_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; wind_thresh = [ NA ]; diff --git a/test/config/PointStatConfig_python b/test/config/PointStatConfig_python index e975b01b9e..2b073fff61 100644 --- a/test/config/PointStatConfig_python +++ b/test/config/PointStatConfig_python @@ -37,6 +37,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = [ NA ]; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/PointStatConfig_sid_inc_exc b/test/config/PointStatConfig_sid_inc_exc index a7766ff324..70f17d7943 100644 --- a/test/config/PointStatConfig_sid_inc_exc +++ b/test/config/PointStatConfig_sid_inc_exc @@ -33,6 +33,8 @@ obs_window = { censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; wind_thresh = [ NA ]; diff --git a/test/config/ref_config/GridStatConfig_03h b/test/config/ref_config/GridStatConfig_03h index dc93b76496..ce8b0f982c 100644 --- a/test/config/ref_config/GridStatConfig_03h +++ b/test/config/ref_config/GridStatConfig_03h @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; diff --git a/test/config/ref_config/GridStatConfig_24h b/test/config/ref_config/GridStatConfig_24h index 260e1e901d..1f7fb01cda 100644 --- a/test/config/ref_config/GridStatConfig_24h +++ b/test/config/ref_config/GridStatConfig_24h @@ -42,6 +42,8 @@ regrid = { // censor_thresh = []; censor_val = []; +mpr_column = []; +mpr_thresh = []; cat_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; @@ -51,6 +53,7 @@ eclv_points = 0.05; nc_pairs_var_name = ""; nc_pairs_var_suffix = ""; rank_corr_flag = FALSE; + // // Forecast and observation fields to be verified // diff --git a/test/config/ref_config/PointStatConfig_ADPUPA b/test/config/ref_config/PointStatConfig_ADPUPA index 9976d42778..a458683711 100644 --- a/test/config/ref_config/PointStatConfig_ADPUPA +++ b/test/config/ref_config/PointStatConfig_ADPUPA @@ -30,6 +30,8 @@ regrid = { //////////////////////////////////////////////////////////////////////////////// +mpr_column = []; +mpr_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; wind_thresh = [ NA ]; diff --git a/test/config/ref_config/PointStatConfig_ONLYSF b/test/config/ref_config/PointStatConfig_ONLYSF index 8c969f69f0..9276f52a45 100644 --- a/test/config/ref_config/PointStatConfig_ONLYSF +++ b/test/config/ref_config/PointStatConfig_ONLYSF @@ -30,6 +30,8 @@ regrid = { //////////////////////////////////////////////////////////////////////////////// +mpr_column = []; +mpr_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; wind_logic = INTERSECTION; diff --git a/test/config/ref_config/PointStatConfig_WINDS b/test/config/ref_config/PointStatConfig_WINDS index 82ba02f5e4..5e18b2f1dc 100644 --- a/test/config/ref_config/PointStatConfig_WINDS +++ b/test/config/ref_config/PointStatConfig_WINDS @@ -30,6 +30,8 @@ regrid = { //////////////////////////////////////////////////////////////////////////////// +mpr_column = []; +mpr_thresh = []; cnt_thresh = [ NA ]; cnt_logic = UNION; wind_logic = INTERSECTION; diff --git a/test/xml/unit_grid_stat.xml b/test/xml/unit_grid_stat.xml index 729761c71d..1d562778f7 100644 --- a/test/xml/unit_grid_stat.xml +++ b/test/xml/unit_grid_stat.xml @@ -234,4 +234,31 @@ + + &MET_BIN;/grid_stat + + OUTPUT_PREFIX MPR_THRESH + DAY_INTERVAL 1 + HOUR_INTERVAL 6 + CLIMO_MEAN_FILE_LIST + "&DATA_DIR_CLIMO;/NCEP_NCAR_40YR_1.0deg/cmean_1d.19590409" + + + CLIMO_STDEV_FILE_LIST + "&DATA_DIR_CLIMO;/NCEP_NCAR_40YR_1.0deg/cstdv_1d.19590409" + + + + \ + &DATA_DIR_MODEL;/grib2/gfs/gfs_2012040900_F012.grib2 \ + &DATA_DIR_MODEL;/grib2/gfsanl/gfsanl_4_20120409_1200_000.grb2 \ + &CONFIG_DIR;/GridStatConfig_mpr_thresh \ + -outdir &OUTPUT_DIR;/grid_stat -v 3 + + + &OUTPUT_DIR;/grid_stat/grid_stat_MPR_THRESH_120000L_20120409_120000V.stat + &OUTPUT_DIR;/grid_stat/grid_stat_MPR_THRESH_120000L_20120409_120000V_pairs.nc + + + diff --git a/test/xml/unit_point_stat.xml b/test/xml/unit_point_stat.xml index c369108a08..8750e1ee68 100644 --- a/test/xml/unit_point_stat.xml +++ b/test/xml/unit_point_stat.xml @@ -8,6 +8,7 @@ + ]> @@ -454,4 +455,30 @@ + + &MET_BIN;/point_stat + + OUTPUT_PREFIX MPR_THRESH + DAY_INTERVAL 1 + HOUR_INTERVAL 6 + CLIMO_MEAN_FILE_LIST + "&DATA_DIR_CLIMO;/NCEP_NCAR_40YR_1.0deg/cmean_1d.19590409" + + + CLIMO_STDEV_FILE_LIST + "&DATA_DIR_CLIMO;/NCEP_NCAR_40YR_1.0deg/cstdv_1d.19590409" + + + + \ + &DATA_DIR_MODEL;/grib2/gfs/gfs_2012040900_F012.grib2 \ + &OUTPUT_DIR;/pb2nc/ndas.20120409.t12z.prepbufr.tm00.nc \ + &CONFIG_DIR;/PointStatConfig_mpr_thresh \ + -outdir &OUTPUT_DIR;/point_stat -v 3 + + + &OUTPUT_DIR;/point_stat/point_stat_MPR_THRESH_120000L_20120409_120000V.stat + + +