diff --git a/docs/Users_Guide/tc-pairs.rst b/docs/Users_Guide/tc-pairs.rst index 40162dee4d..dbacd34839 100644 --- a/docs/Users_Guide/tc-pairs.rst +++ b/docs/Users_Guide/tc-pairs.rst @@ -199,10 +199,11 @@ ____________________ members = [ "MOD1", "MOD2", "MOD3" ]; required = [ true, false, false ]; min_req = 2; + write_members = TRUE; } ]; -The **consensus** field allows the user to generate a user-defined consensus forecasts from any number of models. All models used in the consensus forecast need to be included in the **model** field (first entry in **TCPairsConfig_default**). The name field is the desired consensus model name. The **members** field is a comma-separated list of model IDs that make up the members of the consensus. The **required** field is a comma-separated list of true/false values associated with each consensus member. If a member is designated as true, the member is required to be present in order for the consensus to be generated. If a member is false, the consensus will be generated regardless of whether the member is present. The length of the required array must be the same length as the members array. The **min_req** field is the number of members required in order for the consensus to be computed. The required and min_req field options are applied at each forecast lead time. If any member of the consensus has a non-valid position or intensity value, the consensus for that valid time will not be generated. If a consensus model is indicated in the configuration file there will be non-missing output for the consensus track variables in the output file (NUM_MEMBERS, TRACK_SPREAD, TRACK_STDEV, MSLP_STDEV, MAX_WIND_STDEV). See the TCMPR line type definitions below. +The **consensus** field allows the user to generate a user-defined consensus forecasts from any number of models. All models used in the consensus forecast need to be included in the **model** field (first entry in **TCPairsConfig_default**). The name field is the desired consensus model name. The **members** field is a comma-separated list of model IDs that make up the members of the consensus. The **required** field is a comma-separated list of true/false values associated with each consensus member. If a member is designated as true, the member is required to be present in order for the consensus to be generated. If a member is false, the consensus will be generated regardless of whether the member is present. The length of the required array must be the same length as the members array. The **min_req** field is the number of members required in order for the consensus to be computed. The required and min_req field options are applied at each forecast lead time. If any member of the consensus has a non-valid position or intensity value, the consensus for that valid time will not be generated. The **write_members** field is a boolean that indicates whether or not to write output for the individual consensus members. If set to true, standard output will show up for all members. If set to false, output for the consensus members is excluded from the output, even if they are used to define other consensus tracks in the configuration file. If a consensus model is defined in the configuration file, there will be non-missing output for the consensus track variables in the output file (NUM_MEMBERS, TRACK_SPREAD, TRACK_STDEV, MSLP_STDEV, MAX_WIND_STDEV). See the TCMPR line type definitions below. ____________________ diff --git a/internal/test_unit/config/TCPairsConfig_CONSENSUS b/internal/test_unit/config/TCPairsConfig_CONSENSUS index b157c71264..f7382ae85b 100644 --- a/internal/test_unit/config/TCPairsConfig_CONSENSUS +++ b/internal/test_unit/config/TCPairsConfig_CONSENSUS @@ -107,42 +107,49 @@ consensus = [ "UE35" ]; required = []; min_req = 36; + write_members = FALSE; }, { name = "HCCA_CONS"; members = [ "AEMI", "GFSI", "CTCI", "DSHP", "EGRI", "EMN2", "EMXI", "HWFI", "LGEM" ]; required = []; min_req = 8; + write_members = TRUE; }, { name = "GFEX_CONS"; members = [ "GFSI", "EMXI" ]; required = []; min_req = 2; + write_members = TRUE; }, { name = "TVCA_CONS"; members = [ "GFSI", "EGRI", "HWFI", "EMHI", "CTCI", "EMNI" ]; required = []; min_req = 2; + write_members = TRUE; }, { name = "TVCX_CONS"; members = [ "GFSI", "EMXI", "EMXI", "HWFI", "CTCI", "EGRI" ]; required = [ TRUE, TRUE, FALSE, FALSE, FALSE, FALSE ]; min_req = 2; + write_members = TRUE; }, { name = "ICON_CONS"; members = [ "DSHP", "LGEM", "HWFI", "HMNI" ]; required = [ TRUE, TRUE, TRUE, TRUE ]; min_req = 4; + write_members = TRUE; }, { name = "IVCN_CONS"; members = [ "DSHP", "LGEM", "HWFI", "HMNI", "CTCI" ]; required = []; min_req = 2; + write_members = TRUE; } ]; diff --git a/src/basic/vx_config/config_constants.h b/src/basic/vx_config/config_constants.h index fb49e5cce7..d2e6a25f42 100644 --- a/src/basic/vx_config/config_constants.h +++ b/src/basic/vx_config/config_constants.h @@ -1086,6 +1086,7 @@ static const char conf_key_consensus[] = "consensus"; static const char conf_key_members[] = "members"; static const char conf_key_required[] = "required"; static const char conf_key_min_req[] = "min_req"; +static const char conf_key_write_members[] = "write_members"; static const char conf_key_lag_time[] = "lag_time"; static const char conf_key_best_technique[] = "best_technique"; static const char conf_key_best_baseline[] = "best_baseline"; diff --git a/src/tools/tc_utils/tc_pairs/tc_pairs.cc b/src/tools/tc_utils/tc_pairs/tc_pairs.cc index 734f83d256..618b818d51 100644 --- a/src/tools/tc_utils/tc_pairs/tc_pairs.cc +++ b/src/tools/tc_utils/tc_pairs/tc_pairs.cc @@ -36,6 +36,7 @@ // 012 07/06/22 Howard Soh METplus-Internal #19 Rename main to met_main // 013 09/28/22 Prestopnik MET #2227 Remove namespace std from header files // 014 10/06/22 Halley Gotway MET #392 Incorporate diagnostics +// 015 02/20/23 Seth Linden MET #2429 Added option to prevent output of consensus track members // //////////////////////////////////////////////////////////////////////// @@ -811,19 +812,30 @@ bool is_keeper(const ATCFLineBase * line) { void filter_tracks(TrackInfoArray &tracks) { int i, j; - int n_name, n_vld, n_mask_init, n_mask_vld, n_req_lead; + int n_name, n_vld, n_mask_init, n_mask_vld, n_req_lead, n_members; bool status; TrackInfoArray t = tracks; // Initialize tracks.clear(); - n_name = n_vld = n_mask_init = n_mask_vld = n_req_lead = 0; + n_name = n_vld = n_mask_init = n_mask_vld = n_req_lead = n_members = 0; // Loop through the tracks and determine which should be retained // The is_keeper() function has already filtered by model, storm id, // basin, cyclone, and timing information. for(i=0; i 0 && + conf_info.SkipConsensusMembers.has(t[i].technique())) { + mlog << Debug(4) + << "Discarding track " << i+1 << " since it is listed in SkipConsensusMembers: " + << t[i].technique() << "\n"; + n_members++; + continue; + } + // Check storm name if(conf_info.StormName.n() > 0 && !conf_info.StormName.has(t[i].storm_name())) { @@ -922,6 +934,7 @@ void filter_tracks(TrackInfoArray &tracks) { mlog << Debug(3) << "Total tracks read = " << t.n() << "\n" << "Total tracks kept = " << tracks.n() << "\n" + << "Rejected for skip members = " << n_members << "\n" << "Rejected for storm name = " << n_name << "\n" << "Rejected for valid time = " << n_vld << "\n" << "Rejected for required lead times = " << n_req_lead << "\n" diff --git a/src/tools/tc_utils/tc_pairs/tc_pairs_conf_info.cc b/src/tools/tc_utils/tc_pairs/tc_pairs_conf_info.cc index b4faab8aef..faafaab0e7 100644 --- a/src/tools/tc_utils/tc_pairs/tc_pairs_conf_info.cc +++ b/src/tools/tc_utils/tc_pairs/tc_pairs_conf_info.cc @@ -74,6 +74,7 @@ void TCPairsConfInfo::clear() { Basin.clear(); Cyclone.clear(); StormName.clear(); + SkipConsensusMembers.clear(); InitBeg = InitEnd = (unixtime) 0; InitInc.clear(); InitExc.clear(); @@ -240,12 +241,21 @@ void TCPairsConfInfo::process_config() { // Loop over the consensus entries for(i=0; idict_value()->lookup_string(conf_key_name); Consensus[i].Members = (*dict)[i]->dict_value()->lookup_string_array(conf_key_members); Consensus[i].Required = (*dict)[i]->dict_value()->lookup_num_array(conf_key_required); Consensus[i].MinReq = (*dict)[i]->dict_value()->lookup_int(conf_key_min_req); + // If write_members is missing, print warning message rather than error + Consensus[i].WriteMembers = (*dict)[i]->dict_value()->lookup_bool(conf_key_write_members, false); + if(!(*dict)[i]->dict_value()->last_lookup_status()) { + mlog << Warning + << "\nTCPairsConfInfo::process_config() -> " + << "\"consensus.write_members\" is missing. Using default value of true.\n\n"; + Consensus[i].WriteMembers = true; + } + // If required is empty, default to 0 if(Consensus[i].Required.n_elements() == 0) { for(j=0; j