From 2a159e1b26589a7730cfe3d4ff54998a637c1736 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 5 Nov 2021 14:43:30 -0600 Subject: [PATCH 01/28] Per #1809, define the ProbGenInfo class and update the Makefile to compile it. Define ATCF offsets specific to ATCF EDECK GN lines. Update the is_match() logic slightly by moving the checking for consistent valid times from the base class to the ProbRIRWInfo class. That way we can store all probabilities for the same genesis event (across multiple lead times) in the same object. --- met/src/libcode/vx_tc_util/Makefile.am | 1 + met/src/libcode/vx_tc_util/atcf_offsets.h | 15 +- met/src/libcode/vx_tc_util/atcf_prob_line.cc | 6 +- met/src/libcode/vx_tc_util/prob_gen_info.cc | 203 +++++++++++++++++++ met/src/libcode/vx_tc_util/prob_gen_info.h | 85 ++++++++ met/src/libcode/vx_tc_util/prob_info_base.cc | 1 - met/src/libcode/vx_tc_util/prob_rirw_info.cc | 7 +- 7 files changed, 311 insertions(+), 7 deletions(-) create mode 100644 met/src/libcode/vx_tc_util/prob_gen_info.cc create mode 100644 met/src/libcode/vx_tc_util/prob_gen_info.h diff --git a/met/src/libcode/vx_tc_util/Makefile.am b/met/src/libcode/vx_tc_util/Makefile.am index 4ff97d485f..733ef9cd6b 100644 --- a/met/src/libcode/vx_tc_util/Makefile.am +++ b/met/src/libcode/vx_tc_util/Makefile.am @@ -21,6 +21,7 @@ libvx_tc_util_a_SOURCES = \ prob_info_base.h prob_info_base.cc \ prob_info_array.h prob_info_array.cc \ prob_rirw_info.h prob_rirw_info.cc \ + prob_gen_info.h prob_gen_info.cc \ prob_rirw_pair_info.h prob_rirw_pair_info.cc \ genesis_info.cc genesis_info.h \ pair_data_genesis.cc pair_data_genesis.h \ diff --git a/met/src/libcode/vx_tc_util/atcf_offsets.h b/met/src/libcode/vx_tc_util/atcf_offsets.h index 5a82809c70..01ed25d5cb 100644 --- a/met/src/libcode/vx_tc_util/atcf_offsets.h +++ b/met/src/libcode/vx_tc_util/atcf_offsets.h @@ -100,10 +100,10 @@ static const int GenMax700VortOffset = 30; // static const int ProbOffset = 8; // probability of event (0-100) -static const int ProbItemOffset = 9; // intensity change for event +static const int ProbItemOffset = 9; // RI: intensity change, GN: time window // -// Offsets specific to ATCF RIRW line type +// Offsets specific to ATCF EDECK RI line type // static const int ProbRIRWValueOffset = 10; // final intensity @@ -111,6 +111,16 @@ static const int ProbRIRWInitialsOffset = 11; // forecaster initials static const int ProbRIRWBegOffset = 12; // RIRW start time static const int ProbRIRWEndOffset = 13; // RIRW stop time +// +// Offsets specific to ATCF EDECK GN line type +// + +static const int ProbGenInitialsOffset = 10; // forecaster initials +static const int ProbGenOrDisOffset = 11; // genesis or dissipation: + // invest, genFcst, genesis, + // disFcst, dissipate +static const int ProbGenTimeOffset = 12; // forecast genesis time + // // Minimum number of required elements // @@ -118,6 +128,7 @@ static const int ProbRIRWEndOffset = 13; // RIRW stop time static const int MinATCFTrackElements = 8; static const int MinATCFGenTrackElements = 9; static const int MinATCFProbRIRWElements = 14; +static const int MinATCFProbGNElements = 13; //////////////////////////////////////////////////////////////////////// diff --git a/met/src/libcode/vx_tc_util/atcf_prob_line.cc b/met/src/libcode/vx_tc_util/atcf_prob_line.cc index a06ad1c5eb..cb4735bbce 100644 --- a/met/src/libcode/vx_tc_util/atcf_prob_line.cc +++ b/met/src/libcode/vx_tc_util/atcf_prob_line.cc @@ -124,8 +124,12 @@ int ATCFProbLine::read_line(LineDataFile * ldf) { n_expect = MinATCFProbRIRWElements; break; + case ATCFLineType_ProbGN: + n_expect = MinATCFProbGNElements; + break; + default: - mlog << Debug(4) + mlog << Debug(10) << "ATCFProbLine::read_line(LineDataFile * ldf) -> " << "skipping ATCF line type (" << atcflinetype_to_string(Type) << ")\n"; diff --git a/met/src/libcode/vx_tc_util/prob_gen_info.cc b/met/src/libcode/vx_tc_util/prob_gen_info.cc new file mode 100644 index 0000000000..9d002b9322 --- /dev/null +++ b/met/src/libcode/vx_tc_util/prob_gen_info.cc @@ -0,0 +1,203 @@ +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +// ** Copyright UCAR (c) 1992 - 2021 +// ** University Corporation for Atmospheric Research (UCAR) +// ** National Center for Atmospheric Research (NCAR) +// ** Research Applications Lab (RAL) +// ** P.O.Box 3000, Boulder, Colorado, 80307-3000, USA +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* + +//////////////////////////////////////////////////////////////////////// + +using namespace std; + +#include +#include +#include +#include +#include +#include + +#include "prob_gen_info.h" +#include "atcf_offsets.h" + +//////////////////////////////////////////////////////////////////////// +// +// Code for class ProbGenInfo +// +//////////////////////////////////////////////////////////////////////// + +ProbGenInfo::ProbGenInfo() { + + init_from_scratch(); +} + +//////////////////////////////////////////////////////////////////////// + +ProbGenInfo::~ProbGenInfo() { + + clear(); +} + +//////////////////////////////////////////////////////////////////////// + +ProbGenInfo::ProbGenInfo(const ProbGenInfo & t) { + + init_from_scratch(); + + assign(t); +} + +//////////////////////////////////////////////////////////////////////// + +ProbGenInfo & ProbGenInfo::operator=(const ProbGenInfo & t) { + + if(this == &t) return(*this); + + assign(t); + + return(*this); +} + +//////////////////////////////////////////////////////////////////////// + +void ProbGenInfo::init_from_scratch() { + + clear(); + + return; +} + +//////////////////////////////////////////////////////////////////////// + +void ProbGenInfo::clear() { + + ProbInfoBase::clear(); + + Initials.clear(); + GenOrDis.clear(); + GenTime = (unixtime) 0; + + return; +} + +//////////////////////////////////////////////////////////////////////// + +void ProbGenInfo::dump(ostream &out, int indent_depth) const { + Indent prefix(indent_depth); + + ProbInfoBase::dump(out, indent_depth); + + out << prefix << "Initials = \"" << Initials.contents() << "\"\n"; + out << prefix << "GenOrDis = \"" << GenOrDis.contents() << "\"\n"; + out << prefix << "GenTime = " << unix_to_yyyymmdd_hhmmss(GenTime) << "\n"; + + out << flush; + + return; + +} + +//////////////////////////////////////////////////////////////////////// + +ConcatString ProbGenInfo::serialize() const { + ConcatString s; + + s << ProbInfoBase::serialize() + << ", ProbGenInfo: " + << "Initials = \"" << Initials << "\"" + << ", GenOrDis = \"" << GenOrDis << "\"" + << ", GenTime = " << unix_to_yyyymmdd_hhmmss(GenTime) << "\n"; + + return(s); +} + +//////////////////////////////////////////////////////////////////////// + +ConcatString ProbGenInfo::serialize_r(int n, int indent_depth) const { + ConcatString s; + + s << ProbInfoBase::serialize_r(n, indent_depth); + + return(s); +} + +//////////////////////////////////////////////////////////////////////// + +void ProbGenInfo::assign(const ProbGenInfo &p) { + + clear(); + + ProbInfoBase::assign(p); + + Initials = p.Initials; + GenOrDis = p.GenOrDis; + GenTime = p.GenTime; + + return; +} + +//////////////////////////////////////////////////////////////////////// + +void ProbGenInfo::initialize(const ATCFProbLine &l) { + + clear(); + + ProbInfoBase::initialize(l); + + Initials = l.get_item(ProbGenInitialsOffset); + GenOrDis = l.get_item(ProbGenOrDisOffset); + + // Store an empty string as unixtime 0 + GenTime = (l.get_item(ProbGenTimeOffset).empty() ? + (unixtime) 0 : + parse_time(l.get_item(ProbGenTimeOffset).c_str())); + + return; +} + +//////////////////////////////////////////////////////////////////////// + +bool ProbGenInfo::is_match(const ATCFProbLine &l) const { + + if(!ProbInfoBase::is_match(l)) return(false); + + unixtime gen_ut = (l.get_item(ProbGenTimeOffset).empty() ? + (unixtime) 0 : + parse_time(l.get_item(ProbGenTimeOffset).c_str())); + + return(GenTime == gen_ut); +} + +//////////////////////////////////////////////////////////////////////// + +bool ProbGenInfo::add(const ATCFProbLine &l, bool check_dup) { + + // Check for duplicates + if(check_dup) { + if(has(l)) { + mlog << Warning + << "\nProbGenInfo::add(const ATCFProbLine &l, bool check_dup) -> " + << "skipping duplicate ATCF line:\n" + << l.get_line() << "\n\n"; + return(false); + } + } + + // Initialize the header information, if necessary + if(Type == NoATCFLineType) initialize(l); + + // Check for matching header information + if(!is_match(l)) return(false); + + // Add probability information + NProb++; + Prob.add(l.prob()); + ProbItem.add(l.prob_item()); + + // Store the ATCFProbLine that was just added + if(check_dup) ProbLines.add(l.get_line()); + + return(true); +} + +//////////////////////////////////////////////////////////////////////// diff --git a/met/src/libcode/vx_tc_util/prob_gen_info.h b/met/src/libcode/vx_tc_util/prob_gen_info.h new file mode 100644 index 0000000000..41b4493ddb --- /dev/null +++ b/met/src/libcode/vx_tc_util/prob_gen_info.h @@ -0,0 +1,85 @@ +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +// ** Copyright UCAR (c) 1992 - 2021 +// ** University Corporation for Atmospheric Research (UCAR) +// ** National Center for Atmospheric Research (NCAR) +// ** Research Applications Lab (RAL) +// ** P.O.Box 3000, Boulder, Colorado, 80307-3000, USA +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* + +//////////////////////////////////////////////////////////////////////// + +#ifndef __VX_PROB_GEN_INFO_H__ +#define __VX_PROB_GEN_INFO_H__ + +//////////////////////////////////////////////////////////////////////// + +#include + +#include "prob_info_base.h" + +#include "vx_util.h" + +//////////////////////////////////////////////////////////////////////// +// +// ProbGenInfo class stores probability of rapid intensification. +// +//////////////////////////////////////////////////////////////////////// + +class ProbGenInfo : public ProbInfoBase { + + private: + + void init_from_scratch(); + void assign(const ProbGenInfo &); + + // Probability of Genesis specific values + ConcatString Initials; + ConcatString GenOrDis; + unixtime GenTime; + + public: + + ProbGenInfo(); + ~ProbGenInfo(); + ProbGenInfo(const ProbGenInfo &); + ProbGenInfo & operator=(const ProbGenInfo &); + + void clear(); + + void dump(ostream &, int = 0) const; + ConcatString serialize() const; + ConcatString serialize_r(int, int = 0) const; + + // + // set stuff + // + + // + // get stuff + // + + const ConcatString & initials() const; + const ConcatString & gen_or_dis() const; + unixtime gen_time() const; + + // + // do stuff + // + + void initialize(const ATCFProbLine &); + bool is_match (const ATCFProbLine &) const; + bool add (const ATCFProbLine &, bool check_dup = false); + +}; + +//////////////////////////////////////////////////////////////////////// + +inline const ConcatString & ProbGenInfo::initials() const { return(Initials); } +inline const ConcatString & ProbGenInfo::gen_or_dis() const { return(GenOrDis); } +inline unixtime ProbGenInfo::gen_time() const { return(GenTime); } + +//////////////////////////////////////////////////////////////////////// + +#endif /* __VX_PROB_GEN_INFO_H__ */ + +//////////////////////////////////////////////////////////////////////// diff --git a/met/src/libcode/vx_tc_util/prob_info_base.cc b/met/src/libcode/vx_tc_util/prob_info_base.cc index f8d3bb791e..8e707ccda5 100644 --- a/met/src/libcode/vx_tc_util/prob_info_base.cc +++ b/met/src/libcode/vx_tc_util/prob_info_base.cc @@ -206,7 +206,6 @@ bool ProbInfoBase::is_match(const ATCFProbLine &l) const { Cyclone == l.cyclone_number() && Technique == l.technique() && InitTime == l.warning_time() && - ValidTime == l.valid() && Lat == l.lat() && Lon == l.lon()); } diff --git a/met/src/libcode/vx_tc_util/prob_rirw_info.cc b/met/src/libcode/vx_tc_util/prob_rirw_info.cc index edbd318334..a24194e481 100644 --- a/met/src/libcode/vx_tc_util/prob_rirw_info.cc +++ b/met/src/libcode/vx_tc_util/prob_rirw_info.cc @@ -169,9 +169,10 @@ bool ProbRIRWInfo::is_match(const ATCFProbLine &l) const { if(!ProbInfoBase::is_match(l)) return(false); - return(Value == parse_int(l.get_item(ProbRIRWValueOffset).c_str()) && - RIRWBeg == parse_int(l.get_item(ProbRIRWBegOffset).c_str()) && - RIRWEnd == parse_int(l.get_item(ProbRIRWEndOffset).c_str())); + return(ValidTime == l.valid() && + Value == parse_int(l.get_item(ProbRIRWValueOffset).c_str()) && + RIRWBeg == parse_int(l.get_item(ProbRIRWBegOffset).c_str()) && + RIRWEnd == parse_int(l.get_item(ProbRIRWEndOffset).c_str())); } //////////////////////////////////////////////////////////////////////// From 8b8fc96a337a198c00658abc0613284d4239e2e2 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 5 Nov 2021 14:44:26 -0600 Subject: [PATCH 02/28] Per #1809, update the ProbInfoArray class to store arrays of both ProbRIRWInfo and ProbGenInfo objects. --- met/src/libcode/vx_tc_util/prob_info_array.cc | 142 ++++++++++++++---- met/src/libcode/vx_tc_util/prob_info_array.h | 12 +- 2 files changed, 120 insertions(+), 34 deletions(-) diff --git a/met/src/libcode/vx_tc_util/prob_info_array.cc b/met/src/libcode/vx_tc_util/prob_info_array.cc index 5a8e91844b..e96feea2d7 100644 --- a/met/src/libcode/vx_tc_util/prob_info_array.cc +++ b/met/src/libcode/vx_tc_util/prob_info_array.cc @@ -72,8 +72,9 @@ void ProbInfoArray::init_from_scratch() { void ProbInfoArray::clear() { - // Erase the entire vector + // Erase the entire vectors ProbRIRW.erase(ProbRIRW.begin(), ProbRIRW.end()); + ProbGen.erase(ProbGen.begin(), ProbGen.end()); return; } @@ -82,15 +83,23 @@ void ProbInfoArray::clear() { void ProbInfoArray::dump(ostream &out, int indent_depth) const { Indent prefix(indent_depth); + int i; out << prefix << "ProbInfoArray:\n" - << prefix << "NProbRIRW = " << n_prob_rirw() << "\n"; + << prefix << "NProbRIRW = " << n_prob_rirw() << "\n"; - for(unsigned int i=0; i 0 ) { + s << prefix << serialize() << ", ProbRIRW:\n"; + } + for(i=0; i 0 ) { + s << prefix << serialize() << ", ProbGen:\n"; + } + + for(i=0; i= n_probs())) { - mlog << Error - << "\nProbInfoBase * ProbInfoArray::operator[] -> " + mlog << Error << "\nProbInfoBase * ProbInfoArray::operator[] -> " << "range check error for index value " << n << "\n\n"; exit(1); } - // Return a base pointer to the n-th probability - // Need to revise for each new probability vector + // Get a base pointer to the n-th probability + const ProbInfoBase *ptr; - return(&ProbRIRW[n]); + if(ProbRIRW.size() > 0 && n < ProbRIRW.size()) { + ptr = &ProbRIRW[n]; + } + else { + n -= ProbRIRW.size(); + ptr = &ProbGen[n]; + } + + return(ptr); } //////////////////////////////////////////////////////////////////////// @@ -160,8 +185,7 @@ const ProbRIRWInfo & ProbInfoArray::prob_rirw(int n) const { // Check range if((n < 0) || (n >= (int) ProbRIRW.size())) { - mlog << Error - << "\nProbRIRWInfo & ProbInfoArray::prob_rirw(int) -> " + mlog << Error << "\nProbRIRWInfo & ProbInfoArray::prob_rirw(int) -> " << "range check error for index value " << n << "\n\n"; exit(1); } @@ -171,14 +195,29 @@ const ProbRIRWInfo & ProbInfoArray::prob_rirw(int n) const { //////////////////////////////////////////////////////////////////////// +const ProbGenInfo & ProbInfoArray::prob_gen(int n) const { + + // Check range + if((n < 0) || (n >= (int) ProbGen.size())) { + mlog << Error << "\nProbGenInfo & ProbInfoArray::prob_gen(int) -> " + << "range check error for index value " << n << "\n\n"; + exit(1); + } + + return(ProbGen[n]); +} + +//////////////////////////////////////////////////////////////////////// + bool ProbInfoArray::add(const ATCFProbLine &l, bool check_dup) { + bool status = false; // Range check the probability value if(l.prob() < 0 || l.prob() > 100) { - mlog << Debug(4) - << "\nbool ProbInfoArray::add() -> " + mlog << Debug(4) + << "bool ProbInfoArray::add() -> " << "skipping probability value (" << l.prob() - << ") outside of range (0, 100).\n\n"; + << ") outside of range (0, 100).\n"; return(false); } @@ -187,27 +226,61 @@ bool ProbInfoArray::add(const ATCFProbLine &l, bool check_dup) { case(ATCFLineType_ProbRI): - // Check for no entries or a mismatch with the latest entry - if( ProbRIRW.size() == 0 || - (ProbRIRW.size() > 0 && - !ProbRIRW[ProbRIRW.size()-1].add(l, check_dup))) { - - // Store new entry + // Add line to an existing entry + if(ProbRIRW.size() > 0 && + ProbRIRW[ProbRIRW.size()-1].add(l, check_dup)) { + status = true; + } + // Add a new entry + else { ProbRIRWInfo ri; ri.add(l, check_dup); ProbRIRW.push_back(ri); + status = true; + } + break; + + case(ATCFLineType_ProbGN): + + // Add line to an existing entry + if(ProbGen.size() > 0 && + ProbGen[ProbGen.size()-1].add(l, check_dup)) { + status = true; + } + // Add a new entry + else { + ProbGenInfo gi; + gi.add(l, check_dup); + + // Check for the expected genesis type and predicted location + if(gi.gen_or_dis() != "genFcst") { + mlog << Debug(4) + << "bool ProbInfoArray::add() -> " + << "skipping ATCF " << atcflinetype_to_string(ATCFLineType_ProbGN) + << " line with non-genesis probability type (" + << gi.gen_or_dis() << " != genFcst).\n"; + } + else if(is_bad_data(gi.lat()) || is_bad_data(gi.lon())) { + mlog << Debug(4) + << "bool ProbInfoArray::add() -> " + << "skipping ATCF " << atcflinetype_to_string(ATCFLineType_ProbGN) + << " line with no predicted genesis location.\n"; + } + else { + ProbGen.push_back(gi); + status = true; + } } break; default: - mlog << Warning - << "\nbool ProbInfoArray::add() -> " + mlog << Warning << "\nbool ProbInfoArray::add() -> " << "unexpected ATCF line type (" << atcflinetype_to_string(l.type()) << ")\n\n"; - return(false); + status = false; } - return(true); + return(status); } //////////////////////////////////////////////////////////////////////// @@ -218,3 +291,10 @@ void ProbInfoArray::add(const ProbRIRWInfo &rirw) { } //////////////////////////////////////////////////////////////////////// + +void ProbInfoArray::add(const ProbGenInfo &gn) { + ProbGen.push_back(gn); + return; +} + +//////////////////////////////////////////////////////////////////////// diff --git a/met/src/libcode/vx_tc_util/prob_info_array.h b/met/src/libcode/vx_tc_util/prob_info_array.h index 1228b91880..a897ae0621 100644 --- a/met/src/libcode/vx_tc_util/prob_info_array.h +++ b/met/src/libcode/vx_tc_util/prob_info_array.h @@ -19,6 +19,7 @@ #include "atcf_prob_line.h" #include "prob_info_base.h" #include "prob_rirw_info.h" +#include "prob_gen_info.h" #include "vx_util.h" @@ -36,6 +37,7 @@ class ProbInfoArray { void assign(const ProbInfoArray &); vector ProbRIRW; + vector ProbGen; public: @@ -60,19 +62,23 @@ class ProbInfoArray { int n_prob_rirw() const; const ProbRIRWInfo & prob_rirw(int) const; + int n_prob_gen() const; + const ProbGenInfo & prob_gen(int) const; + // // do stuff // bool add(const ATCFProbLine &, bool check_dup = false); void add(const ProbRIRWInfo &); - + void add(const ProbGenInfo &); }; //////////////////////////////////////////////////////////////////////// -inline int ProbInfoArray::n_probs() const { return(ProbRIRW.size()); } -inline int ProbInfoArray::n_prob_rirw() const { return(ProbRIRW.size()); } +inline int ProbInfoArray::n_probs() const { return(ProbRIRW.size() + ProbGen.size()); } +inline int ProbInfoArray::n_prob_rirw() const { return(ProbRIRW.size()); } +inline int ProbInfoArray::n_prob_gen() const { return(ProbGen.size()); } //////////////////////////////////////////////////////////////////////// From 661b2e7b83a6b7a84034b54c99b28f4f79260992 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 5 Nov 2021 14:45:35 -0600 Subject: [PATCH 03/28] Per #1809, since tc_pairs processes probabilities of RIRW and not genesis, update it to only process RIRW probabilities from the ProbInfoArray class rather than all of them. --- met/src/tools/tc_utils/tc_pairs/tc_pairs.cc | 24 ++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/met/src/tools/tc_utils/tc_pairs/tc_pairs.cc b/met/src/tools/tc_utils/tc_pairs/tc_pairs.cc index 7a70c0736a..167ec7aeaf 100644 --- a/met/src/tools/tc_utils/tc_pairs/tc_pairs.cc +++ b/met/src/tools/tc_utils/tc_pairs/tc_pairs.cc @@ -437,7 +437,7 @@ void process_edecks(const TrackInfoArray &bdeck_tracks) { // Filter the EDECK tracks using the config file information mlog << Debug(2) - << "Filtering " << edeck_probs.n_probs() + << "Filtering " << edeck_probs.n_prob_rirw() << " probabilities based on config file settings.\n"; filter_probs(edeck_probs); @@ -446,11 +446,11 @@ void process_edecks(const TrackInfoArray &bdeck_tracks) { // mlog << Debug(2) - << "Matching " << edeck_probs.n_probs() + << "Matching " << edeck_probs.n_prob_rirw() << " EDECK probabilities to " << bdeck_tracks.n() << " BDECK tracks.\n"; - for(i=0; i= 5) { @@ -717,9 +717,9 @@ void process_prob_files(const StringArray &files, } // Dump out track info else { - for(i=0; iserialize() << "\n"; } } @@ -928,7 +928,7 @@ void filter_probs(ProbInfoArray &probs) { // Loop through the pairs and determine which should be retained // The is_keeper() function has already filtered by model, storm id, // basin, cyclone, initialization time, and initialization hour. - for(i=0; i 0 && @@ -977,11 +977,11 @@ void filter_probs(ProbInfoArray &probs) { // Print summary filtering info mlog << Debug(3) - << "Total probabilities read = " << p.n_probs() << "\n" - << "Total probabilities kept = " << probs.n_probs() << "\n" - << "Rejected for valid time = " << n_vld << "\n" - << "Rejected for init mask = " << n_mask_init << "\n" - << "Rejected for valid mask = " << n_mask_vld << "\n"; + << "Total probabilities read = " << p.n_prob_rirw() << "\n" + << "Total probabilities kept = " << probs.n_prob_rirw() << "\n" + << "Rejected for valid time = " << n_vld << "\n" + << "Rejected for init mask = " << n_mask_init << "\n" + << "Rejected for valid mask = " << n_mask_vld << "\n"; return; } From 79371ca3d327ce17b1b234c939956d6b3e71c421 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 5 Nov 2021 14:46:38 -0600 Subject: [PATCH 04/28] Per #1809, this is definitely a work in progress. TC-Gen parses the genesis probability forecasts and now needs to be enhanced to actually verify them. --- met/src/tools/tc_utils/tc_gen/tc_gen.cc | 402 +++++++++++++++++++++--- met/src/tools/tc_utils/tc_gen/tc_gen.h | 1 + 2 files changed, 361 insertions(+), 42 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 bfb3960226..5b8a2c9b4b 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen.cc +++ b/met/src/tools/tc_utils/tc_gen/tc_gen.cc @@ -20,6 +20,7 @@ // 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 +// 006 11/04/21 Halley Gotway Add -edeck for MET #1809 // //////////////////////////////////////////////////////////////////////// @@ -56,19 +57,24 @@ using namespace std; //////////////////////////////////////////////////////////////////////// static void process_command_line (int, char **); -static void process_genesis (); +static void process_genesis (const GenesisInfoArray &, + const TrackInfoArray &); +static void process_edecks (const GenesisInfoArray &, + const TrackInfoArray &); static void get_atcf_files (const StringArray &, const StringArray &, const char *, StringArray &, StringArray &); -static void process_fcst_tracks (const StringArray &, +static void parse_genesis (const StringArray &, const StringArray &, GenesisInfoArray &); -static void process_best_tracks (const StringArray &, +static void parse_tracks (const StringArray &, const StringArray &, GenesisInfoArray &, TrackInfoArray &); - +static void parse_edecks (const StringArray &, + const StringArray &, + ProbInfoArray &); static void get_genesis_pairs (const TCGenVxOpt &, const ConcatString &, const GenesisInfoArray &, @@ -105,6 +111,7 @@ static void usage (); static void set_source (const StringArray &, const char *, StringArray &, StringArray &); static void set_genesis (const StringArray &); +static void set_edeck (const StringArray &); static void set_track (const StringArray &); static void set_config (const StringArray &); static void set_out (const StringArray &); @@ -119,8 +126,30 @@ int main(int argc, char *argv[]) { // Process the command line arguments process_command_line(argc, argv); - // Identify and process genesis events and write output - process_genesis(); + // Process the verifying BEST and operational tracks + StringArray track_files, track_files_model_suffix; + GenesisInfoArray best_ga; + TrackInfoArray oper_ta; + + // Get the list of verifing track files + get_atcf_files(track_source, track_model_suffix, atcf_reg_exp, + track_files, track_files_model_suffix); + + mlog << Debug(2) + << "Processing " << track_files.n() + << " verifying track files.\n"; + parse_tracks(track_files, track_files_model_suffix, + best_ga, oper_ta); + + // Score genesis events and write output + if(genesis_source.n() > 0) { + process_genesis(best_ga, oper_ta); + } + + // Score EDECK genesis probabilities and write output + if(edeck_source.n() > 0) { + process_edecks(best_ga, oper_ta); + } return(0); } @@ -143,6 +172,7 @@ void process_command_line(int argc, char **argv) { // Add function calls for the arguments cline.add(set_genesis, "-genesis", -1); + cline.add(set_edeck, "-edeck", -1); cline.add(set_track, "-track", -1); cline.add(set_config, "-config", 1); cline.add(set_out, "-out", 1); @@ -154,21 +184,29 @@ void process_command_line(int argc, char **argv) { for(i=genesis_model_suffix.n(); i " - << "the \"-genesis\", \"-track\", and \"-config\" command " + if(genesis_source.n() == 0 && edeck_source.n() == 0) { + mlog << Error << "\nprocess_command_line(int argc, char **argv) -> " + << "at least one of the \"-genesis\" or \"-edeck\" command " << "line options are required\n\n"; usage(); } + // Check for the minimum number of arguments + if(track_source.n() == 0 || config_file.length() == 0) { + mlog << Error << "\nprocess_command_line(int argc, char **argv) -> " + << "the \"-track\" and \"-config\" command line options " + << "are required\n\n"; + usage(); + } + // List the input genesis track files for(i=0; i model_ga_map; map::iterator it; @@ -221,18 +266,8 @@ void process_genesis() { mlog << Debug(2) << "Processing " << genesis_files.n() << " forecast genesis track files.\n"; - process_fcst_tracks(genesis_files, genesis_files_model_suffix, - fcst_ga); - - // Get the list of verifing track files - get_atcf_files(track_source, track_model_suffix, atcf_reg_exp, - track_files, track_files_model_suffix); - - mlog << Debug(2) - << "Processing " << track_files.n() - << " verifying track files.\n"; - process_best_tracks(track_files, track_files_model_suffix, - best_ga, oper_ta); + parse_genesis(genesis_files, genesis_files_model_suffix, + fcst_ga); // Setup output files based on the number of techniques present // and possible pairs. @@ -324,7 +359,126 @@ void process_genesis() { nc_out = (NcFile *) 0; } + return; +} + +//////////////////////////////////////////////////////////////////////// + +void process_edecks(const GenesisInfoArray &best_ga, + const TrackInfoArray &oper_ta) { + int i, j; + StringArray edeck_files, edeck_files_model_suffix; + ProbInfoArray fcst_pa, empty_pa; + ConcatString model, cs; + map model_ta_map; + map::iterator it; + map gen_prob_map; + map::iterator gen_it; + PCTInfo pct_info; + + // Get the list of EDECK files + get_atcf_files(edeck_source, edeck_model_suffix, atcf_reg_exp, + edeck_files, edeck_files_model_suffix); + + mlog << Debug(2) + << "Processing " << edeck_files.n() + << " forecast EDECK files.\n"; + parse_edecks(edeck_files, edeck_files_model_suffix, + fcst_pa); + + /* JHG, need to think about the output files! + // Setup output files based on the number of techniques present + // and possible pairs. + int n_time = (conf_info.FcstSecEnd - conf_info.FcstSecBeg) / + (conf_info.InitFreqHr*sec_per_hour) + 1; + int n_pair = best_ga.n() * n_time + fcst_ga.n(); + setup_txt_files(fcst_ga.n_technique(), n_pair); + // If requested, setup the NetCDF output file + if(!conf_info.NcInfo.all_false()) setup_nc_file(); + + // Process each verification filter + for(i=0; i 0 && + !conf_info.VxOpt[i].Model.has(model)) continue; + + // Add a new map entry, if necessary + if(model_ta_map.count(model) == 0) { + empty_ta.clear(); + model_ta_map[model] = empty_ta; + } + + // Store the current genesis event + model_ta_map[model].add(fcst_ta[j]); + + } // end j + + // Process the genesis probabilities for each model + for(j=0,it=model_ta_map.begin(); it!=model_ta_map.end(); it++,j++) { + + // Initialize + pct_info.clear(); + pct_info.Model = it->first; + pct_info.set_vx_opt(&conf_info.VxOpt[i], + &conf_info.NcOutGrid); + + mlog << Debug(2) + << "[Filter " << i+1 << " (" << conf_info.VxOpt[i].Desc + << ") " << ": Model " << j+1 << "] " << "For " << it->first + << " model, comparing " << it->second.n() + << " genesis forecasts to " << best_ga.n() << " " + << conf_info.BestEventInfo.Technique << " and " + << oper_ta.n() << " " << conf_info.OperTechnique + << " tracks.\n"; + + // Get the pairs + get_genesis_pairs(conf_info.VxOpt[i], it->first, it->second, + best_ga, oper_ta, pairs); + + // Do the categorical verification + do_genesis_ctc(conf_info.VxOpt[i], pairs, ctc_info); + + // Write the statistics output + write_stats(pairs, ctc_info); + + // Write NetCDF output fields + if(!conf_info.VxOpt[i].NcInfo.all_false()) { + write_nc(ctc_info); + } + + + + } // end for j + + } // end for i n_vx + + // Finish output files + finish_txt_files(); + + // Close the NetCDF output file + if(nc_out) { + + // List the NetCDF file after it is finished + mlog << Debug(1) << "Output file: " << out_nc_file << "\n"; + + delete nc_out; + nc_out = (NcFile *) 0; + } +*/ return; } @@ -715,7 +869,7 @@ void get_atcf_files(const StringArray &source, //////////////////////////////////////////////////////////////////////// -void process_fcst_tracks(const StringArray &files, +void parse_genesis(const StringArray &files, const StringArray &model_suffix, GenesisInfoArray &fcst_ga) { int i, j; @@ -737,7 +891,7 @@ void process_fcst_tracks(const StringArray &files, // Open the current file if(!f.open(files[i].c_str())) { - mlog << Error << "\nprocess_fcst_tracks() -> " + mlog << Error << "\nparse_genesis() -> " << "unable to open file \"" << files[i] << "\"\n\n"; exit(1); } @@ -842,10 +996,10 @@ void process_fcst_tracks(const StringArray &files, //////////////////////////////////////////////////////////////////////// -void process_best_tracks(const StringArray &files, - const StringArray &model_suffix, - GenesisInfoArray &best_ga, - TrackInfoArray &oper_ta) { +void parse_tracks(const StringArray &files, + const StringArray &model_suffix, + GenesisInfoArray &best_ga, + TrackInfoArray &oper_ta) { int i, i_bga, n_lines; ConcatString suffix, gen_basin, case_cs, storm_id; StringArray best_tech, oper_tech; @@ -871,8 +1025,7 @@ void process_best_tracks(const StringArray &files, // Open the current file if(!f.open(files[i].c_str())) { - mlog << Error - << "\nprocess_best_tracks() -> " + mlog << Error << "\nparse_tracks() -> " << "unable to open file \"" << files[i] << "\"\n\n"; exit(1); } @@ -976,7 +1129,7 @@ void process_best_tracks(const StringArray &files, i--; } else { - mlog << Warning << "\nprocess_best_tracks() -> " + mlog << Warning << "\nparse_tracks() -> " << case_cs << "neither " << best_ga[i_bga].storm_id() << " nor " << best_gi.storm_id() << " matches the basin!\n\n"; @@ -1000,6 +1153,160 @@ void process_best_tracks(const StringArray &files, return; } +//////////////////////////////////////////////////////////////////////// +/* JHG int i, i_bga; + ConcatString suffix, gen_basin, case_cs, storm_id; + StringArray best_tech, oper_tech; + TrackInfoArray best_ta; + GenesisInfo best_gi; + + + + */ +void parse_edecks(const StringArray &files, + const StringArray &model_suffix, + ProbInfoArray &fcst_pa) { + int i, n_lines; + ConcatString suffix; + LineDataFile f; + ATCFProbLine line; + + int valid_freq_sec = conf_info.ValidFreqHr*sec_per_hour; + + // Initialize + fcst_pa.clear(); + n_lines = 0; + + // Process each of the input ATCF files + for(i=0; i " + << "unable to open file \"" << files[i] << "\"\n\n"; + exit(1); + } + + // Set metadata pointer + suffix = model_suffix[i]; + line.set_tech_suffix(&suffix); + + // Process the input track lines + while(f >> line) { + + // Skip off-hour track points + if((line.valid_hour() % valid_freq_sec) != 0) continue; + + // Only process genesis probability lines + if(line.type() == ATCFLineType_ProbGN) { + if(fcst_pa.add(line)) n_lines++; + } + } + + // Close the current file + f.close(); + + } // end for i + + // Dump out the total number of lines + mlog << Debug(3) + << "Read a total of " << n_lines << " " + << atcflinetype_to_string(ATCFLineType_ProbGN) + << " lines from " << files.n() << " input files.\n"; + + // Dump out very verbose output + if(mlog.verbosity_level() >= 6) { + mlog << Debug(6) << fcst_pa.serialize_r() << "\n"; + } + +/* + + // Dump out very verbose output + if(mlog.verbosity_level() >= 6) { + mlog << Debug(6) << "BEST tracks:\n" + << best_ta.serialize_r() << "\n" + << "Operational tracks:\n" + << oper_ta.serialize_r() << "\n"; + } + + // Search the BEST tracks for genesis events + for(i=0; i max_best_cyclone_number) { + mlog << Debug(6) + << "Skipping Best track genesis event for cyclone number " + << best_ta[i].cyclone() << " > " << max_best_cyclone_number + << ".\n"; + continue; + } + + // Check for duplicates + if(best_ga.has_storm(best_gi, i_bga)) { + + // Determine the basin for this genesis event + gen_basin = conf_info.compute_basin(best_gi.lat(), + -1.0*best_gi.lon()); + + case_cs << cs_erase << "For duplicate " + << unix_to_yyyymmdd_hhmmss(best_gi.genesis_time()) << " " + << best_gi.technique() << " track genesis at (" + << best_gi.lat() << ", " << best_gi.lon() << ") in the " + << gen_basin << " basin, "; + + // Keep existing storm id and discard the new one + if(gen_basin == best_ga[i_bga].basin()) { + mlog << Debug(3) + << case_cs << "keep " << best_ga[i_bga].storm_id() + << " and discard " << best_gi.storm_id() + << ".\n"; + best_ta.erase_storm_id(best_gi.storm_id()); + oper_ta.erase_storm_id(best_gi.storm_id()); + i--; + continue; + } + // Discard the existing storm id and add the new one + else if(gen_basin == best_gi.basin()) { + mlog << Debug(3) + << case_cs << "keep " << best_gi.storm_id() + << " and discard " << best_ga[i_bga].storm_id() + << ".\n"; + best_ga.erase_storm_id(best_ga[i_bga].storm_id()); + best_ta.erase_storm_id(best_ga[i_bga].storm_id()); + oper_ta.erase_storm_id(best_ga[i_bga].storm_id()); + i--; + } + else { + mlog << Warning << "\nparse_tracks() -> " + << case_cs << "neither " << best_ga[i_bga].storm_id() + << " nor " << best_gi.storm_id() + << " matches the basin!\n\n"; + continue; + } + } + + // Compute the distance to land + best_gi.set_dland(conf_info.compute_dland( + best_gi.lat(), -1.0*best_gi.lon())); + + // Store the genesis event + best_ga.add(best_gi); + + } // end for i + + // Dump out the number of genesis events + mlog << Debug(2) << "Found " << best_ga.n() + << " BEST genesis events.\n"; +*/ + return; +} + + //////////////////////////////////////////////////////////////////////// // // Setup the output ASCII files @@ -1547,19 +1854,24 @@ void usage() { << ") ***\n\n" << "Usage: " << program_name << "\n" - << "\t-genesis path\n" - << "\t-track path\n" + << "\t-genesis source and/or -edeck source\n" + << "\t-track source\n" << "\t-config file\n" << "\t[-out base]\n" << "\t[-log file]\n" << "\t[-v level]\n\n" - << "\twhere\t\"-genesis path\" is one or more ATCF genesis " + << "\twhere\t\"-genesis source\" is one or more ATCF genesis " + << "files, an ASCII file list containing them, or a top-level " + << "directory with files matching the regular expression \"" + << atcf_gen_reg_exp << "\" (required if no -edeck).\n" + + << "\t\t\"-edeck source\" is one or more ensemble model output " << "files, an ASCII file list containing them, or a top-level " << "directory with files matching the regular expression \"" - << atcf_gen_reg_exp << "\" (required).\n" + << atcf_reg_exp << "\" (required if no -genesis).\n" - << "\t\t\"-track path\" is one or more ATCF track " + << "\t\t\"-track source\" is one or more ATCF track " << "files, an ASCII file list containing them, or a top-level " << "directory with files matching the regular expression \"" << atcf_reg_exp << "\" for the verifying BEST and operational " @@ -1648,6 +1960,12 @@ void set_genesis(const StringArray & a) { //////////////////////////////////////////////////////////////////////// +void set_edeck(const StringArray & a) { + set_source(a, "edeck", edeck_source, edeck_model_suffix); +} + +//////////////////////////////////////////////////////////////////////// + void set_track(const StringArray & a) { set_source(a, "track", track_source, track_model_suffix); } 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 a531652c32..0bf1bd1819 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen.h +++ b/met/src/tools/tc_utils/tc_gen/tc_gen.h @@ -89,6 +89,7 @@ static const int max_best_cyclone_number = 50; // Input files static StringArray genesis_source, genesis_model_suffix; +static StringArray edeck_source, edeck_model_suffix; static StringArray track_source, track_model_suffix; static ConcatString config_file; static TCGenConfInfo conf_info; From 0c5223454fff42242600e420e0608f6580d2e11f Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 5 Nov 2021 16:35:36 -0600 Subject: [PATCH 05/28] Per #1809, store the distance to land in the ProbInfoBase class and update the other classes accordingly to set it. Also, update tc_pairs to only process ATCF EDECK probability of RI lines. --- met/src/libcode/vx_tc_util/prob_gen_info.cc | 8 ++++---- met/src/libcode/vx_tc_util/prob_gen_info.h | 4 ++-- met/src/libcode/vx_tc_util/prob_info_array.cc | 10 +++++----- met/src/libcode/vx_tc_util/prob_info_array.h | 2 +- met/src/libcode/vx_tc_util/prob_info_base.cc | 20 ++++++++++++++++--- met/src/libcode/vx_tc_util/prob_info_base.h | 7 +++++-- met/src/libcode/vx_tc_util/prob_rirw_info.cc | 8 ++++---- met/src/libcode/vx_tc_util/prob_rirw_info.h | 4 ++-- met/src/tools/tc_utils/tc_pairs/tc_pairs.cc | 16 +++++++++------ 9 files changed, 50 insertions(+), 29 deletions(-) diff --git a/met/src/libcode/vx_tc_util/prob_gen_info.cc b/met/src/libcode/vx_tc_util/prob_gen_info.cc index 9d002b9322..863fc90bc1 100644 --- a/met/src/libcode/vx_tc_util/prob_gen_info.cc +++ b/met/src/libcode/vx_tc_util/prob_gen_info.cc @@ -138,11 +138,11 @@ void ProbGenInfo::assign(const ProbGenInfo &p) { //////////////////////////////////////////////////////////////////////// -void ProbGenInfo::initialize(const ATCFProbLine &l) { +void ProbGenInfo::initialize(const ATCFProbLine &l, double dland) { clear(); - ProbInfoBase::initialize(l); + ProbInfoBase::initialize(l, dland); Initials = l.get_item(ProbGenInitialsOffset); GenOrDis = l.get_item(ProbGenOrDisOffset); @@ -170,7 +170,7 @@ bool ProbGenInfo::is_match(const ATCFProbLine &l) const { //////////////////////////////////////////////////////////////////////// -bool ProbGenInfo::add(const ATCFProbLine &l, bool check_dup) { +bool ProbGenInfo::add(const ATCFProbLine &l, double dland, bool check_dup) { // Check for duplicates if(check_dup) { @@ -184,7 +184,7 @@ bool ProbGenInfo::add(const ATCFProbLine &l, bool check_dup) { } // Initialize the header information, if necessary - if(Type == NoATCFLineType) initialize(l); + if(Type == NoATCFLineType) initialize(l, dland); // Check for matching header information if(!is_match(l)) return(false); diff --git a/met/src/libcode/vx_tc_util/prob_gen_info.h b/met/src/libcode/vx_tc_util/prob_gen_info.h index 41b4493ddb..1ce3dc10d5 100644 --- a/met/src/libcode/vx_tc_util/prob_gen_info.h +++ b/met/src/libcode/vx_tc_util/prob_gen_info.h @@ -66,9 +66,9 @@ class ProbGenInfo : public ProbInfoBase { // do stuff // - void initialize(const ATCFProbLine &); + void initialize(const ATCFProbLine &, double); bool is_match (const ATCFProbLine &) const; - bool add (const ATCFProbLine &, bool check_dup = false); + bool add (const ATCFProbLine &, double, bool check_dup = false); }; diff --git a/met/src/libcode/vx_tc_util/prob_info_array.cc b/met/src/libcode/vx_tc_util/prob_info_array.cc index e96feea2d7..fb336b0654 100644 --- a/met/src/libcode/vx_tc_util/prob_info_array.cc +++ b/met/src/libcode/vx_tc_util/prob_info_array.cc @@ -209,7 +209,7 @@ const ProbGenInfo & ProbInfoArray::prob_gen(int n) const { //////////////////////////////////////////////////////////////////////// -bool ProbInfoArray::add(const ATCFProbLine &l, bool check_dup) { +bool ProbInfoArray::add(const ATCFProbLine &l, double dland, bool check_dup) { bool status = false; // Range check the probability value @@ -228,13 +228,13 @@ bool ProbInfoArray::add(const ATCFProbLine &l, bool check_dup) { // Add line to an existing entry if(ProbRIRW.size() > 0 && - ProbRIRW[ProbRIRW.size()-1].add(l, check_dup)) { + ProbRIRW[ProbRIRW.size()-1].add(l, dland, check_dup)) { status = true; } // Add a new entry else { ProbRIRWInfo ri; - ri.add(l, check_dup); + ri.add(l, dland, check_dup); ProbRIRW.push_back(ri); status = true; } @@ -244,13 +244,13 @@ bool ProbInfoArray::add(const ATCFProbLine &l, bool check_dup) { // Add line to an existing entry if(ProbGen.size() > 0 && - ProbGen[ProbGen.size()-1].add(l, check_dup)) { + ProbGen[ProbGen.size()-1].add(l, dland, check_dup)) { status = true; } // Add a new entry else { ProbGenInfo gi; - gi.add(l, check_dup); + gi.add(l, dland, check_dup); // Check for the expected genesis type and predicted location if(gi.gen_or_dis() != "genFcst") { diff --git a/met/src/libcode/vx_tc_util/prob_info_array.h b/met/src/libcode/vx_tc_util/prob_info_array.h index a897ae0621..c538375941 100644 --- a/met/src/libcode/vx_tc_util/prob_info_array.h +++ b/met/src/libcode/vx_tc_util/prob_info_array.h @@ -69,7 +69,7 @@ class ProbInfoArray { // do stuff // - bool add(const ATCFProbLine &, bool check_dup = false); + bool add(const ATCFProbLine &, double dland, bool check_dup = false); void add(const ProbRIRWInfo &); void add(const ProbGenInfo &); }; diff --git a/met/src/libcode/vx_tc_util/prob_info_base.cc b/met/src/libcode/vx_tc_util/prob_info_base.cc index 8e707ccda5..fb4147226c 100644 --- a/met/src/libcode/vx_tc_util/prob_info_base.cc +++ b/met/src/libcode/vx_tc_util/prob_info_base.cc @@ -79,6 +79,7 @@ void ProbInfoBase::clear() { ValidTime = (unixtime) 0; Lat = bad_data_double; Lon = bad_data_double; + DLand = bad_data_double; NProb = 0; Prob.clear(); ProbItem.clear(); @@ -101,6 +102,7 @@ void ProbInfoBase::dump(ostream &out, int indent_depth) const { out << prefix << "ValidTime = \"" << (ValidTime > 0 ? unix_to_yyyymmdd_hhmmss(ValidTime).text() : na_str) << "\"\n"; out << prefix << "Lat = " << Lat << "\n"; out << prefix << "Lon = " << Lon << "\n"; + out << prefix << "DLand = " << DLand << "\n"; out << prefix << "NProb = " << NProb << "\n"; out << prefix << "Prob:" << "\n"; Prob.dump(out, indent_depth+1); @@ -130,6 +132,7 @@ ConcatString ProbInfoBase::serialize() const { << ", ValidTime = \"" << (ValidTime > 0 ? unix_to_yyyymmdd_hhmmss(ValidTime).text() : na_str) << "\"" << ", Lat = " << Lat << ", Lon = " << Lon + << ", DLand = " << DLand << ", NProb = " << NProb; return(s); @@ -155,6 +158,14 @@ ConcatString ProbInfoBase::serialize_r(int n, int indent_depth) const { //////////////////////////////////////////////////////////////////////// +void ProbInfoBase::set_dland(double d) { + DLand = d; + + return; +} + +//////////////////////////////////////////////////////////////////////// + void ProbInfoBase::assign(const ProbInfoBase &t) { clear(); @@ -168,6 +179,7 @@ void ProbInfoBase::assign(const ProbInfoBase &t) { ValidTime = t.ValidTime; Lat = t.Lat; Lon = t.Lon; + DLand = t.DLand; NProb = t.NProb; Prob = t.Prob; ProbItem = t.ProbItem; @@ -178,7 +190,7 @@ void ProbInfoBase::assign(const ProbInfoBase &t) { //////////////////////////////////////////////////////////////////////// -void ProbInfoBase::initialize(const ATCFProbLine &l) { +void ProbInfoBase::initialize(const ATCFProbLine &l, double dland) { clear(); @@ -192,6 +204,7 @@ void ProbInfoBase::initialize(const ATCFProbLine &l) { ValidTime = l.valid(); Lat = l.lat(); Lon = l.lon(); + DLand = dland; return; } @@ -238,7 +251,7 @@ bool ProbInfoBase::is_match(const TrackInfo &t) const { //////////////////////////////////////////////////////////////////////// -bool ProbInfoBase::add(const ATCFProbLine &l, bool check_dup) { +bool ProbInfoBase::add(const ATCFProbLine &l, double dland, bool check_dup) { // Check for duplicates if(check_dup) { @@ -252,7 +265,7 @@ bool ProbInfoBase::add(const ATCFProbLine &l, bool check_dup) { } // Initialize the header information, if necessary - if(Type == NoATCFLineType) initialize(l); + if(Type == NoATCFLineType) initialize(l, dland); // Check for matching header information if(!is_match(l)) return(false); @@ -296,6 +309,7 @@ void ProbInfoBase::set(const TCStatLine &l) { ValidTime = l.valid(); Lat = atof(l.get_item("ALAT")); Lon = atof(l.get_item("ALON")); + DLand = atof(l.get_item("ADLAND")); NProb = atoi(l.get_item("N_THRESH")); for(int i=1; i<=NProb; i++) { cs << cs_erase << "PROB_" << i; diff --git a/met/src/libcode/vx_tc_util/prob_info_base.h b/met/src/libcode/vx_tc_util/prob_info_base.h index 4f416db319..fff06def24 100644 --- a/met/src/libcode/vx_tc_util/prob_info_base.h +++ b/met/src/libcode/vx_tc_util/prob_info_base.h @@ -50,6 +50,7 @@ class ProbInfoBase { // Location information double Lat; double Lon; + double DLand; // Probability information int NProb; @@ -93,6 +94,7 @@ class ProbInfoBase { int valid_hour() const; double lat() const; double lon() const; + double dland() const; int n_prob() const; double prob(int i) const; double prob_item(int i) const; @@ -101,11 +103,11 @@ class ProbInfoBase { // do stuff // - virtual void initialize(const ATCFProbLine &); + virtual void initialize(const ATCFProbLine &, double); virtual bool is_match (const ATCFProbLine &) const; bool is_match (const TrackInfo &) const; bool has (const ATCFProbLine &) const; - virtual bool add (const ATCFProbLine &, bool check_dup = false); + virtual bool add (const ATCFProbLine &, double, bool check_dup = false); virtual void set (const TCStatLine &); }; @@ -123,6 +125,7 @@ inline unixtime ProbInfoBase::valid() const { return(ValidT inline int ProbInfoBase::valid_hour() const { return(unix_to_sec_of_day(ValidTime)); } inline double ProbInfoBase::lat() const { return(Lat); } inline double ProbInfoBase::lon() const { return(Lon); } +inline double ProbInfoBase::dland() const { return(DLand); } inline int ProbInfoBase::n_prob() const { return(NProb); } inline double ProbInfoBase::prob(int i) const { return(Prob[i]); } inline double ProbInfoBase::prob_item(int i) const { return(ProbItem[i]); } diff --git a/met/src/libcode/vx_tc_util/prob_rirw_info.cc b/met/src/libcode/vx_tc_util/prob_rirw_info.cc index a24194e481..7799e591d3 100644 --- a/met/src/libcode/vx_tc_util/prob_rirw_info.cc +++ b/met/src/libcode/vx_tc_util/prob_rirw_info.cc @@ -149,11 +149,11 @@ int ProbRIRWInfo::rirw_window() const { //////////////////////////////////////////////////////////////////////// -void ProbRIRWInfo::initialize(const ATCFProbLine &l) { +void ProbRIRWInfo::initialize(const ATCFProbLine &l, double dland) { clear(); - ProbInfoBase::initialize(l); + ProbInfoBase::initialize(l, dland); Value = parse_int(l.get_item(ProbRIRWValueOffset).c_str()); Initials = l.get_item(ProbRIRWInitialsOffset); @@ -177,7 +177,7 @@ bool ProbRIRWInfo::is_match(const ATCFProbLine &l) const { //////////////////////////////////////////////////////////////////////// -bool ProbRIRWInfo::add(const ATCFProbLine &l, bool check_dup) { +bool ProbRIRWInfo::add(const ATCFProbLine &l, double dland, bool check_dup) { // Check for duplicates if(check_dup) { @@ -191,7 +191,7 @@ bool ProbRIRWInfo::add(const ATCFProbLine &l, bool check_dup) { } // Initialize the header information, if necessary - if(Type == NoATCFLineType) initialize(l); + if(Type == NoATCFLineType) initialize(l, dland); // Check for matching header information if(!is_match(l)) return(false); diff --git a/met/src/libcode/vx_tc_util/prob_rirw_info.h b/met/src/libcode/vx_tc_util/prob_rirw_info.h index 9f47615dbf..2f04fc4baf 100644 --- a/met/src/libcode/vx_tc_util/prob_rirw_info.h +++ b/met/src/libcode/vx_tc_util/prob_rirw_info.h @@ -69,9 +69,9 @@ class ProbRIRWInfo : public ProbInfoBase { // do stuff // - void initialize(const ATCFProbLine &); + void initialize(const ATCFProbLine &, double); bool is_match (const ATCFProbLine &) const; - bool add (const ATCFProbLine &, bool check_dup = false); + bool add (const ATCFProbLine &, double, bool check_dup = false); void set (const TCStatLine &); }; diff --git a/met/src/tools/tc_utils/tc_pairs/tc_pairs.cc b/met/src/tools/tc_utils/tc_pairs/tc_pairs.cc index 167ec7aeaf..5bf073959e 100644 --- a/met/src/tools/tc_utils/tc_pairs/tc_pairs.cc +++ b/met/src/tools/tc_utils/tc_pairs/tc_pairs.cc @@ -467,8 +467,8 @@ void process_edecks(const TrackInfoArray &bdeck_tracks) { << " BDeck: " << bdeck_tracks[j].serialize() << "\n"; // Compute the distances to land - cur_ri.set_adland(compute_dland(cur_ri.prob_rirw().lat(), -1.0*cur_ri.prob_rirw().lon())); - cur_ri.set_bdland(compute_dland(cur_ri.blat(), -1.0*cur_ri.blon())); + cur_ri.set_adland(edeck_probs[i]->dland()); + cur_ri.set_bdland(compute_dland(cur_ri.blat(), -1.0*cur_ri.blon())); // Store the current pair prob_rirw_pairs.add(cur_ri); @@ -640,6 +640,7 @@ void process_prob_files(const StringArray &files, const StringArray &model_suffix, ProbInfoArray &probs) { int i, cur_read, cur_add, tot_read, tot_add; + double dland; LineDataFile f; ConcatString suffix; ATCFProbLine line; @@ -683,10 +684,13 @@ void process_prob_files(const StringArray &files, // Check the keep status if(!is_keeper(&line)) continue; - // Attempt to add the current line to ProbInfoArray - if(probs.add(line, conf_info.CheckDup)) { - cur_add++; - tot_add++; + // Only process probability of RI lines + if(line.type() == ATCFLineType_ProbRI) { + dland = compute_dland(line.lat(), -1.0*line.lon()); + if(probs.add(line, dland, conf_info.CheckDup)) { + cur_add++; + tot_add++; + } } } From 88ec38e64de5d67fc036c3e6aac35bf1846b7701 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 5 Nov 2021 16:47:20 -0600 Subject: [PATCH 06/28] Per #1809... --- met/internal_tests/libcode/vx_tc_util/test_read_prob.cc | 2 +- met/src/libcode/vx_tc_util/prob_info_array.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/met/internal_tests/libcode/vx_tc_util/test_read_prob.cc b/met/internal_tests/libcode/vx_tc_util/test_read_prob.cc index 402876f47c..eea9a30e2d 100644 --- a/met/internal_tests/libcode/vx_tc_util/test_read_prob.cc +++ b/met/internal_tests/libcode/vx_tc_util/test_read_prob.cc @@ -53,7 +53,7 @@ int main(int argc, char *argv[]) { while(f >> p_line) { // Add the current line to the array of probs - probs.add(p_line); + probs.add(p_line, bad_data_double, false); // Increment the line count count++; diff --git a/met/src/libcode/vx_tc_util/prob_info_array.cc b/met/src/libcode/vx_tc_util/prob_info_array.cc index fb336b0654..2d994d1319 100644 --- a/met/src/libcode/vx_tc_util/prob_info_array.cc +++ b/met/src/libcode/vx_tc_util/prob_info_array.cc @@ -292,8 +292,8 @@ void ProbInfoArray::add(const ProbRIRWInfo &rirw) { //////////////////////////////////////////////////////////////////////// -void ProbInfoArray::add(const ProbGenInfo &gn) { - ProbGen.push_back(gn); +void ProbInfoArray::add(const ProbGenInfo &gi) { + ProbGen.push_back(gi); return; } From 78c930a41ae69033b1f109f53d859062e185cf94 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 9 Nov 2021 12:31:29 -0700 Subject: [PATCH 07/28] Per #1809, work in progress renaming tc_gen functions in a more consistent way. --- met/src/tools/tc_utils/tc_gen/tc_gen.cc | 210 ++++++------------ .../tools/tc_utils/tc_gen/tc_gen_conf_info.cc | 65 ++++++ .../tools/tc_utils/tc_gen/tc_gen_conf_info.h | 1 + 3 files changed, 130 insertions(+), 146 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 5b8a2c9b4b..1171efa5b6 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen.cc +++ b/met/src/tools/tc_utils/tc_gen/tc_gen.cc @@ -57,22 +57,22 @@ using namespace std; //////////////////////////////////////////////////////////////////////// static void process_command_line (int, char **); -static void process_genesis (const GenesisInfoArray &, +static void score_track_genesis (const GenesisInfoArray &, const TrackInfoArray &); -static void process_edecks (const GenesisInfoArray &, +static void score_genesis_prob (const GenesisInfoArray &, const TrackInfoArray &); static void get_atcf_files (const StringArray &, const StringArray &, const char *, StringArray &, StringArray &); -static void parse_genesis (const StringArray &, +static void process_genesis (const StringArray &, const StringArray &, GenesisInfoArray &); -static void parse_tracks (const StringArray &, +static void process_tracks (const StringArray &, const StringArray &, GenesisInfoArray &, TrackInfoArray &); -static void parse_edecks (const StringArray &, +static void process_edecks (const StringArray &, const StringArray &, ProbInfoArray &); static void get_genesis_pairs (const TCGenVxOpt &, @@ -138,17 +138,17 @@ int main(int argc, char *argv[]) { mlog << Debug(2) << "Processing " << track_files.n() << " verifying track files.\n"; - parse_tracks(track_files, track_files_model_suffix, - best_ga, oper_ta); + process_tracks(track_files, track_files_model_suffix, + best_ga, oper_ta); // Score genesis events and write output if(genesis_source.n() > 0) { - process_genesis(best_ga, oper_ta); + score_track_genesis(best_ga, oper_ta); } // Score EDECK genesis probabilities and write output if(edeck_source.n() > 0) { - process_edecks(best_ga, oper_ta); + score_genesis_prob(best_ga, oper_ta); } return(0); @@ -248,8 +248,8 @@ void process_command_line(int argc, char **argv) { //////////////////////////////////////////////////////////////////////// -void process_genesis(const GenesisInfoArray &best_ga, - const TrackInfoArray &oper_ta) { +void score_track_genesis(const GenesisInfoArray &best_ga, + const TrackInfoArray &oper_ta) { int i, j; StringArray genesis_files, genesis_files_model_suffix; GenesisInfoArray fcst_ga, empty_ga; @@ -266,8 +266,8 @@ void process_genesis(const GenesisInfoArray &best_ga, mlog << Debug(2) << "Processing " << genesis_files.n() << " forecast genesis track files.\n"; - parse_genesis(genesis_files, genesis_files_model_suffix, - fcst_ga); + process_genesis(genesis_files, genesis_files_model_suffix, + fcst_ga); // Setup output files based on the number of techniques present // and possible pairs. @@ -307,7 +307,7 @@ void process_genesis(const GenesisInfoArray &best_ga, // Store the current genesis event model_ga_map[model].add(fcst_ga[j]); - } // end j + } // end for j // Process the genesis events for each model. for(j=0,it=model_ga_map.begin(); it!=model_ga_map.end(); it++,j++) { @@ -364,14 +364,14 @@ void process_genesis(const GenesisInfoArray &best_ga, //////////////////////////////////////////////////////////////////////// -void process_edecks(const GenesisInfoArray &best_ga, - const TrackInfoArray &oper_ta) { +void score_genesis_prob(const GenesisInfoArray &best_ga, + const TrackInfoArray &oper_ta) { int i, j; StringArray edeck_files, edeck_files_model_suffix; ProbInfoArray fcst_pa, empty_pa; ConcatString model, cs; - map model_ta_map; - map::iterator it; + map model_pa_map; + map::iterator it; map gen_prob_map; map::iterator gen_it; PCTInfo pct_info; @@ -383,8 +383,8 @@ void process_edecks(const GenesisInfoArray &best_ga, mlog << Debug(2) << "Processing " << edeck_files.n() << " forecast EDECK files.\n"; - parse_edecks(edeck_files, edeck_files_model_suffix, - fcst_pa); + process_edecks(edeck_files, edeck_files_model_suffix, + fcst_pa); /* JHG, need to think about the output files! // Setup output files based on the number of techniques present @@ -396,55 +396,55 @@ void process_edecks(const GenesisInfoArray &best_ga, // If requested, setup the NetCDF output file if(!conf_info.NcInfo.all_false()) setup_nc_file(); - +*/ // Process each verification filter for(i=0; i 0 && !conf_info.VxOpt[i].Model.has(model)) continue; // Add a new map entry, if necessary - if(model_ta_map.count(model) == 0) { - empty_ta.clear(); - model_ta_map[model] = empty_ta; + if(model_pa_map.count(model) == 0) { + empty_pa.clear(); + model_pa_map[model] = empty_pa; } // Store the current genesis event - model_ta_map[model].add(fcst_ta[j]); + model_pa_map[model].add(fcst_pa.prob_gen(j)); - } // end j + } // end for j // Process the genesis probabilities for each model - for(j=0,it=model_ta_map.begin(); it!=model_ta_map.end(); it++,j++) { - + for(j=0,it=model_pa_map.begin(); it!=model_pa_map.end(); it++,j++) { +/* JHG // Initialize pct_info.clear(); pct_info.Model = it->first; pct_info.set_vx_opt(&conf_info.VxOpt[i], &conf_info.NcOutGrid); - +*/ mlog << Debug(2) << "[Filter " << i+1 << " (" << conf_info.VxOpt[i].Desc << ") " << ": Model " << j+1 << "] " << "For " << it->first - << " model, comparing " << it->second.n() + << " model, comparing " << it->second.n_prob_gen() << " genesis forecasts to " << best_ga.n() << " " << conf_info.BestEventInfo.Technique << " and " << oper_ta.n() << " " << conf_info.OperTechnique << " tracks.\n"; - +/* // Get the pairs get_genesis_pairs(conf_info.VxOpt[i], it->first, it->second, best_ga, oper_ta, pairs); @@ -459,13 +459,13 @@ void process_edecks(const GenesisInfoArray &best_ga, if(!conf_info.VxOpt[i].NcInfo.all_false()) { write_nc(ctc_info); } - +*/ } // end for j } // end for i n_vx - +/* // Finish output files finish_txt_files(); @@ -869,9 +869,9 @@ void get_atcf_files(const StringArray &source, //////////////////////////////////////////////////////////////////////// -void parse_genesis(const StringArray &files, - const StringArray &model_suffix, - GenesisInfoArray &fcst_ga) { +void process_genesis(const StringArray &files, + const StringArray &model_suffix, + GenesisInfoArray &fcst_ga) { int i, j; int n_lines, tot_lines, tot_tracks, n_genesis; ConcatString suffix; @@ -891,7 +891,7 @@ void parse_genesis(const StringArray &files, // Open the current file if(!f.open(files[i].c_str())) { - mlog << Error << "\nparse_genesis() -> " + mlog << Error << "\nprocess_genesis() -> " << "unable to open file \"" << files[i] << "\"\n\n"; exit(1); } @@ -996,10 +996,10 @@ void parse_genesis(const StringArray &files, //////////////////////////////////////////////////////////////////////// -void parse_tracks(const StringArray &files, - const StringArray &model_suffix, - GenesisInfoArray &best_ga, - TrackInfoArray &oper_ta) { +void process_tracks(const StringArray &files, + const StringArray &model_suffix, + GenesisInfoArray &best_ga, + TrackInfoArray &oper_ta) { int i, i_bga, n_lines; ConcatString suffix, gen_basin, case_cs, storm_id; StringArray best_tech, oper_tech; @@ -1025,7 +1025,7 @@ void parse_tracks(const StringArray &files, // Open the current file if(!f.open(files[i].c_str())) { - mlog << Error << "\nparse_tracks() -> " + mlog << Error << "\nprocess_tracks() -> " << "unable to open file \"" << files[i] << "\"\n\n"; exit(1); } @@ -1129,7 +1129,7 @@ void parse_tracks(const StringArray &files, i--; } else { - mlog << Warning << "\nparse_tracks() -> " + mlog << Warning << "\nprocess_tracks() -> " << case_cs << "neither " << best_ga[i_bga].storm_id() << " nor " << best_gi.storm_id() << " matches the basin!\n\n"; @@ -1154,19 +1154,12 @@ void parse_tracks(const StringArray &files, } //////////////////////////////////////////////////////////////////////// -/* JHG int i, i_bga; - ConcatString suffix, gen_basin, case_cs, storm_id; - StringArray best_tech, oper_tech; - TrackInfoArray best_ta; - GenesisInfo best_gi; - - - */ -void parse_edecks(const StringArray &files, - const StringArray &model_suffix, - ProbInfoArray &fcst_pa) { +void process_edecks(const StringArray &files, + const StringArray &model_suffix, + ProbInfoArray &probs) { int i, n_lines; + double dland; ConcatString suffix; LineDataFile f; ATCFProbLine line; @@ -1174,7 +1167,7 @@ void parse_edecks(const StringArray &files, int valid_freq_sec = conf_info.ValidFreqHr*sec_per_hour; // Initialize - fcst_pa.clear(); + probs.clear(); n_lines = 0; // Process each of the input ATCF files @@ -1182,7 +1175,7 @@ void parse_edecks(const StringArray &files, // Open the current file if(!f.open(files[i].c_str())) { - mlog << Error << "\nparse_edecks() -> " + mlog << Error << "\nprocess_edecks() -> " << "unable to open file \"" << files[i] << "\"\n\n"; exit(1); } @@ -1199,7 +1192,8 @@ void parse_edecks(const StringArray &files, // Only process genesis probability lines if(line.type() == ATCFLineType_ProbGN) { - if(fcst_pa.add(line)) n_lines++; + dland = conf_info.compute_dland(line.lat(), -1.0*line.lon()); + if(probs.add(line, dland, false)) n_lines++; } } @@ -1216,96 +1210,20 @@ void parse_edecks(const StringArray &files, // Dump out very verbose output if(mlog.verbosity_level() >= 6) { - mlog << Debug(6) << fcst_pa.serialize_r() << "\n"; + mlog << Debug(6) << probs.serialize_r() << "\n"; } -/* - - // Dump out very verbose output - if(mlog.verbosity_level() >= 6) { - mlog << Debug(6) << "BEST tracks:\n" - << best_ta.serialize_r() << "\n" - << "Operational tracks:\n" - << oper_ta.serialize_r() << "\n"; - } - - // Search the BEST tracks for genesis events - for(i=0; i max_best_cyclone_number) { - mlog << Debug(6) - << "Skipping Best track genesis event for cyclone number " - << best_ta[i].cyclone() << " > " << max_best_cyclone_number - << ".\n"; - continue; - } - - // Check for duplicates - if(best_ga.has_storm(best_gi, i_bga)) { - - // Determine the basin for this genesis event - gen_basin = conf_info.compute_basin(best_gi.lat(), - -1.0*best_gi.lon()); - - case_cs << cs_erase << "For duplicate " - << unix_to_yyyymmdd_hhmmss(best_gi.genesis_time()) << " " - << best_gi.technique() << " track genesis at (" - << best_gi.lat() << ", " << best_gi.lon() << ") in the " - << gen_basin << " basin, "; - - // Keep existing storm id and discard the new one - if(gen_basin == best_ga[i_bga].basin()) { - mlog << Debug(3) - << case_cs << "keep " << best_ga[i_bga].storm_id() - << " and discard " << best_gi.storm_id() - << ".\n"; - best_ta.erase_storm_id(best_gi.storm_id()); - oper_ta.erase_storm_id(best_gi.storm_id()); - i--; - continue; - } - // Discard the existing storm id and add the new one - else if(gen_basin == best_gi.basin()) { - mlog << Debug(3) - << case_cs << "keep " << best_gi.storm_id() - << " and discard " << best_ga[i_bga].storm_id() - << ".\n"; - best_ga.erase_storm_id(best_ga[i_bga].storm_id()); - best_ta.erase_storm_id(best_ga[i_bga].storm_id()); - oper_ta.erase_storm_id(best_ga[i_bga].storm_id()); - i--; - } - else { - mlog << Warning << "\nparse_tracks() -> " - << case_cs << "neither " << best_ga[i_bga].storm_id() - << " nor " << best_gi.storm_id() - << " matches the basin!\n\n"; - continue; - } - } - - // Compute the distance to land - best_gi.set_dland(conf_info.compute_dland( - best_gi.lat(), -1.0*best_gi.lon())); - - // Store the genesis event - best_ga.add(best_gi); - - } // end for i - - // Dump out the number of genesis events - mlog << Debug(2) << "Found " << best_ga.n() - << " BEST genesis events.\n"; -*/ return; } +/* JHG + // Compute the distance to land + for(i=0; i 0 && + !has_storm_id(StormId, gi.basin(), gi.cyclone(), gi.init())) + keep = false; + + // Check storm name: no included in genesis probabilities + + // Initialization time + if((InitBeg > 0 && InitBeg > gi.init()) || + (InitEnd > 0 && InitEnd < gi.init()) || + (InitInc.n() > 0 && !InitInc.has(gi.init())) || + (InitExc.n() > 0 && InitExc.has(gi.init()))) + keep = false; + + // Initialization hours + if(InitHour.n() > 0 && !InitHour.has(gi.init_hour())) + keep = false; + + // Lead times: JHG, gi has up to 3 lead times!? + /* + if(Lead.n() > 0 && !Lead.has(gi.lead())) + keep = false; +*/ + + // Valid time window: JHG, gi has 3 valid times!? +/* + if((ValidBeg > 0 && ValidBeg > gi.valid_min()) || + (ValidEnd > 0 && ValidEnd < gi.valid_max())) + keep = false; +*/ + // Poly masking + if(VxPolyMask.n_points() > 0 && + !VxPolyMask.latlon_is_inside(gi.lat(), gi.lon())) + keep = false; + + // Area masking + if(!VxAreaMask.is_empty()) { + double x, y; + VxGridMask.latlon_to_xy(gi.lat(), -1.0*gi.lon(), x, y); + if(x < 0 || x >= VxGridMask.nx() || + y < 0 || y >= VxGridMask.ny()) { + keep = false; + } + else { + keep = VxAreaMask(nint(x), nint(y)); + } + } + + // Distance to land + if((DLandThresh.get_type() != no_thresh_type) && + (is_bad_data(gi.dland()) || !DLandThresh.check(gi.dland()))) + keep = false; + + // Return the keep status + return(keep); +} + + //////////////////////////////////////////////////////////////////////// STATOutputType TCGenVxOpt::output_map(STATLineType t) const { 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 a02a62e562..a35cafd11b 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 @@ -161,6 +161,7 @@ class TCGenVxOpt { void parse_nc_info(Dictionary &); bool is_keeper(const GenesisInfo &) const; + bool is_keeper(const ProbGenInfo &) const; STATOutputType output_map(STATLineType) const; }; From 9929924bb60f06dd34d0a374be8a3636598d8d59 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 9 Nov 2021 15:28:33 -0700 Subject: [PATCH 08/28] Per #1809, make the genesis probability thresholds configurable. --- met/data/config/TCGenConfig_default | 5 +++++ met/src/basic/vx_config/config_constants.h | 1 + .../tools/tc_utils/tc_gen/tc_gen_conf_info.cc | 21 +++++++------------ .../tools/tc_utils/tc_gen/tc_gen_conf_info.h | 1 + 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/met/data/config/TCGenConfig_default b/met/data/config/TCGenConfig_default index 9ed75cc2c2..748d0e9fa6 100644 --- a/met/data/config/TCGenConfig_default +++ b/met/data/config/TCGenConfig_default @@ -212,6 +212,11 @@ ops_method_flag = TRUE; // //////////////////////////////////////////////////////////////////////////////// +// +// Genesis probability thresholds +// +genesis_prob_thresh = ==0.25; + // // Confidence interval alpha value // diff --git a/met/src/basic/vx_config/config_constants.h b/met/src/basic/vx_config/config_constants.h index a46559ca02..3082eb69d7 100644 --- a/met/src/basic/vx_config/config_constants.h +++ b/met/src/basic/vx_config/config_constants.h @@ -1097,6 +1097,7 @@ 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"; +static const char conf_key_genesis_prob_thresh[] = "genesis_prob_thresh"; static const char conf_key_fcst_fy_oy[] = "fcst_fy_oy"; static const char conf_key_fcst_fy_on[] = "fcst_fy_on"; static const char conf_key_fcst_tracks[] = "fcst_tracks"; 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 d2dc1e0547..dc626e5fee 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 @@ -164,6 +164,7 @@ void TCGenVxOpt::clear() { OpsHitBeg = OpsHitEnd = bad_data_int; DiscardFlag = false; DevFlag = OpsFlag = false; + GenProbThresh.clear(); CIAlpha = bad_data_double; OutputMap.clear(); NcInfo.clear(); @@ -288,7 +289,10 @@ void TCGenVxOpt::process_config(Dictionary &dict) { << " must be set to true!\n\n"; exit(1); } - + + // Conf: genesis_prob_thresh + GenProbThresh = dict.lookup_thresh_array(conf_key_genesis_prob_thresh); + // Conf: ci_alpha CIAlpha = dict.lookup_double(conf_key_ci_alpha); @@ -531,18 +535,10 @@ bool TCGenVxOpt::is_keeper(const ProbGenInfo &gi) const { if(InitHour.n() > 0 && !InitHour.has(gi.init_hour())) keep = false; - // Lead times: JHG, gi has up to 3 lead times!? - /* - if(Lead.n() > 0 && !Lead.has(gi.lead())) - keep = false; -*/ + // Lead and valid times: + // ProbGenInfo objects can contain multiple lead/valid times. + // Do not filter by them here. - // Valid time window: JHG, gi has 3 valid times!? -/* - if((ValidBeg > 0 && ValidBeg > gi.valid_min()) || - (ValidEnd > 0 && ValidEnd < gi.valid_max())) - keep = false; -*/ // Poly masking if(VxPolyMask.n_points() > 0 && !VxPolyMask.latlon_is_inside(gi.lat(), gi.lon())) @@ -570,7 +566,6 @@ bool TCGenVxOpt::is_keeper(const ProbGenInfo &gi) const { return(keep); } - //////////////////////////////////////////////////////////////////////// STATOutputType TCGenVxOpt::output_map(STATLineType t) const { 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 a35cafd11b..0265c5bbbb 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 @@ -145,6 +145,7 @@ class TCGenVxOpt { bool DiscardFlag, DevFlag, OpsFlag; // Output file options + ThreshArray GenProbThresh; double CIAlpha; map OutputMap; TCGenNcOutInfo NcInfo; From 475c96aa6a199dcdeb111830305850b41ed98e8b Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 11 Nov 2021 09:26:41 -0700 Subject: [PATCH 09/28] Per #1809, add ProbInfoArray::n_technique() member function to count up the unique model names from the input. --- met/src/libcode/vx_tc_util/prob_info_array.cc | 20 +++++++++++++++++++ met/src/libcode/vx_tc_util/prob_info_array.h | 2 ++ 2 files changed, 22 insertions(+) diff --git a/met/src/libcode/vx_tc_util/prob_info_array.cc b/met/src/libcode/vx_tc_util/prob_info_array.cc index 2d994d1319..26abc5213a 100644 --- a/met/src/libcode/vx_tc_util/prob_info_array.cc +++ b/met/src/libcode/vx_tc_util/prob_info_array.cc @@ -209,6 +209,26 @@ const ProbGenInfo & ProbInfoArray::prob_gen(int n) const { //////////////////////////////////////////////////////////////////////// +int ProbInfoArray::n_technique() const { + StringArray sa; + + // Count the number of unique technique names + for(int i=0; i Date: Thu, 11 Nov 2021 09:27:37 -0700 Subject: [PATCH 10/28] Per #1809, update PCTInfo to add the set_fthresh() function and expand probability thresholds, as needed. --- met/src/libcode/vx_statistics/met_stats.cc | 21 +++++++++++++++++++++ met/src/libcode/vx_statistics/met_stats.h | 1 + 2 files changed, 22 insertions(+) diff --git a/met/src/libcode/vx_statistics/met_stats.cc b/met/src/libcode/vx_statistics/met_stats.cc index 2975b03432..3880ab204a 100644 --- a/met/src/libcode/vx_statistics/met_stats.cc +++ b/met/src/libcode/vx_statistics/met_stats.cc @@ -2424,6 +2424,27 @@ void PCTInfo::allocate_n_alpha(int i) { //////////////////////////////////////////////////////////////////////// +void PCTInfo::set_fthresh(const ThreshArray &ta) { + + // Expand the probability thresholds, as needed + fthresh = string_to_prob_thresh(ta.get_str().c_str()); + + // Validate the threshold settings + check_prob_thresh(fthresh, true); + + // Store the values in an array + NumArray prob_vals; + for(int i=0; i Date: Thu, 11 Nov 2021 09:30:05 -0700 Subject: [PATCH 11/28] Per #1809, update TC-Gen to add options for probabilistic outputs when evaluating the genesis probability forecasts. --- met/data/config/TCGenConfig_default | 6 +- met/src/tools/tc_utils/tc_gen/tc_gen.cc | 410 ++++++++++++------ met/src/tools/tc_utils/tc_gen/tc_gen.h | 14 +- .../tools/tc_utils/tc_gen/tc_gen_conf_info.cc | 15 + .../tools/tc_utils/tc_gen/tc_gen_conf_info.h | 18 +- 5 files changed, 329 insertions(+), 134 deletions(-) diff --git a/met/data/config/TCGenConfig_default b/met/data/config/TCGenConfig_default index 748d0e9fa6..0de6a27844 100644 --- a/met/data/config/TCGenConfig_default +++ b/met/data/config/TCGenConfig_default @@ -227,8 +227,12 @@ ci_alpha = 0.05; // output_flag = { fho = NONE; - ctc = BOTH; + ctc = BOTH; cts = BOTH; + pct = NONE; + pstd = NONE; + pjc = NONE; + prc = NONE; genmpr = NONE; } 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 1171efa5b6..f2a26967d8 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen.cc +++ b/met/src/tools/tc_utils/tc_gen/tc_gen.cc @@ -95,8 +95,9 @@ static void setup_txt_files (int, int); static void setup_table (AsciiTable &); static void setup_nc_file (); -static void write_stats (const PairDataGenesis &, +static void write_ctc_stats (const PairDataGenesis &, GenCTCInfo &); +static void write_pct_stats (int, PCTInfo &, PCTInfo &); static void write_genmpr_row (StatHdrColumns &, const PairDataGenesis &, STATOutputType, @@ -151,6 +152,19 @@ int main(int argc, char *argv[]) { score_genesis_prob(best_ga, oper_ta); } + // Finish output files + finish_txt_files(); + + // Close the NetCDF output file + if(nc_out) { + + // List the NetCDF file after it is finished + mlog << Debug(1) << "Output file: " << out_nc_file << "\n"; + + delete nc_out; + nc_out = (NcFile *) 0; + } + return(0); } @@ -335,7 +349,7 @@ void score_track_genesis(const GenesisInfoArray &best_ga, do_genesis_ctc(conf_info.VxOpt[i], pairs, ctc_info); // Write the statistics output - write_stats(pairs, ctc_info); + write_ctc_stats(pairs, ctc_info); // Write NetCDF output fields if(!conf_info.VxOpt[i].NcInfo.all_false()) { @@ -346,19 +360,6 @@ void score_track_genesis(const GenesisInfoArray &best_ga, } // end for i n_vx - // Finish output files - finish_txt_files(); - - // Close the NetCDF output file - if(nc_out) { - - // List the NetCDF file after it is finished - mlog << Debug(1) << "Output file: " << out_nc_file << "\n"; - - delete nc_out; - nc_out = (NcFile *) 0; - } - return; } @@ -366,15 +367,16 @@ void score_track_genesis(const GenesisInfoArray &best_ga, void score_genesis_prob(const GenesisInfoArray &best_ga, const TrackInfoArray &oper_ta) { - int i, j; + int i, j, k, l, prob_time; + double prob_value; + IntArray prob_times; StringArray edeck_files, edeck_files_model_suffix; ProbInfoArray fcst_pa, empty_pa; ConcatString model, cs; map model_pa_map; - map::iterator it; - map gen_prob_map; - map::iterator gen_it; - PCTInfo pct_info; + map::iterator model_it; + map pct_dev_map, pct_ops_map; + PCTInfo empty_pct; // Get the list of EDECK files get_atcf_files(edeck_source, edeck_model_suffix, atcf_reg_exp, @@ -386,17 +388,9 @@ void score_genesis_prob(const GenesisInfoArray &best_ga, process_edecks(edeck_files, edeck_files_model_suffix, fcst_pa); - /* JHG, need to think about the output files! - // Setup output files based on the number of techniques present - // and possible pairs. - int n_time = (conf_info.FcstSecEnd - conf_info.FcstSecBeg) / - (conf_info.InitFreqHr*sec_per_hour) + 1; - int n_pair = best_ga.n() * n_time + fcst_ga.n(); - setup_txt_files(fcst_ga.n_technique(), n_pair); + // Setup output files based on the number of techniques + setup_txt_files(fcst_pa.n_technique(), 0); - // If requested, setup the NetCDF output file - if(!conf_info.NcInfo.all_false()) setup_nc_file(); -*/ // Process each verification filter for(i=0; ifirst; - pct_info.set_vx_opt(&conf_info.VxOpt[i], - &conf_info.NcOutGrid); -*/ + for(j=0,model_it=model_pa_map.begin(); + model_it!=model_pa_map.end(); + model_it++,j++) { + mlog << Debug(2) << "[Filter " << i+1 << " (" << conf_info.VxOpt[i].Desc - << ") " << ": Model " << j+1 << "] " << "For " << it->first - << " model, comparing " << it->second.n_prob_gen() + << ") " << ": Model " << j+1 << "] " << "For " << model_it->first + << " model, comparing " << model_it->second.n_prob_gen() << " genesis forecasts to " << best_ga.n() << " " << conf_info.BestEventInfo.Technique << " and " << oper_ta.n() << " " << conf_info.OperTechnique << " tracks.\n"; -/* - // Get the pairs - get_genesis_pairs(conf_info.VxOpt[i], it->first, it->second, - best_ga, oper_ta, pairs); - - // Do the categorical verification - do_genesis_ctc(conf_info.VxOpt[i], pairs, ctc_info); - - // Write the statistics output - write_stats(pairs, ctc_info); - // Write NetCDF output fields - if(!conf_info.VxOpt[i].NcInfo.all_false()) { - write_nc(ctc_info); + // Loop over the probability of genesis events + for(k=0; ksecond.n_prob_gen(); k++) { + + // JHG search for a match! + // For now, just assume it's a hit. + // Also need to define SHC values. + bool dev_match = true; + bool ops_match = true; + + // Loop over the individual probabilities + for(l=0; lsecond.prob_gen(k).n_prob(); l++) { + + // Current lead time + prob_time = nint(model_it->second.prob_gen(k).prob_item(l)); + prob_value = model_it->second.prob_gen(k).prob(l) / 100.0; + + // Add a new map entries for this lead time, if necessary + if(!prob_times.has(prob_time)) { + prob_times.add(prob_time); + pct_dev_map[prob_time] = empty_pct; + pct_ops_map[prob_time] = empty_pct; + } + + // Increment counts + if(dev_match) pct_dev_map[prob_time].pct.inc_event (prob_value); + else pct_dev_map[prob_time].pct.inc_nonevent(prob_value); + if(ops_match) pct_ops_map[prob_time].pct.inc_event (prob_value); + else pct_ops_map[prob_time].pct.inc_nonevent(prob_value); + + } // end for l + } // end for k + + // Write probabilistic output + for(k=0; k 0 || stat_at.ncols() > 0) return; + // Check to see if the stat file stream has already been setup + bool init_from_scratch = (stat_out == (ofstream *) 0); - // Initialize file stream - stat_out = (ofstream *) 0; + // Get the maximum number of probability thresholds + n_prob = conf_info.get_max_n_prob_thresh(); - // Build the file name - stat_file << out_base << stat_file_ext; + // Compute the number of rows/cols needs for each file type + for(i=0, stat_rows=0, stat_cols=0; i Date: Thu, 11 Nov 2021 12:31:26 -0700 Subject: [PATCH 12/28] Per #1809, switch to consistently naming classes related to the probability of genesis as ProbGen rather than mixing it with GenProb, for consistency. Also define ProbGenPCTInfo class for storing PCTInfo. --- met/data/config/TCGenConfig_default | 4 +- met/src/basic/vx_config/config_constants.h | 2 +- met/src/tools/tc_utils/tc_gen/tc_gen.cc | 312 ++++++++++-------- met/src/tools/tc_utils/tc_gen/tc_gen.h | 2 + .../tools/tc_utils/tc_gen/tc_gen_conf_info.cc | 107 +++++- .../tools/tc_utils/tc_gen/tc_gen_conf_info.h | 37 ++- 6 files changed, 319 insertions(+), 145 deletions(-) diff --git a/met/data/config/TCGenConfig_default b/met/data/config/TCGenConfig_default index 0de6a27844..839d8bd21d 100644 --- a/met/data/config/TCGenConfig_default +++ b/met/data/config/TCGenConfig_default @@ -213,9 +213,9 @@ ops_method_flag = TRUE; //////////////////////////////////////////////////////////////////////////////// // -// Genesis probability thresholds +// Probability of genesis thresholds // -genesis_prob_thresh = ==0.25; +prob_genesis_thresh = ==0.25; // // Confidence interval alpha value diff --git a/met/src/basic/vx_config/config_constants.h b/met/src/basic/vx_config/config_constants.h index 3082eb69d7..01c598bd72 100644 --- a/met/src/basic/vx_config/config_constants.h +++ b/met/src/basic/vx_config/config_constants.h @@ -1097,7 +1097,7 @@ 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"; -static const char conf_key_genesis_prob_thresh[] = "genesis_prob_thresh"; +static const char conf_key_prob_genesis_thresh[] = "prob_genesis_thresh"; static const char conf_key_fcst_fy_oy[] = "fcst_fy_oy"; static const char conf_key_fcst_fy_on[] = "fcst_fy_on"; static const char conf_key_fcst_tracks[] = "fcst_tracks"; 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 f2a26967d8..dcbd87f7c6 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen.cc +++ b/met/src/tools/tc_utils/tc_gen/tc_gen.cc @@ -85,6 +85,11 @@ static void get_genesis_pairs (const TCGenVxOpt &, static void do_genesis_ctc (const TCGenVxOpt &, PairDataGenesis &, GenCTCInfo &); +static void do_probgen_pct (const TCGenVxOpt &, + const ProbInfoArray &, + const GenesisInfoArray &, + const TrackInfoArray &, + ProbGenPCTInfo &); static int find_genesis_match (const GenesisInfo &, const GenesisInfoArray &, @@ -97,7 +102,8 @@ static void setup_nc_file (); static void write_ctc_stats (const PairDataGenesis &, GenCTCInfo &); -static void write_pct_stats (int, PCTInfo &, PCTInfo &); +static void write_pct_stats (ProbGenPCTInfo &); + static void write_genmpr_row (StatHdrColumns &, const PairDataGenesis &, STATOutputType, @@ -271,7 +277,7 @@ void score_track_genesis(const GenesisInfoArray &best_ga, map model_ga_map; map::iterator it; PairDataGenesis pairs; - GenCTCInfo ctc_info; + GenCTCInfo genesis_ctc; // Get the list of genesis track files get_atcf_files(genesis_source, genesis_model_suffix, atcf_gen_reg_exp, @@ -323,14 +329,14 @@ void score_track_genesis(const GenesisInfoArray &best_ga, } // end for j - // Process the genesis events for each model. + // Process the genesis events for each model for(j=0,it=model_ga_map.begin(); it!=model_ga_map.end(); it++,j++) { // Initialize - ctc_info.clear(); - ctc_info.Model = it->first; - ctc_info.set_vx_opt(&conf_info.VxOpt[i], - &conf_info.NcOutGrid); + genesis_ctc.clear(); + genesis_ctc.Model = it->first; + genesis_ctc.set_vx_opt(&conf_info.VxOpt[i], + &conf_info.NcOutGrid); mlog << Debug(2) << "[Filter " << i+1 << " (" << conf_info.VxOpt[i].Desc @@ -346,14 +352,14 @@ void score_track_genesis(const GenesisInfoArray &best_ga, best_ga, oper_ta, pairs); // Do the categorical verification - do_genesis_ctc(conf_info.VxOpt[i], pairs, ctc_info); + do_genesis_ctc(conf_info.VxOpt[i], pairs, genesis_ctc); // Write the statistics output - write_ctc_stats(pairs, ctc_info); + write_ctc_stats(pairs, genesis_ctc); // Write NetCDF output fields if(!conf_info.VxOpt[i].NcInfo.all_false()) { - write_nc(ctc_info); + write_nc(genesis_ctc); } } // end for j @@ -367,16 +373,13 @@ void score_track_genesis(const GenesisInfoArray &best_ga, void score_genesis_prob(const GenesisInfoArray &best_ga, const TrackInfoArray &oper_ta) { - int i, j, k, l, prob_time; - double prob_value; - IntArray prob_times; + int i, j; StringArray edeck_files, edeck_files_model_suffix; ProbInfoArray fcst_pa, empty_pa; - ConcatString model, cs; + ConcatString model; map model_pa_map; - map::iterator model_it; - map pct_dev_map, pct_ops_map; - PCTInfo empty_pct; + map::iterator it; + ProbGenPCTInfo probgen_pct; // Get the list of EDECK files get_atcf_files(edeck_source, edeck_model_suffix, atcf_reg_exp, @@ -397,8 +400,8 @@ void score_genesis_prob(const GenesisInfoArray &best_ga, // Initialize model_pa_map.clear(); - // Subset the forecast genesis probabilities - // Organize them into a map by model name + // Organize the forecast genesis probabilities + // into a map by model name for(j=0; jfirst - << " model, comparing " << model_it->second.n_prob_gen() - << " genesis forecasts to " << best_ga.n() << " " + << ") " << ": Model " << j+1 << "] " << "For " << it->first + << " model, comparing " << it->second.n_prob_gen() + << " probability of genesis forecasts to " << best_ga.n() << " " << conf_info.BestEventInfo.Technique << " and " << oper_ta.n() << " " << conf_info.OperTechnique << " tracks.\n"; - // Loop over the probability of genesis events - for(k=0; ksecond.n_prob_gen(); k++) { - - // JHG search for a match! - // For now, just assume it's a hit. - // Also need to define SHC values. - bool dev_match = true; - bool ops_match = true; - - // Loop over the individual probabilities - for(l=0; lsecond.prob_gen(k).n_prob(); l++) { - - // Current lead time - prob_time = nint(model_it->second.prob_gen(k).prob_item(l)); - prob_value = model_it->second.prob_gen(k).prob(l) / 100.0; - - // Add a new map entries for this lead time, if necessary - if(!prob_times.has(prob_time)) { - prob_times.add(prob_time); - pct_dev_map[prob_time] = empty_pct; - pct_ops_map[prob_time] = empty_pct; - } - - // Increment counts - if(dev_match) pct_dev_map[prob_time].pct.inc_event (prob_value); - else pct_dev_map[prob_time].pct.inc_nonevent(prob_value); - if(ops_match) pct_ops_map[prob_time].pct.inc_event (prob_value); - else pct_ops_map[prob_time].pct.inc_nonevent(prob_value); - - } // end for l - } // end for k - - // Write probabilistic output - for(k=0; ksecond, + best_ga, oper_ta, probgen_pct); + + // Write the statistics output + write_pct_stats(probgen_pct); } // end for j - } // end for i n_vx + } // end for i return; } @@ -758,6 +718,51 @@ void do_genesis_ctc(const TCGenVxOpt &vx_opt, return; } +//////////////////////////////////////////////////////////////////////// + +void do_probgen_pct(const TCGenVxOpt &vx_opt, + const ProbInfoArray &model_pa, + const GenesisInfoArray &best_ga, + const TrackInfoArray &oper_ta, + ProbGenPCTInfo &pgi) { + int i, j, prob_lead; + double prob_value; + + // Initialize + pgi.clear(); + pgi.set_vx_opt(&vx_opt); + + // Score each of the probability forecasts + for(i=0; iDesc.c_str()); + shc.set_obtype(conf_info.BestEventInfo.Technique.c_str()); + shc.set_mask(pgi.VxOpt->VxMaskName.empty() ? + na_str : pgi.VxOpt->VxMaskName.c_str()); - if(conf_info.VxOpt[i_vx].DevFlag) { - write_pct_row(shc, pct_dev, - conf_info.VxOpt[i_vx].OutputMap[txt_file_type[i_pct]], - 1, 1, stat_at, i_stat_row, - txt_at[i_pct], i_txt_row[i_pct]); - } - if(conf_info.VxOpt[i_vx].OpsFlag) { - write_pct_row(shc, pct_ops, - conf_info.VxOpt[i_vx].OutputMap[txt_file_type[i_pct]], - 1, 1, stat_at, i_stat_row, - txt_at[i_pct], i_txt_row[i_pct]); - } - } + // Write results for each lead time + for(i=0; ioutput_map(stat_pct) != STATOutputType_None) { + + if(pgi.VxOpt->DevFlag) { + shc.set_fcst_var(probgen_dev_name); + shc.set_obs_var (probgen_dev_name); + write_pct_row(shc, pgi.PCTDev[lead_hr], + pgi.VxOpt->output_map(stat_pct), + 1, 1, stat_at, i_stat_row, + txt_at[i_pct], i_txt_row[i_pct]); + } + if(pgi.VxOpt->OpsFlag) { + shc.set_fcst_var(probgen_ops_name); + shc.set_obs_var (probgen_ops_name); + write_pct_row(shc, pgi.PCTOps[lead_hr], + pgi.VxOpt->output_map(stat_pct), + 1, 1, stat_at, i_stat_row, + txt_at[i_pct], i_txt_row[i_pct]); + } } - if(conf_info.VxOpt[i_vx].OpsFlag) { - pct_ops.compute_stats(); - pct_ops.compute_ci(); - write_pstd_row(shc, pct_ops, - conf_info.VxOpt[i_vx].OutputMap[txt_file_type[i_pstd]], - 1, 1, stat_at, i_stat_row, - txt_at[i_pstd], i_txt_row[i_pstd]); + + // Write PSTD output + if(pgi.VxOpt->output_map(stat_pstd) != STATOutputType_None) { + + if(pgi.VxOpt->DevFlag) { + pgi.PCTDev[lead_hr].compute_stats(); + pgi.PCTDev[lead_hr].compute_ci(); + shc.set_fcst_var(probgen_dev_name); + shc.set_obs_var (probgen_dev_name); + write_pstd_row(shc, pgi.PCTDev[lead_hr], + pgi.VxOpt->output_map(stat_pstd), + 1, 1, stat_at, i_stat_row, + txt_at[i_pstd], i_txt_row[i_pstd]); + } + if(pgi.VxOpt->OpsFlag) { + pgi.PCTOps[lead_hr].compute_stats(); + pgi.PCTOps[lead_hr].compute_ci(); + shc.set_fcst_var(probgen_ops_name); + shc.set_obs_var (probgen_ops_name); + write_pstd_row(shc, pgi.PCTOps[lead_hr], + pgi.VxOpt->output_map(stat_pstd) , + 1, 1, stat_at, i_stat_row, + txt_at[i_pstd], i_txt_row[i_pstd]); + } } - } - // Write PJC output - if(conf_info.VxOpt[i_vx].OutputMap[txt_file_type[i_pjc]] != STATOutputType_None) { + // Write PJC output + if(pgi.VxOpt->output_map(stat_pjc) != STATOutputType_None) { - if(conf_info.VxOpt[i_vx].DevFlag) { - write_pct_row(shc, pct_dev, - conf_info.VxOpt[i_vx].OutputMap[txt_file_type[i_pjc]], - 1, 1, stat_at, i_stat_row, - txt_at[i_pjc], i_txt_row[i_pjc]); - } - if(conf_info.VxOpt[i_vx].OpsFlag) { - write_pct_row(shc, pct_ops, - conf_info.VxOpt[i_vx].OutputMap[txt_file_type[i_pjc]], - 1, 1, stat_at, i_stat_row, - txt_at[i_pjc], i_txt_row[i_pjc]); + if(pgi.VxOpt->DevFlag) { + shc.set_fcst_var(probgen_dev_name); + shc.set_obs_var (probgen_dev_name); + write_pct_row(shc, pgi.PCTDev[lead_hr], + pgi.VxOpt->output_map(stat_pjc), + 1, 1, stat_at, i_stat_row, + txt_at[i_pjc], i_txt_row[i_pjc]); + } + if(pgi.VxOpt->OpsFlag) { + shc.set_fcst_var(probgen_ops_name); + shc.set_obs_var (probgen_ops_name); + write_pct_row(shc, pgi.PCTOps[lead_hr], + pgi.VxOpt->output_map(stat_pjc), + 1, 1, stat_at, i_stat_row, + txt_at[i_pjc], i_txt_row[i_pjc]); + } } - } - // Write PRC output - if(conf_info.VxOpt[i_vx].OutputMap[txt_file_type[i_pjc]] != STATOutputType_None) { + // Write PRC output + if(pgi.VxOpt->output_map(stat_pjc) != STATOutputType_None) { - if(conf_info.VxOpt[i_vx].DevFlag) { - write_pct_row(shc, pct_dev, - conf_info.VxOpt[i_vx].OutputMap[txt_file_type[i_prc]], - 1, 1, stat_at, i_stat_row, - txt_at[i_prc], i_txt_row[i_prc]); - } - if(conf_info.VxOpt[i_vx].OpsFlag) { - write_pct_row(shc, pct_ops, - conf_info.VxOpt[i_vx].OutputMap[txt_file_type[i_prc]], - 1, 1, stat_at, i_stat_row, - txt_at[i_prc], i_txt_row[i_prc]); + if(pgi.VxOpt->DevFlag) { + shc.set_fcst_var(probgen_dev_name); + shc.set_obs_var (probgen_dev_name); + write_pct_row(shc, pgi.PCTDev[lead_hr], + pgi.VxOpt->output_map(stat_pjc), + 1, 1, stat_at, i_stat_row, + txt_at[i_prc], i_txt_row[i_prc]); + } + if(pgi.VxOpt->OpsFlag) { + shc.set_fcst_var(probgen_ops_name); + shc.set_obs_var (probgen_ops_name); + write_pct_row(shc, pgi.PCTOps[lead_hr], + pgi.VxOpt->output_map(stat_pjc), + 1, 1, stat_at, i_stat_row, + txt_at[i_prc], i_txt_row[i_prc]); + } } - } + } // end for i return; } 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 fc2ce357eb..085b2a7cf8 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen.h +++ b/met/src/tools/tc_utils/tc_gen/tc_gen.h @@ -80,6 +80,8 @@ static const char *txt_file_abbr[n_txt] = { const ConcatString genesis_name ("GENESIS"); const ConcatString genesis_dev_name("GENESIS_DEV"); const ConcatString genesis_ops_name("GENESIS_OPS"); +const ConcatString probgen_dev_name("PROBGEN_DEV"); +const ConcatString probgen_ops_name("PROBGEN_OPS"); // Maximum Best track cyclone number to be processed // Cyclone numbers > 50 are for testing or invests 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 ee3b30679a..389bf5d603 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 @@ -164,7 +164,7 @@ void TCGenVxOpt::clear() { OpsHitBeg = OpsHitEnd = bad_data_int; DiscardFlag = false; DevFlag = OpsFlag = false; - GenProbThresh.clear(); + ProbGenThresh.clear(); CIAlpha = bad_data_double; OutputMap.clear(); NcInfo.clear(); @@ -290,10 +290,10 @@ void TCGenVxOpt::process_config(Dictionary &dict) { exit(1); } - // Conf: genesis_prob_thresh - GenProbThresh = dict.lookup_thresh_array(conf_key_genesis_prob_thresh); - GenProbThresh = string_to_prob_thresh(GenProbThresh.get_str().c_str()); - check_prob_thresh(GenProbThresh); + // Conf: prob_genesis_thresh + ProbGenThresh = dict.lookup_thresh_array(conf_key_prob_genesis_thresh); + ProbGenThresh = string_to_prob_thresh(ProbGenThresh.get_str().c_str()); + check_prob_thresh(ProbGenThresh); // Conf: ci_alpha CIAlpha = dict.lookup_double(conf_key_ci_alpha); @@ -891,13 +891,12 @@ int TCGenConfInfo::get_max_n_prob_thresh() const { int i, n; for(i=0,n=0; iValidGenesisDHrThresh; + + // Setup the default PCTInfo object + DefaultPCT.set_fthresh(VxOpt->ProbGenThresh); + DefaultPCT.allocate_n_alpha(1); + DefaultPCT.alpha[0] = VxOpt->CIAlpha; + + return; +} + +//////////////////////////////////////////////////////////////////////// + +void ProbGenPCTInfo::add(const ProbGenInfo &pgi) { + int i, lead_hr; + + // Store the model name + if(Model.empty()) Model = pgi.technique(); + + // Track the range of valid times + if(InitBeg == 0 || InitBeg > pgi.init()) InitBeg = pgi.init(); + if(InitEnd == 0 || InitEnd < pgi.init()) InitEnd = pgi.init(); + + // Add new map entry for each lead time, if needed + for(i=0; i OutputMap; TCGenNcOutInfo NcInfo; @@ -315,6 +315,41 @@ class GenCTCInfo { //////////////////////////////////////////////////////////////////////// +class ProbGenPCTInfo { + + private: + + void init_from_scratch(); + + PCTInfo DefaultPCT; + + public: + + ProbGenPCTInfo(); + ~ProbGenPCTInfo(); + + ////////////////////////////////////////////////////////////////// + + ConcatString Model; + unixtime InitBeg, InitEnd; + const TCGenVxOpt* VxOpt; + IntArray LeadTimes; + map PCTDev, PCTOps; + + SingleThresh ValidGenesisDHrThresh; + + ////////////////////////////////////////////////////////////////// + + void clear(); + + void set_vx_opt(const TCGenVxOpt *); + + void add(const ProbGenInfo &); + +}; + +//////////////////////////////////////////////////////////////////////// + #endif /* __TC_GEN_CONF_INFO_H__ */ //////////////////////////////////////////////////////////////////////// From aa858f3f45d0b268d6f88496759fab0e5ec1c345 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 12 Nov 2021 10:32:41 -0700 Subject: [PATCH 13/28] Per #1809, saving off the current state of development before proceeding with changes to simplify the matching logic. --- met/src/libcode/vx_tc_util/prob_gen_info.cc | 24 ++++ met/src/libcode/vx_tc_util/prob_gen_info.h | 8 +- met/src/tools/tc_utils/tc_gen/tc_gen.cc | 128 +++++++++++++++++++- met/src/tools/tc_utils/tc_pairs/Makefile.am | 1 + 4 files changed, 154 insertions(+), 7 deletions(-) diff --git a/met/src/libcode/vx_tc_util/prob_gen_info.cc b/met/src/libcode/vx_tc_util/prob_gen_info.cc index 863fc90bc1..e292ce897a 100644 --- a/met/src/libcode/vx_tc_util/prob_gen_info.cc +++ b/met/src/libcode/vx_tc_util/prob_gen_info.cc @@ -17,6 +17,8 @@ using namespace std; #include #include +#include "nav.h" + #include "prob_gen_info.h" #include "atcf_offsets.h" @@ -201,3 +203,25 @@ bool ProbGenInfo::add(const ATCFProbLine &l, double dland, bool check_dup) { } //////////////////////////////////////////////////////////////////////// + +bool ProbGenInfo::is_match(const TrackPoint &p, const double rad, + const int beg, const int end) const { + + // Check for matching in time and space + return(p.valid() >= (GenTime + beg) && + p.valid() <= (GenTime + end) && + gc_dist(Lat, Lon, p.lat(), p.lon()) <= rad); +} + +//////////////////////////////////////////////////////////////////////// + +bool ProbGenInfo::is_match(const GenesisInfo &gi, const double rad, + const int beg, const int end) const { + + // 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/prob_gen_info.h b/met/src/libcode/vx_tc_util/prob_gen_info.h index 1ce3dc10d5..49a6534ea1 100644 --- a/met/src/libcode/vx_tc_util/prob_gen_info.h +++ b/met/src/libcode/vx_tc_util/prob_gen_info.h @@ -16,6 +16,7 @@ #include #include "prob_info_base.h" +#include "genesis_info.h" #include "vx_util.h" @@ -69,7 +70,12 @@ class ProbGenInfo : public ProbInfoBase { void initialize(const ATCFProbLine &, double); bool is_match (const ATCFProbLine &) const; bool add (const ATCFProbLine &, double, bool check_dup = false); - + + 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 dcbd87f7c6..eb65f75ec5 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen.cc +++ b/met/src/tools/tc_utils/tc_gen/tc_gen.cc @@ -95,6 +95,10 @@ static int find_genesis_match (const GenesisInfo &, const GenesisInfoArray &, const TrackInfoArray &, bool, double, int, int); +static int find_probgen_match (const ProbGenInfo &, + const GenesisInfoArray &, + const TrackInfoArray &, + bool, double, int, int); static void setup_txt_files (int, int); static void setup_table (AsciiTable &); @@ -725,8 +729,9 @@ void do_probgen_pct(const TCGenVxOpt &vx_opt, const GenesisInfoArray &best_ga, const TrackInfoArray &oper_ta, ProbGenPCTInfo &pgi) { - int i, j, prob_lead; + int i, j, i_bga, prob_lead; double prob_value; + bool dev_match, ops_match; // Initialize pgi.clear(); @@ -738,11 +743,12 @@ void do_probgen_pct(const TCGenVxOpt &vx_opt, // Store info about each probability of genesis forecast pgi.add(model_pa.prob_gen(i)); - // JHG search for a match! - // For now, just assume it's a hit. - // Also need to define SHC values. - bool dev_match = true; - bool ops_match = true; + // Search for a BEST track match + i_bga = find_probgen_match(model_pa.prob_gen(i), best_ga, oper_ta, + vx_opt.GenesisMatchPointTrack, + vx_opt.GenesisMatchRadius, + vx_opt.GenesisMatchBeg, + vx_opt.GenesisMatchEnd); // Loop over the individual probabilities for(j=0; j 6) { + mlog << Debug(6) << best_ga.serialize_r() << "\n"; + } + // Dump out track info + else { + for(i=0; i Date: Fri, 12 Nov 2021 13:17:47 -0700 Subject: [PATCH 14/28] Per #1809, keep track of the min/max BEST track genesis times, and we only need 1 PCT table, not two. --- .../tools/tc_utils/tc_gen/tc_gen_conf_info.cc | 21 ++++++++++--------- .../tools/tc_utils/tc_gen/tc_gen_conf_info.h | 5 ++--- 2 files changed, 13 insertions(+), 13 deletions(-) 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 389bf5d603..2294b99fdb 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 @@ -1243,15 +1243,13 @@ void ProbGenPCTInfo::clear() { Model.clear(); InitBeg = InitEnd = (unixtime) 0; + BestBeg = BestEnd = (unixtime) 0; - PCTDev.clear(); - PCTOps.clear(); + PCT.clear(); VxOpt = (const TCGenVxOpt *) 0; LeadTimes.clear(); - ValidGenesisDHrThresh.clear(); - return; } @@ -1264,9 +1262,6 @@ void ProbGenPCTInfo::set_vx_opt(const TCGenVxOpt *vx_opt) { // Store pointer VxOpt = vx_opt; - // Store config options - ValidGenesisDHrThresh = VxOpt->ValidGenesisDHrThresh; - // Setup the default PCTInfo object DefaultPCT.set_fthresh(VxOpt->ProbGenThresh); DefaultPCT.allocate_n_alpha(1); @@ -1283,10 +1278,17 @@ void ProbGenPCTInfo::add(const ProbGenInfo &pgi) { // Store the model name if(Model.empty()) Model = pgi.technique(); - // Track the range of valid times + // Track the range of forecast initalization times if(InitBeg == 0 || InitBeg > pgi.init()) InitBeg = pgi.init(); if(InitEnd == 0 || InitEnd < pgi.init()) InitEnd = pgi.init(); + // Track the range of verifying BEST genesis events + if(pgi.best_gen()) { + unixtime ut = pgi.best_gen()->genesis_time(); + if(BestBeg == 0 || BestBeg > ut) BestBeg = ut; + if(BestEnd == 0 || BestEnd < ut) BestEnd = ut; + } + // Add new map entry for each lead time, if needed for(i=0; i PCTDev, PCTOps; - - SingleThresh ValidGenesisDHrThresh; + map PCT; ////////////////////////////////////////////////////////////////// From 3b0a2df1e8c4d73d59ee12cfaf47bde5799ba80a Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 12 Nov 2021 13:18:30 -0700 Subject: [PATCH 15/28] Per #1809, make access to ProbGenInfoArray elements non-constant so that the tc-gen application can modify their contents. --- met/src/libcode/vx_tc_util/prob_info_array.cc | 4 ++-- met/src/libcode/vx_tc_util/prob_info_array.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/met/src/libcode/vx_tc_util/prob_info_array.cc b/met/src/libcode/vx_tc_util/prob_info_array.cc index 26abc5213a..64809049ec 100644 --- a/met/src/libcode/vx_tc_util/prob_info_array.cc +++ b/met/src/libcode/vx_tc_util/prob_info_array.cc @@ -181,7 +181,7 @@ const ProbInfoBase * ProbInfoArray::operator[](int n) const { //////////////////////////////////////////////////////////////////////// -const ProbRIRWInfo & ProbInfoArray::prob_rirw(int n) const { +ProbRIRWInfo & ProbInfoArray::prob_rirw(int n) { // Check range if((n < 0) || (n >= (int) ProbRIRW.size())) { @@ -195,7 +195,7 @@ const ProbRIRWInfo & ProbInfoArray::prob_rirw(int n) const { //////////////////////////////////////////////////////////////////////// -const ProbGenInfo & ProbInfoArray::prob_gen(int n) const { +ProbGenInfo & ProbInfoArray::prob_gen(int n) { // Check range if((n < 0) || (n >= (int) ProbGen.size())) { diff --git a/met/src/libcode/vx_tc_util/prob_info_array.h b/met/src/libcode/vx_tc_util/prob_info_array.h index 016073d412..881cf3dcfb 100644 --- a/met/src/libcode/vx_tc_util/prob_info_array.h +++ b/met/src/libcode/vx_tc_util/prob_info_array.h @@ -60,10 +60,10 @@ class ProbInfoArray { const ProbInfoBase * operator[](int) const; int n_prob_rirw() const; - const ProbRIRWInfo & prob_rirw(int) const; + ProbRIRWInfo & prob_rirw(int); int n_prob_gen() const; - const ProbGenInfo & prob_gen(int) const; + ProbGenInfo & prob_gen(int); int n_technique() const; From 42d6faded9e434341a70c4f001207d6239ff7ebe Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 12 Nov 2021 13:19:11 -0700 Subject: [PATCH 16/28] Per #1809, Update the ProbGenInfo class to store a pointer to the matching Best Genesis event. --- met/src/libcode/vx_tc_util/prob_gen_info.cc | 23 ++++++++++++++++++--- met/src/libcode/vx_tc_util/prob_gen_info.h | 7 +++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/met/src/libcode/vx_tc_util/prob_gen_info.cc b/met/src/libcode/vx_tc_util/prob_gen_info.cc index e292ce897a..77ef2b9007 100644 --- a/met/src/libcode/vx_tc_util/prob_gen_info.cc +++ b/met/src/libcode/vx_tc_util/prob_gen_info.cc @@ -79,6 +79,8 @@ void ProbGenInfo::clear() { GenOrDis.clear(); GenTime = (unixtime) 0; + BestGen = (const GenesisInfo *) 0; + return; } @@ -92,6 +94,7 @@ void ProbGenInfo::dump(ostream &out, int indent_depth) const { out << prefix << "Initials = \"" << Initials.contents() << "\"\n"; out << prefix << "GenOrDis = \"" << GenOrDis.contents() << "\"\n"; out << prefix << "GenTime = " << unix_to_yyyymmdd_hhmmss(GenTime) << "\n"; + out << prefix << "BestGen = " << (BestGen ? "set" : "(nul)") << "\n"; out << flush; @@ -108,7 +111,8 @@ ConcatString ProbGenInfo::serialize() const { << ", ProbGenInfo: " << "Initials = \"" << Initials << "\"" << ", GenOrDis = \"" << GenOrDis << "\"" - << ", GenTime = " << unix_to_yyyymmdd_hhmmss(GenTime) << "\n"; + << ", GenTime = " << unix_to_yyyymmdd_hhmmss(GenTime) + << ", BestGen = " << (BestGen ? "set" : "(nul)") << "\n"; return(s); } @@ -135,6 +139,17 @@ void ProbGenInfo::assign(const ProbGenInfo &p) { GenOrDis = p.GenOrDis; GenTime = p.GenTime; + BestGen = p.BestGen; + + return; +} + +//////////////////////////////////////////////////////////////////////// + +void ProbGenInfo::set_best_gen(const GenesisInfo *bg) { + + BestGen = bg; + return; } @@ -146,14 +161,16 @@ void ProbGenInfo::initialize(const ATCFProbLine &l, double dland) { ProbInfoBase::initialize(l, dland); - Initials = l.get_item(ProbGenInitialsOffset); - GenOrDis = l.get_item(ProbGenOrDisOffset); + Initials = l.get_item(ProbGenInitialsOffset); + GenOrDis = l.get_item(ProbGenOrDisOffset); // Store an empty string as unixtime 0 GenTime = (l.get_item(ProbGenTimeOffset).empty() ? (unixtime) 0 : parse_time(l.get_item(ProbGenTimeOffset).c_str())); + BestGen = (const GenesisInfo *) 0; + return; } diff --git a/met/src/libcode/vx_tc_util/prob_gen_info.h b/met/src/libcode/vx_tc_util/prob_gen_info.h index 49a6534ea1..7ee0d75eb8 100644 --- a/met/src/libcode/vx_tc_util/prob_gen_info.h +++ b/met/src/libcode/vx_tc_util/prob_gen_info.h @@ -38,6 +38,9 @@ class ProbGenInfo : public ProbInfoBase { ConcatString GenOrDis; unixtime GenTime; + // Pointer to the matching BEST genesis event + const GenesisInfo * BestGen; + public: ProbGenInfo(); @@ -55,6 +58,8 @@ class ProbGenInfo : public ProbInfoBase { // set stuff // + void set_best_gen(const GenesisInfo *); + // // get stuff // @@ -62,6 +67,7 @@ class ProbGenInfo : public ProbInfoBase { const ConcatString & initials() const; const ConcatString & gen_or_dis() const; unixtime gen_time() const; + const GenesisInfo * best_gen() const; // // do stuff @@ -83,6 +89,7 @@ class ProbGenInfo : public ProbInfoBase { inline const ConcatString & ProbGenInfo::initials() const { return(Initials); } inline const ConcatString & ProbGenInfo::gen_or_dis() const { return(GenOrDis); } inline unixtime ProbGenInfo::gen_time() const { return(GenTime); } +inline const GenesisInfo * ProbGenInfo::best_gen() const { return(BestGen); } //////////////////////////////////////////////////////////////////////// From 5c2575e685d7a53a53e7e927e47c4a68f8496c1d Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 12 Nov 2021 13:20:15 -0700 Subject: [PATCH 17/28] Per #1809, this is a good stopping point. I have tc-gen accurately verifying genesis probabilities. Still need to add a probgen_mpr line type, a unit test, and documentaiton. --- met/src/tools/tc_utils/tc_gen/tc_gen.cc | 158 +++++++++--------------- met/src/tools/tc_utils/tc_gen/tc_gen.h | 3 +- 2 files changed, 56 insertions(+), 105 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 eb65f75ec5..a7098872a6 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen.cc +++ b/met/src/tools/tc_utils/tc_gen/tc_gen.cc @@ -86,7 +86,7 @@ static void do_genesis_ctc (const TCGenVxOpt &, PairDataGenesis &, GenCTCInfo &); static void do_probgen_pct (const TCGenVxOpt &, - const ProbInfoArray &, + ProbInfoArray &, const GenesisInfoArray &, const TrackInfoArray &, ProbGenPCTInfo &); @@ -95,7 +95,7 @@ static int find_genesis_match (const GenesisInfo &, const GenesisInfoArray &, const TrackInfoArray &, bool, double, int, int); -static int find_probgen_match (const ProbGenInfo &, +static void find_probgen_match (ProbGenInfo &, const GenesisInfoArray &, const TrackInfoArray &, bool, double, int, int); @@ -725,13 +725,13 @@ void do_genesis_ctc(const TCGenVxOpt &vx_opt, //////////////////////////////////////////////////////////////////////// void do_probgen_pct(const TCGenVxOpt &vx_opt, - const ProbInfoArray &model_pa, + ProbInfoArray &model_pa, const GenesisInfoArray &best_ga, const TrackInfoArray &oper_ta, ProbGenPCTInfo &pgi) { - int i, j, i_bga, prob_lead; + int i, j, prob_lead, time_diff; double prob_value; - bool dev_match, ops_match; + bool is_event; // Initialize pgi.clear(); @@ -740,36 +740,36 @@ void do_probgen_pct(const TCGenVxOpt &vx_opt, // Score each of the probability forecasts for(i=0; igenesis_time() - + model_pa.prob_gen(i).init(); + is_event = time_diff >= 0 && + time_diff <= (prob_lead * sec_per_hour); } - // Otherwise, check the time window else { - dev_match = ops_match = true; + is_event = false; } // Increment counts - if(dev_match) pgi.PCTDev[prob_lead].pct.inc_event (prob_value); - else pgi.PCTDev[prob_lead].pct.inc_nonevent(prob_value); - if(ops_match) pgi.PCTOps[prob_lead].pct.inc_event (prob_value); - else pgi.PCTOps[prob_lead].pct.inc_nonevent(prob_value); + if(is_event) pgi.PCT[prob_lead].pct.inc_event (prob_value); + else pgi.PCT[prob_lead].pct.inc_nonevent(prob_value); } // end for j } // end for i @@ -868,11 +868,11 @@ int find_genesis_match(const GenesisInfo &fcst_gi, //////////////////////////////////////////////////////////////////////// -int find_probgen_match(const ProbGenInfo &prob_gi, - const GenesisInfoArray &bga, - const TrackInfoArray &ota, - bool point2track, double rad, - int beg, int end) { +void find_probgen_match(ProbGenInfo &prob_gi, + const GenesisInfoArray &bga, + const TrackInfoArray &ota, + bool point2track, double rad, + int beg, int end) { int i, j, i_best, i_oper; ConcatString case_cs; @@ -950,7 +950,11 @@ int find_probgen_match(const ProbGenInfo &prob_gi, << " has NO MATCH in the BEST or operational tracks.\n"; } - return(i_best); + // Store a pointer to the match + if(!is_bad_data(i_best)) prob_gi.set_best_gen(&bga[i_best]); + else prob_gi.set_best_gen((GenesisInfo *) 0); + + return; } @@ -1378,12 +1382,12 @@ void setup_txt_files(int n_model, int n_pair) { break; // Nx2 probabilistic contingency table output: - // 1 header + 2 vx methods * 3 leads * # models * # filters + // 1 header + 1 vx method * 3 leads * # models * # filters case(i_pct): case(i_pstd): case(i_pjc): case(i_prc): - n_rows = 1 + 2 * 3 * n_model * conf_info.n_vx(); + n_rows = 1 * 3 * n_model * conf_info.n_vx(); break; // For stat_genmpr: @@ -1680,6 +1684,8 @@ void write_pct_stats(ProbGenPCTInfo &pgi) { shc.set_obtype(conf_info.BestEventInfo.Technique.c_str()); shc.set_mask(pgi.VxOpt->VxMaskName.empty() ? na_str : pgi.VxOpt->VxMaskName.c_str()); + shc.set_fcst_var(probgenesis_name); + shc.set_obs_var (probgenesis_name); // Write results for each lead time for(i=0; ioutput_map(stat_pct) != STATOutputType_None) { - - if(pgi.VxOpt->DevFlag) { - shc.set_fcst_var(probgen_dev_name); - shc.set_obs_var (probgen_dev_name); - write_pct_row(shc, pgi.PCTDev[lead_hr], - pgi.VxOpt->output_map(stat_pct), - 1, 1, stat_at, i_stat_row, - txt_at[i_pct], i_txt_row[i_pct]); - } - if(pgi.VxOpt->OpsFlag) { - shc.set_fcst_var(probgen_ops_name); - shc.set_obs_var (probgen_ops_name); - write_pct_row(shc, pgi.PCTOps[lead_hr], - pgi.VxOpt->output_map(stat_pct), - 1, 1, stat_at, i_stat_row, - txt_at[i_pct], i_txt_row[i_pct]); - } + write_pct_row(shc, pgi.PCT[lead_hr], + pgi.VxOpt->output_map(stat_pct), + 1, 1, stat_at, i_stat_row, + txt_at[i_pct], i_txt_row[i_pct]); } // Write PSTD output if(pgi.VxOpt->output_map(stat_pstd) != STATOutputType_None) { - - if(pgi.VxOpt->DevFlag) { - pgi.PCTDev[lead_hr].compute_stats(); - pgi.PCTDev[lead_hr].compute_ci(); - shc.set_fcst_var(probgen_dev_name); - shc.set_obs_var (probgen_dev_name); - write_pstd_row(shc, pgi.PCTDev[lead_hr], - pgi.VxOpt->output_map(stat_pstd), - 1, 1, stat_at, i_stat_row, - txt_at[i_pstd], i_txt_row[i_pstd]); - } - if(pgi.VxOpt->OpsFlag) { - pgi.PCTOps[lead_hr].compute_stats(); - pgi.PCTOps[lead_hr].compute_ci(); - shc.set_fcst_var(probgen_ops_name); - shc.set_obs_var (probgen_ops_name); - write_pstd_row(shc, pgi.PCTOps[lead_hr], - pgi.VxOpt->output_map(stat_pstd) , - 1, 1, stat_at, i_stat_row, - txt_at[i_pstd], i_txt_row[i_pstd]); - } + pgi.PCT[lead_hr].compute_stats(); + pgi.PCT[lead_hr].compute_ci(); + write_pstd_row(shc, pgi.PCT[lead_hr], + pgi.VxOpt->output_map(stat_pstd), + 1, 1, stat_at, i_stat_row, + txt_at[i_pstd], i_txt_row[i_pstd]); } // Write PJC output if(pgi.VxOpt->output_map(stat_pjc) != STATOutputType_None) { - - if(pgi.VxOpt->DevFlag) { - shc.set_fcst_var(probgen_dev_name); - shc.set_obs_var (probgen_dev_name); - write_pct_row(shc, pgi.PCTDev[lead_hr], - pgi.VxOpt->output_map(stat_pjc), - 1, 1, stat_at, i_stat_row, - txt_at[i_pjc], i_txt_row[i_pjc]); - } - if(pgi.VxOpt->OpsFlag) { - shc.set_fcst_var(probgen_ops_name); - shc.set_obs_var (probgen_ops_name); - write_pct_row(shc, pgi.PCTOps[lead_hr], - pgi.VxOpt->output_map(stat_pjc), - 1, 1, stat_at, i_stat_row, - txt_at[i_pjc], i_txt_row[i_pjc]); - } + write_pct_row(shc, pgi.PCT[lead_hr], + pgi.VxOpt->output_map(stat_pjc), + 1, 1, stat_at, i_stat_row, + txt_at[i_pjc], i_txt_row[i_pjc]); } // Write PRC output if(pgi.VxOpt->output_map(stat_pjc) != STATOutputType_None) { - - if(pgi.VxOpt->DevFlag) { - shc.set_fcst_var(probgen_dev_name); - shc.set_obs_var (probgen_dev_name); - write_pct_row(shc, pgi.PCTDev[lead_hr], - pgi.VxOpt->output_map(stat_pjc), - 1, 1, stat_at, i_stat_row, - txt_at[i_prc], i_txt_row[i_prc]); - } - if(pgi.VxOpt->OpsFlag) { - shc.set_fcst_var(probgen_ops_name); - shc.set_obs_var (probgen_ops_name); - write_pct_row(shc, pgi.PCTOps[lead_hr], - pgi.VxOpt->output_map(stat_pjc), - 1, 1, stat_at, i_stat_row, - txt_at[i_prc], i_txt_row[i_prc]); - } + write_pct_row(shc, pgi.PCT[lead_hr], + pgi.VxOpt->output_map(stat_pjc), + 1, 1, stat_at, i_stat_row, + txt_at[i_prc], i_txt_row[i_prc]); } } // end for i 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 085b2a7cf8..fd9e69a5c1 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen.h +++ b/met/src/tools/tc_utils/tc_gen/tc_gen.h @@ -80,8 +80,7 @@ static const char *txt_file_abbr[n_txt] = { const ConcatString genesis_name ("GENESIS"); const ConcatString genesis_dev_name("GENESIS_DEV"); const ConcatString genesis_ops_name("GENESIS_OPS"); -const ConcatString probgen_dev_name("PROBGEN_DEV"); -const ConcatString probgen_ops_name("PROBGEN_OPS"); +const ConcatString probgenesis_name("PROBGENESIS"); // Maximum Best track cyclone number to be processed // Cyclone numbers > 50 are for testing or invests From bfbf5707a0a1a9e5c66af8982e95b22454db9c00 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 12 Nov 2021 14:06:40 -0700 Subject: [PATCH 18/28] Per #1809, have to link to vx_nav to call gc_dist(). --- met/internal_tests/libcode/vx_tc_util/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/met/internal_tests/libcode/vx_tc_util/Makefile.am b/met/internal_tests/libcode/vx_tc_util/Makefile.am index a5fc96c5d0..a1d0fed6c5 100644 --- a/met/internal_tests/libcode/vx_tc_util/Makefile.am +++ b/met/internal_tests/libcode/vx_tc_util/Makefile.am @@ -43,6 +43,7 @@ test_read_LDADD = -lvx_stat_out \ -lvx_config \ -lvx_gsl_prob \ -lvx_cal \ + -lvx_nav \ -lvx_util \ -lvx_math \ -lvx_color \ @@ -75,6 +76,7 @@ test_read_prob_LDADD = -lvx_stat_out \ -lvx_config \ -lvx_gsl_prob \ -lvx_cal \ + -lvx_nav \ -lvx_util \ -lvx_math \ -lvx_color \ From d9f438209d2b97a8c67c4802d29b383cb5a59e8e Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Sat, 13 Nov 2021 10:16:05 -0700 Subject: [PATCH 19/28] Per #1809, add PROB_LEAD and PROB_VAL to the GENMPR line type. --- met/data/table_files/met_header_columns_V10.1.txt | 2 +- test/hdr/met_10_1.hdr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/met/data/table_files/met_header_columns_V10.1.txt b/met/data/table_files/met_header_columns_V10.1.txt index c0218275ec..1dbd3c2849 100644 --- a/met/data/table_files/met_header_columns_V10.1.txt +++ b/met/data/table_files/met_header_columns_V10.1.txt @@ -28,7 +28,7 @@ V10.1 : STAT : SSVAR : VERSION MODEL DESC FCST_LEAD FCST_VALID_BEG FCST_VALID V10.1 : STAT : VAL1L2 : VERSION MODEL DESC FCST_LEAD FCST_VALID_BEG FCST_VALID_END OBS_LEAD OBS_VALID_BEG OBS_VALID_END FCST_VAR FCST_UNITS FCST_LEV OBS_VAR OBS_UNITS OBS_LEV OBTYPE VX_MASK INTERP_MTHD INTERP_PNTS FCST_THRESH OBS_THRESH COV_THRESH ALPHA LINE_TYPE TOTAL UFABAR VFABAR UOABAR VOABAR UVFOABAR UVFFABAR UVOOABAR V10.1 : STAT : VL1L2 : VERSION MODEL DESC FCST_LEAD FCST_VALID_BEG FCST_VALID_END OBS_LEAD OBS_VALID_BEG OBS_VALID_END FCST_VAR FCST_UNITS FCST_LEV OBS_VAR OBS_UNITS OBS_LEV OBTYPE VX_MASK INTERP_MTHD INTERP_PNTS FCST_THRESH OBS_THRESH COV_THRESH ALPHA LINE_TYPE TOTAL UFBAR VFBAR UOBAR VOBAR UVFOBAR UVFFBAR UVOOBAR F_SPEED_BAR O_SPEED_BAR V10.1 : STAT : VCNT : VERSION MODEL DESC FCST_LEAD FCST_VALID_BEG FCST_VALID_END OBS_LEAD OBS_VALID_BEG OBS_VALID_END FCST_VAR FCST_UNITS FCST_LEV OBS_VAR OBS_UNITS OBS_LEV OBTYPE VX_MASK INTERP_MTHD INTERP_PNTS FCST_THRESH OBS_THRESH COV_THRESH ALPHA LINE_TYPE TOTAL FBAR FBAR_BCL FBAR_BCU OBAR OBAR_BCL OBAR_BCU FS_RMS FS_RMS_BCL FS_RMS_BCU OS_RMS OS_RMS_BCL OS_RMS_BCU MSVE MSVE_BCL MSVE_BCU RMSVE RMSVE_BCL RMSVE_BCU FSTDEV FSTDEV_BCL FSTDEV_BCU OSTDEV OSTDEV_BCL OSTDEV_BCU FDIR FDIR_BCL FDIR_BCU ODIR ODIR_BCL ODIR_BCU FBAR_SPEED FBAR_SPEED_BCL FBAR_SPEED_BCU OBAR_SPEED OBAR_SPEED_BCL OBAR_SPEED_BCU VDIFF_SPEED VDIFF_SPEED_BCL VDIFF_SPEED_BCU VDIFF_DIR VDIFF_DIR_BCL VDIFF_DIR_BCU SPEED_ERR SPEED_ERR_BCL SPEED_ERR_BCU SPEED_ABSERR SPEED_ABSERR_BCL SPEED_ABSERR_BCU DIR_ERR DIR_ERR_BCL DIR_ERR_BCU DIR_ABSERR DIR_ABSERR_BCL DIR_ABSERR_BCU -V10.1 : STAT : GENMPR : VERSION MODEL DESC FCST_LEAD FCST_VALID_BEG FCST_VALID_END OBS_LEAD OBS_VALID_BEG OBS_VALID_END FCST_VAR FCST_UNITS FCST_LEV OBS_VAR OBS_UNITS OBS_LEV OBTYPE VX_MASK INTERP_MTHD INTERP_PNTS FCST_THRESH OBS_THRESH COV_THRESH ALPHA LINE_TYPE TOTAL INDEX STORM_ID AGEN_INIT AGEN_FHR AGEN_LAT AGEN_LON AGEN_DLAND BGEN_LAT BGEN_LON BGEN_DLAND GEN_DIST GEN_TDIFF INIT_TDIFF DEV_CAT OPS_CAT +V10.1 : STAT : GENMPR : VERSION MODEL DESC FCST_LEAD FCST_VALID_BEG FCST_VALID_END OBS_LEAD OBS_VALID_BEG OBS_VALID_END FCST_VAR FCST_UNITS FCST_LEV OBS_VAR OBS_UNITS OBS_LEV OBTYPE VX_MASK INTERP_MTHD INTERP_PNTS FCST_THRESH OBS_THRESH COV_THRESH ALPHA LINE_TYPE TOTAL INDEX STORM_ID PROB_LEAD PROB_VAL AGEN_INIT AGEN_FHR AGEN_LAT AGEN_LON AGEN_DLAND BGEN_LAT BGEN_LON BGEN_DLAND GEN_DIST GEN_TDIFF INIT_TDIFF DEV_CAT OPS_CAT V10.1 : STAT : SSIDX : VERSION MODEL DESC FCST_LEAD FCST_VALID_BEG FCST_VALID_END OBS_LEAD OBS_VALID_BEG OBS_VALID_END FCST_VAR FCST_UNITS FCST_LEV OBS_VAR OBS_UNITS OBS_LEV OBTYPE VX_MASK INTERP_MTHD INTERP_PNTS FCST_THRESH OBS_THRESH COV_THRESH ALPHA LINE_TYPE FCST_MODEL REF_MODEL N_INIT N_TERM N_VLD SS_INDEX V10.1 : MODE : OBJ : VERSION MODEL N_VALID GRID_RES DESC FCST_LEAD FCST_VALID FCST_ACCUM OBS_LEAD OBS_VALID OBS_ACCUM FCST_RAD FCST_THR OBS_RAD OBS_THR FCST_VAR FCST_UNITS FCST_LEV OBS_VAR OBS_UNITS OBS_LEV OBTYPE OBJECT_ID OBJECT_CAT CENTROID_X CENTROID_Y CENTROID_LAT CENTROID_LON AXIS_ANG LENGTH WIDTH AREA AREA_THRESH CURVATURE CURVATURE_X CURVATURE_Y COMPLEXITY INTENSITY_10 INTENSITY_25 INTENSITY_50 INTENSITY_75 INTENSITY_90 INTENSITY_USER INTENSITY_SUM CENTROID_DIST BOUNDARY_DIST CONVEX_HULL_DIST ANGLE_DIFF ASPECT_DIFF AREA_RATIO INTERSECTION_AREA UNION_AREA SYMMETRIC_DIFF INTERSECTION_OVER_AREA CURVATURE_RATIO COMPLEXITY_RATIO PERCENTILE_INTENSITY_RATIO INTEREST diff --git a/test/hdr/met_10_1.hdr b/test/hdr/met_10_1.hdr index 641ac25813..84f5b5a950 100644 --- a/test/hdr/met_10_1.hdr +++ b/test/hdr/met_10_1.hdr @@ -28,7 +28,7 @@ SSVAR : VERSION MODEL DESC FCST_LEAD FCST_VALID_BEG FCST_VALID_END OBS_L VL1L2 : VERSION MODEL DESC FCST_LEAD FCST_VALID_BEG FCST_VALID_END OBS_LEAD OBS_VALID_BEG OBS_VALID_END FCST_VAR FCST_UNITS FCST_LEV OBS_VAR OBS_UNITS OBS_LEV OBTYPE VX_MASK INTERP_MTHD INTERP_PNTS FCST_THRESH OBS_THRESH COV_THRESH ALPHA LINE_TYPE TOTAL UFBAR VFBAR UOBAR VOBAR UVFOBAR UVFFBAR UVOOBAR F_SPEED_BAR O_SPEED_BAR VAL1L2 : VERSION MODEL DESC FCST_LEAD FCST_VALID_BEG FCST_VALID_END OBS_LEAD OBS_VALID_BEG OBS_VALID_END FCST_VAR FCST_UNITS FCST_LEV OBS_VAR OBS_UNITS OBS_LEV OBTYPE VX_MASK INTERP_MTHD INTERP_PNTS FCST_THRESH OBS_THRESH COV_THRESH ALPHA LINE_TYPE TOTAL UFABAR VFABAR UOABAR VOABAR UVFOABAR UVFFABAR UVOOABAR VCNT : VERSION MODEL DESC FCST_LEAD FCST_VALID_BEG FCST_VALID_END OBS_LEAD OBS_VALID_BEG OBS_VALID_END FCST_VAR FCST_UNITS FCST_LEV OBS_VAR OBS_UNITS OBS_LEV OBTYPE VX_MASK INTERP_MTHD INTERP_PNTS FCST_THRESH OBS_THRESH COV_THRESH ALPHA LINE_TYPE TOTAL FBAR FBAR_BCL FBAR_BCU OBAR OBAR_BCL OBAR_BCU FS_RMS FS_RMS_BCL FS_RMS_BCU OS_RMS OS_RMS_BCL OS_RMS_BCU MSVE MSVE_BCL MSVE_BCU RMSVE RMSVE_BCL RMSVE_BCU FSTDEV FSTDEV_BCL FSTDEV_BCU OSTDEV OSTDEV_BCL OSTDEV_BCU FDIR FDIR_BCL FDIR_BCU ODIR ODIR_BCL ODIR_BCU FBAR_SPEED FBAR_SPEED_BCL FBAR_SPEED_BCU OBAR_SPEED OBAR_SPEED_BCL OBAR_SPEED_BCU VDIFF_SPEED VDIFF_SPEED_BCL VDIFF_SPEED_BCU VDIFF_DIR VDIFF_DIR_BCL VDIFF_DIR_BCU SPEED_ERR SPEED_ERR_BCL SPEED_ERR_BCU SPEED_ABSERR SPEED_ABSERR_BCL SPEED_ABSERR_BCU DIR_ERR DIR_ERR_BCL DIR_ERR_BCU DIR_ABSERR DIR_ABSERR_BCL DIR_ABSERR_BCU -GENMPR : VERSION MODEL DESC FCST_LEAD FCST_VALID_BEG FCST_VALID_END OBS_LEAD OBS_VALID_BEG OBS_VALID_END FCST_VAR FCST_UNITS FCST_LEV OBS_VAR OBS_UNITS OBS_LEV OBTYPE VX_MASK INTERP_MTHD INTERP_PNTS FCST_THRESH OBS_THRESH COV_THRESH ALPHA LINE_TYPE TOTAL INDEX STORM_ID AGEN_INIT AGEN_FHR AGEN_LAT AGEN_LON AGEN_DLAND BGEN_LAT BGEN_LON BGEN_DLAND GEN_DIST GEN_TDIFF INIT_TDIFF DEV_CAT OPS_CAT +GENMPR : VERSION MODEL DESC FCST_LEAD FCST_VALID_BEG FCST_VALID_END OBS_LEAD OBS_VALID_BEG OBS_VALID_END FCST_VAR FCST_UNITS FCST_LEV OBS_VAR OBS_UNITS OBS_LEV OBTYPE VX_MASK INTERP_MTHD INTERP_PNTS FCST_THRESH OBS_THRESH COV_THRESH ALPHA LINE_TYPE TOTAL INDEX STORM_ID PROB_LEAD PROB_VAL AGEN_INIT AGEN_FHR AGEN_LAT AGEN_LON AGEN_DLAND BGEN_LAT BGEN_LON BGEN_DLAND GEN_DIST GEN_TDIFF INIT_TDIFF DEV_CAT OPS_CAT SSIDX : VERSION MODEL DESC FCST_LEAD FCST_VALID_BEG FCST_VALID_END OBS_LEAD OBS_VALID_BEG OBS_VALID_END FCST_VAR FCST_UNITS FCST_LEV OBS_VAR OBS_UNITS OBS_LEV OBTYPE VX_MASK INTERP_MTHD INTERP_PNTS FCST_THRESH OBS_THRESH COV_THRESH ALPHA LINE_TYPE FCST_MODEL REF_MODEL N_INIT N_TERM N_VLD SS_INDEX MODE_SOA : VERSION MODEL DESC FCST_LEAD FCST_VALID_BEG FCST_VALID_END OBS_LEAD OBS_VALID_BEG OBS_VALID_END FCST_VAR FCST_UNITS FCST_LEV OBS_VAR OBS_UNITS OBS_LEV OBTYPE VX_MASK INTERP_MTHD INTERP_PNTS FCST_THRESH OBS_THRESH COV_THRESH ALPHA LINE_TYPE N_VALID GRID_RES OBJECT_ID OBJECT_CAT CENTROID_X CENTROID_Y CENTROID_LAT CENTROID_LON AXIS_ANG LENGTH WIDTH AREA AREA_THRESH CURVATURE CURVATURE_X CURVATURE_Y COMPLEXITY INTENSITY_10 INTENSITY_25 INTENSITY_50 INTENSITY_75 INTENSITY_90 INTENSITY_50 INTENSITY_SUM MODE_POA : VERSION MODEL DESC FCST_LEAD FCST_VALID_BEG FCST_VALID_END OBS_LEAD OBS_VALID_BEG OBS_VALID_END FCST_VAR FCST_UNITS FCST_LEV OBS_VAR OBS_UNITS OBS_LEV OBTYPE VX_MASK INTERP_MTHD INTERP_PNTS FCST_THRESH OBS_THRESH COV_THRESH ALPHA LINE_TYPE N_VALID GRID_RES OBJECT_ID OBJECT_CAT CENTROID_DIST BOUNDARY_DIST CONVEX_HULL_DIST ANGLE_DIFF ASPECT_DIFF AREA_RATIO INTERSECTION_AREA UNION_AREA SYMMETRIC_DIFF INTERSECTION_OVER_AREA CURVATURE_RATIO COMPLEXITY_RATIO PERCENTILE_INTENSITY_RATIO INTEREST From 17b132363021ee71cbfde704860986506b9da961 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Sat, 13 Nov 2021 10:16:27 -0700 Subject: [PATCH 20/28] Per #1809, add PROB_LEAD and PROB_VAL to the GENMPR line type. --- met/src/basic/vx_util/stat_column_defs.h | 1 + 1 file changed, 1 insertion(+) diff --git a/met/src/basic/vx_util/stat_column_defs.h b/met/src/basic/vx_util/stat_column_defs.h index b8ddc583bc..9b21762513 100644 --- a/met/src/basic/vx_util/stat_column_defs.h +++ b/met/src/basic/vx_util/stat_column_defs.h @@ -320,6 +320,7 @@ static const char * ssidx_columns [] = { static const char * genmpr_columns [] = { "TOTAL", "INDEX", "STORM_ID", + "PROB_LEAD", "PROB_VAL", "AGEN_INIT", "AGEN_FHR", "AGEN_LAT", "AGEN_LON", "AGEN_DLAND", "BGEN_LAT", "BGEN_LON", "BGEN_DLAND", From 9f834d160fe7f162c636f308ce86d50cb4e735eb Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Sat, 13 Nov 2021 10:17:57 -0700 Subject: [PATCH 21/28] Per #1809, add GenesisLead to the ProbGenInfo class to track the lead time for which genesis is forecast. --- met/src/libcode/vx_tc_util/prob_gen_info.cc | 42 +++++++++++++-------- met/src/libcode/vx_tc_util/prob_gen_info.h | 22 ++++++----- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/met/src/libcode/vx_tc_util/prob_gen_info.cc b/met/src/libcode/vx_tc_util/prob_gen_info.cc index 77ef2b9007..732df86384 100644 --- a/met/src/libcode/vx_tc_util/prob_gen_info.cc +++ b/met/src/libcode/vx_tc_util/prob_gen_info.cc @@ -77,8 +77,8 @@ void ProbGenInfo::clear() { Initials.clear(); GenOrDis.clear(); - GenTime = (unixtime) 0; - + GenesisTime = (unixtime) 0; + GenesisLead = 0; BestGen = (const GenesisInfo *) 0; return; @@ -93,7 +93,8 @@ void ProbGenInfo::dump(ostream &out, int indent_depth) const { out << prefix << "Initials = \"" << Initials.contents() << "\"\n"; out << prefix << "GenOrDis = \"" << GenOrDis.contents() << "\"\n"; - out << prefix << "GenTime = " << unix_to_yyyymmdd_hhmmss(GenTime) << "\n"; + out << prefix << "GenesisTime = " << unix_to_yyyymmdd_hhmmss(GenesisTime) << "\n"; + out << prefix << "GenesisLead = " << sec_to_hhmmss(GenesisLead) << "\n"; out << prefix << "BestGen = " << (BestGen ? "set" : "(nul)") << "\n"; out << flush; @@ -111,7 +112,8 @@ ConcatString ProbGenInfo::serialize() const { << ", ProbGenInfo: " << "Initials = \"" << Initials << "\"" << ", GenOrDis = \"" << GenOrDis << "\"" - << ", GenTime = " << unix_to_yyyymmdd_hhmmss(GenTime) + << ", GenesisTime = " << unix_to_yyyymmdd_hhmmss(GenesisTime) + << ", GenesisLead = " << sec_to_hhmmss(GenesisLead) << ", BestGen = " << (BestGen ? "set" : "(nul)") << "\n"; return(s); @@ -135,11 +137,11 @@ void ProbGenInfo::assign(const ProbGenInfo &p) { ProbInfoBase::assign(p); - Initials = p.Initials; - GenOrDis = p.GenOrDis; - GenTime = p.GenTime; - - BestGen = p.BestGen; + Initials = p.Initials; + GenOrDis = p.GenOrDis; + GenesisTime = p.GenesisTime; + GenesisLead = p.GenesisLead; + BestGen = p.BestGen; return; } @@ -155,6 +157,14 @@ void ProbGenInfo::set_best_gen(const GenesisInfo *bg) { //////////////////////////////////////////////////////////////////////// +int ProbGenInfo::genesis_fhr() const { + return(is_bad_data(GenesisLead) ? + bad_data_int : + nint((double) GenesisLead/sec_per_hour)); +} + +//////////////////////////////////////////////////////////////////////// + void ProbGenInfo::initialize(const ATCFProbLine &l, double dland) { clear(); @@ -165,9 +175,11 @@ void ProbGenInfo::initialize(const ATCFProbLine &l, double dland) { GenOrDis = l.get_item(ProbGenOrDisOffset); // Store an empty string as unixtime 0 - GenTime = (l.get_item(ProbGenTimeOffset).empty() ? - (unixtime) 0 : - parse_time(l.get_item(ProbGenTimeOffset).c_str())); + GenesisTime = (l.get_item(ProbGenTimeOffset).empty() ? + (unixtime) 0 : + parse_time(l.get_item(ProbGenTimeOffset).c_str())); + GenesisLead = (GenesisTime == 0 ? bad_data_int : + GenesisTime - InitTime); BestGen = (const GenesisInfo *) 0; @@ -184,7 +196,7 @@ bool ProbGenInfo::is_match(const ATCFProbLine &l) const { (unixtime) 0 : parse_time(l.get_item(ProbGenTimeOffset).c_str())); - return(GenTime == gen_ut); + return(GenesisTime == gen_ut); } //////////////////////////////////////////////////////////////////////// @@ -225,8 +237,8 @@ bool ProbGenInfo::is_match(const TrackPoint &p, const double rad, const int beg, const int end) const { // Check for matching in time and space - return(p.valid() >= (GenTime + beg) && - p.valid() <= (GenTime + end) && + 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/prob_gen_info.h b/met/src/libcode/vx_tc_util/prob_gen_info.h index 7ee0d75eb8..9e09749fa4 100644 --- a/met/src/libcode/vx_tc_util/prob_gen_info.h +++ b/met/src/libcode/vx_tc_util/prob_gen_info.h @@ -36,7 +36,8 @@ class ProbGenInfo : public ProbInfoBase { // Probability of Genesis specific values ConcatString Initials; ConcatString GenOrDis; - unixtime GenTime; + unixtime GenesisTime; + int GenesisLead; // Pointer to the matching BEST genesis event const GenesisInfo * BestGen; @@ -64,10 +65,12 @@ class ProbGenInfo : public ProbInfoBase { // get stuff // - const ConcatString & initials() const; - const ConcatString & gen_or_dis() const; - unixtime gen_time() const; - const GenesisInfo * best_gen() const; + const ConcatString & initials() const; + const ConcatString & gen_or_dis() const; + unixtime genesis_time() const; + int genesis_lead() const; + int genesis_fhr() const; + const GenesisInfo * best_gen() const; // // do stuff @@ -86,10 +89,11 @@ class ProbGenInfo : public ProbInfoBase { //////////////////////////////////////////////////////////////////////// -inline const ConcatString & ProbGenInfo::initials() const { return(Initials); } -inline const ConcatString & ProbGenInfo::gen_or_dis() const { return(GenOrDis); } -inline unixtime ProbGenInfo::gen_time() const { return(GenTime); } -inline const GenesisInfo * ProbGenInfo::best_gen() const { return(BestGen); } +inline const ConcatString & ProbGenInfo::initials() const { return(Initials); } +inline const ConcatString & ProbGenInfo::gen_or_dis() const { return(GenOrDis); } +inline unixtime ProbGenInfo::genesis_time() const { return(GenesisTime); } +inline int ProbGenInfo::genesis_lead() const { return(GenesisLead); } +inline const GenesisInfo * ProbGenInfo::best_gen() const { return(BestGen); } //////////////////////////////////////////////////////////////////////// From 9a722e16da69b288ceb73e0153debf751f4218c8 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Sat, 13 Nov 2021 10:19:15 -0700 Subject: [PATCH 22/28] Per #1809, update tc_gen to write PROB_GENESIS matched pair output to the newly-updated GENMPR line type. --- met/src/tools/tc_utils/tc_gen/tc_gen.cc | 320 +++++++++++++----- met/src/tools/tc_utils/tc_gen/tc_gen.h | 8 +- .../tools/tc_utils/tc_gen/tc_gen_conf_info.cc | 39 ++- .../tools/tc_utils/tc_gen/tc_gen_conf_info.h | 11 +- 4 files changed, 281 insertions(+), 97 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 a7098872a6..3e948efac4 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen.cc +++ b/met/src/tools/tc_utils/tc_gen/tc_gen.cc @@ -106,15 +106,23 @@ static void setup_nc_file (); static void write_ctc_stats (const PairDataGenesis &, GenCTCInfo &); -static void write_pct_stats (ProbGenPCTInfo &); - -static void write_genmpr_row (StatHdrColumns &, +static void write_ctc_genmpr_row (StatHdrColumns &, const PairDataGenesis &, STATOutputType, AsciiTable &, int &, AsciiTable &, int &); -static void write_genmpr_cols (const PairDataGenesis &, int, +static void write_ctc_genmpr_cols(const PairDataGenesis &, int, + AsciiTable &, int, int); + +static void write_pct_stats (ProbGenPCTInfo &); +static void write_pct_genmpr_row (StatHdrColumns &, + ProbGenPCTInfo &, int, + STATOutputType, + AsciiTable &, int &, + AsciiTable &, int &); +static void write_pct_genmpr_cols(ProbGenPCTInfo &, int, int, AsciiTable &, int, int); + static void write_nc (GenCTCInfo &); static void finish_txt_files (); @@ -396,7 +404,7 @@ void score_genesis_prob(const GenesisInfoArray &best_ga, fcst_pa); // Setup output files based on the number of techniques - setup_txt_files(fcst_pa.n_technique(), 0); + setup_txt_files(fcst_pa.n_technique(), fcst_pa.n_prob_gen() * 3); // Process each verification filter for(i=0; igenesis_time() - model_pa.prob_gen(i).init(); is_event = time_diff >= 0 && - time_diff <= (prob_lead * sec_per_hour); + time_diff <= (model_pa.prob_gen(i).prob_item(j) * sec_per_hour); } else { is_event = false; } - // Increment counts - if(is_event) pgi.PCT[prob_lead].pct.inc_event (prob_value); - else pgi.PCT[prob_lead].pct.inc_nonevent(prob_value); + // Store pair info + pgi.add(model_pa.prob_gen(i), j, is_event); } // end for j } // end for i @@ -879,7 +879,7 @@ void find_probgen_match(ProbGenInfo &prob_gi, case_cs << prob_gi.technique() << " " << unix_to_yyyymmdd_hhmmss(prob_gi.init()) << " initialization, " - << unix_to_yyyymmdd_hhmmss(prob_gi.gen_time()) + << unix_to_yyyymmdd_hhmmss(prob_gi.genesis_time()) << " forecast genesis at (" << prob_gi.lat() << ", " << prob_gi.lon() << ")"; @@ -1595,7 +1595,7 @@ void write_ctc_stats(const PairDataGenesis &gpd, shc.set_fcst_var(genesis_dev_name); shc.set_obs_var (genesis_dev_name); write_fho_row(shc, gci.CTSDev, - gci.VxOpt->OutputMap.at(stat_fho), + gci.VxOpt->output_map(stat_fho), stat_at, i_stat_row, txt_at[i_fho], i_txt_row[i_fho]); } @@ -1604,7 +1604,7 @@ void write_ctc_stats(const PairDataGenesis &gpd, shc.set_fcst_var(genesis_ops_name); shc.set_obs_var (genesis_ops_name); write_fho_row(shc, gci.CTSOps, - gci.VxOpt->OutputMap.at(stat_fho), + gci.VxOpt->output_map(stat_fho), stat_at, i_stat_row, txt_at[i_fho], i_txt_row[i_fho]); } @@ -1617,7 +1617,7 @@ void write_ctc_stats(const PairDataGenesis &gpd, shc.set_fcst_var(genesis_dev_name); shc.set_obs_var (genesis_dev_name); write_ctc_row(shc, gci.CTSDev, - gci.VxOpt->OutputMap.at(stat_ctc), + gci.VxOpt->output_map(stat_ctc), stat_at, i_stat_row, txt_at[i_ctc], i_txt_row[i_ctc]); } @@ -1626,7 +1626,7 @@ void write_ctc_stats(const PairDataGenesis &gpd, shc.set_fcst_var(genesis_ops_name); shc.set_obs_var (genesis_ops_name); write_ctc_row(shc, gci.CTSOps, - gci.VxOpt->OutputMap.at(stat_ctc), + gci.VxOpt->output_map(stat_ctc), stat_at, i_stat_row, txt_at[i_ctc], i_txt_row[i_ctc]); } @@ -1642,7 +1642,7 @@ void write_ctc_stats(const PairDataGenesis &gpd, shc.set_fcst_var(genesis_dev_name); shc.set_obs_var (genesis_dev_name); write_cts_row(shc, gci.CTSDev, - gci.VxOpt->OutputMap.at(stat_cts), + gci.VxOpt->output_map(stat_cts), stat_at, i_stat_row, txt_at[i_cts], i_txt_row[i_cts]); } @@ -1654,7 +1654,7 @@ void write_ctc_stats(const PairDataGenesis &gpd, shc.set_fcst_var(genesis_ops_name); shc.set_obs_var (genesis_ops_name); write_cts_row(shc, gci.CTSOps, - gci.VxOpt->OutputMap.at(stat_cts), + gci.VxOpt->output_map(stat_cts), stat_at, i_stat_row, txt_at[i_cts], i_txt_row[i_cts]); } @@ -1664,15 +1664,148 @@ void write_ctc_stats(const PairDataGenesis &gpd, if(gci.VxOpt->output_map(stat_genmpr) != STATOutputType_None) { shc.set_fcst_var(genesis_name); shc.set_obs_var (genesis_name); - write_genmpr_row(shc, gpd, - gci.VxOpt->OutputMap.at(stat_genmpr), - stat_at, i_stat_row, - txt_at[i_genmpr], i_txt_row[i_genmpr]); + write_ctc_genmpr_row(shc, gpd, + gci.VxOpt->output_map(stat_genmpr), + stat_at, i_stat_row, + txt_at[i_genmpr], i_txt_row[i_genmpr]); + } + + return; +} + +//////////////////////////////////////////////////////////////////////// + +void write_ctc_genmpr_row(StatHdrColumns &shc, + const PairDataGenesis &gpd, + STATOutputType out_type, + AsciiTable &stat_at, int &stat_row, + AsciiTable &txt_at, int &txt_row) { + int i; + unixtime ut; + + // GENMPR line type + shc.set_line_type(stat_genmpr_str); + + // Not Applicable + shc.set_fcst_thresh(na_str); + shc.set_obs_thresh(na_str); + shc.set_alpha(bad_data_double); + + // Write a line for each matched pair + for(i=0; igenesis_time() : bgi->genesis_time()); + shc.set_fcst_valid_beg(ut); + shc.set_fcst_valid_end(ut); + shc.set_obs_lead_sec(bad_data_int); + ut = (bgi ? bgi->genesis_time() : fgi->genesis_time()); + shc.set_obs_valid_beg(ut); + shc.set_obs_valid_end(ut); + + // Write the header columns + write_header_cols(shc, stat_at, stat_row); + + // Write the data columns + write_ctc_genmpr_cols(gpd, i, stat_at, stat_row, n_header_columns); + + // If requested, copy row to the text file + if(out_type == STATOutputType_Both) { + copy_ascii_table_row(stat_at, stat_row, txt_at, txt_row); + + // Increment the text row counter + txt_row++; + } + + // Increment the STAT row counter + stat_row++; } return; } +//////////////////////////////////////////////////////////////////////// + + void write_ctc_genmpr_cols(const PairDataGenesis &gpd, int i, + AsciiTable &at, int r, int c) { + + // Pointers for current case + const GenesisInfo* fgi = gpd.fcst_gen(i); + const GenesisInfo* bgi = gpd.best_gen(i); + + // + // Genesis Matched Pairs (GENMPR): + // TOTAL, INDEX, STORM_ID, + // PROB_LEAD, PROB_VAL, + // AGEN_INIT, AGEN_FHR, + // AGEN_LAT, AGEN_LON, AGEN_DLAND, + // BGEN_LAT, BGEN_LON, BGEN_DLAND, + // GEN_DIST, GEN_TDIFF, INIT_TDIFF, + // DEV_CAT, OPS_CAT + // + + at.set_entry(r, c+0, // Total number of pairs + gpd.n_pair()); + + at.set_entry(r, c+1, // Index of current pair + i+1); + + at.set_entry(r, c+2, // Best track Storm ID + gpd.best_storm_id(i)); + + at.set_entry(r, c+3, // Probability lead time + na_str); + + at.set_entry(r, c+4, // Probability value + na_str); + + at.set_entry(r, c+5, // Fcst genesis initialization time + fgi ? unix_to_yyyymmdd_hhmmss(fgi->init()) : na_str); + + at.set_entry(r, c+6, // Fcst genesis hour + fgi ? fgi->genesis_fhr() : bad_data_int); + + at.set_entry(r, c+7, // Fcst track latitude + fgi ? fgi->lat() : bad_data_double); + + at.set_entry(r, c+8, // Fcst track longitude + fgi ? fgi->lon() : bad_data_double); + + at.set_entry(r, c+9, // Fcst track distance to land + fgi ? fgi->dland() : bad_data_double); + + at.set_entry(r, c+10, // Best track latitude + bgi ? bgi->lat() : bad_data_double); + + at.set_entry(r, c+11, // Best track longitude + bgi ? bgi->lon() : bad_data_double); + + at.set_entry(r, c+12, // Best track distance to land + bgi ? bgi->dland() : bad_data_double); + + at.set_entry(r, c+13, // Genesis distance + gpd.gen_diff(i).DevDist); + + at.set_entry(r, c+14, // Genesis time difference + sec_to_hhmmss(gpd.gen_diff(i).DevDSec)); + + at.set_entry(r, c+15, // Genesis - Init time + sec_to_hhmmss(gpd.gen_diff(i).OpsDSec)); + + at.set_entry(r, c+16, // Development category + genesispaircategory_to_string(gpd.gen_diff(i).DevCategory)); + + at.set_entry(r, c+17, // Operational category + genesispaircategory_to_string(gpd.gen_diff(i).OpsCategory)); + + return; + } + //////////////////////////////////////////////////////////////////////// void write_pct_stats(ProbGenPCTInfo &pgi) { @@ -1684,8 +1817,8 @@ void write_pct_stats(ProbGenPCTInfo &pgi) { shc.set_obtype(conf_info.BestEventInfo.Technique.c_str()); shc.set_mask(pgi.VxOpt->VxMaskName.empty() ? na_str : pgi.VxOpt->VxMaskName.c_str()); - shc.set_fcst_var(probgenesis_name); - shc.set_obs_var (probgenesis_name); + shc.set_fcst_var(prob_genesis_name); + shc.set_obs_var (prob_genesis_name); // Write results for each lead time for(i=0; ioutput_map(stat_pct) != STATOutputType_None) { - write_pct_row(shc, pgi.PCT[lead_hr], + write_pct_row(shc, pgi.PCTMap[lead_hr], pgi.VxOpt->output_map(stat_pct), 1, 1, stat_at, i_stat_row, txt_at[i_pct], i_txt_row[i_pct]); @@ -1711,9 +1844,9 @@ void write_pct_stats(ProbGenPCTInfo &pgi) { // Write PSTD output if(pgi.VxOpt->output_map(stat_pstd) != STATOutputType_None) { - pgi.PCT[lead_hr].compute_stats(); - pgi.PCT[lead_hr].compute_ci(); - write_pstd_row(shc, pgi.PCT[lead_hr], + pgi.PCTMap[lead_hr].compute_stats(); + pgi.PCTMap[lead_hr].compute_ci(); + write_pstd_row(shc, pgi.PCTMap[lead_hr], pgi.VxOpt->output_map(stat_pstd), 1, 1, stat_at, i_stat_row, txt_at[i_pstd], i_txt_row[i_pstd]); @@ -1721,7 +1854,7 @@ void write_pct_stats(ProbGenPCTInfo &pgi) { // Write PJC output if(pgi.VxOpt->output_map(stat_pjc) != STATOutputType_None) { - write_pct_row(shc, pgi.PCT[lead_hr], + write_pct_row(shc, pgi.PCTMap[lead_hr], pgi.VxOpt->output_map(stat_pjc), 1, 1, stat_at, i_stat_row, txt_at[i_pjc], i_txt_row[i_pjc]); @@ -1729,11 +1862,22 @@ void write_pct_stats(ProbGenPCTInfo &pgi) { // Write PRC output if(pgi.VxOpt->output_map(stat_pjc) != STATOutputType_None) { - write_pct_row(shc, pgi.PCT[lead_hr], + write_pct_row(shc, pgi.PCTMap[lead_hr], pgi.VxOpt->output_map(stat_pjc), 1, 1, stat_at, i_stat_row, txt_at[i_prc], i_txt_row[i_prc]); } + + // Write out GENMPR + if(pgi.VxOpt->output_map(stat_genmpr) != STATOutputType_None) { + shc.set_fcst_var(prob_genesis_name); + shc.set_obs_var (prob_genesis_name); + write_pct_genmpr_row(shc, pgi, lead_hr, + pgi.VxOpt->output_map(stat_genmpr), + stat_at, i_stat_row, + txt_at[i_genmpr], i_txt_row[i_genmpr]); + } + } // end for i return; @@ -1741,11 +1885,12 @@ void write_pct_stats(ProbGenPCTInfo &pgi) { //////////////////////////////////////////////////////////////////////// -void write_genmpr_row(StatHdrColumns &shc, - const PairDataGenesis &gpd, - STATOutputType out_type, - AsciiTable &stat_at, int &stat_row, - AsciiTable &txt_at, int &txt_row) { +void write_pct_genmpr_row(StatHdrColumns &shc, + ProbGenPCTInfo &pgi, + int lead_hr, + STATOutputType out_type, + AsciiTable &stat_at, int &stat_row, + AsciiTable &txt_at, int &txt_row) { int i; unixtime ut; @@ -1753,22 +1898,24 @@ void write_genmpr_row(StatHdrColumns &shc, shc.set_line_type(stat_genmpr_str); // Not Applicable + shc.set_fcst_thresh(na_str); + shc.set_obs_thresh(na_str); shc.set_alpha(bad_data_double); // Write a line for each matched pair - for(i=0; ibest_gen(); + // Store timing info - shc.set_fcst_lead_sec(gpd.lead_time(i)); - ut = (fgi ? fgi->genesis_time() : bgi->genesis_time()); + shc.set_fcst_lead_sec(fgi->genesis_lead()); + ut = fgi->genesis_time(); shc.set_fcst_valid_beg(ut); shc.set_fcst_valid_end(ut); shc.set_obs_lead_sec(bad_data_int); - ut = (bgi ? bgi->genesis_time() : fgi->genesis_time()); + ut = (bgi ? bgi->genesis_time() : ut); shc.set_obs_valid_beg(ut); shc.set_obs_valid_end(ut); @@ -1776,7 +1923,8 @@ void write_genmpr_row(StatHdrColumns &shc, write_header_cols(shc, stat_at, stat_row); // Write the data columns - write_genmpr_cols(gpd, i, stat_at, stat_row, n_header_columns); + write_pct_genmpr_cols(pgi, lead_hr, i, + stat_at, stat_row, n_header_columns); // If requested, copy row to the text file if(out_type == STATOutputType_Both) { @@ -1788,6 +1936,7 @@ void write_genmpr_row(StatHdrColumns &shc, // Increment the STAT row counter stat_row++; + } return; @@ -1795,16 +1944,19 @@ void write_genmpr_row(StatHdrColumns &shc, //////////////////////////////////////////////////////////////////////// - void write_genmpr_cols(const PairDataGenesis &gpd, int i, - AsciiTable &at, int r, int c) { + void write_pct_genmpr_cols(ProbGenPCTInfo &pgi, + int lead_hr, int index, + AsciiTable &at, int r, int c) { + + // Pointers for current case + const ProbGenInfo *fgi = pgi.PGIMap[lead_hr][index]; + const GenesisInfo *bgi = fgi->best_gen(); + int i_prob = pgi.IdxMap[lead_hr][index]; - // Pointers for current case - const GenesisInfo* fgi = gpd.fcst_gen(i); - const GenesisInfo* bgi = gpd.best_gen(i); - // // Genesis Matched Pairs (GENMPR): // TOTAL, INDEX, STORM_ID, + // PROB_LEAD, PROB_VAL, // AGEN_INIT, AGEN_FHR, // AGEN_LAT, AGEN_LON, AGEN_DLAND, // BGEN_LAT, BGEN_LON, BGEN_DLAND, @@ -1813,52 +1965,58 @@ void write_genmpr_row(StatHdrColumns &shc, // at.set_entry(r, c+0, // Total number of pairs - gpd.n_pair()); + (int) pgi.PGIMap[lead_hr].size()); at.set_entry(r, c+1, // Index of current pair - i+1); + index+1); at.set_entry(r, c+2, // Best track Storm ID - gpd.best_storm_id(i)); + (bgi ? bgi->storm_id() : na_str)); - at.set_entry(r, c+3, // Fcst genesis initialization time - fgi ? unix_to_yyyymmdd_hhmmss(fgi->init()) : na_str); + at.set_entry(r, c+3, // Probability lead time + fgi->prob_item(i_prob)); - at.set_entry(r, c+4, // Fcst genesis hour - fgi ? fgi->genesis_fhr() : bad_data_int); + at.set_entry(r, c+4, // Probability value + fgi->prob(i_prob)); - at.set_entry(r, c+5, // Fcst track latitude - fgi ? fgi->lat() : bad_data_double); + at.set_entry(r, c+5, // Fcst genesis initialization time + unix_to_yyyymmdd_hhmmss(fgi->init())); - at.set_entry(r, c+6, // Fcst track longitude - fgi ? fgi->lon() : bad_data_double); + at.set_entry(r, c+6, // Fcst genesis hour + fgi->genesis_fhr()); - at.set_entry(r, c+7, // Fcst track distance to land - fgi ? fgi->dland() : bad_data_double); + at.set_entry(r, c+7, // Fcst genesis latitude + fgi->lat()); + + at.set_entry(r, c+8, // Fcst genesis longitude + fgi->lon()); - at.set_entry(r, c+8, // Best track latitude + at.set_entry(r, c+9, // Fcst genesis distance to land + fgi->dland()); + + at.set_entry(r, c+10, // Best track latitude bgi ? bgi->lat() : bad_data_double); - at.set_entry(r, c+9, // Best track longitude + at.set_entry(r, c+11, // Best track longitude bgi ? bgi->lon() : bad_data_double); - at.set_entry(r, c+10, // Best track distance to land + at.set_entry(r, c+12, // Best track distance to land bgi ? bgi->dland() : bad_data_double); - at.set_entry(r, c+11, // Genesis distance - gpd.gen_diff(i).DevDist); + at.set_entry(r, c+13, // Genesis distance + na_str); - at.set_entry(r, c+12, // Genesis time difference - sec_to_hhmmss(gpd.gen_diff(i).DevDSec)); + at.set_entry(r, c+14, // Genesis time difference + na_str); - at.set_entry(r, c+13, // Genesis - Init time - sec_to_hhmmss(gpd.gen_diff(i).OpsDSec)); + at.set_entry(r, c+15, // Genesis - Init time + na_str); - at.set_entry(r, c+14, // Development category - genesispaircategory_to_string(gpd.gen_diff(i).DevCategory)); + at.set_entry(r, c+16, // Development category + na_str); - at.set_entry(r, c+15, // Operational category - genesispaircategory_to_string(gpd.gen_diff(i).OpsCategory)); + at.set_entry(r, c+17, // Operational category + (pgi.EvtMap[lead_hr][index] ? "FY_OY" : "FY_ON" )); return; } 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 fd9e69a5c1..19461c5941 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen.h +++ b/met/src/tools/tc_utils/tc_gen/tc_gen.h @@ -77,10 +77,10 @@ static const char *txt_file_abbr[n_txt] = { "fho", "ctc", "cts", "pct", "pstd", "pjc", "prc", "genmpr" }; -const ConcatString genesis_name ("GENESIS"); -const ConcatString genesis_dev_name("GENESIS_DEV"); -const ConcatString genesis_ops_name("GENESIS_OPS"); -const ConcatString probgenesis_name("PROBGENESIS"); +const ConcatString genesis_name ("GENESIS"); +const ConcatString genesis_dev_name ("GENESIS_DEV"); +const ConcatString genesis_ops_name ("GENESIS_OPS"); +const ConcatString prob_genesis_name("PROB_GENESIS"); // Maximum Best track cyclone number to be processed // Cyclone numbers > 50 are for testing or invests 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 2294b99fdb..d32528073b 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 @@ -1245,7 +1245,10 @@ void ProbGenPCTInfo::clear() { InitBeg = InitEnd = (unixtime) 0; BestBeg = BestEnd = (unixtime) 0; - PCT.clear(); + PCTMap.clear(); + PGIMap.clear(); + IdxMap.clear(); + EvtMap.clear(); VxOpt = (const TCGenVxOpt *) 0; LeadTimes.clear(); @@ -1272,8 +1275,8 @@ void ProbGenPCTInfo::set_vx_opt(const TCGenVxOpt *vx_opt) { //////////////////////////////////////////////////////////////////////// -void ProbGenPCTInfo::add(const ProbGenInfo &pgi) { - int i, lead_hr; +void ProbGenPCTInfo::add(const ProbGenInfo &pgi, int index, bool is_event) { + int i; // Store the model name if(Model.empty()) Model = pgi.technique(); @@ -1289,17 +1292,33 @@ void ProbGenPCTInfo::add(const ProbGenInfo &pgi) { if(BestEnd == 0 || BestEnd < ut) BestEnd = ut; } - // Add new map entry for each lead time, if needed - for(i=0; i empty_pgi; + vector empty_idx; + vector empty_evt; + + PCTMap[lead_hr] = DefaultPCT; + PGIMap[lead_hr] = empty_pgi; + IdxMap[lead_hr] = empty_idx; + EvtMap[lead_hr] = empty_evt; } + // Update map entries + PGIMap[lead_hr].push_back(&pgi); + IdxMap[lead_hr].push_back(index); + EvtMap[lead_hr].push_back(is_event); + + // Increment counts + if(is_event) PCTMap[lead_hr].pct.inc_event (prob); + else PCTMap[lead_hr].pct.inc_nonevent(prob); + return; } 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 b15bfdbf4d..a1cb9b5b24 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 @@ -335,7 +335,14 @@ class ProbGenPCTInfo { unixtime BestBeg, BestEnd; const TCGenVxOpt* VxOpt; IntArray LeadTimes; - map PCT; + + // Map of lead times to PCT tables + map PCTMap; + + // Map of lead times to vectors of pair info + map> PGIMap; + map> IdxMap; + map> EvtMap; ////////////////////////////////////////////////////////////////// @@ -343,7 +350,7 @@ class ProbGenPCTInfo { void set_vx_opt(const TCGenVxOpt *); - void add(const ProbGenInfo &); + void add(const ProbGenInfo &, int, bool); }; From b9dd9f0821d955d43364844a17caf9f5467c99d0 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Sat, 13 Nov 2021 10:57:12 -0700 Subject: [PATCH 23/28] Per #1809, stop storing a pointer to the BEST genesis info object in ProbGenInfo. That was kludgy. --- met/src/libcode/vx_tc_util/prob_gen_info.cc | 17 +---------------- met/src/libcode/vx_tc_util/prob_gen_info.h | 4 ---- 2 files changed, 1 insertion(+), 20 deletions(-) diff --git a/met/src/libcode/vx_tc_util/prob_gen_info.cc b/met/src/libcode/vx_tc_util/prob_gen_info.cc index 732df86384..c0db7ce9fb 100644 --- a/met/src/libcode/vx_tc_util/prob_gen_info.cc +++ b/met/src/libcode/vx_tc_util/prob_gen_info.cc @@ -79,7 +79,6 @@ void ProbGenInfo::clear() { GenOrDis.clear(); GenesisTime = (unixtime) 0; GenesisLead = 0; - BestGen = (const GenesisInfo *) 0; return; } @@ -95,7 +94,6 @@ void ProbGenInfo::dump(ostream &out, int indent_depth) const { out << prefix << "GenOrDis = \"" << GenOrDis.contents() << "\"\n"; out << prefix << "GenesisTime = " << unix_to_yyyymmdd_hhmmss(GenesisTime) << "\n"; out << prefix << "GenesisLead = " << sec_to_hhmmss(GenesisLead) << "\n"; - out << prefix << "BestGen = " << (BestGen ? "set" : "(nul)") << "\n"; out << flush; @@ -113,8 +111,7 @@ ConcatString ProbGenInfo::serialize() const { << "Initials = \"" << Initials << "\"" << ", GenOrDis = \"" << GenOrDis << "\"" << ", GenesisTime = " << unix_to_yyyymmdd_hhmmss(GenesisTime) - << ", GenesisLead = " << sec_to_hhmmss(GenesisLead) - << ", BestGen = " << (BestGen ? "set" : "(nul)") << "\n"; + << ", GenesisLead = " << sec_to_hhmmss(GenesisLead) << "\n"; return(s); } @@ -141,16 +138,6 @@ void ProbGenInfo::assign(const ProbGenInfo &p) { GenOrDis = p.GenOrDis; GenesisTime = p.GenesisTime; GenesisLead = p.GenesisLead; - BestGen = p.BestGen; - - return; -} - -//////////////////////////////////////////////////////////////////////// - -void ProbGenInfo::set_best_gen(const GenesisInfo *bg) { - - BestGen = bg; return; } @@ -181,8 +168,6 @@ void ProbGenInfo::initialize(const ATCFProbLine &l, double dland) { GenesisLead = (GenesisTime == 0 ? bad_data_int : GenesisTime - InitTime); - BestGen = (const GenesisInfo *) 0; - return; } diff --git a/met/src/libcode/vx_tc_util/prob_gen_info.h b/met/src/libcode/vx_tc_util/prob_gen_info.h index 9e09749fa4..af97bb03fa 100644 --- a/met/src/libcode/vx_tc_util/prob_gen_info.h +++ b/met/src/libcode/vx_tc_util/prob_gen_info.h @@ -39,9 +39,6 @@ class ProbGenInfo : public ProbInfoBase { unixtime GenesisTime; int GenesisLead; - // Pointer to the matching BEST genesis event - const GenesisInfo * BestGen; - public: ProbGenInfo(); @@ -93,7 +90,6 @@ inline const ConcatString & ProbGenInfo::initials() const { return(Initials) inline const ConcatString & ProbGenInfo::gen_or_dis() const { return(GenOrDis); } inline unixtime ProbGenInfo::genesis_time() const { return(GenesisTime); } inline int ProbGenInfo::genesis_lead() const { return(GenesisLead); } -inline const GenesisInfo * ProbGenInfo::best_gen() const { return(BestGen); } //////////////////////////////////////////////////////////////////////// From ac1045c135b7a8a18ebe580197a8b0753fb0b7a3 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Sat, 13 Nov 2021 10:58:17 -0700 Subject: [PATCH 24/28] Per #1809, use ProbGenPCTInfo to store pointers to the individual matched pair objects. This is cleaner than the last kludgy solution. --- met/src/tools/tc_utils/tc_gen/tc_gen.cc | 63 ++++++++++--------- .../tools/tc_utils/tc_gen/tc_gen_conf_info.cc | 45 +++++++------ .../tools/tc_utils/tc_gen/tc_gen_conf_info.h | 10 +-- 3 files changed, 65 insertions(+), 53 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 3e948efac4..483fcdaca5 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen.cc +++ b/met/src/tools/tc_utils/tc_gen/tc_gen.cc @@ -95,7 +95,7 @@ static int find_genesis_match (const GenesisInfo &, const GenesisInfoArray &, const TrackInfoArray &, bool, double, int, int); -static void find_probgen_match (ProbGenInfo &, +static int find_probgen_match (const ProbGenInfo &, const GenesisInfoArray &, const TrackInfoArray &, bool, double, int, int); @@ -737,8 +737,9 @@ void do_probgen_pct(const TCGenVxOpt &vx_opt, const GenesisInfoArray &best_ga, const TrackInfoArray &oper_ta, ProbGenPCTInfo &pgi) { - int i, j, time_diff; + int i, i_bga, j, time_diff; bool is_event; + const GenesisInfo *bgi; // Initialize pgi.clear(); @@ -748,18 +749,23 @@ void do_probgen_pct(const TCGenVxOpt &vx_opt, for(i=0; igenesis_time() - + if(bgi) { + time_diff = bgi->genesis_time() - model_pa.prob_gen(i).init(); is_event = time_diff >= 0 && time_diff <= (model_pa.prob_gen(i).prob_item(j) * sec_per_hour); @@ -769,7 +775,7 @@ void do_probgen_pct(const TCGenVxOpt &vx_opt, } // Store pair info - pgi.add(model_pa.prob_gen(i), j, is_event); + pgi.add(model_pa.prob_gen(i), j, bgi, is_event); } // end for j } // end for i @@ -780,9 +786,9 @@ void do_probgen_pct(const TCGenVxOpt &vx_opt, //////////////////////////////////////////////////////////////////////// -int find_genesis_match(const GenesisInfo &fcst_gi, +int find_genesis_match(const GenesisInfo &fcst_gi, const GenesisInfoArray &bga, - const TrackInfoArray &ota, + const TrackInfoArray &ota, bool point2track, double rad, int beg, int end) { int i, j, i_best, i_oper; @@ -868,11 +874,11 @@ int find_genesis_match(const GenesisInfo &fcst_gi, //////////////////////////////////////////////////////////////////////// -void find_probgen_match(ProbGenInfo &prob_gi, - const GenesisInfoArray &bga, - const TrackInfoArray &ota, - bool point2track, double rad, - int beg, int end) { +int find_probgen_match(const ProbGenInfo &prob_gi, + const GenesisInfoArray &bga, + const TrackInfoArray &ota, + bool point2track, double rad, + int beg, int end) { int i, j, i_best, i_oper; ConcatString case_cs; @@ -950,11 +956,7 @@ void find_probgen_match(ProbGenInfo &prob_gi, << " has NO MATCH in the BEST or operational tracks.\n"; } - // Store a pointer to the match - if(!is_bad_data(i_best)) prob_gi.set_best_gen(&bga[i_best]); - else prob_gi.set_best_gen((GenesisInfo *) 0); - - return; + return(i_best); } @@ -1903,11 +1905,11 @@ void write_pct_genmpr_row(StatHdrColumns &shc, shc.set_alpha(bad_data_double); // Write a line for each matched pair - for(i=0; ibest_gen(); + const ProbGenInfo *fgi = pgi.FcstGenMap[lead_hr][i]; + const GenesisInfo *bgi = pgi.BestGenMap[lead_hr][i]; // Store timing info shc.set_fcst_lead_sec(fgi->genesis_lead()); @@ -1949,9 +1951,10 @@ void write_pct_genmpr_row(StatHdrColumns &shc, AsciiTable &at, int r, int c) { // Pointers for current case - const ProbGenInfo *fgi = pgi.PGIMap[lead_hr][index]; - const GenesisInfo *bgi = fgi->best_gen(); - int i_prob = pgi.IdxMap[lead_hr][index]; + const ProbGenInfo *fgi = pgi.FcstGenMap[lead_hr][index]; + const GenesisInfo *bgi = pgi.BestGenMap[lead_hr][index]; + + int i_prob = pgi.FcstIdxMap[lead_hr][index]; // // Genesis Matched Pairs (GENMPR): @@ -1965,7 +1968,7 @@ void write_pct_genmpr_row(StatHdrColumns &shc, // at.set_entry(r, c+0, // Total number of pairs - (int) pgi.PGIMap[lead_hr].size()); + (int) pgi.FcstGenMap[lead_hr].size()); at.set_entry(r, c+1, // Index of current pair index+1); @@ -2016,7 +2019,7 @@ void write_pct_genmpr_row(StatHdrColumns &shc, na_str); at.set_entry(r, c+17, // Operational category - (pgi.EvtMap[lead_hr][index] ? "FY_OY" : "FY_ON" )); + (pgi.BestEvtMap[lead_hr][index] ? "FYOY" : "FYON" )); return; } 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 d32528073b..0592c667b4 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 @@ -1246,9 +1246,10 @@ void ProbGenPCTInfo::clear() { BestBeg = BestEnd = (unixtime) 0; PCTMap.clear(); - PGIMap.clear(); - IdxMap.clear(); - EvtMap.clear(); + FcstGenMap.clear(); + FcstIdxMap.clear(); + BestGenMap.clear(); + BestEvtMap.clear(); VxOpt = (const TCGenVxOpt *) 0; LeadTimes.clear(); @@ -1275,45 +1276,51 @@ void ProbGenPCTInfo::set_vx_opt(const TCGenVxOpt *vx_opt) { //////////////////////////////////////////////////////////////////////// -void ProbGenPCTInfo::add(const ProbGenInfo &pgi, int index, bool is_event) { +void ProbGenPCTInfo::add(const ProbGenInfo &fgi, int index, + const GenesisInfo *bgi, bool is_event) { int i; + unixtime ut; // Store the model name - if(Model.empty()) Model = pgi.technique(); + if(Model.empty()) Model = fgi.technique(); // Track the range of forecast initalization times - if(InitBeg == 0 || InitBeg > pgi.init()) InitBeg = pgi.init(); - if(InitEnd == 0 || InitEnd < pgi.init()) InitEnd = pgi.init(); + ut = fgi.init(); + if(InitBeg == 0 || InitBeg > ut) InitBeg = ut; + if(InitEnd == 0 || InitEnd < ut) InitEnd = ut; // Track the range of verifying BEST genesis events - if(pgi.best_gen()) { - unixtime ut = pgi.best_gen()->genesis_time(); + if(bgi) { + ut = bgi->genesis_time(); if(BestBeg == 0 || BestBeg > ut) BestBeg = ut; if(BestEnd == 0 || BestEnd < ut) BestEnd = ut; } // Current lead time and probability value - int lead_hr = nint(pgi.prob_item(index)); - double prob = pgi.prob(index) / 100.0; + int lead_hr = nint(fgi.prob_item(index)); + double prob = fgi.prob(index) / 100.0; // Add new map entries, if needed if(!LeadTimes.has(lead_hr)) { LeadTimes.add(lead_hr); - vector empty_pgi; + vector empty_fgi; vector empty_idx; + vector empty_bgi; vector empty_evt; - PCTMap[lead_hr] = DefaultPCT; - PGIMap[lead_hr] = empty_pgi; - IdxMap[lead_hr] = empty_idx; - EvtMap[lead_hr] = empty_evt; + PCTMap [lead_hr] = DefaultPCT; + FcstGenMap[lead_hr] = empty_fgi; + FcstIdxMap[lead_hr] = empty_idx; + BestGenMap[lead_hr] = empty_bgi; + BestEvtMap[lead_hr] = empty_evt; } // Update map entries - PGIMap[lead_hr].push_back(&pgi); - IdxMap[lead_hr].push_back(index); - EvtMap[lead_hr].push_back(is_event); + FcstGenMap[lead_hr].push_back(&fgi); + FcstIdxMap[lead_hr].push_back(index); + BestGenMap[lead_hr].push_back(bgi); + BestEvtMap[lead_hr].push_back(is_event); // Increment counts if(is_event) PCTMap[lead_hr].pct.inc_event (prob); 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 a1cb9b5b24..fe1b3c3f57 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 @@ -340,9 +340,10 @@ class ProbGenPCTInfo { map PCTMap; // Map of lead times to vectors of pair info - map> PGIMap; - map> IdxMap; - map> EvtMap; + map> FcstGenMap; + map> FcstIdxMap; + map> BestGenMap; + map> BestEvtMap; ////////////////////////////////////////////////////////////////// @@ -350,7 +351,8 @@ class ProbGenPCTInfo { void set_vx_opt(const TCGenVxOpt *); - void add(const ProbGenInfo &, int, bool); + void add(const ProbGenInfo &, int, + const GenesisInfo *, bool); }; From 540a4f47a153b8552ae6f9be7b8d00b29b183029 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Sat, 13 Nov 2021 11:44:32 -0700 Subject: [PATCH 25/28] Per #1809, add a call to tc_gen in unit_tc_gen.xml. --- met/src/tools/tc_utils/tc_gen/tc_gen.cc | 23 +- test/config/TCGenConfig_prob | 288 ++++++++++++++++++++++++ test/xml/unit_tc_gen.xml | 28 ++- 3 files changed, 328 insertions(+), 11 deletions(-) create mode 100644 test/config/TCGenConfig_prob 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 483fcdaca5..fb05b4c743 100644 --- a/met/src/tools/tc_utils/tc_gen/tc_gen.cc +++ b/met/src/tools/tc_utils/tc_gen/tc_gen.cc @@ -100,7 +100,7 @@ static int find_probgen_match (const ProbGenInfo &, const TrackInfoArray &, bool, double, int, int); -static void setup_txt_files (int, int); +static void setup_txt_files (int, int, int); static void setup_table (AsciiTable &); static void setup_nc_file (); @@ -306,7 +306,7 @@ void score_track_genesis(const GenesisInfoArray &best_ga, int n_time = (conf_info.FcstSecEnd - conf_info.FcstSecBeg) / (conf_info.InitFreqHr*sec_per_hour) + 1; int n_pair = best_ga.n() * n_time + fcst_ga.n(); - setup_txt_files(fcst_ga.n_technique(), n_pair); + setup_txt_files(fcst_ga.n_technique(), 1, n_pair); // If requested, setup the NetCDF output file if(!conf_info.NcInfo.all_false()) setup_nc_file(); @@ -385,7 +385,7 @@ void score_track_genesis(const GenesisInfoArray &best_ga, void score_genesis_prob(const GenesisInfoArray &best_ga, const TrackInfoArray &oper_ta) { - int i, j; + int i, j, n, max_n_prob, n_pair; StringArray edeck_files, edeck_files_model_suffix; ProbInfoArray fcst_pa, empty_pa; ConcatString model; @@ -403,8 +403,15 @@ void score_genesis_prob(const GenesisInfoArray &best_ga, process_edecks(edeck_files, edeck_files_model_suffix, fcst_pa); + // Count up the total number of probabilities + for(i=0,max_n_prob=0,n_pair=0; i max_n_prob) max_n_prob = n; + n_pair += n; + } + // Setup output files based on the number of techniques - setup_txt_files(fcst_pa.n_technique(), fcst_pa.n_prob_gen() * 3); + setup_txt_files(fcst_pa.n_technique(), max_n_prob, n_pair); // Process each verification filter for(i=0; i - + ]> @@ -17,8 +17,8 @@ &MET_BIN;/tc_gen \ - -genesis &DATA_DIR;/suite1/2016*/genesis*2016* \ - -track &DATA_DIR;/atcf/2016 \ + -genesis &DATA_DIR;/genesis/suite1/2016*/genesis*2016* \ + -track &DATA_DIR;/genesis/atcf/2016 \ -config &CONFIG_DIR;/TCGenConfig_2016 \ -out &OUTPUT_DIR;/tc_gen/tc_gen_2016 \ -log &OUTPUT_DIR;/tc_gen/tc_gen_2016.log \ @@ -31,4 +31,26 @@ + + + + &MET_BIN;/tc_gen + \ + -edeck &DATA_DIR;/edeck/eal152020*dat \ + -track &DATA_DIR;/bdeck/bal152020.dat \ + -config &CONFIG_DIR;/TCGenConfig_prob \ + -out &OUTPUT_DIR;/tc_gen/tc_gen_prob \ + -log &OUTPUT_DIR;/tc_gen/tc_gen_prob.log \ + -v 4 + + + &OUTPUT_DIR;/tc_gen/tc_gen_prob.stat + &OUTPUT_DIR;/tc_gen/tc_gen_prob_pct.txt + &OUTPUT_DIR;/tc_gen/tc_gen_prob_pstd.txt + &OUTPUT_DIR;/tc_gen/tc_gen_prob_pjc.txt + &OUTPUT_DIR;/tc_gen/tc_gen_prob_prc.txt + &OUTPUT_DIR;/tc_gen/tc_gen_prob_genmpr.txt + + + From effa6292a25b78b867ebf857c69f540658463939 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Sun, 14 Nov 2021 19:48:00 -0700 Subject: [PATCH 26/28] Per #1809, update the tc_gen chapter of the user's guide. --- met/docs/Users_Guide/tc-gen.rst | 142 +++++++++++++++++++++----------- 1 file changed, 95 insertions(+), 47 deletions(-) diff --git a/met/docs/Users_Guide/tc-gen.rst b/met/docs/Users_Guide/tc-gen.rst index 61209566dc..d068ed4432 100644 --- a/met/docs/Users_Guide/tc-gen.rst +++ b/met/docs/Users_Guide/tc-gen.rst @@ -6,14 +6,16 @@ TC-Gen Tool Introduction ____________ -The TC-Gen tool provides verification of tropical cyclone genesis forecasts in ATCF file format. Producing reliable tropical cyclone genesis forecasts is an important metric for global numerical weather prediction models. This tool ingests deterministic model output post-processed by a genesis tracking software (e.g. GFDL vortex tracker) and ATCF format reference dataset(s) (e.g. Best Track analysis and CARQ operational tracks) and outputs categorical counts and statistics. The capability to modify the spatial and temporal tolerances that define a "hit" forecast is included to give users the ability to condition the criteria based on model performance and/or conduct sensitivity analyses. Statistical aspects are outlined in :numref:`tc-gen_stat_aspects` and practical aspects of the TC-Gen tool are described in :numref:`tc-gen_practical_info`. +The TC-Gen tool provides verification of tropical cyclone genesis forecasts in the ATCF file format as well at the probability of genesis forecasts. Producing reliable tropical cyclone genesis forecasts is an important metric for global numerical weather prediction models. This tool ingests probabilistic and deterministic model output post-processed by a genesis tracking software (e.g. GFDL vortex tracker) and ATCF format reference dataset(s) (e.g. Best Track analysis and CARQ operational tracks) and outputs categorical counts and statistics. The capability to modify the spatial and temporal tolerances that define a "hit" forecast is included to give users the ability to condition the criteria based on model performance and/or conduct sensitivity analyses. Statistical aspects are outlined in :numref:`tc-gen_stat_aspects` and practical aspects of the TC-Gen tool are described in :numref:`tc-gen_practical_info`. .. _tc-gen_stat_aspects: Statistical aspects ___________________ -The TC-Gen tool populates a contingency tables with hits, misses, and false alarms. As with other extreme events (where the event occurs much less frequently than the non-event), the correct negative category is not computed the non-events would dominate the contingency table. Therefore, only statistics that do not include correct negatives should be considered for this tool. The following CTS statistics are relevant: Base rate (BASER), Mean forecast (FMEAN), Frequency Bias (FBIAS), Probability of Detection (PODY), False Alarm Ratio (FAR), Critical Success Index (CSI), Gilbert Skill Score (GSS), Extreme Dependency Score (EDS), Symmetric Extreme Dependency Score (SEDS), Bias Adjusted Gilbert Skill Score (BAGSS). +The TC-Gen tool processes both deterministic and probabilistic forecasts. For deterministic forecasts specified using the **-track** command line option, it identifies genesis events in both the forecasts and reference datasets, typically Best tracks. It applies user-specified configuration options to pair up the forecast and reference genesis events and categorize each pair as a hit, miss, or false alarm. As with other extreme events (where the event occurs much less frequently than the non-event), the correct negative category is not computed since the non-events would dominate the contingency table. Therefore, only statistics that do not include correct negatives should be considered for this tool. The following CTS statistics are relevant: Base rate (BASER), Mean forecast (FMEAN), Frequency Bias (FBIAS), Probability of Detection (PODY), False Alarm Ratio (FAR), Critical Success Index (CSI), Gilbert Skill Score (GSS), Extreme Dependency Score (EDS), Symmetric Extreme Dependency Score (SEDS), Bias Adjusted Gilbert Skill Score (BAGSS). + +For probabilistic forecasts specified using the **-edeck** command line option, it identifies genesis events in the reference dataset. It applies user-specified configuration options to pair the forecast probabilities to the reference genesis events. These pairs are added to an Nx2 probabilistic contingency table. If the reference genesis event occurs within in the predicted time window, the pair is counted in the observation-yes column. Otherwise, it is added to the observation-no column. Other considerations for interpreting the output of the TC-Gen tool involve the size of the contingency table output. The size of the contingency table will change depending on the number of matches. Additionally, the number of misses is based on the forecast duration and interval (specified in the configuration file). This change is due to the number of model opportunities to forecast the event, which is determined by the specified duration/interval. @@ -34,8 +36,8 @@ The usage statement for tc_gen is shown below: .. code-block:: none Usage: tc_gen - -genesis path - -track path + -genesis source and/or -edeck source + -track source -config file [-out base] [-log file] @@ -46,50 +48,76 @@ TC-Gen has three required arguments and accepts optional ones. Required arguments for tc_gen ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -1. The **-genesis path** argument is the path to one or more ATCF or fort.66 (see documentation listed below) files generated by the Geophysical Fluid Dynamics Laboratory (GFDL) Vortex Tracker when run in tcgen mode or an ASCII file list or a top-level directory containing them. The **-genesis** option must be used at least once. The required file format is described in the "Output formats" section of the `GFDL Vortex Tracker users guide. `_ +1. The **-genesis source** argument is the path to one or more ATCF or fort.66 (see documentation listed below) files generated by the Geophysical Fluid Dynamics Laboratory (GFDL) Vortex Tracker when run in tcgen mode or an ASCII file list or a top-level directory containing them. The required file format is described in the "Output formats" section of the `GFDL Vortex Tracker users guide. `_ + +2. The **-edeck source** argument is the path to one or more ATCF edeck files, an ASCII file list containing them, or a top-level directory with files matching the regular expression ".dat". The probability of genesis are read from each edeck input file and verified against at the **-track** data. The **-genesis** or **-edeck** option must be used at least once. -2. The **-track path** argument is one or more ATCF reference track files or an ASCII file list or top-level directory containing them, with files ending in ".dat". This tool processes either Best track data from bdeck files, or operational track data (e.g. CARQ) from adeck files, or both. Providing both bdeck and adeck files will result in a richer dataset to match with the **-genesis** files. Both adeck and bdeck data should be provided using the **-track** option. The **-track** option must be used at least once. +3. The **-track source** argument is one or more ATCF reference track files or an ASCII file list or top-level directory containing them, with files ending in ".dat". This tool processes either Best track data from bdeck files, or operational track data (e.g. CARQ) from adeck files, or both. Providing both bdeck and adeck files will result in a richer dataset to match with the **-genesis** files. Both adeck and bdeck data should be provided using the **-track** option. The **-track** option must be used at least once. -3. The **-config** file argument indicates the name of the configuration file to be used. The contents of the configuration file are discussed below. +4. The **-config** file argument indicates the name of the configuration file to be used. The contents of the configuration file are discussed below. Optional arguments for tc_gen ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -4. The **-out base** argument indicates the path of the output file base. This argument overrides the default output file base (./tc_gen) +5. The **-out base** argument indicates the path of the output file base. This argument overrides the default output file base (./tc_gen) -5. The **-log file** option directs output and errors to the specified log file. All messages will be written to that file as well as standard out and error. Thus, users can save the messages without having to redirect the output on the command line. The default behavior is no log file. +6. The **-log file** option directs output and errors to the specified log file. All messages will be written to that file as well as standard out and error. Thus, users can save the messages without having to redirect the output on the command line. The default behavior is no log file. -6. The **-v level** option indicates the desired level of verbosity. The contents of "level" will override the default setting of 2. Setting the verbosity to 0 will make the tool run with no log messages, while increasing the verbosity above 1 will increase the amount of logging. +7. The **-v level** option indicates the desired level of verbosity. The contents of "level" will override the default setting of 2. Setting the verbosity to 0 will make the tool run with no log messages, while increasing the verbosity above 1 will increase the amount of logging. -The TC-Gen tool implements the following logic: +Scoring Logic +^^^^^^^^^^^^^ -* Parse the forecast genesis data and identify forecast genesis events separately for each model present. +The TC-Gen tool implements the following logic: * 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. +* For **-track** inputs: + + * Parse the forecast genesis data and identify forecast genesis events separately for each model present. + + * Loop over the filters defined in the configuration file and apply the following logic for each. - * 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 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 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. + * 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 operational track points with lead time of 0 hours. If an operational match is found, store the storm ID. + * If 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. + * If a matching storm ID is found, match the forecast genesis event to the Best track genesis event for that storm ID. - * If no matching storm ID is found, store an unmatched pair for the genesis forecast. + * If no matching storm ID is found, store an unmatched pair for the genesis forecast. - * Loop through the genesis pairs and populate contingency tables using two methods, the developement (dev) and operational (ops) methods. For each pair, if the forecast genesis event is unmatched, score it as a dev and ops FALSE ALARM. If the Best track genesis event is unmatched, score it as a dev and ops MISS. Score each matched genesis pair as follows: + * Loop through the genesis pairs and populate contingency tables using two methods, the development (dev) and operational (ops) methods. For each pair, if the forecast genesis event is unmatched, score it as a dev and ops FALSE ALARM. If the Best track genesis event is unmatched, score it as a dev and ops MISS. Score each matched genesis pair as follows: - * If the forecast initialization time is at or after the Best track genesis event, DISCARD this case and exclude it from the statistics. + * If the forecast initialization time is at or after the Best track genesis event, DISCARD this case and exclude it from the statistics. - * Compute the difference between the forecast and Best track genesis events in time and space. If they are both within the configurable tolerance, score it as a dev HIT. If not, score it as a dev FALSE ALARM. + * Compute the difference between the forecast and Best track genesis events in time and space. If they are both within the configurable tolerance, score it as a dev HIT. If not, score it as a dev FALSE ALARM. - * Compute the difference between the Best track genesis time and model initialization time. If it is within the configurable tolerance, score it as an ops HIT. If not, score it as an ops FALSE ALARM. + * Compute the difference between the Best track genesis time and model initialization time. If it is within the configurable tolerance, score it as an ops HIT. If not, score it as an ops FALSE ALARM. + + * Do not count any CORRECT NEGATIVES. + + * Report the contingency table hits, misses, and false alarms separately for each forecast model and configuration file filter. The development (dev) scoring method is indicated in the output as *GENESIS_DEV* while the operational (ops) scoring method is indicated as *GENESIS_OPS*. + +* For **-edeck** inputs: + + * Parse the ATCF edeck files. Ignore any lines not containing "GN" and "genFcst", which indicate a genesis probability forecast. Also, ignore any lines which do not contain a predicted genesis location (latitude and longitude) or genesis time. + + * Loop over the filters defined in the configuration file and apply the following logic for each. + + * Subset the genesis probability forecasts based on the current filter criteria. Typically, genesis probability forecast are provided for multiple lead times. Create separate Nx2 probabilistic contingency tables for each unique combination of predicted lead time and model name. - * Do not count any CORRECT NEGATIVES. + * For each genesis probability forecast, 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. + + * If 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 no matching storm ID is found, add the unmatched forecast to the observation-no column of the Nx2 probabilistic contingency table. + + * If a matching storm ID is found, check whether that storm's genesis occurred within the predicted time window: between the forecast initialization time and the predicted lead time. If so, add the matched forecast to the observation-yes column. If not, add it to observation-no column. + + * Report the Nx2 probabilistic contingency table counts and statistics for each forecast model, lead time, and configuration file filter. These counts and statistics are identified in the output files as *PROB_GENESIS*. -* Report the contingency table hits, misses, and false alarms separately for each forecast model and configuration file filter. The development (dev) scoring method is indicated in the output as *GENESIS_DEV* while the operational (ops) scoring method is indicated as *GENESIS_OPS*. tc_gen configuration file ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -381,18 +409,32 @@ The **nc_pairs_grid** entry is a string which defines the grid to be used for th ______________________ +.. code-block:: none + + prob_genesis_thresh = ==0.25; + +The **prob_genesis_thresh** entry defines the probability thresholds used to create the output Nx2 contingency table when verifying edeck probability of genesis forecasts. The default is probability bins of width 0.25. These probabilities may be specified as a list (>0.00,>0.25,>0.50,>0.75,>1.00) or using shorthand notation (==0.25) for bins of equal width. + +______________________ + .. code-block:: none ci_alpha = 0.05; output_flag = { - fho = BOTH; - ctc = BOTH; - cts = BOTH; + fho = BOTH; + ctc = BOTH; + cts = BOTH; + pct = NONE; + pstd = NONE; + pjc = NONE; + prc = NONE; + genmpr = NONE; +} } dland_file = "MET_BASE/tc_data/dland_global_tenth_degree.nc"; version = "VN.N"; -The configuration options listed above are common to many MET tools and are described in :numref:`config_options`. Note that TC-Gen writes output for 2x2 contingency tables to the **FHO, CTC**, and **CTS** line types. +The configuration options listed above are common to many MET tools and are described in :numref:`config_options`. TC-Gen writes output for 2x2 contingency tables to the **FHO**, **CTC**, and **CTS** line types when verifying deterministic genesis forecasts specified using the **-track** command line option. TC-Gen writes output for Nx2 probabilistic contingency tables to the **PCT**, **PSTD**, **PJC**, and **PRC** line types when verifying the probability of genesis forecasts specified using the **-edeck** command line option. Note that the **genmpr** line type is specific to TC-Gen and describes individual genesis matched pairs. tc_gen output ~~~~~~~~~~~~~ @@ -440,7 +482,7 @@ TC-Gen produces output in STAT and, optionally, ASCII and NetCDF formats. The AS - Maximum Best track valid time in YYYYMMDD_HHMMSS format * - 10 - FCST_VAR - - Genesis methodology + - Genesis methodology (GENESIS_DEV, GENESIS_OPS, or PROB_GENESIS) * - 11 - FCST_UNITS - Does not apply and is set to NA @@ -449,7 +491,7 @@ TC-Gen produces output in STAT and, optionally, ASCII and NetCDF formats. The AS - Does not apply and is set to NA * - 13 - OBS_VAR - - Genesis methodology + - Genesis methodology (GENESIS_DEV, GENESIS_OPS, or PROB_GENESIS) * - 14 - OBS_UNITS - Does not apply and is set to NA @@ -515,44 +557,50 @@ TC-Gen produces output in STAT and, optionally, ASCII and NetCDF formats. The AS - STORM_ID - BBCCYYYY designation of storm (basin, cyclone number, and year) * - 28 + - PROB_LEAD + - Lead time in HHH format for the predicted probability of genesis (only for **-edeck** inputs) + * - 29 + - PROB_VAL + - Predicted probability of genesis (only for **-edeck** inputs) + * - 30 - AGEN_INIT - Forecast initialization time - * - 29 + * - 31 - AGEN_FHR - Forecast hour of genesis event - * - 30 + * - 32 - AGEN_LAT - Latitude position of the forecast genesis event - * - 31 + * - 33 - AGEN_LON - Longitude position of the forecast genesis event - * - 32 + * - 34 - AGEN_DLAND - Forecast genesis event distance to land (nm) - * - 33 + * - 35 - BGEN_LAT - Latitude position of the verifying Best track genesis event - * - 34 + * - 36 - BGEN_LON - Longitude position of the verifying Best track genesis event - * - 35 + * - 37 - BGEN_DLAND - Best track genesis event distance to land (nm) - * - 36 + * - 38 - GEN_DIST - - Distance between the forecast and Best track genesis events (km) - * - 37 + - Distance between the forecast and Best track genesis events (km) (only for **-track** inputs) + * - 39 - GEN_TDIFF - - Forecast minus Best track genesis time in HHMMSS format - * - 38 + - Forecast minus Best track genesis time in HHMMSS format (only for **-track** inputs) + * - 40 - INIT_TDIFF - - Best track genesis minus forecast initialization time in HHMMSS format - * - 39 + - Best track genesis minus forecast initialization time in HHMMSS format (only for **-track** inputs) + * - 41 - DEV_CAT - - Development methodology category (FYOY, FYON, FNOY, or DISCARD) - * - 40 + - Category for the development methodology (FYOY, FYON, FNOY, or DISCARD) (only for **-track** inputs) + * - 42 - OPS_CAT - - Operational methodology category (FYOY, FYON, FNOY, or DISCARD) + - Category for the operational methodology (FYOY, FYON, FNOY, or DISCARD for **-track** inputs and FYOY or FYON for **-edeck** inputs) .. _table_TG_var_NetCDF_matched_pair_out: From 7bc3d70bab11f400d86c7db71e9d0d4a535885cf Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Sun, 14 Nov 2021 19:52:36 -0700 Subject: [PATCH 27/28] Per #1809, fix typo in docs. --- met/docs/Users_Guide/tc-gen.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/met/docs/Users_Guide/tc-gen.rst b/met/docs/Users_Guide/tc-gen.rst index d068ed4432..e5c206316d 100644 --- a/met/docs/Users_Guide/tc-gen.rst +++ b/met/docs/Users_Guide/tc-gen.rst @@ -429,7 +429,6 @@ ______________________ pjc = NONE; prc = NONE; genmpr = NONE; -} } dland_file = "MET_BASE/tc_data/dland_global_tenth_degree.nc"; version = "VN.N"; From a18b069e71875b72ff0af89e22ee12ecf97e0d7c Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Sun, 14 Nov 2021 20:00:59 -0700 Subject: [PATCH 28/28] Per #1809, doc updates. --- met/docs/Users_Guide/tc-gen.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/met/docs/Users_Guide/tc-gen.rst b/met/docs/Users_Guide/tc-gen.rst index e5c206316d..b67f1a26b9 100644 --- a/met/docs/Users_Guide/tc-gen.rst +++ b/met/docs/Users_Guide/tc-gen.rst @@ -6,14 +6,16 @@ TC-Gen Tool Introduction ____________ -The TC-Gen tool provides verification of tropical cyclone genesis forecasts in the ATCF file format as well at the probability of genesis forecasts. Producing reliable tropical cyclone genesis forecasts is an important metric for global numerical weather prediction models. This tool ingests probabilistic and deterministic model output post-processed by a genesis tracking software (e.g. GFDL vortex tracker) and ATCF format reference dataset(s) (e.g. Best Track analysis and CARQ operational tracks) and outputs categorical counts and statistics. The capability to modify the spatial and temporal tolerances that define a "hit" forecast is included to give users the ability to condition the criteria based on model performance and/or conduct sensitivity analyses. Statistical aspects are outlined in :numref:`tc-gen_stat_aspects` and practical aspects of the TC-Gen tool are described in :numref:`tc-gen_practical_info`. +The TC-Gen tool provides verification of deterministic and probabilistic tropical cyclone genesis forecasts in the ATCF file format. Producing reliable tropical cyclone genesis forecasts is an important metric for global numerical weather prediction models. This tool ingests deterministic model output post-processed by a genesis tracking software (e.g. GFDL vortex tracker), ATCF edeck files containing probability of genesis forecasts, and ATCF reference track dataset(s) (e.g. Best Track analysis and CARQ operational tracks). It writes categorical counts and statistics. The capability to modify the spatial and temporal tolerances when matching forecasts to reference genesis events, as well as scoring those matched pairs, gives users the ability to condition the criteria based on model performance and/or conduct sensitivity analyses. Statistical aspects are outlined in :numref:`tc-gen_stat_aspects` and practical aspects of the TC-Gen tool are described in :numref:`tc-gen_practical_info`. .. _tc-gen_stat_aspects: Statistical aspects ___________________ -The TC-Gen tool processes both deterministic and probabilistic forecasts. For deterministic forecasts specified using the **-track** command line option, it identifies genesis events in both the forecasts and reference datasets, typically Best tracks. It applies user-specified configuration options to pair up the forecast and reference genesis events and categorize each pair as a hit, miss, or false alarm. As with other extreme events (where the event occurs much less frequently than the non-event), the correct negative category is not computed since the non-events would dominate the contingency table. Therefore, only statistics that do not include correct negatives should be considered for this tool. The following CTS statistics are relevant: Base rate (BASER), Mean forecast (FMEAN), Frequency Bias (FBIAS), Probability of Detection (PODY), False Alarm Ratio (FAR), Critical Success Index (CSI), Gilbert Skill Score (GSS), Extreme Dependency Score (EDS), Symmetric Extreme Dependency Score (SEDS), Bias Adjusted Gilbert Skill Score (BAGSS). +The TC-Gen tool processes both deterministic and probabilistic forecasts. For deterministic forecasts specified using the **-track** command line option, it identifies genesis events in both the forecasts and reference datasets, typically Best tracks. It applies user-specified configuration options to pair up the forecast and reference genesis events and categorize each pair as a hit, miss, or false alarm. + +As with other extreme events (where the event occurs much less frequently than the non-event), the correct negative category is not computed since the non-events would dominate the contingency table. Therefore, only statistics that do not include correct negatives should be considered for this tool. The following CTS statistics are relevant: Base rate (BASER), Mean forecast (FMEAN), Frequency Bias (FBIAS), Probability of Detection (PODY), False Alarm Ratio (FAR), Critical Success Index (CSI), Gilbert Skill Score (GSS), Extreme Dependency Score (EDS), Symmetric Extreme Dependency Score (SEDS), Bias Adjusted Gilbert Skill Score (BAGSS). For probabilistic forecasts specified using the **-edeck** command line option, it identifies genesis events in the reference dataset. It applies user-specified configuration options to pair the forecast probabilities to the reference genesis events. These pairs are added to an Nx2 probabilistic contingency table. If the reference genesis event occurs within in the predicted time window, the pair is counted in the observation-yes column. Otherwise, it is added to the observation-no column.