Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature 2476 tc pairs diag #2694

Merged
merged 25 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b7f9573
Per #2476, clarify the match_to_track TC-Pairs config option for CIRA…
JohnHalleyGotway Sep 7, 2023
3335d58
Per #2476, add a fake data example of including diagnostics in the co…
JohnHalleyGotway Sep 7, 2023
7b623d2
Per issue #2476, added code to compute consensus (avg) diagnostic val…
Sep 20, 2023
70219a0
Per issue #2476, moved derive_consensus() to be after process_diags()…
Sep 20, 2023
c99a3bd
Per issue #2476, cleaned up some unused test code. SL
Sep 21, 2023
5840c93
Per #2476, when computing a consensus, clear the psum diagnostic valu…
JohnHalleyGotway Sep 21, 2023
20d2e25
Per issue #2476, added new function get_diag_val() that will retrieve…
Sep 22, 2023
5e8587b
Per issue #2476, in get_diag_val, added check that DiagVal array has …
Sep 22, 2023
4613e7c
Per issue #2476, updated the diag code in consensus() to use tavg.dia…
Sep 22, 2023
c122eb7
Per issue #2476, latest version for producing consensus diagnostic va…
Sep 27, 2023
de73d9d
Merge branch 'develop' into feature_2476_tc_pairs_diag
Sep 27, 2023
cf8644c
Per #2476, fix track_point.h to define the scope for std::string.
JohnHalleyGotway Sep 27, 2023
09f015f
Merge branch 'feature_2476_tc_pairs_diag' of github.com:dtcenter/MET …
Sep 27, 2023
10dfdae
Per issue #2476, updated void add_uniq_diag_name() to use std::string…
Sep 27, 2023
4ad55a6
Update src/libcode/vx_tc_util/track_info.cc
sethlinden Oct 2, 2023
c3c8c25
Update src/libcode/vx_tc_util/track_info.cc
sethlinden Oct 2, 2023
f553cc8
Update src/libcode/vx_tc_util/track_info.cc
sethlinden Oct 2, 2023
85b73e5
Update src/libcode/vx_tc_util/track_info.cc
sethlinden Oct 2, 2023
7871739
Update src/libcode/vx_tc_util/track_info.cc
sethlinden Oct 2, 2023
5a26c2f
Update src/libcode/vx_tc_util/track_info.cc
sethlinden Oct 2, 2023
262264c
Update src/libcode/vx_tc_util/track_info.cc
sethlinden Oct 2, 2023
a6b0aff
Update src/libcode/vx_tc_util/track_info.cc
sethlinden Oct 2, 2023
f9bf0ec
Update src/libcode/vx_tc_util/track_info.cc
sethlinden Oct 2, 2023
3b7d653
Update src/libcode/vx_tc_util/track_info.h
sethlinden Oct 2, 2023
f691e98
Per issue #2476, in consensus, fixed a debug / log statement. Also in…
Oct 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion data/config/TCPairsConfig_default
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ diag_info_map = [
diag_source = "CIRA_DIAG_RT";
track_source = "GFS";
field_source = "GFS_0p50";
match_to_track = [ "GFS" ];
match_to_track = [];
diag_name = [];
},
{
Expand Down
8 changes: 6 additions & 2 deletions docs/Users_Guide/tc-pairs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ ____________________
diag_source = "CIRA_DIAG_RT";
track_source = "GFS";
field_source = "GFS_0p50";
match_to_track = [ "GFS" ];
match_to_track = [];
diag_name = [];
},
{
Expand All @@ -307,7 +307,11 @@ A TCMPR line is written to the output for each track point. If diagnostics data

The **diag_info_map** entries define how the diagnostics read with the **-diag** command line option should be used. Each array element is a dictionary consisting of entries for **diag_source**, **track_source**, **field_source**, **match_to_track**, and **diag_name**.

The **diag_source** entry is one of the supported diagnostics data sources. The **track_source** entry is a string defining the ATCF ID of the track data used to define the locations at which diagnostics are computed. This string is written to the **TRACK_SOURCE** column of the TCDIAG output line. The **field_source** entry is a string describing the gridded model data from which the diagnostics are computed. This string is written to the **FIELD_SOURCE** column of the TCDIAG output line type. The **match_to_track** entry specifies a comma-separated list of strings defining the ATCF ID(s) of the tracks to which these diagnostic values should be matched. The **diag_name** entry specifies a comma-separated list of strings for the tropical cyclone diagnostics of interest. If a non-zero list of diagnostic names is specified, only those diagnostics appearing in the list are written to the TCDIAG output line type. If defined as an empty list (default), all diagnostics found in the input are written to the TCDIAG output lines.
- The **diag_source** entry is one of the supported diagnostics data sources.
- The **track_source** entry is a string defining the ATCF ID of the track data used to define the locations at which diagnostics are computed. This string is written to the **TRACK_SOURCE** column of the TCDIAG output line.
- The **field_source** entry is a string describing the gridded model data from which the diagnostics are computed. This string is written to the **FIELD_SOURCE** column of the TCDIAG output line type.
- The **match_to_track** entry specifies a comma-separated list of strings defining the ATCF ID(s) of the tracks to which these diagnostic values should be matched. For the SHIPS_DIAG_RT source, this is required since it is the only way to associate diagnostics with track ATCF IDs. For the CIRA_DIAG_RT source, this is optional. If a non-zero list is provided, the diagnostics will be matched to tracks for the specified ATCF ID(s). If defined as an empty list (default), the ATCF ID will be extracted from each CIRA diagnostic file and used to match the diagnostics to track data.
- The **diag_name** entry specifies a comma-separated list of strings for the tropical cyclone diagnostics of interest. If a non-zero list of diagnostic names is specified, only those diagnostics appearing in the list are written to the TCDIAG output line type. If defined as an empty list (default), all diagnostics found in the input are written to the TCDIAG output lines.

____________________

Expand Down
2 changes: 1 addition & 1 deletion internal/test_unit/config/TCPairsConfig_DIAGNOSTICS
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ diag_info_map = [
diag_source = "CIRA_DIAG_RT";
track_source = "GFS";
field_source = "GFS_0p50";
match_to_track = [ "GFS" ];
match_to_track = [];
diag_name = [ ${CIRA_RT_DIAG_NAME} ];
},
{
Expand Down
175 changes: 175 additions & 0 deletions internal/test_unit/config/TCPairsConfig_DIAGNOSTICS_CONSENSUS
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
////////////////////////////////////////////////////////////////////////////////
//
// TC-Pairs configuration file.
//
// For additional information, please see the MET User's Guide.
//
////////////////////////////////////////////////////////////////////////////////

//
// ATCF file format reference:
// http://www.nrlmry.navy.mil/atcf_web/docs/database/new/abrdeck.html
//

//
// Models
//
model = [ "GFSI", "EMXI" ];

//
// Description
//
desc = "NA";

//
// Storm identifiers
//
storm_id = [ ${STORM_ID} ];

//
// Basins
//
basin = [];

//
// Cyclone numbers
//
cyclone = [];

//
// Storm names
//
storm_name = [];

//
// Model initialization time windows to include or exclude
//
init_beg = "";
init_end = "";
init_inc = [ ${INIT_INC} ];
init_exc = [];

//
// Valid model time windows to include or exclude
//
valid_beg = "";
valid_end = "";
valid_inc = [];
valid_exc = [];

//
// Valid times for which output should be written
//
write_valid = [];

//
// Model initialization hours
//
init_hour = [];

//
// Required lead time in hours
//
lead_req = [];

//
// lat/lon polylines defining masking regions
//
init_mask = "";
valid_mask = "";

//
// Specify if the code should check for duplicate ATCF lines
//
check_dup = TRUE;

//
// Specify special processing to be performed for interpolated models.
// Set to NONE, FILL, or REPLACE.
//
interp12 = NONE;

//
// Specify how consensus forecasts should be defined
// See NHC Consensus Definitions in Table 2:
// https://www.nhc.noaa.gov/modelsummary.shtml
//
consensus = [
{
name = "GFEX_CONS";
members = [ "GFSI", "EMXI" ];
required = [];
min_req = 2;
write_members = TRUE;
}
];

//
// Forecast lag times
//
lag_time = [];

//
// CLIPER/SHIFOR baseline forecasts to be derived from the BEST
// and operational (CARQ) tracks.
//
best_baseline = [];
oper_baseline = [];

//
// Specify if only those track points common to both the ADECK and BDECK
// tracks be written out.
//
match_points = TRUE;

//
// Specify the NetCDF output of the gen_dland tool containing a gridded
// representation of the minimum distance to land.
//
dland_file = "${MET_TEST_OUTPUT}/tc_dland/tc_dland_half_deg.nc";

//
// Specify watch/warning information:
// - Input watch/warning filename
// - Watch/warning time offset in seconds
//
watch_warn = {
file_name = "MET_BASE/tc_data/wwpts_us.txt";
time_offset = -14400;
}

//
// Diagnostics to be extracted
//
diag_info_map = [
{
diag_source = "CIRA_DIAG_RT";
track_source = "TRACK_MODEL";
field_source = "0p50RES";
match_to_track = [ ];
diag_name = [ ${CIRA_RT_DIAG_NAME} ];
}
];

//
// Unit conversions to be applied based on diagnostic names and units
// Commented out to use settings from the default config file
//
// diag_convert_map = [];

//
// Modify basin names to make them consistent across ATCF input files.
//
basin_map = [
{ key = "SI"; val = "SH"; },
{ key = "SP"; val = "SH"; },
{ key = "AU"; val = "SH"; },
{ key = "AB"; val = "IO"; },
{ key = "BB"; val = "IO"; }
];

//
// Indicate a version number for the contents of this configuration file.
// The value should generally not be modified.
//
version = "V12.0.0";
23 changes: 23 additions & 0 deletions internal/test_unit/xml/unit_tc_pairs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -206,4 +206,27 @@
</output>
</test>

<test name="tc_pairs_DIAGNOSTICS_CONSENSUS">
sethlinden marked this conversation as resolved.
Show resolved Hide resolved
<exec>&MET_BIN;/tc_pairs</exec>
<env>
<pair><name>STORM_ID</name> <value>"AL092022"</value></pair>
<pair><name>INIT_INC</name> <value>"20220926_06", "20220926_18"</value></pair>
<pair><name>CIRA_RT_DIAG_NAME</name> <value>"TPW", "LAND", "SHR_MAG", "STM_SPD"</value></pair>
</env>
<param> \
-adeck &DATA_DIR;/adeck/aal092022.dat \
-bdeck &DATA_DIR;/bdeck/bal092022.dat \
-diag CIRA_DIAG_RT &DATA_DIR;/diag/cira_diag_rt/2022/GFSI/sal092022_avni_doper_20220926*_diag.dat \
-diag CIRA_DIAG_RT &DATA_DIR;/diag/cira_diag_rt/2022/EMXI/sal092022_emxi_doper_20220926*_diag.dat \
-config &CONFIG_DIR;/TCPairsConfig_DIAGNOSTICS_CONSENSUS \
-out &OUTPUT_DIR;/tc_pairs/al092022_20220926_DIAGNOSTICS_CONSENSUS \
-log &OUTPUT_DIR;/tc_pairs/tc_pairs_DIAGNOSTICS_CONSENSUS.log \
-v 4
</param>
<output>
<stat>&OUTPUT_DIR;/tc_pairs/al092022_20220926_DIAGNOSTICS_CONSENSUS.tcst</stat>
</output>
</test>


</met_test>
84 changes: 77 additions & 7 deletions src/libcode/vx_tc_util/track_info.cc
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ bool TrackInfo::add_diag_data(DiagFile &diag_file, const StringArray &req_diag_n
// Store the diagnostic name
DiagName.add(diag_file.diag_name()[i_name]);
NumArray diag_val = diag_file.diag_val(diag_file.diag_name()[i_name]);

sethlinden marked this conversation as resolved.
Show resolved Hide resolved
// Add diagnostic values to the TrackPoints
for(i_time=0; i_time<diag_file.n_time(); i_time++) {

Expand Down Expand Up @@ -618,6 +618,16 @@ void TrackInfo::add_diag_value(int i_pnt, double val) {

////////////////////////////////////////////////////////////////////////

void TrackInfo::add_uniq_diag_name(const string diag_name) {

// Store the diagnostic name
DiagName.add_uniq(diag_name);

return;
}

////////////////////////////////////////////////////////////////////////

bool TrackInfo::has(const ATCFTrackLine &l) const {
return(TrackLines.has(l.get_line()));
}
Expand Down Expand Up @@ -965,11 +975,11 @@ int TrackInfoArray::add_diag_data(DiagFile &diag_file, const StringArray &diag_n
TrackInfo consensus(const TrackInfoArray &tracks,
const ConcatString &model, int req,
const StringArray &req_list) {
int i, j, i_pnt;
int i, j, k, i_pnt;
bool skip;
TrackInfo tavg;
NumArray lead_list;

sethlinden marked this conversation as resolved.
Show resolved Hide resolved
// Variables for average TrackPoint
int pcnt;
TrackPoint pavg, psum;
Expand All @@ -993,7 +1003,7 @@ TrackInfo consensus(const TrackInfoArray &tracks,
tavg.set_technique(model.c_str());
tavg.set_init(tracks[0].init());
tavg.set_storm_id();

sethlinden marked this conversation as resolved.
Show resolved Hide resolved
// Loop through the tracks and build a list of lead times
for(i=0; i<tracks.n(); i++) {

Expand All @@ -1016,6 +1026,13 @@ TrackInfo consensus(const TrackInfoArray &tracks,
<< tracks[i].technique_number() << ").\n\n";
}

// Get unique diag names
// Store diag_names in tavg object
for(j=0; j<tracks[i].diag_name().n(); j++) {
mlog << Debug(3) << "TrackInfo::consensus(). Found unique diag_name[" << j << "] = " << tracks[i].diag_name()[j] << "\n";
sethlinden marked this conversation as resolved.
Show resolved Hide resolved
tavg.add_uniq_diag_name(tracks[i].diag_name()[j]);
}

// Loop through the points for the lead times
for(j=0; j<tracks[i].n_points(); j++) {

Expand Down Expand Up @@ -1056,11 +1073,18 @@ TrackInfo consensus(const TrackInfoArray &tracks,
}
continue;
}

sethlinden marked this conversation as resolved.
Show resolved Hide resolved
// Increment the TrackPoint count and sums
// Remove diagnostic values from the TrackPoint object (psum) for the consensus values
// Consensus diag values computed below this
pcnt++;
if(pcnt == 1) psum = tracks.Track[j][i_pnt];
else psum += tracks.Track[j][i_pnt];
if(pcnt == 1) {
psum = tracks.Track[j][i_pnt];
psum.clear_diag_value();
}
else {
psum += tracks.Track[j][i_pnt];
}

// Store the track point latitude, longitude v_max and mslp values
plon.add(tracks.Track[j][i_pnt].lon());
Expand Down Expand Up @@ -1138,6 +1162,52 @@ TrackInfo consensus(const TrackInfoArray &tracks,
// Compute consensus CycloneLevel
if(!is_bad_data(pavg.v_max())) pavg.set_level(wind_speed_to_cyclonelevel(pavg.v_max()));

// Loop over the diag name and the input track points and get consensus diag value
// (mean value across all members that have the diag value)
for (j=0; j<tavg.diag_name().n(); j++){
mlog << Debug(3) << "TrackInfo::consensus(). Working on calculating mean values for tavg.diag_name()[" << j << "] = " << tavg.diag_name()[j] << "\n";
sethlinden marked this conversation as resolved.
Show resolved Hide resolved

// Store diag_vals for one diag_name across all lead-times (track points)
NumArray diag_vals;
double cons_diag_val;

// Initializ diag_vals array for this diag name
diag_vals.clear();

// Loop through the tracks to get average diagnostic values
for(k=0; k<tracks.n(); k++) {

// Get the index of the TrackPoint for this lead time
i_pnt = tracks.Track[k].lead_index(nint(lead_list[i]));

// Check for missing TrackPoint in a required member
if(i_pnt < 0) {
if(req_list.has(tracks.Track[k].technique())) {
skip = true;
break;
}
continue;
}

// Add non-missing diag values to local NumArray
if(!is_bad_data( tracks.Track[k][i_pnt].get_diag_val(tavg.diag_name(), tavg.diag_name()[j]) )) {
mlog << Debug(3) << " Adding values for k: " << k << ", i_pnt: " << i_pnt << " tracks.Track[k][i_pnt].get_diag_val(tavg.diag_name(), tavg.diag_name()[j]) = " << tracks.Track[k][i_pnt].get_diag_val(tavg.diag_name(), tavg.diag_name()[j]) << "\n";
sethlinden marked this conversation as resolved.
Show resolved Hide resolved
diag_vals.add(tracks.Track[k][i_pnt].get_diag_val(tavg.diag_name(), tavg.diag_name()[j]));
}

} // end loop over ensemble of tracks (for given lead-time: i_pnt)

cons_diag_val = diag_vals.mean();
mlog << Debug(3) << " cons_diag_val = " << cons_diag_val << "\n";
sethlinden marked this conversation as resolved.
Show resolved Hide resolved

// Add the cons_diag_val to the pavg DiagVal NumArray (using add_diag_value)
if(!is_bad_data(cons_diag_val)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we actually NEED to store the computed diagnostic value regardless of whether or not it contains bad data? For example, let's say all the input tracks report a diag value with bad data. If we fail to write bad data to the output, we'll end up with a mismatch of diagnostic names and values.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi John, I wasn't sure if we wanted to save the missing data. But based on what you are saying it makes sense.

mlog << Debug(3) << " Adding cons_diag_val to pavg DiagVal array" << "\n";
sethlinden marked this conversation as resolved.
Show resolved Hide resolved
pavg.add_diag_value(cons_diag_val);
}

} // end loop over diag names

// Add the current track point
tavg.add(pavg);
}
Expand Down
4 changes: 3 additions & 1 deletion src/libcode/vx_tc_util/track_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@ class TrackInfo {
void add_watch_warn(const ConcatString &, WatchWarnType, unixtime);
bool add_diag_data(DiagFile &, const StringArray &);
void add_diag_value(int, double);

//void add_uniq_diag_name(const string diag_name);
sethlinden marked this conversation as resolved.
Show resolved Hide resolved
void add_uniq_diag_name(const std::string);

bool has(const ATCFTrackLine &) const;

bool is_match(const ATCFTrackLine &);
Expand Down
Loading
Loading