From c18601b5943650a4d343c936f9230084ff8567e8 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Mon, 15 Mar 2021 13:49:11 -0600 Subject: [PATCH 01/15] Per #1714, add tc_gen genesis_match_window configuration option to define a search window relative to the forecast genesis time. --- met/data/config/TCGenConfig_default | 9 +++++++++ met/docs/Users_Guide/tc-gen.rst | 13 ++++++++++++- met/src/basic/vx_config/config_constants.h | 1 + met/src/libcode/vx_tc_util/genesis_info.cc | 7 ++++--- met/src/libcode/vx_tc_util/genesis_info.h | 4 ++-- met/src/tools/tc_utils/tc_gen/tc_gen.cc | 13 ++++++++----- met/src/tools/tc_utils/tc_gen/tc_gen_conf_info.cc | 10 ++++++++-- met/src/tools/tc_utils/tc_gen/tc_gen_conf_info.h | 9 ++++----- test/config/TCGenConfig_2016 | 9 +++++++++ 9 files changed, 57 insertions(+), 18 deletions(-) diff --git a/met/data/config/TCGenConfig_default b/met/data/config/TCGenConfig_default index db38b1302b..8c9f60a90b 100644 --- a/met/data/config/TCGenConfig_default +++ b/met/data/config/TCGenConfig_default @@ -155,6 +155,15 @@ dland_thresh = NA; // genesis_match_radius = 500; +// +// Time window in hours, relative to the model genesis time, to search for a +// matching Best track point +// +genesis_match_window = { + beg = 0; + end = 0; +} + // // Radius in km for a development scoring method hit // diff --git a/met/docs/Users_Guide/tc-gen.rst b/met/docs/Users_Guide/tc-gen.rst index 45bd9e7404..40efd7b746 100644 --- a/met/docs/Users_Guide/tc-gen.rst +++ b/met/docs/Users_Guide/tc-gen.rst @@ -255,7 +255,18 @@ ______________________ genesis_match_radius = 500; -The **genesis_match_radius** entry defines a search radius, in km, relative to the forecast genesis location. When searching for a match, only those Best genesis events which occur within this radius will be considered. Increasing this search radius should lead to an increase in the number of matched genesis pairs. +The **genesis_match_radius** entry defines a search radius, in km, relative to the forecast genesis location. When searching for a match, only Best or operational tracks with a track point within this radius will be considered. Increasing this search radius should lead to an increase in the number of matched genesis pairs. + +______________________ + +.. code-block:: none + + genesis_match_window = { + beg = 0; + end = 0; + } + +The **genesis_match_window** entry defines a time window, in hours, relative to the forecast genesis time. When searching for a match, only Best or operational tracks with a track point falling within this time window will be considered. The default time window of 0 requires a Best or operational track to exist at the forecast genesis time for a match to be found. Increasing this time window should lead to an increase in the number matched genesis pairs. For example, setting *beg = -12;* would allow the forecast genesis events to be up to 12 hours early. ______________________ diff --git a/met/src/basic/vx_config/config_constants.h b/met/src/basic/vx_config/config_constants.h index 1ae8d5d90d..a2e730086a 100644 --- a/met/src/basic/vx_config/config_constants.h +++ b/met/src/basic/vx_config/config_constants.h @@ -1071,6 +1071,7 @@ static const char conf_key_vmax_thresh[] = "vmax_thresh"; static const char conf_key_mslp_thresh[] = "mslp_thresh"; static const char conf_key_basin_mask[] = "basin_mask"; static const char conf_key_genesis_match_radius[] = "genesis_match_radius"; +static const char conf_key_genesis_match_window[] = "genesis_match_window"; static const char conf_key_dev_hit_radius[] = "dev_hit_radius"; static const char conf_key_dev_hit_window[] = "dev_hit_window"; static const char conf_key_ops_hit_tdiff[] = "ops_hit_tdiff"; diff --git a/met/src/libcode/vx_tc_util/genesis_info.cc b/met/src/libcode/vx_tc_util/genesis_info.cc index 8cc5ea36d9..4124fdd873 100644 --- a/met/src/libcode/vx_tc_util/genesis_info.cc +++ b/met/src/libcode/vx_tc_util/genesis_info.cc @@ -298,11 +298,12 @@ int GenesisInfo::genesis_fhr() const { //////////////////////////////////////////////////////////////////////// -bool GenesisInfo::is_match(const TrackPoint &p, - const double rad) const { +bool GenesisInfo::is_match(const TrackPoint &p, const double rad, + const int beg, const int end) const { // Check for matching in time and space - return(GenesisTime == p.valid() && + return(p.valid() >= (GenesisTime + beg) && + p.valid() <= (GenesisTime + end) && gc_dist(Lat, Lon, p.lat(), p.lon()) <= rad); } diff --git a/met/src/libcode/vx_tc_util/genesis_info.h b/met/src/libcode/vx_tc_util/genesis_info.h index bc4a511020..fa91077dc7 100644 --- a/met/src/libcode/vx_tc_util/genesis_info.h +++ b/met/src/libcode/vx_tc_util/genesis_info.h @@ -104,8 +104,8 @@ class GenesisInfo : public TrackInfo { // do stuff // - bool is_match(const TrackPoint &, - const double) const; + bool is_match(const TrackPoint &, const double, + const int, const int) const; }; //////////////////////////////////////////////////////////////////////// diff --git a/met/src/tools/tc_utils/tc_gen/tc_gen.cc b/met/src/tools/tc_utils/tc_gen/tc_gen.cc index f3b614960c..f8d214642d 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen.cc +++ b/met/src/tools/tc_utils/tc_gen/tc_gen.cc @@ -82,7 +82,7 @@ static void do_genesis_ctc (const TCGenVxOpt &, static int find_genesis_match (const GenesisInfo &, const GenesisInfoArray &, const TrackInfoArray &, - double); + double, int, int); static void setup_txt_files (int, int); static void setup_table (AsciiTable &); @@ -377,7 +377,9 @@ void get_genesis_pairs(const TCGenVxOpt &vx_opt, // Search for a BEST track match i_bga = find_genesis_match(fga[i], bga, ota, - vx_opt.GenesisMatchRadius); + vx_opt.GenesisMatchRadius, + vx_opt.GenesisMatchBeg, + vx_opt.GenesisMatchEnd); // Add the matched genesis pair if(!is_bad_data(i_bga)) { @@ -591,7 +593,8 @@ void do_genesis_ctc(const TCGenVxOpt &vx_opt, int find_genesis_match(const GenesisInfo &fcst_gi, const GenesisInfoArray &bga, const TrackInfoArray &ota, - const double rad) { + const double rad, + const int beg, const int end) { int i, j; int i_best = bad_data_int; int i_oper = bad_data_int; @@ -610,7 +613,7 @@ int find_genesis_match(const GenesisInfo &fcst_gi, i Date: Mon, 15 Mar 2021 15:09:48 -0600 Subject: [PATCH 02/15] Per #1714, clarify docs to state the genesis_match_window.end = 12 allows for matches for early forecasts. Also add an example of this option to the tc_gen unit test. --- met/data/config/TCGenConfig_default | 3 ++- met/docs/Users_Guide/tc-gen.rst | 2 +- test/config/TCGenConfig_2016 | 8 +++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/met/data/config/TCGenConfig_default b/met/data/config/TCGenConfig_default index 8c9f60a90b..612625940b 100644 --- a/met/data/config/TCGenConfig_default +++ b/met/data/config/TCGenConfig_default @@ -170,7 +170,8 @@ genesis_match_window = { dev_hit_radius = 500; // -// Time window in hours for a development scoring method hit +// Time window in hours, relative to the model genesis time, for a development +// scoring method hit // dev_hit_window = { beg = -24; diff --git a/met/docs/Users_Guide/tc-gen.rst b/met/docs/Users_Guide/tc-gen.rst index 40efd7b746..56aee713e0 100644 --- a/met/docs/Users_Guide/tc-gen.rst +++ b/met/docs/Users_Guide/tc-gen.rst @@ -266,7 +266,7 @@ ______________________ end = 0; } -The **genesis_match_window** entry defines a time window, in hours, relative to the forecast genesis time. When searching for a match, only Best or operational tracks with a track point falling within this time window will be considered. The default time window of 0 requires a Best or operational track to exist at the forecast genesis time for a match to be found. Increasing this time window should lead to an increase in the number matched genesis pairs. For example, setting *beg = -12;* would allow the forecast genesis events to be up to 12 hours early. +The **genesis_match_window** entry defines a time window, in hours, relative to the forecast genesis time. When searching for a match, only Best or operational tracks with a track point falling within this time window will be considered. The default time window of 0 requires a Best or operational track to exist at the forecast genesis time for a match to be found. Increasing this time window should lead to an increase in the number matched genesis pairs. For example, setting *end = 12;* would allow forecast genesis events to match Best tracks up to 12 hours prior to their existence. ______________________ diff --git a/test/config/TCGenConfig_2016 b/test/config/TCGenConfig_2016 index a8db29b839..ab9d29a8b8 100644 --- a/test/config/TCGenConfig_2016 +++ b/test/config/TCGenConfig_2016 @@ -90,6 +90,11 @@ filter = [ nc_pairs_flag = TRUE; output_flag = { genmpr = BOTH; } }, + { + desc = "AL_MATCH24HR"; + basin_mask = "AL"; + genesis_match_window = { beg = 0; end = 24; }; + }, { desc = "AL_DLAND_300NM"; basin_mask = "AL"; @@ -213,7 +218,8 @@ genesis_match_window = { dev_hit_radius = 500; // -// Time window in hours for a development scoring method hit +// Time window in hours, relative to the model genesis time, for a development +// scoring method hit // dev_hit_window = { beg = -24; From 3d90539fc61b192099cc87757ef46883d997e5e8 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 2 Apr 2021 14:29:18 -0600 Subject: [PATCH 03/15] Per #1714, switch ops_hit_tdiff to ops_hit_window. --- met/data/config/TCGenConfig_default | 9 ++++++--- met/docs/Users_Guide/tc-gen.rst | 9 ++++++--- met/src/basic/vx_config/config_constants.h | 2 +- met/src/tools/tc_utils/tc_gen/tc_gen.cc | 13 +++++++------ met/src/tools/tc_utils/tc_gen/tc_gen_conf_info.cc | 13 +++++++------ met/src/tools/tc_utils/tc_gen/tc_gen_conf_info.h | 2 +- test/config/TCGenConfig_2016 | 11 +++++++---- 7 files changed, 35 insertions(+), 24 deletions(-) diff --git a/met/data/config/TCGenConfig_default b/met/data/config/TCGenConfig_default index 612625940b..1c72a4c5d6 100644 --- a/met/data/config/TCGenConfig_default +++ b/met/data/config/TCGenConfig_default @@ -179,10 +179,13 @@ dev_hit_window = { } // -// Maximum Best track genesis minus model initialization time difference for an -// operational scoring method hit +// Time window in hours for the Best track genesis minus model initialization +// time difference for an operational scoring method hit // -ops_hit_tdiff = 48; +ops_hit_window = { + beg = 0; + end = 48; +} // // Discard genesis forecasts for initializations at or after the matching diff --git a/met/docs/Users_Guide/tc-gen.rst b/met/docs/Users_Guide/tc-gen.rst index 56aee713e0..a8719f9cb4 100644 --- a/met/docs/Users_Guide/tc-gen.rst +++ b/met/docs/Users_Guide/tc-gen.rst @@ -285,15 +285,18 @@ ______________________ end = 24; } -The **dev_hit_window** entry defines a time window, in hours, relative to the forecast genesis time. The Best track genesis event must occur within this time window for the pair to be counted as contingency table HIT for the development scoring method. Tightening this window may cause development method HITS to become FALSE ALARMS. +The **dev_hit_window** entry defines a time window, in hours, relative to the forecast genesis time. The Best track genesis event must occur within this time window for the pair to be counted as a contingency table HIT for the development scoring method. Tightening this window may cause development method HITS to become FALSE ALARMS. ______________________ .. code-block:: none - ops_hit_tdiff = 48; + ops_hit_window = { + beg = 0; + end = 48; + } -The **ops_hit_tdiff** entry is an integer which defines a maximum allowable time difference in hours. For each matching forecast and Best track genesis event, if the difference between the Best track genesis time and the forecast initialization time is less than or equal to this value, then the pair is counted as a contingency table HIT for the operational scoring method. Otherwise, it is counted as a FALSE ALARM. +The **ops_hit_window** entry defines a time window, in hours, relative to the Best track genesis time. The model initialization time for the forecast genesis event must occur within this time window for the pairs to be counted as a contingency table HIT for the operationl scoring method. Otherwise, the pair is counted as a FALSE ALARM. ______________________ diff --git a/met/src/basic/vx_config/config_constants.h b/met/src/basic/vx_config/config_constants.h index a07de36d1d..e814703d38 100644 --- a/met/src/basic/vx_config/config_constants.h +++ b/met/src/basic/vx_config/config_constants.h @@ -1080,7 +1080,7 @@ static const char conf_key_genesis_match_radius[] = "genesis_match_ra static const char conf_key_genesis_match_window[] = "genesis_match_window"; static const char conf_key_dev_hit_radius[] = "dev_hit_radius"; static const char conf_key_dev_hit_window[] = "dev_hit_window"; -static const char conf_key_ops_hit_tdiff[] = "ops_hit_tdiff"; +static const char conf_key_ops_hit_window[] = "ops_hit_window"; static const char conf_key_discard_init_post_genesis_flag[] = "discard_init_post_genesis_flag"; static const char conf_key_dev_method_flag[] = "dev_method_flag"; static const char conf_key_ops_method_flag[] = "ops_method_flag"; diff --git a/met/src/tools/tc_utils/tc_gen/tc_gen.cc b/met/src/tools/tc_utils/tc_gen/tc_gen.cc index f8d214642d..ce3756d7c0 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen.cc +++ b/met/src/tools/tc_utils/tc_gen/tc_gen.cc @@ -19,6 +19,7 @@ // 002 12/15/20 Halley Gotway Matching logic for MET #1448 // 003 12/31/20 Halley Gotway Add NetCDF output for MET #1430 // 004 01/14/21 Halley Gotway Add GENMPR output for MET #1597 +// 005 04/02/21 Halley Gotway Refinements for MET #1714 // //////////////////////////////////////////////////////////////////////// @@ -525,19 +526,19 @@ void do_genesis_ctc(const TCGenVxOpt &vx_opt, // FALSE ALARM for the development method diff.DevCategory = FYONGenesis; } - - // Ops Method: - // HIT if forecast init time is close enough to - // the BEST genesis time. - // Compute time offset + // Compute init/genesis time offset diff.OpsDSec = bgi->genesis_time() - fgi->init(); offset_cs << cs_erase << "with an init vs genesis time offset of " << diff.OpsDSec/sec_per_hour << " hours.\n"; - if(diff.OpsDSec <= vx_opt.OpsHitDSec) { + // Ops Method: + // HIT if forecast init time is close enough to + // the BEST genesis time. + if(diff.OpsDSec >= vx_opt.OpsHitBeg && + diff.OpsDSec <= vx_opt.OpsHitEnd) { mlog << Debug(4) << case_cs << " is an ops method HIT " << offset_cs; diff --git a/met/src/tools/tc_utils/tc_gen/tc_gen_conf_info.cc b/met/src/tools/tc_utils/tc_gen/tc_gen_conf_info.cc index 0ebf880d7e..5a740c02a5 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen_conf_info.cc +++ b/met/src/tools/tc_utils/tc_gen/tc_gen_conf_info.cc @@ -160,7 +160,7 @@ void TCGenVxOpt::clear() { GenesisMatchBeg = GenesisMatchEnd = bad_data_int; DevHitRadius = bad_data_double; DevHitBeg = DevHitEnd = bad_data_int; - OpsHitDSec = bad_data_int; + OpsHitBeg = OpsHitEnd = bad_data_int; DiscardFlag = false; DevFlag = OpsFlag = false; CIAlpha = bad_data_double; @@ -256,16 +256,17 @@ void TCGenVxOpt::process_config(Dictionary &dict) { // Conf: dev_hit_radius DevHitRadius = dict.lookup_double(conf_key_dev_hit_radius); - // Conf: genesis_hit_window + // Conf: dev_hit_window dict2 = dict.lookup_dictionary(conf_key_dev_hit_window); parse_conf_range_int(dict2, beg, end); DevHitBeg = beg*sec_per_hour; DevHitEnd = end*sec_per_hour; - // Conf: ops_hit_tdiff - OpsHitDSec = nint( - dict.lookup_double(conf_key_ops_hit_tdiff) * - sec_per_hour); + // Conf: ops_hit_window + dict2 = dict.lookup_dictionary(conf_key_ops_hit_window); + parse_conf_range_int(dict2, beg, end); + OpsHitBeg = beg*sec_per_hour; + OpsHitEnd = end*sec_per_hour; // Conf: discard_init_post_genesis_flag DiscardFlag = diff --git a/met/src/tools/tc_utils/tc_gen/tc_gen_conf_info.h b/met/src/tools/tc_utils/tc_gen/tc_gen_conf_info.h index d1c0e941d6..9e3c93bd9d 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen_conf_info.h +++ b/met/src/tools/tc_utils/tc_gen/tc_gen_conf_info.h @@ -138,7 +138,7 @@ class TCGenVxOpt { // Temporal and spatial scoring options double DevHitRadius; int DevHitBeg, DevHitEnd; - int OpsHitDSec; + int OpsHitBeg, OpsHitEnd; bool DiscardFlag, DevFlag, OpsFlag; // Output file options diff --git a/test/config/TCGenConfig_2016 b/test/config/TCGenConfig_2016 index ab9d29a8b8..87ff147fb0 100644 --- a/test/config/TCGenConfig_2016 +++ b/test/config/TCGenConfig_2016 @@ -124,7 +124,7 @@ filter = [ { desc = "ALL_MATCH_600KM_OPS60HR"; genesis_match_radius = 600; - ops_hit_tdiff = 60; + ops_hit_window = { beg = -60; end = 60; }; dev_method_flag = FALSE; ops_method_flag = TRUE; } @@ -227,10 +227,13 @@ dev_hit_window = { } // -// Maximum Best track genesis minus model initialization time difference for an -// operational scoring method hit +// Time window in hours for the Best track genesis minus model initialization +// time difference for an operational scoring method hit // -ops_hit_tdiff = 48; +ops_hit_window = { + beg = 0; + end = 48; +} // // Discard genesis forecasts for initializations at or after the matching From 002275499f626fcbefd48c8b070c3bbd20a29850 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 2 Apr 2021 14:46:59 -0600 Subject: [PATCH 04/15] Per #1714, skip genesis events for tracks where the cyclone number is > 50. --- met/src/tools/tc_utils/tc_gen/tc_gen.cc | 31 +++++++++++++++++++++---- met/src/tools/tc_utils/tc_gen/tc_gen.h | 2 ++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/met/src/tools/tc_utils/tc_gen/tc_gen.cc b/met/src/tools/tc_utils/tc_gen/tc_gen.cc index ce3756d7c0..75b816ae42 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen.cc +++ b/met/src/tools/tc_utils/tc_gen/tc_gen.cc @@ -752,18 +752,32 @@ void process_fcst_tracks(const StringArray &files, continue; } + // Skip invest tracks with a large cyclone number + if(atof(fcst_ta[j].cyclone().c_str()) > max_cyclone_number) { + mlog << Debug(6) + << "Skipping forecast genesis event for cyclone number " + << fcst_ta[j].cyclone() << " > " << max_cyclone_number + << ".\n"; + continue; + } + // Check the forecast lead time window if(fcst_gi.genesis_lead() < conf_info.FcstSecBeg || fcst_gi.genesis_lead() > conf_info.FcstSecEnd) { - mlog << Debug(6) << "Skipping genesis event for forecast hour " - << fcst_gi.genesis_fhr() << ".\n"; + mlog << Debug(6) + << "Skipping forecast genesis event for forecast hour " + << fcst_gi.genesis_fhr() << " not between " + << conf_info.FcstSecBeg/sec_per_hour << " and " + << conf_info.FcstSecEnd/sec_per_hour << ".\n"; continue; } // Check the forecast track minimum duration if(fcst_gi.duration() < conf_info.MinDur*sec_per_hour) { - mlog << Debug(6) << "Skipping genesis event for track duration of " - << fcst_gi.duration()/sec_per_hour << ".\n"; + mlog << Debug(6) + << "Skipping forecast genesis event for track duration of " + << fcst_gi.duration()/sec_per_hour << " < " + << conf_info.MinDur << ".\n"; continue; } @@ -903,6 +917,15 @@ void process_best_tracks(const StringArray &files, continue; } + // Skip invest tracks with a large cyclone number + if(atof(best_ta[i].cyclone().c_str()) > max_cyclone_number) { + mlog << Debug(6) + << "Skipping Best track genesis event for cyclone number " + << best_ta[i].cyclone() << " > " << max_cyclone_number + << ".\n"; + continue; + } + // Check for duplicates if(best_ga.has_storm(best_gi, i_bga)) { diff --git a/met/src/tools/tc_utils/tc_gen/tc_gen.h b/met/src/tools/tc_utils/tc_gen/tc_gen.h index 3d6ff17e9c..94b3078d90 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen.h +++ b/met/src/tools/tc_utils/tc_gen/tc_gen.h @@ -77,6 +77,8 @@ const ConcatString genesis_name ("GENESIS"); const ConcatString genesis_dev_name("GENESIS_DEV"); const ConcatString genesis_ops_name("GENESIS_OPS"); +static const int max_cyclone_number = 50; + //////////////////////////////////////////////////////////////////////// // // Variables for Command Line Arguments From f784f8fa70dfd64dcae925cd2c625dd61b63677f Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 2 Apr 2021 15:01:16 -0600 Subject: [PATCH 05/15] Per #1714, only discard cyclone numbers > 50 from the Best track, not the forecast tracks. --- met/src/tools/tc_utils/tc_gen/tc_gen.cc | 13 ++----------- met/src/tools/tc_utils/tc_gen/tc_gen.h | 4 +++- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/met/src/tools/tc_utils/tc_gen/tc_gen.cc b/met/src/tools/tc_utils/tc_gen/tc_gen.cc index 75b816ae42..c920956139 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen.cc +++ b/met/src/tools/tc_utils/tc_gen/tc_gen.cc @@ -752,15 +752,6 @@ void process_fcst_tracks(const StringArray &files, continue; } - // Skip invest tracks with a large cyclone number - if(atof(fcst_ta[j].cyclone().c_str()) > max_cyclone_number) { - mlog << Debug(6) - << "Skipping forecast genesis event for cyclone number " - << fcst_ta[j].cyclone() << " > " << max_cyclone_number - << ".\n"; - continue; - } - // Check the forecast lead time window if(fcst_gi.genesis_lead() < conf_info.FcstSecBeg || fcst_gi.genesis_lead() > conf_info.FcstSecEnd) { @@ -918,10 +909,10 @@ void process_best_tracks(const StringArray &files, } // Skip invest tracks with a large cyclone number - if(atof(best_ta[i].cyclone().c_str()) > max_cyclone_number) { + if(atof(best_ta[i].cyclone().c_str()) > max_best_cyclone_number) { mlog << Debug(6) << "Skipping Best track genesis event for cyclone number " - << best_ta[i].cyclone() << " > " << max_cyclone_number + << best_ta[i].cyclone() << " > " << max_best_cyclone_number << ".\n"; continue; } diff --git a/met/src/tools/tc_utils/tc_gen/tc_gen.h b/met/src/tools/tc_utils/tc_gen/tc_gen.h index 94b3078d90..10118842c6 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen.h +++ b/met/src/tools/tc_utils/tc_gen/tc_gen.h @@ -77,7 +77,9 @@ const ConcatString genesis_name ("GENESIS"); const ConcatString genesis_dev_name("GENESIS_DEV"); const ConcatString genesis_ops_name("GENESIS_OPS"); -static const int max_cyclone_number = 50; +// Maximum Best track cyclone number to be processed +// Cyclone numbers > 50 are for testing or invests +static const int max_best_cyclone_number = 50; //////////////////////////////////////////////////////////////////////// // From 1d42f4045468ac1229ab92d9150f7f374fcbe7a4 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 2 Apr 2021 15:08:22 -0600 Subject: [PATCH 06/15] Per #1716, add note to the tc_gen chapter about skipping Best tracks with cyclone number > 50. --- met/docs/Users_Guide/tc-gen.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/met/docs/Users_Guide/tc-gen.rst b/met/docs/Users_Guide/tc-gen.rst index a8719f9cb4..84479c90fc 100644 --- a/met/docs/Users_Guide/tc-gen.rst +++ b/met/docs/Users_Guide/tc-gen.rst @@ -61,7 +61,7 @@ The TC-Gen tool implements the following logic: * Parse the forecast genesis data and identify forecast genesis events separately for each model present. -* Parse the Best and operational track data, and identify Best track genesis events. +* Parse the Best and operational track data, and identify Best track genesis events. Note that Best tracks with a cyclone number greater than 50 are automatically discarded from the analysis. Large cyclone numbers are used for pre-season testing or to track invests prior to a storm actually forming. Running this tool at verbosity level 6 (-v 6) prints details about which tracks are discarded. * Loop over the filters defined in the configuration file and apply the following logic for each. From 5cfd9d03e0ce6371219b3ab61c7917500ae24531 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Wed, 7 Apr 2021 11:16:17 -0600 Subject: [PATCH 07/15] Per #1714, adding genesis_match_point_to_track config file option for TC-Gen. Note that this version of the code is close but doesn't actually compile yet. I still need to figure out exactly how to process the operational tracks. Should this logic also apply to the matching for those tracks? --- met/data/config/TCGenConfig_default | 6 +++ met/src/basic/vx_config/config_constants.h | 1 + met/src/libcode/vx_tc_util/genesis_info.cc | 8 +++ met/src/libcode/vx_tc_util/genesis_info.h | 11 ++-- met/src/tools/tc_utils/tc_gen/tc_gen.cc | 53 +++++++++++++++---- .../tools/tc_utils/tc_gen/tc_gen_conf_info.cc | 5 ++ .../tools/tc_utils/tc_gen/tc_gen_conf_info.h | 3 ++ test/config/TCGenConfig_2016 | 6 +++ 8 files changed, 78 insertions(+), 15 deletions(-) diff --git a/met/data/config/TCGenConfig_default b/met/data/config/TCGenConfig_default index 1c72a4c5d6..1a135491f5 100644 --- a/met/data/config/TCGenConfig_default +++ b/met/data/config/TCGenConfig_default @@ -150,6 +150,12 @@ dland_thresh = NA; // //////////////////////////////////////////////////////////////////////////////// +// +// Genesis matching logic. Compare the forecast genesis point to all points in +// the Best track (TRUE) or the single Best track genesis point (FALSE). +// +genesis_match_point_to_track = TRUE; + // // Radius in km to search for a matching genesis event // diff --git a/met/src/basic/vx_config/config_constants.h b/met/src/basic/vx_config/config_constants.h index e814703d38..a6431fca54 100644 --- a/met/src/basic/vx_config/config_constants.h +++ b/met/src/basic/vx_config/config_constants.h @@ -1076,6 +1076,7 @@ static const char conf_key_category[] = "category"; static const char conf_key_vmax_thresh[] = "vmax_thresh"; static const char conf_key_mslp_thresh[] = "mslp_thresh"; static const char conf_key_basin_mask[] = "basin_mask"; +static const char conf_key_genesis_match_point_to_track[] = "genesis_match_point_to_track"; static const char conf_key_genesis_match_radius[] = "genesis_match_radius"; static const char conf_key_genesis_match_window[] = "genesis_match_window"; static const char conf_key_dev_hit_radius[] = "dev_hit_radius"; diff --git a/met/src/libcode/vx_tc_util/genesis_info.cc b/met/src/libcode/vx_tc_util/genesis_info.cc index 4124fdd873..4927b3851c 100644 --- a/met/src/libcode/vx_tc_util/genesis_info.cc +++ b/met/src/libcode/vx_tc_util/genesis_info.cc @@ -307,6 +307,14 @@ bool GenesisInfo::is_match(const TrackPoint &p, const double rad, gc_dist(Lat, Lon, p.lat(), p.lon()) <= rad); } +//////////////////////////////////////////////////////////////////////// + +bool GenesisInfo::is_match(const GenesisInfo &gi, const double rad, + const int beg, const int end) const { + return(is_bad_data(GenesisIndex) ? false : + is_match((*this)[GenesisIndex], rad, beg, end)); +} + //////////////////////////////////////////////////////////////////////// // // Code for class GenesisInfoArray diff --git a/met/src/libcode/vx_tc_util/genesis_info.h b/met/src/libcode/vx_tc_util/genesis_info.h index fa91077dc7..588d877d57 100644 --- a/met/src/libcode/vx_tc_util/genesis_info.h +++ b/met/src/libcode/vx_tc_util/genesis_info.h @@ -55,11 +55,8 @@ class GenesisInfo : public TrackInfo { bool IsSet; - // TrackInfo for this Genesis event - TrackInfo Track; - int GenesisIndex; - // Genesis Information + int GenesisIndex; unixtime GenesisTime; int GenesisLead; double Lat; @@ -104,7 +101,11 @@ class GenesisInfo : public TrackInfo { // do stuff // - bool is_match(const TrackPoint &, const double, + bool is_match(const TrackPoint &, + const double, + const int, const int) const; + bool is_match(const GenesisInfo &, + const double, const int, const int) const; }; diff --git a/met/src/tools/tc_utils/tc_gen/tc_gen.cc b/met/src/tools/tc_utils/tc_gen/tc_gen.cc index c920956139..2d0c773d9e 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen.cc +++ b/met/src/tools/tc_utils/tc_gen/tc_gen.cc @@ -83,7 +83,7 @@ static void do_genesis_ctc (const TCGenVxOpt &, static int find_genesis_match (const GenesisInfo &, const GenesisInfoArray &, const TrackInfoArray &, - double, int, int); + bool, double, int, int); static void setup_txt_files (int, int); static void setup_table (AsciiTable &); @@ -378,6 +378,7 @@ void get_genesis_pairs(const TCGenVxOpt &vx_opt, // Search for a BEST track match i_bga = find_genesis_match(fga[i], bga, ota, + vx_opt.GenesisMatchPointTrack, vx_opt.GenesisMatchRadius, vx_opt.GenesisMatchBeg, vx_opt.GenesisMatchEnd); @@ -594,8 +595,8 @@ void do_genesis_ctc(const TCGenVxOpt &vx_opt, int find_genesis_match(const GenesisInfo &fcst_gi, const GenesisInfoArray &bga, const TrackInfoArray &ota, - const double rad, - const int beg, const int end) { + bool point2track, double rad, + int beg, int end) { int i, j; int i_best = bad_data_int; int i_oper = bad_data_int; @@ -609,15 +610,31 @@ int find_genesis_match(const GenesisInfo &fcst_gi, << " forecast genesis at (" << fcst_gi.lat() << ", " << fcst_gi.lon() << ")"; - // Search the BEST track points for a match + // Search for a BEST track genesis match for(i=0, i_best=bad_data_int; i Date: Wed, 7 Apr 2021 11:51:59 -0600 Subject: [PATCH 08/15] Per #1714, the logic for checking the operational tracks is pretty simple. We only store/check operational track points for lead time = 0. So applying the genesis_match_point_to_track boolean config option does not make sense. --- met/src/libcode/vx_tc_util/genesis_info.cc | 1 + met/src/libcode/vx_tc_util/genesis_info.h | 1 - met/src/tools/tc_utils/tc_gen/tc_gen.cc | 30 ++++++---------------- 3 files changed, 9 insertions(+), 23 deletions(-) diff --git a/met/src/libcode/vx_tc_util/genesis_info.cc b/met/src/libcode/vx_tc_util/genesis_info.cc index 4927b3851c..1fecde31e9 100644 --- a/met/src/libcode/vx_tc_util/genesis_info.cc +++ b/met/src/libcode/vx_tc_util/genesis_info.cc @@ -311,6 +311,7 @@ bool GenesisInfo::is_match(const TrackPoint &p, const double rad, bool GenesisInfo::is_match(const GenesisInfo &gi, const double rad, const int beg, const int end) const { + return(is_bad_data(GenesisIndex) ? false : is_match((*this)[GenesisIndex], rad, beg, end)); } diff --git a/met/src/libcode/vx_tc_util/genesis_info.h b/met/src/libcode/vx_tc_util/genesis_info.h index 588d877d57..39ef811c60 100644 --- a/met/src/libcode/vx_tc_util/genesis_info.h +++ b/met/src/libcode/vx_tc_util/genesis_info.h @@ -162,7 +162,6 @@ class GenesisInfoArray { const GenesisInfo & operator[](int) const; int n() const; int n_technique() const; - }; //////////////////////////////////////////////////////////////////////// diff --git a/met/src/tools/tc_utils/tc_gen/tc_gen.cc b/met/src/tools/tc_utils/tc_gen/tc_gen.cc index 2d0c773d9e..b89eaf8b5a 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen.cc +++ b/met/src/tools/tc_utils/tc_gen/tc_gen.cc @@ -648,29 +648,15 @@ int find_genesis_match(const GenesisInfo &fcst_gi, i Date: Wed, 7 Apr 2021 12:08:08 -0600 Subject: [PATCH 09/15] Per #1714, update the tc-gen user's guide chapter to describe the updated logic and new config file option. --- met/docs/Users_Guide/tc-gen.rst | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/met/docs/Users_Guide/tc-gen.rst b/met/docs/Users_Guide/tc-gen.rst index 84479c90fc..7104f1aadc 100644 --- a/met/docs/Users_Guide/tc-gen.rst +++ b/met/docs/Users_Guide/tc-gen.rst @@ -67,9 +67,9 @@ The TC-Gen tool implements the following logic: * For each Best track genesis event meeting the filter critera, determine the initialization and lead times for which the model had an opportunity to forecast that genesis event. Store an unmatched genesis pair for each case. - * For each forecast genesis event, search for a matching Best track. A Best track matches if the valid time of one of its track points matches the forecast genesis time and is within a configurable radius of the forecast genesis location. If a Best track match is found, store the storm ID. + * For each forecast genesis event, search for a matching Best track. A configurable boolean option controls whether all Best track points are considered for a match or only the single Best track genesis point. A match occurs if the Best track point valid time is within a configurable window around the forecast genesis time and the Best track point location is within a configurable radius of the forecast genesis location. If a Best track match is found, store the storm ID. - * In no Best track match is found, apply the same logic to search the 0-hour operational track points. If an operational match is found, store the storm ID. + * In no Best track match is found, apply the same logic to search the operational track points with lead time of 0 hours. If an operational match is found, store the storm ID. * If a matching storm ID is found, match the forecast genesis event to the Best track genesis event for that storm ID. @@ -251,6 +251,14 @@ The **dland_thresh** entry is a threshold defining whether the genesis event sho ______________________ +.. code-block:: none + + genesis_match_point_to_track = TRUE; + +The **genesis_match_point_to_track** entry is a boolean which controls the matching logic. When set to its default value of TRUE, for each forecast genesis event, all Best track points are searched for a match. This logic implements the method used by the NOAA National Hurricane Center. When set to FALSE, only the single Best track genesis point is considered for a match. When selecting FALSE, users are encouraged to adjust the **genesis_match_radius** and/or **gensesis_match_window** options, described below, to enable matches to be found. + +______________________ + .. code-block:: none genesis_match_radius = 500; From 75a0161f05ca59d54b6dec02045e25f7fb22fbbd Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Wed, 7 Apr 2021 15:13:20 -0600 Subject: [PATCH 10/15] Per #1714, fix the logic of the is_match() function. --- met/src/libcode/vx_tc_util/genesis_info.cc | 2 +- met/src/tools/tc_utils/tc_gen/tc_gen.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/met/src/libcode/vx_tc_util/genesis_info.cc b/met/src/libcode/vx_tc_util/genesis_info.cc index 1fecde31e9..6ddeb9cd7f 100644 --- a/met/src/libcode/vx_tc_util/genesis_info.cc +++ b/met/src/libcode/vx_tc_util/genesis_info.cc @@ -313,7 +313,7 @@ bool GenesisInfo::is_match(const GenesisInfo &gi, const double rad, const int beg, const int end) const { return(is_bad_data(GenesisIndex) ? false : - is_match((*this)[GenesisIndex], rad, beg, end)); + is_match(gi[GenesisIndex], rad, beg, end)); } //////////////////////////////////////////////////////////////////////// diff --git a/met/src/tools/tc_utils/tc_gen/tc_gen.cc b/met/src/tools/tc_utils/tc_gen/tc_gen.cc index b89eaf8b5a..87f1cb235f 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen.cc +++ b/met/src/tools/tc_utils/tc_gen/tc_gen.cc @@ -371,7 +371,7 @@ void get_genesis_pairs(const TCGenVxOpt &vx_opt, conf_info.InitFreqHr*sec_per_hour, vx_opt.InitBeg, vx_opt.InitEnd, vx_opt.InitInc, vx_opt.InitExc); - } + } // end for i bga // Loop over the model genesis events looking for pairs. for(i=0; i Date: Wed, 7 Apr 2021 15:17:27 -0600 Subject: [PATCH 11/15] Per #1714, reconfigure the call to tc_gen to exercise the new genesis_match_track_to_point option. --- test/config/TCGenConfig_2016 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/config/TCGenConfig_2016 b/test/config/TCGenConfig_2016 index bd5c452892..28ec263e85 100644 --- a/test/config/TCGenConfig_2016 +++ b/test/config/TCGenConfig_2016 @@ -95,6 +95,12 @@ filter = [ basin_mask = "AL"; genesis_match_window = { beg = 0; end = 24; }; }, + { + desc = "AL_POINT2POINT"; + basin_mask = "AL"; + genesis_match_window = { beg = 0; end = 24; }; + genesis_match_point_to_track = FALSE; + }, { desc = "AL_DLAND_300NM"; basin_mask = "AL"; From 612db89d4a8ebe0e4e7eaefb8d649eb65e1fad49 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Wed, 7 Apr 2021 17:19:45 -0600 Subject: [PATCH 12/15] Per #1714, just fixing spacing in source code. --- met/src/libcode/vx_tc_util/atcf_line_base.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/met/src/libcode/vx_tc_util/atcf_line_base.cc b/met/src/libcode/vx_tc_util/atcf_line_base.cc index 5ae638f44f..d90da4d8b1 100644 --- a/met/src/libcode/vx_tc_util/atcf_line_base.cc +++ b/met/src/libcode/vx_tc_util/atcf_line_base.cc @@ -252,7 +252,8 @@ ConcatString ATCFLineBase::basin() const { //////////////////////////////////////////////////////////////////////// ConcatString ATCFLineBase::cyclone_number() const { - return(get_item(CycloneNumberOffset)); } + return(get_item(CycloneNumberOffset)); +} //////////////////////////////////////////////////////////////////////// From 1569668ac092c3eda9ac503ac49b175a95a0bfeb Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Wed, 7 Apr 2021 20:56:30 -0600 Subject: [PATCH 13/15] Committing 2 small changes not specifically related to #1714, but related the processing of genesis tracks. When getting items from ATCFGenLines, the columns to be shifted are off by one. We had been shifting offset 2 up to 3, but it should have remained at 2. Also when initializing a TrackInfo object, set the StormID by calling ATCFLineBase::storm_id() instead of constructing it from BASIN:CYCLONE:YYYY. For ATCFGenLines we want to set the Storm ID equal to the 3rd column rather than constructing it! --- met/src/libcode/vx_tc_util/atcf_line_base.cc | 9 +++++---- met/src/libcode/vx_tc_util/track_info.cc | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/met/src/libcode/vx_tc_util/atcf_line_base.cc b/met/src/libcode/vx_tc_util/atcf_line_base.cc index d90da4d8b1..117461f223 100644 --- a/met/src/libcode/vx_tc_util/atcf_line_base.cc +++ b/met/src/libcode/vx_tc_util/atcf_line_base.cc @@ -211,10 +211,11 @@ ConcatString ATCFLineBase::get_item(int i) const { int i_col = i; // For ATCFLineType_GenTrack: - // Columns 1 and 2 are consistent, use offsets 0 and 1 - // Columns 4-20 are the same as columns 3-19 of ATCFLineType_Track - // Shift those column indices by 1. - if(Type == ATCFLineType_GenTrack && i >= 2 && i <= 18) i_col++; + // Columns 1 and 2 are consistent: use offsets 0 and 1 + // Column 3 has the GenStormIdOffset: use offset 2 + // Columns 4-20 are the same as columns 3-19 of ATCFLineType_Track: + // Shift offsets 3 through 18 up by 1. + if(Type == ATCFLineType_GenTrack && i >= 3 && i <= 18) i_col++; cs = DataLine::get_item(i_col); diff --git a/met/src/libcode/vx_tc_util/track_info.cc b/met/src/libcode/vx_tc_util/track_info.cc index 312d9aa620..215f0c3b38 100644 --- a/met/src/libcode/vx_tc_util/track_info.cc +++ b/met/src/libcode/vx_tc_util/track_info.cc @@ -299,7 +299,7 @@ void TrackInfo::initialize(const ATCFTrackLine &l, bool check_anly) { MinValidTime = MaxValidTime = l.valid(); // Create the storm id - set_storm_id(); + set_storm_id(l.storm_id().c_str()); return; } From f35a777e4096c490d660f0d0b748b5f1fddb67cb Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 8 Apr 2021 15:06:16 -0600 Subject: [PATCH 14/15] Per #1714, fix an error in the logic of GenesisInfo::is_match(const GenesisInfo &,...). I was using the index of the current GenesisInfo object instead of the one from the input argument. Fix this by adding GenesisInfo::genesis() member function to return a reference the TrackPoint for Genesis. --- met/src/libcode/vx_tc_util/genesis_info.cc | 13 +++++++++++-- met/src/libcode/vx_tc_util/genesis_info.h | 2 ++ met/src/tools/tc_utils/tc_gen/tc_gen.cc | 4 +--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/met/src/libcode/vx_tc_util/genesis_info.cc b/met/src/libcode/vx_tc_util/genesis_info.cc index 6ddeb9cd7f..91c708ff82 100644 --- a/met/src/libcode/vx_tc_util/genesis_info.cc +++ b/met/src/libcode/vx_tc_util/genesis_info.cc @@ -259,6 +259,7 @@ void GenesisInfo::set_dland(double d) { bool GenesisInfo::set(const TrackInfo &ti, const GenesisEventInfo &event_info) { + // Initialize clear(); @@ -298,6 +299,12 @@ int GenesisInfo::genesis_fhr() const { //////////////////////////////////////////////////////////////////////// +const TrackPoint * GenesisInfo::genesis() const { + return(is_bad_data(GenesisIndex) ? 0 : &(Point[GenesisIndex])); +} + +//////////////////////////////////////////////////////////////////////// + bool GenesisInfo::is_match(const TrackPoint &p, const double rad, const int beg, const int end) const { @@ -312,8 +319,10 @@ bool GenesisInfo::is_match(const TrackPoint &p, const double rad, bool GenesisInfo::is_match(const GenesisInfo &gi, const double rad, const int beg, const int end) const { - return(is_bad_data(GenesisIndex) ? false : - is_match(gi[GenesisIndex], rad, beg, end)); + // Input genesis point + const TrackPoint *p = gi.genesis(); + + return(p ? is_match(*p, rad, beg, end) : false); } //////////////////////////////////////////////////////////////////////// diff --git a/met/src/libcode/vx_tc_util/genesis_info.h b/met/src/libcode/vx_tc_util/genesis_info.h index 39ef811c60..9ef8afb742 100644 --- a/met/src/libcode/vx_tc_util/genesis_info.h +++ b/met/src/libcode/vx_tc_util/genesis_info.h @@ -90,6 +90,8 @@ class GenesisInfo : public TrackInfo { // get stuff // + const TrackPoint *genesis() const; + double lat() const; double lon() const; double dland() const; diff --git a/met/src/tools/tc_utils/tc_gen/tc_gen.cc b/met/src/tools/tc_utils/tc_gen/tc_gen.cc index 87f1cb235f..743db7fd44 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen.cc +++ b/met/src/tools/tc_utils/tc_gen/tc_gen.cc @@ -597,9 +597,7 @@ int find_genesis_match(const GenesisInfo &fcst_gi, const TrackInfoArray &ota, bool point2track, double rad, int beg, int end) { - int i, j; - int i_best = bad_data_int; - int i_oper = bad_data_int; + int i, j, i_best, i_oper; ConcatString case_cs; case_cs << fcst_gi.technique() << " " From 9f41da5562323c3af7a28e8830ef15c6868ad5e0 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 9 Apr 2021 13:27:01 -0600 Subject: [PATCH 15/15] Per #1714, correcting logic for parsing the storm_id and warning_time columns for ATCFGen and regular ATCF line types. For ATCFGen line types, the code was incorrectly using the 3rd column when it should have used the 4th column! --- met/src/libcode/vx_tc_util/atcf_line_base.cc | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/met/src/libcode/vx_tc_util/atcf_line_base.cc b/met/src/libcode/vx_tc_util/atcf_line_base.cc index 117461f223..aa970dc117 100644 --- a/met/src/libcode/vx_tc_util/atcf_line_base.cc +++ b/met/src/libcode/vx_tc_util/atcf_line_base.cc @@ -211,11 +211,13 @@ ConcatString ATCFLineBase::get_item(int i) const { int i_col = i; // For ATCFLineType_GenTrack: - // Columns 1 and 2 are consistent: use offsets 0 and 1 - // Column 3 has the GenStormIdOffset: use offset 2 + // Columns 1 and 2 are consistent: + // Use offsets 0 and 1 + // Column 3 for is an EXTRA column for this line type: + // Add special handling in storm_id() // Columns 4-20 are the same as columns 3-19 of ATCFLineType_Track: - // Shift offsets 3 through 18 up by 1. - if(Type == ATCFLineType_GenTrack && i >= 3 && i <= 18) i_col++; + // Shift those column indices by 1. + if(Type == ATCFLineType_GenTrack && i >= 2 && i <= 18) i_col++; cs = DataLine::get_item(i_col); @@ -359,8 +361,10 @@ int ATCFLineBase::lead() const { ConcatString ATCFLineBase::storm_id() const { ConcatString cs; + // For ATCFLineType_GenTrack, use the contents of the extra 3rd column + // Call DataLine::get_item() to avoid the column shifting logic if(Type == ATCFLineType_GenTrack) { - cs = get_item(GenStormIdOffset); + cs = DataLine::get_item(GenStormIdOffset); } else { unixtime ut = valid();