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 #2366 pyembed_winds #2371

Merged
merged 7 commits into from
Dec 7, 2022
10 changes: 7 additions & 3 deletions internal/test_unit/config/GridStatConfig_python
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,16 @@ rank_corr_flag = FALSE;
//
fcst = {
field = [ { name = "${FCST_COMMAND}"; },
{ name = "${OBS_COMMAND}"; } ];
{ name = "${OBS_COMMAND}"; },
{ name = "${FCST_COMMAND}"; set_attr_name = "FCST_UWIND"; level = "Surface"; is_u_wind = TRUE; },
{ name = "${OBS_COMMAND}"; set_attr_name = "OBS_VWIND"; level = "Surface"; is_v_wind = TRUE; } ];
}

obs = {
field = [ { name = "${OBS_COMMAND}"; },
{ name = "${FCST_COMMAND}"; } ];
{ name = "${FCST_COMMAND}"; },
{ name = "${OBS_COMMAND}"; set_attr_name = "OBS_UWIND"; level = "Surface"; is_u_wind = TRUE; },
{ name = "${FCST_COMMAND}"; set_attr_name = "FCST_VWIND"; level = "Surface"; is_v_wind = TRUE; } ];
}

////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -173,7 +177,7 @@ output_flag = {
cnt = NONE;
sl1l2 = STAT;
sal1l2 = NONE;
vl1l2 = NONE;
vl1l2 = STAT;
val1l2 = NONE;
vcnt = NONE;
pct = NONE;
Expand Down
11 changes: 11 additions & 0 deletions src/libcode/vx_data2d/var_info.cc
Original file line number Diff line number Diff line change
Expand Up @@ -933,3 +933,14 @@ ConcatString raw_magic_str(Dictionary i_edict, GrdFileType file_type) {
}

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

bool is_req_level_match(const ConcatString &s1, const ConcatString &s2) {
bool match = true;

// No match if either is non-empty and they are not equal.
if((s1.nonempty() || s2.nonempty()) && !(s1 == s2)) match = false;

return(match);
}

////////////////////////////////////////////////////////////////////////
1 change: 1 addition & 0 deletions src/libcode/vx_data2d/var_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ class EnsVarInfo {
////////////////////////////////////////////////////////////////////////

ConcatString raw_magic_str(Dictionary i_edict, GrdFileType file_type);
bool is_req_level_match(const ConcatString &, const ConcatString &);

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

Expand Down
7 changes: 7 additions & 0 deletions src/libcode/vx_data2d_python/var_info_python.cc
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,13 @@ void VarInfoPython::set_dict(Dictionary & dict) {

ReqName = dict.lookup_string(conf_key_name, true);

//
// the "level" entry is optional but is used when pairing U/V verification
// tasks and is stored in LevelInfo::ReqName
//

Level.set_req_name(dict.lookup_string(conf_key_level, false, false).c_str());

//
// hard-code the magic string as PYTHON
//
Expand Down
80 changes: 60 additions & 20 deletions src/tools/core/grid_stat/grid_stat_conf_info.cc
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,10 @@ void GridStatConfInfo::process_config(GrdFileType ftype,
// Summarize output flags across all verification tasks
process_flags();

// If VL1L2 or VAL1L2 is requested, set the uv_index
// If VL1L2, VAL1L2, or VCNT is requested, set the uv_index
if(output_flag[i_vl1l2] != STATOutputType_None ||
output_flag[i_val1l2] != STATOutputType_None) {
output_flag[i_val1l2] != STATOutputType_None ||
output_flag[i_vcnt] != STATOutputType_None) {

for(i=0; i<n_vx; i++) {

Expand All @@ -185,37 +186,70 @@ void GridStatConfInfo::process_config(GrdFileType ftype,

// Search for corresponding v-wind
for(j=0; j<n_vx; j++) {
if(vx_opt[j].fcst_info->is_v_wind() &&
vx_opt[j].obs_info->is_v_wind() &&
vx_opt[i].fcst_info->req_level_name() ==
vx_opt[j].fcst_info->req_level_name() &&
vx_opt[i].obs_info->req_level_name() ==
vx_opt[j].obs_info->req_level_name() &&
if(vx_opt[j].fcst_info->is_v_wind() &&
vx_opt[j].obs_info->is_v_wind() &&
vx_opt[i].is_uv_match(vx_opt[j])) {

vx_opt[i].fcst_info->set_uv_index(j);
vx_opt[i].obs_info->set_uv_index(j);
mlog << Debug(3) << "U-wind field array entry " << i+1
<< " matches V-wind field array entry " << j+1 << ".\n";

// Print warning about multiple matches
if(vx_opt[i].fcst_info->uv_index() >= 0 ||
vx_opt[i].obs_info->uv_index() >= 0) {
mlog << Warning << "\nGridStatConfInfo::process_config() -> "
<< "For U-wind, found multiple matching V-wind field array entries! "
<< "Using the first match found. Set the \"level\" strings to "
<< "differentiate between them.\n\n";
}
else {
vx_opt[i].fcst_info->set_uv_index(j);
vx_opt[i].obs_info->set_uv_index(j);
}
}
}

// No match found
if(vx_opt[i].fcst_info->uv_index() < 0 ||
vx_opt[i].obs_info->uv_index() < 0) {
mlog << Debug(3) << "U-wind field array entry " << i+1
<< " has no matching V-wind field array entry.\n";
}

}
// Process v-wind
else if(vx_opt[i].fcst_info->is_v_wind() &&
vx_opt[i].obs_info->is_v_wind()) {

// Search for corresponding u-wind
for(j=0; j<n_vx; j++) {
if(vx_opt[j].fcst_info->is_u_wind() &&
vx_opt[j].obs_info->is_u_wind() &&
vx_opt[i].fcst_info->req_level_name() ==
vx_opt[j].fcst_info->req_level_name() &&
vx_opt[i].obs_info->req_level_name() ==
vx_opt[j].obs_info->req_level_name() &&
if(vx_opt[j].fcst_info->is_u_wind() &&
vx_opt[j].obs_info->is_u_wind() &&
vx_opt[i].is_uv_match(vx_opt[j])) {

mlog << Debug(3) << "V-wind field array entry " << i+1
<< " matches U-wind field array entry " << j+1 << ".\n";

// Print warning about multiple matches
if(vx_opt[i].fcst_info->uv_index() >= 0 ||
vx_opt[i].obs_info->uv_index() >= 0) {
mlog << Warning << "\nGridStatConfInfo::process_config() -> "
<< "For V-wind, found multiple matching U-wind field array entries! "
<< "Using the first match found. Set the \"level\" strings to "
<< "differentiate between them.\n\n";
}

vx_opt[i].fcst_info->set_uv_index(j);
vx_opt[i].obs_info->set_uv_index(j);
}
}

// No match found
if(vx_opt[i].fcst_info->uv_index() < 0 ||
vx_opt[i].obs_info->uv_index() < 0) {
mlog << Debug(3) << "V-wind field array entry " << i+1
<< " has no matching U-wind field array entry.\n";
}

}
} // end for i
} // end if
Expand Down Expand Up @@ -904,6 +938,10 @@ void GridStatVxOpt::parse_nc_info(Dictionary &odict) {
bool GridStatVxOpt::is_uv_match(const GridStatVxOpt &v) const {
bool match = true;

//
// Check that requested forecast and observation levels match.
// Requested levels are optional for python embedding and may be empty.
// Check that the masking regions and interpolation options match.
//
// The following do not impact matched pairs:
// desc, var_name, var_suffix,
Expand All @@ -917,12 +955,14 @@ bool GridStatVxOpt::is_uv_match(const GridStatVxOpt &v) const {
// hss_ec_value, rank_corr_flag, output_flag, nc_info
//

if(!(mask_grid == v.mask_grid ) ||
if(!is_req_level_match( fcst_info->req_level_name(),
v.fcst_info->req_level_name()) ||
!is_req_level_match( obs_info->req_level_name(),
v.obs_info->req_level_name()) ||
!(mask_grid == v.mask_grid ) ||
!(mask_poly == v.mask_poly ) ||
!(mask_name == v.mask_name ) ||
!(interp_info == v.interp_info)) {
match = false;
}
!(interp_info == v.interp_info)) match = false;

return(match);
}
Expand Down
80 changes: 60 additions & 20 deletions src/tools/core/point_stat/point_stat_conf_info.cc
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,12 @@ void PointStatConfInfo::process_config(GrdFileType ftype) {
// Summarize output flags across all verification tasks
process_flags();

// If VL1L2 or VAL1L2 is requested, set the uv_index.
// If VL1L2, VAL1L2, or VCNT is requested, set the uv_index.
// When processing vectors, need to make sure the message types,
// masking regions, and interpolation methods are consistent.
if(output_flag[i_vl1l2] != STATOutputType_None ||
output_flag[i_val1l2] != STATOutputType_None) {
output_flag[i_val1l2] != STATOutputType_None ||
output_flag[i_vcnt] != STATOutputType_None) {

for(i=0; i<n_vx; i++) {

Expand All @@ -179,37 +180,70 @@ void PointStatConfInfo::process_config(GrdFileType ftype) {

// Search for corresponding v-wind
for(j=0; j<n_vx; j++) {
if(vx_opt[j].vx_pd.fcst_info->is_v_wind() &&
vx_opt[j].vx_pd.obs_info->is_v_wind() &&
vx_opt[i].vx_pd.fcst_info->req_level_name() ==
vx_opt[j].vx_pd.fcst_info->req_level_name() &&
vx_opt[i].vx_pd.obs_info->req_level_name() ==
vx_opt[j].vx_pd.obs_info->req_level_name() &&
if(vx_opt[j].vx_pd.fcst_info->is_v_wind() &&
vx_opt[j].vx_pd.obs_info->is_v_wind() &&
vx_opt[i].is_uv_match(vx_opt[j])) {

mlog << Debug(3) << "U-wind field array entry " << i+1
<< " matches V-wind field array entry " << j+1 << ".\n";

// Print warning about multiple matches
if(vx_opt[i].vx_pd.fcst_info->uv_index() >= 0 ||
vx_opt[i].vx_pd.obs_info->uv_index() >= 0) {
mlog << Warning << "\nPointStatConfInfo::process_config() -> "
<< "For U-wind, found multiple matching V-wind field array entries! "
<< "Using the first match found. Set the \"level\" strings to "
<< "differentiate between them.\n\n";
}

vx_opt[i].vx_pd.fcst_info->set_uv_index(j);
vx_opt[i].vx_pd.obs_info->set_uv_index(j);
}
}

// No match found
if(vx_opt[i].vx_pd.fcst_info->uv_index() < 0 ||
vx_opt[i].vx_pd.obs_info->uv_index() < 0) {
mlog << Debug(3) << "U-wind field array entry " << i+1
<< " has no matching V-wind field array entry.\n";
}

}
// Process v-wind
else if(vx_opt[i].vx_pd.fcst_info->is_v_wind() &&
vx_opt[i].vx_pd.obs_info->is_v_wind()) {

// Search for corresponding u-wind
for(j=0; j<n_vx; j++) {
if(vx_opt[j].vx_pd.fcst_info->is_u_wind() &&
vx_opt[j].vx_pd.obs_info->is_u_wind() &&
vx_opt[i].vx_pd.fcst_info->req_level_name() ==
vx_opt[j].vx_pd.fcst_info->req_level_name() &&
vx_opt[i].vx_pd.obs_info->req_level_name() ==
vx_opt[j].vx_pd.obs_info->req_level_name() &&
if(vx_opt[j].vx_pd.fcst_info->is_u_wind() &&
vx_opt[j].vx_pd.obs_info->is_u_wind() &&
vx_opt[i].is_uv_match(vx_opt[j])) {

vx_opt[i].vx_pd.fcst_info->set_uv_index(j);
vx_opt[i].vx_pd.obs_info->set_uv_index(j);
mlog << Debug(3) << "V-wind field array entry " << i+1
<< " matches U-wind field array entry " << j+1 << ".\n";

// Print warning about multiple matches
if(vx_opt[i].vx_pd.fcst_info->uv_index() >= 0 ||
vx_opt[i].vx_pd.obs_info->uv_index() >= 0) {
mlog << Warning << "\nPointStatConfInfo::process_config() -> "
<< "For U-wind, found multiple matching V-wind field array entries! "
<< "Using the first match found. Set the \"level\" strings to "
<< "differentiate between them.\n\n";
}
else {
vx_opt[i].vx_pd.fcst_info->set_uv_index(j);
vx_opt[i].vx_pd.obs_info->set_uv_index(j);
}
}
}

// No match found
if(vx_opt[i].vx_pd.fcst_info->uv_index() < 0 ||
vx_opt[i].vx_pd.obs_info->uv_index() < 0) {
mlog << Debug(3) << "V-wind field array entry " << i+1
<< " has no matching U-wind field array entry.\n";
}

}
} // end for i
} // end if
Expand Down Expand Up @@ -704,6 +738,10 @@ void PointStatVxOpt::clear() {
bool PointStatVxOpt::is_uv_match(const PointStatVxOpt &v) const {
bool match = true;

//
// Check that requested forecast and observation levels match.
// Requested levels are optional for python embedding and may be empty.
// Check that several other config options also match.
//
// The following do not impact matched pairs:
// fcat_ta, ocat_ta,
Expand All @@ -714,7 +752,11 @@ bool PointStatVxOpt::is_uv_match(const PointStatVxOpt &v) const {
// rank_corr_flag, output_flag
//

if(!(beg_ds == v.beg_ds ) ||
if(!is_req_level_match( vx_pd.fcst_info->req_level_name(),
v.vx_pd.fcst_info->req_level_name()) ||
!is_req_level_match( vx_pd.obs_info->req_level_name(),
v.vx_pd.obs_info->req_level_name()) ||
!(beg_ds == v.beg_ds ) ||
!(end_ds == v.end_ds ) ||
!(land_flag == v.land_flag ) ||
!(topo_flag == v.topo_flag ) ||
Expand All @@ -727,9 +769,7 @@ bool PointStatVxOpt::is_uv_match(const PointStatVxOpt &v) const {
!(msg_typ == v.msg_typ ) ||
!(duplicate_flag == v.duplicate_flag) ||
!(obs_summary == v.obs_summary ) ||
!(obs_perc == v.obs_perc )) {
match = false;
}
!(obs_perc == v.obs_perc )) match = false;

return(match);
}
Expand Down