From 6bb06865217f78e6cf776580b4c0ac5377c95532 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Wed, 3 Jun 2026 22:52:58 +0000 Subject: [PATCH 01/63] Per #1518, add WindVectorInfo struct along with code to parse it. --- data/config/ConfigConstants | 13 +++ src/basic/vx_config/config_constants.h | 39 ++++++- src/basic/vx_config/config_util.cc | 106 ++++++++++++++++++++ src/libcode/vx_data2d/data2d_utils.cc | 36 ++++--- src/libcode/vx_data2d/data2d_utils.h | 48 +++++---- src/libcode/vx_data2d_grib/data2d_grib.cc | 6 +- src/libcode/vx_data2d_grib2/data2d_grib2.cc | 10 +- 7 files changed, 213 insertions(+), 45 deletions(-) diff --git a/data/config/ConfigConstants b/data/config/ConfigConstants index acf34b788a..2bca8b6756 100644 --- a/data/config/ConfigConstants +++ b/data/config/ConfigConstants @@ -22,6 +22,19 @@ output_precision = 5; // MET_TMP_DIR. tmp_dir = "/tmp"; +//////////////////////////////////////////////////////////////////////////////// +// +// Settings to define wind vector metadata. +// +//////////////////////////////////////////////////////////////////////////////// + +// Comma-separated lists of wind variable names for rotating and deriving +u_wind_field_name = "UGRD,U"; +v_wind_field_name = "VGRD,V"; +wind_speed_field_name = "WIND,SP"; +wind_direction_field_name = "WDIR,DD"; +kinetic_energy_field_name = "KENG,KE"; + //////////////////////////////////////////////////////////////////////////////// // // Standard unit conversion functions. diff --git a/src/basic/vx_config/config_constants.h b/src/basic/vx_config/config_constants.h index 75e0629123..ae238dd53d 100644 --- a/src/basic/vx_config/config_constants.h +++ b/src/basic/vx_config/config_constants.h @@ -456,6 +456,33 @@ struct MaskLatLon { //////////////////////////////////////////////////////////////////////// +// +// Struct to store wind vector metadata +// + +struct WindVectorInfo { + StringArray u_wind; // U-wind field names + StringArray v_wind; // V-wind field names + StringArray wind_speed; // Wind speed field names + StringArray wind_direction; // Wind direction field names + StringArray kinetic_energy; // Kinetic energy field names + + WindVectorInfo() { clear(); } + ~WindVectorInfo() { clear(); } + WindVectorInfo(WindVectorInfo const &i) { *this = i; } + WindVectorInfo &operator=(const WindVectorInfo &a) noexcept; + bool operator==(const WindVectorInfo &) const; + void clear(); + + bool is_u_wind(const std::string &) const; + bool is_v_wind(const std::string &) const; + bool is_wind_speed(const std::string &) const; + bool is_wind_direction(const std::string &) const; + bool is_kinetic_energy(const std::string &) const; +}; + +//////////////////////////////////////////////////////////////////////// + // // Enumeration for duplicate_flag configuration parameter // @@ -751,6 +778,16 @@ static const char conf_key_ugrid_map_config[] = "ugrid_map_config"; static const char conf_key_ugrid_max_distance_km[] = "ugrid_max_distance_km"; static const char conf_key_ugrid_metadata_map[] = "ugrid_metadata_map"; +// +// Entries to define wind vector metadata +// + +static const char conf_key_u_wind_field_name[] = "u_wind_field_name"; +static const char conf_key_v_wind_field_name[] = "v_wind_field_name"; +static const char conf_key_wind_speed_field_name[] = "wind_speed_field_name"; +static const char conf_key_wind_direction_field_name[] = "wind_direction_field_name"; +static const char conf_key_kinetic_energy_field_name[] = "kinetic_energy_field_name"; + // // Entries to override file metadata // @@ -1329,8 +1366,6 @@ static const char conf_key_n_azimuth[] = "n_azimuth"; static const char conf_key_delta_range[] = "delta_range_km"; static const char conf_key_rmw_scale[] = "rmw_scale"; static const char conf_key_compute_tangential_and_radial_winds[] = "compute_tangential_and_radial_winds"; -static const char conf_key_u_wind_field_name[] = "u_wind_field_name"; -static const char conf_key_v_wind_field_name[] = "v_wind_field_name"; static const char conf_key_radial_velocity_field_name[] = "radial_velocity_field_name"; static const char conf_key_tangential_velocity_field_name[] = "tangential_velocity_field_name"; static const char conf_key_radial_velocity_long_field_name[] = "radial_velocity_long_field_name"; diff --git a/src/basic/vx_config/config_util.cc b/src/basic/vx_config/config_util.cc index d9ec914550..bf3841d199 100644 --- a/src/basic/vx_config/config_util.cc +++ b/src/basic/vx_config/config_util.cc @@ -817,6 +817,112 @@ vector parse_conf_llpnt_mask(Dictionary *dict) { return v; } +/////////////////////////////////////////////////////////////////////////////// +// +// Code for WindVectorInfo struct +// +/////////////////////////////////////////////////////////////////////////////// + +void WindVectorInfo::clear() { + u_wind.clear(); + v_wind.clear(); + wind_speed.clear(); + wind_direction.clear(); + kinetic_energy.clear(); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool WindVectorInfo::operator==(const WindVectorInfo &v) const { + bool match = true; + + if(!(u_wind == v.u_wind ) || + !(v_wind == v.v_wind ) || + !(wind_speed == v.wind_speed ) || + !(wind_direction == v.wind_direction) || + !(kinetic_energy == v.kinetic_energy)) { + match = false; + } + + return match; +} + +/////////////////////////////////////////////////////////////////////////////// + +WindVectorInfo &WindVectorInfo::operator=(const WindVectorInfo &a) noexcept { + if(this != &a) { + u_wind = a.u_wind; + v_wind = a.v_wind; + wind_speed = a.wind_speed; + wind_direction = a.wind_direction; + kinetic_energy = a.kinetic_energy; + } + return *this; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool WindVectorInfo::is_u_wind(const string &s) const { + return u_wind.has(s); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool WindVectorInfo::is_v_wind(const string &s) const { + return v_wind.has(s); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool WindVectorInfo::is_wind_speed(const string &s) const { + return wind_speed.has(s); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool WindVectorInfo::is_wind_direction(const string &s) const { + return wind_direction.has(s); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool WindVectorInfo::is_kinetic_energy(const string &s) const { + return kinetic_energy.has(s); +} + +/////////////////////////////////////////////////////////////////////////////// + +WindVectorInfo parse_conf_wind_vector_info(Dictionary *dict) { + WindVectorInfo info; + + if(!dict) { + mlog << Error << "\nparse_conf_wind_vector_info() -> " + << "empty dictionary!\n\n"; + exit(1); + } + + // Conf: u_wind_field_name + info.u_wind = dict->lookup_string_array(conf_key_u_wind_field_name); + + // Conf: v_wind_field_name + info.v_wind = dict->lookup_string_array(conf_key_v_wind_field_name); + + // Conf: wind_speed_field_name + info.wind_speed = dict->lookup_string_array(conf_key_wind_speed_field_name); + + // Conf: wind_direction_field_name + info.wind_direction = dict->lookup_string_array(conf_key_wind_direction_field_name); + + // Conf: kinetic_energy_field_name + info.kinetic_energy = dict->lookup_string_array(conf_key_kinetic_energy_field_name); + + return info; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Utility parsing functions +// /////////////////////////////////////////////////////////////////////////////// SingleThresh parse_conf_quality_mark_thresh(Dictionary *dict) { diff --git a/src/libcode/vx_data2d/data2d_utils.cc b/src/libcode/vx_data2d/data2d_utils.cc index 69992e4955..d93c028b0a 100644 --- a/src/libcode/vx_data2d/data2d_utils.cc +++ b/src/libcode/vx_data2d/data2d_utils.cc @@ -24,8 +24,9 @@ using namespace std; //////////////////////////////////////////////////////////////////////// -bool build_grid_by_grid_string(const char *grid_str, Grid &grid, - const char *caller_name, bool do_warning) { +bool build_grid_by_grid_string( + const char *grid_str, Grid &grid, + const char *caller_name, bool do_warning) { bool status = false; if (nullptr != grid_str && m_strlen(grid_str) > 0) { @@ -58,8 +59,9 @@ bool build_grid_by_grid_string(const char *grid_str, Grid &grid, //////////////////////////////////////////////////////////////////////// -bool build_grid_by_grid_string(const ConcatString &grid_str, Grid &grid, - const char *caller_name, bool do_warning) { +bool build_grid_by_grid_string( + const ConcatString &grid_str, Grid &grid, + const char *caller_name, bool do_warning) { bool status = false; if(grid_str.nonempty()) { @@ -72,8 +74,9 @@ bool build_grid_by_grid_string(const ConcatString &grid_str, Grid &grid, //////////////////////////////////////////////////////////////////////// -bool derive_wdir(const DataPlane &u2d, const DataPlane &v2d, - DataPlane &wdir2d) { +bool derive_wind_direction( + const DataPlane &u2d, const DataPlane &v2d, + DataPlane &wdir2d) { const int nx = u2d.nx(); const int ny = u2d.ny(); @@ -84,7 +87,7 @@ bool derive_wdir(const DataPlane &u2d, const DataPlane &v2d, // Check that the dimensions match // if(u2d.nx() != v2d.nx() || u2d.ny() != v2d.ny()) { - mlog << Warning << "\nderive_wdir() -> " + mlog << Warning << "\nderive_wind_direction() -> " << "the dimensions for U and V do not match: (" << u2d.nx() << ", " << u2d.ny() << ") != (" << v2d.nx() << ", " << v2d.ny() << ")\n\n"; @@ -138,8 +141,9 @@ bool derive_wdir(const DataPlane &u2d, const DataPlane &v2d, //////////////////////////////////////////////////////////////////////// -bool derive_wind(const DataPlane &u2d, const DataPlane &v2d, - DataPlane &wind2d) { +bool derive_wind_speed( + const DataPlane &u2d, const DataPlane &v2d, + DataPlane &wind2d) { const int nx = u2d.nx(); const int ny = u2d.ny(); @@ -150,7 +154,7 @@ bool derive_wind(const DataPlane &u2d, const DataPlane &v2d, // Check that the dimensions match // if(u2d.nx() != v2d.nx() || u2d.ny() != v2d.ny()) { - mlog << Warning << "\nderive_wind() -> " + mlog << Warning << "\nderive_wind_speed() -> " << "the dimensions for U and V do not match: (" << u2d.nx() << ", " << u2d.ny() << ") != (" << v2d.nx() << ", " << v2d.ny() << ")\n\n"; @@ -204,8 +208,9 @@ bool derive_wind(const DataPlane &u2d, const DataPlane &v2d, //////////////////////////////////////////////////////////////////////// -void rotate_wdir_grid_to_earth(const DataPlane &wdir2d, const Grid &g, - DataPlane &wdir2d_rot) { +void rotate_wind_direction_grid_to_earth( + const DataPlane &wdir2d, const Grid &g, + DataPlane &wdir2d_rot) { const int nx = wdir2d.nx(); const int ny = wdir2d.ny(); @@ -263,9 +268,10 @@ void rotate_wdir_grid_to_earth(const DataPlane &wdir2d, const Grid &g, //////////////////////////////////////////////////////////////////////// -bool rotate_uv_grid_to_earth(const DataPlane &u2d, const DataPlane &v2d, - const Grid &g, - DataPlane &u2d_rot, DataPlane &v2d_rot) { +bool rotate_uv_grid_to_earth( + const DataPlane &u2d, const DataPlane &v2d, + const Grid &g, + DataPlane &u2d_rot, DataPlane &v2d_rot) { const int nx = u2d.nx(); const int ny = u2d.ny(); diff --git a/src/libcode/vx_data2d/data2d_utils.h b/src/libcode/vx_data2d/data2d_utils.h index 25e65d0000..2318a12759 100644 --- a/src/libcode/vx_data2d/data2d_utils.h +++ b/src/libcode/vx_data2d/data2d_utils.h @@ -20,27 +20,33 @@ //////////////////////////////////////////////////////////////////////// -extern bool build_grid_by_grid_string(const char *attr_grid, Grid &grid, - const char *caller_name=nullptr, - bool do_warning=true); - -extern bool build_grid_by_grid_string(const ConcatString &attr_grid, Grid &grid, - const char *caller_name=nullptr, - bool do_warning=true); - -extern bool derive_wdir(const DataPlane &u2d, const DataPlane &v2d, - DataPlane &wdir); - -extern bool derive_wind(const DataPlane &u2d, const DataPlane &v2d, - DataPlane &wind); - -extern void rotate_wdir_grid_to_earth(const DataPlane &wdir2d, - const Grid &, - DataPlane &wdir2d_rot); - -extern bool rotate_uv_grid_to_earth(const DataPlane &u2d, const DataPlane &v2d, - const Grid &, - DataPlane &u2d_rot, DataPlane &v2d_rot); +extern bool build_grid_by_grid_string( + const char *attr_grid, Grid &grid, + const char *caller_name=nullptr, + bool do_warning=true); + +extern bool build_grid_by_grid_string( + const ConcatString &attr_grid, Grid &grid, + const char *caller_name=nullptr, + bool do_warning=true); + +extern bool derive_wind_direction( + const DataPlane &u2d, const DataPlane &v2d, + DataPlane &wdir); + +extern bool derive_wind_speed( + const DataPlane &u2d, const DataPlane &v2d, + DataPlane &wind); + +extern void rotate_wind_direction_grid_to_earth( + const DataPlane &wdir2d, + const Grid &, + DataPlane &wdir2d_rot); + +extern bool rotate_uv_grid_to_earth( + const DataPlane &u2d, const DataPlane &v2d, + const Grid &, + DataPlane &u2d_rot, DataPlane &v2d_rot); extern void set_attrs(const VarInfo *info, DataPlane &dp); diff --git a/src/libcode/vx_data2d_grib/data2d_grib.cc b/src/libcode/vx_data2d_grib/data2d_grib.cc index a004f5fca0..7c881c0a92 100644 --- a/src/libcode/vx_data2d_grib/data2d_grib.cc +++ b/src/libcode/vx_data2d_grib/data2d_grib.cc @@ -595,11 +595,11 @@ int MetGrib1DataFile::data_plane_array(VarInfo &vinfo, // Derive wind direction if(vinfo_grib->code() == wdir_grib_code) { - derive_wdir(u_plane_array[i], v_plane_array[i], cur_plane); + derive_wind_direction(u_plane_array[i], v_plane_array[i], cur_plane); } // Derive wind speed else { - derive_wind(u_plane_array[i], v_plane_array[i], cur_plane); + derive_wind_speed(u_plane_array[i], v_plane_array[i], cur_plane); } // Add the current data plane @@ -656,7 +656,7 @@ void MetGrib1DataFile::rotate_winds(VarInfoGrib &vinfo_grib, DataPlane &plane) { else if(vinfo_grib.is_wind_direction()) { mlog << Debug(3) << "MetGrib1DataFile::rotate_winds() -> " << "Have wind direction, calling rotate.\n"; - rotate_wdir_grid_to_earth(plane, grid(), u2d); + rotate_wind_direction_grid_to_earth(plane, grid(), u2d); plane = u2d; } diff --git a/src/libcode/vx_data2d_grib2/data2d_grib2.cc b/src/libcode/vx_data2d_grib2/data2d_grib2.cc index 4508f334f1..103c0bbf1e 100644 --- a/src/libcode/vx_data2d_grib2/data2d_grib2.cc +++ b/src/libcode/vx_data2d_grib2/data2d_grib2.cc @@ -673,10 +673,12 @@ DataPlaneArray MetGrib2DataFile::check_derived( const VarInfoGrib2 *vinfo ){ // perform the derivation DataPlane plane_deriv; - if(vinfo->name() == "WIND") derive_wind(array_u[i], array_v[i], - plane_deriv); - else derive_wdir(array_u[i], array_v[i], - plane_deriv); + if(vinfo->name() == "WIND") derive_wind_speed( + array_u[i], array_v[i], + plane_deriv); + else derive_wind_direction( + array_u[i], array_v[i], + plane_deriv); // add the current data plane array_ret.add(plane_deriv, array_u.lower(i), array_u.upper(i)); From 373f3e880197d41fe8e007f2dd59369ac6d522f8 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 4 Jun 2026 20:29:41 +0000 Subject: [PATCH 02/63] Per #1518, switch to WindMetadata struct name and parse it for the VarInfo base class. --- src/basic/vx_config/config_constants.h | 12 ++++----- src/basic/vx_config/config_util.cc | 34 +++++++++++++------------- src/basic/vx_config/config_util.h | 1 + src/libcode/vx_data2d/var_info.cc | 7 ++++++ src/libcode/vx_data2d/var_info.h | 2 ++ src/libcode/vx_ioda/ioda.h | 13 ---------- 6 files changed, 33 insertions(+), 36 deletions(-) diff --git a/src/basic/vx_config/config_constants.h b/src/basic/vx_config/config_constants.h index ae238dd53d..78f8d269ae 100644 --- a/src/basic/vx_config/config_constants.h +++ b/src/basic/vx_config/config_constants.h @@ -460,18 +460,18 @@ struct MaskLatLon { // Struct to store wind vector metadata // -struct WindVectorInfo { +struct WindMetadata { StringArray u_wind; // U-wind field names StringArray v_wind; // V-wind field names StringArray wind_speed; // Wind speed field names StringArray wind_direction; // Wind direction field names StringArray kinetic_energy; // Kinetic energy field names - WindVectorInfo() { clear(); } - ~WindVectorInfo() { clear(); } - WindVectorInfo(WindVectorInfo const &i) { *this = i; } - WindVectorInfo &operator=(const WindVectorInfo &a) noexcept; - bool operator==(const WindVectorInfo &) const; + WindMetadata() { clear(); } + ~WindMetadata() { clear(); } + WindMetadata(WindMetadata const &i) { *this = i; } + WindMetadata &operator=(const WindMetadata &a) noexcept; + bool operator==(const WindMetadata &) const; void clear(); bool is_u_wind(const std::string &) const; diff --git a/src/basic/vx_config/config_util.cc b/src/basic/vx_config/config_util.cc index bf3841d199..ac750a8a42 100644 --- a/src/basic/vx_config/config_util.cc +++ b/src/basic/vx_config/config_util.cc @@ -819,11 +819,11 @@ vector parse_conf_llpnt_mask(Dictionary *dict) { /////////////////////////////////////////////////////////////////////////////// // -// Code for WindVectorInfo struct +// Code for WindMetadata struct // /////////////////////////////////////////////////////////////////////////////// -void WindVectorInfo::clear() { +void WindMetadata::clear() { u_wind.clear(); v_wind.clear(); wind_speed.clear(); @@ -833,7 +833,7 @@ void WindVectorInfo::clear() { /////////////////////////////////////////////////////////////////////////////// -bool WindVectorInfo::operator==(const WindVectorInfo &v) const { +bool WindMetadata::operator==(const WindMetadata &v) const { bool match = true; if(!(u_wind == v.u_wind ) || @@ -849,7 +849,7 @@ bool WindVectorInfo::operator==(const WindVectorInfo &v) const { /////////////////////////////////////////////////////////////////////////////// -WindVectorInfo &WindVectorInfo::operator=(const WindVectorInfo &a) noexcept { +WindMetadata &WindMetadata::operator=(const WindMetadata &a) noexcept { if(this != &a) { u_wind = a.u_wind; v_wind = a.v_wind; @@ -862,59 +862,59 @@ WindVectorInfo &WindVectorInfo::operator=(const WindVectorInfo &a) noexcept { /////////////////////////////////////////////////////////////////////////////// -bool WindVectorInfo::is_u_wind(const string &s) const { +bool WindMetadata::is_u_wind(const string &s) const { return u_wind.has(s); } /////////////////////////////////////////////////////////////////////////////// -bool WindVectorInfo::is_v_wind(const string &s) const { +bool WindMetadata::is_v_wind(const string &s) const { return v_wind.has(s); } /////////////////////////////////////////////////////////////////////////////// -bool WindVectorInfo::is_wind_speed(const string &s) const { +bool WindMetadata::is_wind_speed(const string &s) const { return wind_speed.has(s); } /////////////////////////////////////////////////////////////////////////////// -bool WindVectorInfo::is_wind_direction(const string &s) const { +bool WindMetadata::is_wind_direction(const string &s) const { return wind_direction.has(s); } /////////////////////////////////////////////////////////////////////////////// -bool WindVectorInfo::is_kinetic_energy(const string &s) const { +bool WindMetadata::is_kinetic_energy(const string &s) const { return kinetic_energy.has(s); } /////////////////////////////////////////////////////////////////////////////// -WindVectorInfo parse_conf_wind_vector_info(Dictionary *dict) { - WindVectorInfo info; +WindMetadata parse_conf_wind_metadata(Dictionary *dict) { + WindMetadata info; if(!dict) { - mlog << Error << "\nparse_conf_wind_vector_info() -> " + mlog << Error << "\nparse_conf_wind_metadata() -> " << "empty dictionary!\n\n"; exit(1); } // Conf: u_wind_field_name - info.u_wind = dict->lookup_string_array(conf_key_u_wind_field_name); + info.u_wind.parse_css(dict->lookup_string(conf_key_u_wind_field_name)); // Conf: v_wind_field_name - info.v_wind = dict->lookup_string_array(conf_key_v_wind_field_name); + info.v_wind.parse_css(dict->lookup_string(conf_key_v_wind_field_name)); // Conf: wind_speed_field_name - info.wind_speed = dict->lookup_string_array(conf_key_wind_speed_field_name); + info.wind_speed.parse_css(dict->lookup_string(conf_key_wind_speed_field_name)); // Conf: wind_direction_field_name - info.wind_direction = dict->lookup_string_array(conf_key_wind_direction_field_name); + info.wind_direction.parse_css(dict->lookup_string(conf_key_wind_direction_field_name)); // Conf: kinetic_energy_field_name - info.kinetic_energy = dict->lookup_string_array(conf_key_kinetic_energy_field_name); + info.kinetic_energy.parse_css(dict->lookup_string(conf_key_kinetic_energy_field_name)); return info; } diff --git a/src/basic/vx_config/config_util.h b/src/basic/vx_config/config_util.h index 3ed2fe9e7a..39ff66c2c5 100644 --- a/src/basic/vx_config/config_util.h +++ b/src/basic/vx_config/config_util.h @@ -143,6 +143,7 @@ extern void parse_add_conf_ugrid_metadata_map( std::map *m); extern SurfaceInfo parse_conf_surface_info(Dictionary *dict); extern void parse_conf_topo_mask_interp(Dictionary *dict, SurfaceInfo &); +extern WindMetadata parse_conf_wind_metadata(Dictionary *dict); extern void check_full_grid_mask(StringArray &, const StringArray *, const StringArray *, diff --git a/src/libcode/vx_data2d/var_info.cc b/src/libcode/vx_data2d/var_info.cc index 5e6aa8dd6a..aec804e1d3 100644 --- a/src/libcode/vx_data2d/var_info.cc +++ b/src/libcode/vx_data2d/var_info.cc @@ -119,6 +119,8 @@ void VarInfo::assign(const VarInfo &v) { DefaultRegrid = v.DefaultRegrid; Regrid = v.Regrid; + WindInfo = v.WindInfo; + SetAttrName = v.SetAttrName; SetAttrUnits = v.SetAttrUnits; SetAttrLevel = v.SetAttrLevel; @@ -180,6 +182,8 @@ void VarInfo::clear() { DefaultRegrid.clear(); Regrid.clear(); + WindInfo.clear(); + SetAttrName.clear(); SetAttrUnits.clear(); SetAttrLevel.clear(); @@ -549,6 +553,9 @@ bool VarInfo::set_dict(Dictionary &dict, bool do_exit) { // Parse regrid, if present Regrid = parse_conf_regrid(&dict, &DefaultRegrid, false); + // Parse wind metadata + WindInfo = parse_conf_wind_metadata(&dict); + // Parse set_attr strings SetAttrName = parse_set_attr_string(dict, conf_key_set_attr_name, true); diff --git a/src/libcode/vx_data2d/var_info.h b/src/libcode/vx_data2d/var_info.h index bc3b32ae13..c3c545ff00 100644 --- a/src/libcode/vx_data2d/var_info.h +++ b/src/libcode/vx_data2d/var_info.h @@ -60,6 +60,8 @@ class VarInfo RegridInfo DefaultRegrid; // Default regridding logic RegridInfo Regrid; // Regridding logic + WindMetadata WindInfo; // Wind variable metadata + // Options to override metadata ConcatString SetAttrName; ConcatString SetAttrUnits; diff --git a/src/libcode/vx_ioda/ioda.h b/src/libcode/vx_ioda/ioda.h index 7b256549bc..be256bd370 100644 --- a/src/libcode/vx_ioda/ioda.h +++ b/src/libcode/vx_ioda/ioda.h @@ -24,19 +24,6 @@ enum class e_ioda_format { v1, v2 }; //////////////////////////////////////////////////////////////////////// -struct IODAHeaders { - void clear(); -}; - -//////////////////////////////////////////////////////////////////////// - -struct IODAMetadata { - - void clear(); -}; - -//////////////////////////////////////////////////////////////////////// - class IODAReader { public: From 87337dc48837c749493652463c865d8fb5986f12 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 5 Jun 2026 19:56:51 +0000 Subject: [PATCH 03/63] Per #1518, refine logic for checking wind metadata. --- src/libcode/vx_data2d/var_info.cc | 23 +++++++++++++++++++---- src/libcode/vx_data2d/var_info.h | 3 ++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/libcode/vx_data2d/var_info.cc b/src/libcode/vx_data2d/var_info.cc index aec804e1d3..86c5447b8a 100644 --- a/src/libcode/vx_data2d/var_info.cc +++ b/src/libcode/vx_data2d/var_info.cc @@ -781,6 +781,21 @@ bool VarInfo::is_flag_set(int flag) const { /////////////////////////////////////////////////////////////////////////////// +int VarInfo::check_wind_info(const int set_attr_val, + const StringArray &field_names) const { + int flag = bad_data_double; + + // Use explicit definition, if provided + if(!is_bad_data(set_attr_val)) flag = set_attr_val != 0; + + // Otherwise, check the list of field names + if(is_bad_data(flag) && field_names.has(Name)) flag = 1; + + return flag; +} + +/////////////////////////////////////////////////////////////////////////////// + bool VarInfo::is_precipitation() const { return is_flag_set(SetAttrIsPrecipitation); } @@ -794,25 +809,25 @@ bool VarInfo::is_specific_humidity() const { /////////////////////////////////////////////////////////////////////////////// bool VarInfo::is_u_wind() const { - return is_flag_set(SetAttrIsUWind); + return is_flag_set(check_wind_info(SetAttrIsUWind, WindInfo.u_wind)); } /////////////////////////////////////////////////////////////////////////////// bool VarInfo::is_v_wind() const { - return is_flag_set(SetAttrIsVWind); + return is_flag_set(check_wind_info(SetAttrIsVWind, WindInfo.v_wind)); } /////////////////////////////////////////////////////////////////////////////// bool VarInfo::is_wind_speed() const { - return is_flag_set(SetAttrIsWindSpeed); + return is_flag_set(check_wind_info(SetAttrIsWindSpeed, WindInfo.wind_speed)); } /////////////////////////////////////////////////////////////////////////////// bool VarInfo::is_wind_direction() const { - return is_flag_set(SetAttrIsWindDirection); + return is_flag_set(check_wind_info(SetAttrIsWindDirection, WindInfo.wind_speed)); } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_data2d/var_info.h b/src/libcode/vx_data2d/var_info.h index c3c545ff00..060de3fa4f 100644 --- a/src/libcode/vx_data2d/var_info.h +++ b/src/libcode/vx_data2d/var_info.h @@ -87,7 +87,8 @@ class VarInfo void init_from_scratch(); void assign(const VarInfo &); bool handle_config_error(const ConcatString &msg, bool do_exit) const; - bool is_flag_set(int flag) const; + bool is_flag_set(int) const; + int check_wind_info(int, const StringArray &) const; void parse_and_set_name_level(Dictionary &dict); bool validate_censor_arrays(const ThreshArray &ta, const NumArray &na, bool do_exit, const char *caller_name=nullptr) const; From 3364edacdba07ae456642785a1b09533a45f84a0 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 5 Jun 2026 22:24:31 +0000 Subject: [PATCH 04/63] Per #1518, don't need kinetic_energy_field_name config option. Instead, used a pre-defined hard-coded list of variable names to drive the derivation logic. --- data/config/ConfigConstants | 1 - src/basic/vx_config/config_constants.h | 17 +++++++----- src/basic/vx_config/config_util.cc | 38 +------------------------- src/libcode/vx_data2d/var_info.cc | 12 +++++--- 4 files changed, 19 insertions(+), 49 deletions(-) diff --git a/data/config/ConfigConstants b/data/config/ConfigConstants index 2bca8b6756..f6edb9906a 100644 --- a/data/config/ConfigConstants +++ b/data/config/ConfigConstants @@ -33,7 +33,6 @@ u_wind_field_name = "UGRD,U"; v_wind_field_name = "VGRD,V"; wind_speed_field_name = "WIND,SP"; wind_direction_field_name = "WDIR,DD"; -kinetic_energy_field_name = "KENG,KE"; //////////////////////////////////////////////////////////////////////////////// // diff --git a/src/basic/vx_config/config_constants.h b/src/basic/vx_config/config_constants.h index 78f8d269ae..0ae2b4ac20 100644 --- a/src/basic/vx_config/config_constants.h +++ b/src/basic/vx_config/config_constants.h @@ -465,7 +465,7 @@ struct WindMetadata { StringArray v_wind; // V-wind field names StringArray wind_speed; // Wind speed field names StringArray wind_direction; // Wind direction field names - StringArray kinetic_energy; // Kinetic energy field names + ConcatString standard_name; // Standard field name, optional WindMetadata() { clear(); } ~WindMetadata() { clear(); } @@ -474,11 +474,15 @@ struct WindMetadata { bool operator==(const WindMetadata &) const; void clear(); - bool is_u_wind(const std::string &) const; - bool is_v_wind(const std::string &) const; - bool is_wind_speed(const std::string &) const; - bool is_wind_direction(const std::string &) const; - bool is_kinetic_energy(const std::string &) const; + bool is_u_wind(const std::string &s) const { return u_wind.has(s); } + bool is_v_wind(const std::string &s) const { return v_wind.has(s); } + bool is_wind_speed(const std::string &s) const { return wind_speed.has(s); } + bool is_wind_direction(const std::string &s) const { return wind_direction.has(s); } + + // Supported derivations + bool is_kinetic_energy(const std::string &s) const { return s == "KENG"; } + bool is_vorticity(const std::string &s) const { return s == "ABSV"; } + bool is_divergence(const std::string &s) const { return s == "ABSD"; } }; //////////////////////////////////////////////////////////////////////// @@ -786,7 +790,6 @@ static const char conf_key_u_wind_field_name[] = "u_wind_field_name"; static const char conf_key_v_wind_field_name[] = "v_wind_field_name"; static const char conf_key_wind_speed_field_name[] = "wind_speed_field_name"; static const char conf_key_wind_direction_field_name[] = "wind_direction_field_name"; -static const char conf_key_kinetic_energy_field_name[] = "kinetic_energy_field_name"; // // Entries to override file metadata diff --git a/src/basic/vx_config/config_util.cc b/src/basic/vx_config/config_util.cc index ac750a8a42..941ceac733 100644 --- a/src/basic/vx_config/config_util.cc +++ b/src/basic/vx_config/config_util.cc @@ -828,7 +828,6 @@ void WindMetadata::clear() { v_wind.clear(); wind_speed.clear(); wind_direction.clear(); - kinetic_energy.clear(); } /////////////////////////////////////////////////////////////////////////////// @@ -839,8 +838,7 @@ bool WindMetadata::operator==(const WindMetadata &v) const { if(!(u_wind == v.u_wind ) || !(v_wind == v.v_wind ) || !(wind_speed == v.wind_speed ) || - !(wind_direction == v.wind_direction) || - !(kinetic_energy == v.kinetic_energy)) { + !(wind_direction == v.wind_direction)) { match = false; } @@ -855,43 +853,12 @@ WindMetadata &WindMetadata::operator=(const WindMetadata &a) noexcept { v_wind = a.v_wind; wind_speed = a.wind_speed; wind_direction = a.wind_direction; - kinetic_energy = a.kinetic_energy; } return *this; } /////////////////////////////////////////////////////////////////////////////// -bool WindMetadata::is_u_wind(const string &s) const { - return u_wind.has(s); -} - -/////////////////////////////////////////////////////////////////////////////// - -bool WindMetadata::is_v_wind(const string &s) const { - return v_wind.has(s); -} - -/////////////////////////////////////////////////////////////////////////////// - -bool WindMetadata::is_wind_speed(const string &s) const { - return wind_speed.has(s); -} - -/////////////////////////////////////////////////////////////////////////////// - -bool WindMetadata::is_wind_direction(const string &s) const { - return wind_direction.has(s); -} - -/////////////////////////////////////////////////////////////////////////////// - -bool WindMetadata::is_kinetic_energy(const string &s) const { - return kinetic_energy.has(s); -} - -/////////////////////////////////////////////////////////////////////////////// - WindMetadata parse_conf_wind_metadata(Dictionary *dict) { WindMetadata info; @@ -913,9 +880,6 @@ WindMetadata parse_conf_wind_metadata(Dictionary *dict) { // Conf: wind_direction_field_name info.wind_direction.parse_css(dict->lookup_string(conf_key_wind_direction_field_name)); - // Conf: kinetic_energy_field_name - info.kinetic_energy.parse_css(dict->lookup_string(conf_key_kinetic_energy_field_name)); - return info; } diff --git a/src/libcode/vx_data2d/var_info.cc b/src/libcode/vx_data2d/var_info.cc index 86c5447b8a..97918d9059 100644 --- a/src/libcode/vx_data2d/var_info.cc +++ b/src/libcode/vx_data2d/var_info.cc @@ -809,25 +809,29 @@ bool VarInfo::is_specific_humidity() const { /////////////////////////////////////////////////////////////////////////////// bool VarInfo::is_u_wind() const { - return is_flag_set(check_wind_info(SetAttrIsUWind, WindInfo.u_wind)); + return is_flag_set(check_wind_info(SetAttrIsUWind, + WindInfo.u_wind)); } /////////////////////////////////////////////////////////////////////////////// bool VarInfo::is_v_wind() const { - return is_flag_set(check_wind_info(SetAttrIsVWind, WindInfo.v_wind)); + return is_flag_set(check_wind_info(SetAttrIsVWind, + WindInfo.v_wind)); } /////////////////////////////////////////////////////////////////////////////// bool VarInfo::is_wind_speed() const { - return is_flag_set(check_wind_info(SetAttrIsWindSpeed, WindInfo.wind_speed)); + return is_flag_set(check_wind_info(SetAttrIsWindSpeed, + WindInfo.wind_speed)); } /////////////////////////////////////////////////////////////////////////////// bool VarInfo::is_wind_direction() const { - return is_flag_set(check_wind_info(SetAttrIsWindDirection, WindInfo.wind_speed)); + return is_flag_set(check_wind_info(SetAttrIsWindDirection, + WindInfo.wind_direction)); } /////////////////////////////////////////////////////////////////////////////// From 1c4fd7177dbeaed0a9b0a7951a106a26df163929 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 5 Jun 2026 23:56:00 +0000 Subject: [PATCH 05/63] Per #1518, update the VarInfo is_... functions throughout. --- src/libcode/vx_data2d/var_info.cc | 28 +++++++----- src/libcode/vx_data2d/var_info.h | 3 +- src/libcode/vx_data2d_grib/var_info_grib.cc | 30 +++++-------- src/libcode/vx_data2d_grib2/var_info_grib2.cc | 30 +++++-------- src/libcode/vx_data2d_nc_cf/var_info_nc_cf.cc | 30 +++++-------- .../vx_data2d_nc_met/var_info_nc_met.cc | 32 ++++++-------- .../vx_data2d_nc_wrf/var_info_nc_wrf.cc | 44 +++++++++---------- .../vx_data2d_nc_wrf/var_info_nc_wrf.h | 2 +- src/libcode/vx_data2d_ugrid/var_info_ugrid.cc | 30 +++++-------- 9 files changed, 101 insertions(+), 128 deletions(-) diff --git a/src/libcode/vx_data2d/var_info.cc b/src/libcode/vx_data2d/var_info.cc index 97918d9059..b67d18ab13 100644 --- a/src/libcode/vx_data2d/var_info.cc +++ b/src/libcode/vx_data2d/var_info.cc @@ -781,11 +781,11 @@ bool VarInfo::is_flag_set(int flag) const { /////////////////////////////////////////////////////////////////////////////// -int VarInfo::check_wind_info(const int set_attr_val, - const StringArray &field_names) const { +int VarInfo::get_wind_flag(const int set_attr_val, + const StringArray &field_names) const { int flag = bad_data_double; - // Use explicit definition, if provided + // Use explicit boolean definition, if provided if(!is_bad_data(set_attr_val)) flag = set_attr_val != 0; // Otherwise, check the list of field names @@ -809,29 +809,35 @@ bool VarInfo::is_specific_humidity() const { /////////////////////////////////////////////////////////////////////////////// bool VarInfo::is_u_wind() const { - return is_flag_set(check_wind_info(SetAttrIsUWind, - WindInfo.u_wind)); + return is_flag_set(get_wind_flag(SetAttrIsUWind, + WindInfo.u_wind)); } /////////////////////////////////////////////////////////////////////////////// bool VarInfo::is_v_wind() const { - return is_flag_set(check_wind_info(SetAttrIsVWind, - WindInfo.v_wind)); + return is_flag_set(get_wind_flag(SetAttrIsVWind, + WindInfo.v_wind)); } /////////////////////////////////////////////////////////////////////////////// bool VarInfo::is_wind_speed() const { - return is_flag_set(check_wind_info(SetAttrIsWindSpeed, - WindInfo.wind_speed)); + return is_flag_set(get_wind_flag(SetAttrIsWindSpeed, + WindInfo.wind_speed)); } /////////////////////////////////////////////////////////////////////////////// bool VarInfo::is_wind_direction() const { - return is_flag_set(check_wind_info(SetAttrIsWindDirection, - WindInfo.wind_direction)); + return is_flag_set(get_wind_flag(SetAttrIsWindDirection, + WindInfo.wind_direction)); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool VarInfo::is_grid_relative() const { + return is_flag_set(SetAttrIsGridRelative); } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_data2d/var_info.h b/src/libcode/vx_data2d/var_info.h index 060de3fa4f..21f7747704 100644 --- a/src/libcode/vx_data2d/var_info.h +++ b/src/libcode/vx_data2d/var_info.h @@ -88,7 +88,7 @@ class VarInfo void assign(const VarInfo &); bool handle_config_error(const ConcatString &msg, bool do_exit) const; bool is_flag_set(int) const; - int check_wind_info(int, const StringArray &) const; + int get_wind_flag(int, const StringArray &) const; void parse_and_set_name_level(Dictionary &dict); bool validate_censor_arrays(const ThreshArray &ta, const NumArray &na, bool do_exit, const char *caller_name=nullptr) const; @@ -216,6 +216,7 @@ class VarInfo virtual bool is_v_wind() const; virtual bool is_wind_speed() const; virtual bool is_wind_direction() const; + virtual bool is_grid_relative() const; bool is_prob() const; }; diff --git a/src/libcode/vx_data2d_grib/var_info_grib.cc b/src/libcode/vx_data2d_grib/var_info_grib.cc index abb48a9321..2cb7622d7a 100644 --- a/src/libcode/vx_data2d_grib/var_info_grib.cc +++ b/src/libcode/vx_data2d_grib/var_info_grib.cc @@ -353,9 +353,8 @@ bool VarInfoGrib::is_precipitation() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsPrecipitation)) { - return(SetAttrIsPrecipitation != 0); - } + int flag = SetAttrIsPrecipitation; + if(!is_bad_data(flag)) return is_flag_set(flag); // // The ReqName member contains the requested GRIB code abbreviation. @@ -379,9 +378,8 @@ bool VarInfoGrib::is_specific_humidity() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsSpecificHumidity)) { - return(SetAttrIsSpecificHumidity != 0); - } + int flag = SetAttrIsSpecificHumidity; + if(!is_bad_data(flag)) return is_flag_set(flag); // // The ReqName member contains the requested GRIB code abbreviation. @@ -405,9 +403,8 @@ bool VarInfoGrib::is_u_wind() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsUWind)) { - return(SetAttrIsUWind != 0); - } + int flag = get_wind_flag(SetAttrIsUWind, WindInfo.u_wind); + if(!is_bad_data(flag)) return is_flag_set(flag); return Code == ugrd_grib_code || ReqName == ugrd_abbr_str; @@ -420,9 +417,8 @@ bool VarInfoGrib::is_v_wind() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsVWind)) { - return(SetAttrIsVWind != 0); - } + int flag = get_wind_flag(SetAttrIsVWind, WindInfo.v_wind); + if(!is_bad_data(flag)) return is_flag_set(flag); return Code == vgrd_grib_code || ReqName == vgrd_abbr_str; @@ -435,9 +431,8 @@ bool VarInfoGrib::is_wind_speed() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsWindSpeed)) { - return(SetAttrIsWindSpeed != 0); - } + int flag = get_wind_flag(SetAttrIsWindSpeed, WindInfo.wind_speed); + if(!is_bad_data(flag)) return is_flag_set(flag); return Code == wind_grib_code || ReqName == wind_abbr_str; @@ -450,9 +445,8 @@ bool VarInfoGrib::is_wind_direction() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsWindDirection)) { - return(SetAttrIsWindDirection != 0); - } + int flag = get_wind_flag(SetAttrIsWindDirection, WindInfo.wind_direction); + if(!is_bad_data(flag)) return is_flag_set(flag); return Code == wdir_grib_code || ReqName == wdir_abbr_str; diff --git a/src/libcode/vx_data2d_grib2/var_info_grib2.cc b/src/libcode/vx_data2d_grib2/var_info_grib2.cc index 297694fb3e..d63c7d1b46 100644 --- a/src/libcode/vx_data2d_grib2/var_info_grib2.cc +++ b/src/libcode/vx_data2d_grib2/var_info_grib2.cc @@ -482,9 +482,8 @@ bool VarInfoGrib2::is_precipitation() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsPrecipitation)) { - return(SetAttrIsPrecipitation != 0); - } + int flag = SetAttrIsPrecipitation; + if(!is_bad_data(flag)) return is_flag_set(flag); // // Reference: @@ -507,9 +506,8 @@ bool VarInfoGrib2::is_specific_humidity() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsSpecificHumidity)) { - return(SetAttrIsSpecificHumidity != 0); - } + int flag = SetAttrIsSpecificHumidity; + if(!is_bad_data(flag)) return is_flag_set(flag); // // Reference: @@ -527,9 +525,8 @@ bool VarInfoGrib2::is_u_wind() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsUWind)) { - return(SetAttrIsUWind != 0); - } + int flag = get_wind_flag(SetAttrIsUWind, WindInfo.u_wind); + if(!is_bad_data(flag)) return is_flag_set(flag); // // Reference: @@ -549,9 +546,8 @@ bool VarInfoGrib2::is_v_wind() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsVWind)) { - return(SetAttrIsVWind != 0); - } + int flag = get_wind_flag(SetAttrIsVWind, WindInfo.v_wind); + if(!is_bad_data(flag)) return is_flag_set(flag); // // Reference: @@ -571,9 +567,8 @@ bool VarInfoGrib2::is_wind_speed() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsWindSpeed)) { - return(SetAttrIsWindSpeed != 0); - } + int flag = get_wind_flag(SetAttrIsWindSpeed, WindInfo.wind_speed); + if(!is_bad_data(flag)) return is_flag_set(flag); // // Reference: @@ -593,9 +588,8 @@ bool VarInfoGrib2::is_wind_direction() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsWindDirection)) { - return(SetAttrIsWindDirection != 0); - } + int flag = get_wind_flag(SetAttrIsWindDirection, WindInfo.wind_direction); + if(!is_bad_data(flag)) return is_flag_set(flag); // // Reference: diff --git a/src/libcode/vx_data2d_nc_cf/var_info_nc_cf.cc b/src/libcode/vx_data2d_nc_cf/var_info_nc_cf.cc index 52e550f06e..a136425cd8 100644 --- a/src/libcode/vx_data2d_nc_cf/var_info_nc_cf.cc +++ b/src/libcode/vx_data2d_nc_cf/var_info_nc_cf.cc @@ -383,9 +383,8 @@ bool VarInfoNcCF::is_precipitation() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsPrecipitation)) { - return(SetAttrIsPrecipitation != 0); - } + int flag = SetAttrIsPrecipitation; + if(!is_bad_data(flag)) return is_flag_set(flag); // // Check to see if the VarInfo name begins with the GRIB code abbreviation @@ -403,9 +402,8 @@ bool VarInfoNcCF::is_specific_humidity() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsSpecificHumidity)) { - return(SetAttrIsSpecificHumidity != 0); - } + int flag = SetAttrIsSpecificHumidity; + if(!is_bad_data(flag)) return is_flag_set(flag); // // Check to see if the VarInfo name begins with the GRIB code abbreviation @@ -423,9 +421,8 @@ bool VarInfoNcCF::is_u_wind() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsUWind)) { - return(SetAttrIsUWind != 0); - } + int flag = get_wind_flag(SetAttrIsUWind, WindInfo.u_wind); + if(!is_bad_data(flag)) return is_flag_set(flag); return is_grib_code_abbr_match(Name, ugrd_grib_code); } @@ -437,9 +434,8 @@ bool VarInfoNcCF::is_v_wind() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsVWind)) { - return(SetAttrIsVWind != 0); - } + int flag = get_wind_flag(SetAttrIsVWind, WindInfo.v_wind); + if(!is_bad_data(flag)) return is_flag_set(flag); return is_grib_code_abbr_match(Name, vgrd_grib_code); } @@ -451,9 +447,8 @@ bool VarInfoNcCF::is_wind_speed() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsWindSpeed)) { - return(SetAttrIsWindSpeed != 0); - } + int flag = get_wind_flag(SetAttrIsWindSpeed, WindInfo.wind_speed); + if(!is_bad_data(flag)) return is_flag_set(flag); return is_grib_code_abbr_match(Name, wind_grib_code); } @@ -465,9 +460,8 @@ bool VarInfoNcCF::is_wind_direction() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsWindDirection)) { - return(SetAttrIsWindDirection != 0); - } + int flag = get_wind_flag(SetAttrIsWindDirection, WindInfo.wind_direction); + if(!is_bad_data(flag)) return is_flag_set(flag); return is_grib_code_abbr_match(Name, wdir_grib_code); } diff --git a/src/libcode/vx_data2d_nc_met/var_info_nc_met.cc b/src/libcode/vx_data2d_nc_met/var_info_nc_met.cc index ea10b2df40..4b7d96ecf9 100644 --- a/src/libcode/vx_data2d_nc_met/var_info_nc_met.cc +++ b/src/libcode/vx_data2d_nc_met/var_info_nc_met.cc @@ -266,9 +266,8 @@ bool VarInfoNcMet::is_precipitation() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsPrecipitation)) { - return(SetAttrIsPrecipitation != 0); - } + int flag = SetAttrIsPrecipitation; + if(!is_bad_data(flag)) return is_flag_set(flag); // // Check to see if the VarInfo name begins with the GRIB code abbreviation @@ -286,9 +285,8 @@ bool VarInfoNcMet::is_specific_humidity() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsSpecificHumidity)) { - return(SetAttrIsSpecificHumidity != 0); - } + int flag = SetAttrIsSpecificHumidity; + if(!is_bad_data(flag)) return is_flag_set(flag); // // Check to see if the VarInfo name begins with the GRIB code abbreviation @@ -306,9 +304,8 @@ bool VarInfoNcMet::is_u_wind() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsUWind)) { - return(SetAttrIsUWind != 0); - } + int flag = get_wind_flag(SetAttrIsUWind, WindInfo.u_wind); + if(!is_bad_data(flag)) return is_flag_set(flag); return is_grib_code_abbr_match(Name, ugrd_grib_code); } @@ -320,10 +317,9 @@ bool VarInfoNcMet::is_v_wind() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsVWind)) { - return(SetAttrIsVWind != 0); - } - + int flag = get_wind_flag(SetAttrIsVWind, WindInfo.v_wind); + if(!is_bad_data(flag)) return is_flag_set(flag); + return is_grib_code_abbr_match(Name, vgrd_grib_code); } @@ -334,9 +330,8 @@ bool VarInfoNcMet::is_wind_speed() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsWindSpeed)) { - return(SetAttrIsWindSpeed != 0); - } + int flag = get_wind_flag(SetAttrIsWindSpeed, WindInfo.wind_speed); + if(!is_bad_data(flag)) return is_flag_set(flag); return is_grib_code_abbr_match(Name, wind_grib_code); } @@ -348,9 +343,8 @@ bool VarInfoNcMet::is_wind_direction() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsWindDirection)) { - return(SetAttrIsWindDirection != 0); - } + int flag = get_wind_flag(SetAttrIsWindDirection, WindInfo.wind_direction); + if(!is_bad_data(flag)) return is_flag_set(flag); return is_grib_code_abbr_match(Name, wdir_grib_code); } diff --git a/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.cc b/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.cc index e05a4c0f32..41b6fdd73f 100644 --- a/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.cc +++ b/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.cc @@ -303,9 +303,8 @@ bool VarInfoNcWrf::is_precipitation() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsPrecipitation)) { - return(SetAttrIsPrecipitation != 0); - } + int flag = SetAttrIsPrecipitation; + if(!is_bad_data(flag)) return is_flag_set(flag); // // Check to see if the VarInfo name matches any of expected Pinterp @@ -323,9 +322,8 @@ bool VarInfoNcWrf::is_specific_humidity() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsSpecificHumidity)) { - return(SetAttrIsSpecificHumidity != 0); - } + int flag = SetAttrIsSpecificHumidity; + if(!is_bad_data(flag)) return is_flag_set(flag); // // Check to see if the VarInfo name matches any of expected Pinterp @@ -343,14 +341,11 @@ bool VarInfoNcWrf::is_u_wind() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsUWind)) { - return(SetAttrIsUWind != 0); - } + int flag = get_wind_flag(SetAttrIsUWind, WindInfo.u_wind); + if(!is_bad_data(flag)) return is_flag_set(flag); // Check if the VarInfo name is U or U where is an integer - if( regex_match (Name.c_str(), regex("^U[0-9]*$") )) { - return true; - } + if(regex_match(Name.c_str(), regex("^U[0-9]*$"))) return true; // // Check to see if the VarInfo name matches any of expected Pinterp @@ -368,14 +363,11 @@ bool VarInfoNcWrf::is_v_wind() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsVWind)) { - return(SetAttrIsVWind != 0); - } + int flag = get_wind_flag(SetAttrIsVWind, WindInfo.v_wind); + if(!is_bad_data(flag)) return is_flag_set(flag); // Check if the VarInfo name is V or V where is an integer - if( regex_match (Name.c_str(), regex("^V[0-9]*$") )) { - return true; - } + if(regex_match(Name.c_str(), regex("^V[0-9]*$"))) return true; // // Check to see if the VarInfo name matches any of expected Pinterp @@ -393,9 +385,8 @@ bool VarInfoNcWrf::is_wind_speed() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsWindSpeed)) { - return(SetAttrIsWindSpeed != 0); - } + int flag = get_wind_flag(SetAttrIsWindSpeed, WindInfo.wind_speed); + if(!is_bad_data(flag)) return is_flag_set(flag); // // Check to see if the VarInfo name matches any of expected Pinterp @@ -413,9 +404,8 @@ bool VarInfoNcWrf::is_wind_direction() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsWindDirection)) { - return(SetAttrIsWindDirection != 0); - } + int flag = get_wind_flag(SetAttrIsWindDirection, WindInfo.wind_direction); + if(!is_bad_data(flag)) return is_flag_set(flag); return false; } @@ -425,6 +415,12 @@ bool VarInfoNcWrf::is_wind_direction() const { bool VarInfoNcWrf::is_grid_relative() const { + // + // Check set_attrs entry + // + int flag = SetAttrIsGridRelative; + if(!is_bad_data(flag)) return is_flag_set(flag); + // // Check to see if the VarInfo name matches any of expected Pinterp // variables that should be rotated from grid-relative to earth-relative. diff --git a/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.h b/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.h index 6acae0afef..bc55f426c0 100644 --- a/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.h +++ b/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.h @@ -242,7 +242,7 @@ class VarInfoNcWrf : public VarInfo bool is_v_wind() const override; bool is_wind_speed() const override; bool is_wind_direction() const override; - bool is_grid_relative() const; + bool is_grid_relative() const override; }; /////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_data2d_ugrid/var_info_ugrid.cc b/src/libcode/vx_data2d_ugrid/var_info_ugrid.cc index ab71e4bdb7..51fe233880 100644 --- a/src/libcode/vx_data2d_ugrid/var_info_ugrid.cc +++ b/src/libcode/vx_data2d_ugrid/var_info_ugrid.cc @@ -319,9 +319,8 @@ bool VarInfoUGrid::is_precipitation() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsPrecipitation)) { - return(SetAttrIsPrecipitation != 0); - } + int flag = SetAttrIsPrecipitation; + if(!is_bad_data(flag)) return is_flag_set(flag); // // Check to see if the VarInfo name begins with the GRIB code abbreviation @@ -339,9 +338,8 @@ bool VarInfoUGrid::is_specific_humidity() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsSpecificHumidity)) { - return(SetAttrIsSpecificHumidity != 0); - } + int flag = SetAttrIsSpecificHumidity; + if(!is_bad_data(flag)) return is_flag_set(flag); // // Check to see if the VarInfo name begins with the GRIB code abbreviation @@ -359,9 +357,8 @@ bool VarInfoUGrid::is_u_wind() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsUWind)) { - return(SetAttrIsUWind != 0); - } + int flag = get_wind_flag(SetAttrIsUWind, WindInfo.u_wind); + if(!is_bad_data(flag)) return is_flag_set(flag); return is_grib_code_abbr_match(Name, ugrd_grib_code); } @@ -373,9 +370,8 @@ bool VarInfoUGrid::is_v_wind() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsVWind)) { - return(SetAttrIsVWind != 0); - } + int flag = get_wind_flag(SetAttrIsVWind, WindInfo.v_wind); + if(!is_bad_data(flag)) return is_flag_set(flag); return is_grib_code_abbr_match(Name, vgrd_grib_code); } @@ -387,9 +383,8 @@ bool VarInfoUGrid::is_wind_speed() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsWindSpeed)) { - return(SetAttrIsWindSpeed != 0); - } + int flag = get_wind_flag(SetAttrIsWindSpeed, WindInfo.wind_speed); + if(!is_bad_data(flag)) return is_flag_set(flag); return is_grib_code_abbr_match(Name, wind_grib_code); } @@ -401,9 +396,8 @@ bool VarInfoUGrid::is_wind_direction() const { // // Check set_attrs entry // - if(!is_bad_data(SetAttrIsWindDirection)) { - return(SetAttrIsWindDirection != 0); - } + int flag = get_wind_flag(SetAttrIsWindDirection, WindInfo.wind_direction); + if(!is_bad_data(flag)) return is_flag_set(flag); return is_grib_code_abbr_match(Name, wdir_grib_code); } From 36f1774b0e71eb7db9146fa58ceb0ce171df23a0 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 11 Jun 2026 04:57:04 +0000 Subject: [PATCH 06/63] Per #1518, lots of changes for handling wind deriviation in the base class. Next up are handling wind rotations and adding lots of tests. --- src/libcode/vx_data2d/data2d_utils.cc | 156 +++++++---- src/libcode/vx_data2d/data2d_utils.h | 16 +- src/libcode/vx_data2d/data_class.cc | 255 ++++++++++++++++++ src/libcode/vx_data2d/data_class.h | 12 +- src/libcode/vx_data2d/var_info.h | 2 + src/libcode/vx_data2d_grib/data2d_grib.cc | 81 +----- src/libcode/vx_data2d_grib/data2d_grib.h | 4 +- src/libcode/vx_data2d_grib2/data2d_grib2.cc | 97 ++----- src/libcode/vx_data2d_grib2/data2d_grib2.h | 8 +- src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc | 77 +++--- src/libcode/vx_data2d_nc_cf/data2d_nc_cf.h | 4 +- src/libcode/vx_data2d_nc_met/data2d_nc_met.cc | 13 +- src/libcode/vx_data2d_nc_met/data2d_nc_met.h | 4 +- src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc | 30 ++- src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.h | 4 +- src/libcode/vx_data2d_python/data2d_python.cc | 6 +- src/libcode/vx_data2d_python/data2d_python.h | 4 +- src/libcode/vx_data2d_ugrid/data2d_ugrid.cc | 16 +- src/libcode/vx_data2d_ugrid/data2d_ugrid.h | 4 +- 19 files changed, 515 insertions(+), 278 deletions(-) diff --git a/src/libcode/vx_data2d/data2d_utils.cc b/src/libcode/vx_data2d/data2d_utils.cc index d93c028b0a..bfeb9da72e 100644 --- a/src/libcode/vx_data2d/data2d_utils.cc +++ b/src/libcode/vx_data2d/data2d_utils.cc @@ -24,6 +24,18 @@ using namespace std; //////////////////////////////////////////////////////////////////////// +static bool derive_wind_speed_and_direction( + const DataPlane &u2d, const DataPlane &v2d, + bool want_wspd, + DataPlane &dp); + +static bool derive_u_and_v_wind( + const DataPlane &spd, const DataPlane &dir, + bool want_uwnd, + DataPlane &dp); + +//////////////////////////////////////////////////////////////////////// + bool build_grid_by_grid_string( const char *grid_str, Grid &grid, const char *caller_name, bool do_warning) { @@ -74,39 +86,59 @@ bool build_grid_by_grid_string( //////////////////////////////////////////////////////////////////////// +bool derive_wind_speed( + const DataPlane &uwnd, const DataPlane &vwnd, + DataPlane &wspd) { + + mlog << Debug(3) + << "Deriving wind speed from U and V wind components.\n"; + + return derive_wind_speed_and_direction(uwnd, vwnd, true, wspd); +} + +//////////////////////////////////////////////////////////////////////// + bool derive_wind_direction( - const DataPlane &u2d, const DataPlane &v2d, - DataPlane &wdir2d) { - const int nx = u2d.nx(); - const int ny = u2d.ny(); + const DataPlane &uwnd, const DataPlane &vwnd, + DataPlane &wdir) { mlog << Debug(3) << "Deriving wind direction from U and V wind components.\n"; + return derive_wind_speed_and_direction(uwnd, vwnd, false, wdir); +} + +//////////////////////////////////////////////////////////////////////// + +static bool derive_wind_speed_and_direction( + const DataPlane &uwnd, const DataPlane &vwnd, + bool want_wspd, + DataPlane &dp) { + // // Check that the dimensions match // - if(u2d.nx() != v2d.nx() || u2d.ny() != v2d.ny()) { - mlog << Warning << "\nderive_wind_direction() -> " + if(uwnd.nx() != vwnd.nx() || uwnd.ny() != vwnd.ny()) { + mlog << Warning << "\nderive_wind_speed_and_direction() -> " << "the dimensions for U and V do not match: (" - << u2d.nx() << ", " << u2d.ny() << ") != (" - << v2d.nx() << ", " << v2d.ny() << ")\n\n"; + << uwnd.nx() << ", " << uwnd.ny() << ") != (" + << vwnd.nx() << ", " << vwnd.ny() << ")\n\n"; return false; } // - // Initialize by setting to u2d + // Initialize output // - wdir2d = u2d; - wdir2d.set_constant(bad_data_double); + dp = uwnd; + dp.set_constant(bad_data_double); + + const int nx = uwnd.nx(); + const int ny = uwnd.ny(); #pragma omp parallel default(shared) \ - shared(u2d, v2d, wdir2d) + shared(uwnd, vwnd, dp) { - // - // Compute the wind direction - // #pragma omp for schedule(static) \ collapse(2) for(int x=0; x " - << "the dimensions for U and V do not match: (" - << u2d.nx() << ", " << u2d.ny() << ") != (" - << v2d.nx() << ", " << v2d.ny() << ")\n\n"; + if(wspd.nx() != wdir.nx() || wspd.ny() != wdir.ny()) { + mlog << Warning << "\nderive_u_and_v_wind() -> " + << "the dimensions for wind speed and direction do not match: (" + << wspd.nx() << ", " << wspd.ny() << ") != (" + << wdir.nx() << ", " << wdir.ny() << ")\n\n"; return false; } // - // Initialize by setting to u2d + // Initialize output // - wind2d = u2d; - wind2d.set_constant(bad_data_double); + dp = wspd; + dp.set_constant(bad_data_double); + + const int nx = wspd.nx(); + const int ny = wspd.ny(); #pragma omp parallel default(shared) \ - shared(u2d, v2d, wind2d) + shared(wspd, wdir, dp) { - // - // Compute the wind direction - // #pragma omp for schedule(static) \ collapse(2) for(int x=0; xis_wind_speed() || vinfo->is_wind_direction()) { + DataPlane u_dp; + DataPlane v_dp; + status = read_wind_data_plane(vinfo, vinfo->wind_info().u_wind, u_dp) && + read_wind_data_plane(vinfo, vinfo->wind_info().v_wind, v_dp); + + if(status) { + if(vinfo->is_wind_speed()) { + status = derive_wind_speed(u_dp, v_dp, dp); + } + else { + status = derive_wind_direction(u_dp, v_dp, dp); + } + } +} + + // + // Derive U and V from wind speed and direction + // + +else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { + DataPlane spd_dp; + DataPlane dir_dp; + status = read_wind_data_plane(vinfo, vinfo->wind_info().wind_speed, spd_dp) && + read_wind_data_plane(vinfo, vinfo->wind_info().wind_direction, dir_dp); + + if(status) { + if(vinfo->is_wind_speed()) { + status = derive_u_wind(spd_dp, dir_dp, dp); + } + else { + status = derive_v_wind(spd_dp, dir_dp, dp); + } + } +} + +return status; + +} + + +//////////////////////////////////////////////////////////////////////// + + +bool Met2dDataFile::derive_data_plane_array(VarInfo *vinfo, + DataPlaneArray &dpa) + +{ + +if(!vinfo) return false; + +bool status = false; + + // + // Derive wind speed and direction from U and V + // + +if(vinfo->is_wind_speed() || vinfo->is_wind_direction()) { + DataPlaneArray uwnd_dpa; + DataPlaneArray vwnd_dpa; + status = read_wind_data_plane_array(vinfo, vinfo->wind_info().u_wind, uwnd_dpa) && + read_wind_data_plane_array(vinfo, vinfo->wind_info().v_wind, vwnd_dpa); + + if(!status) return status; + + if(uwnd_dpa.n_planes() != vwnd_dpa.n_planes()) { + mlog << Warning << "\nMet2dDataFile::derive_data_plane_array() -> " + << "when deriving winds, the number of U-wind records (" + << uwnd_dpa.n_planes() + << ") does not match the number of V-wind records (" + << vwnd_dpa.n_planes() + << ") for file '" << filename() << "'\n\n"; + return false; + } + + // + // Loop through each of the data planes + // + for(int i=0; i " + << "when deriving winds for level " << i+1 + << ", the U-wind levels (" << uwnd_dpa.lower(i) + << ", " << uwnd_dpa.upper(i) + << ") do not match the V-wind levels (" + << vwnd_dpa.lower(i) << ", " << vwnd_dpa.upper(i) + << ") in file '" << filename() << "'\n\n"; + return false; + } + + // Do the derivation + DataPlane dp; + if(vinfo->is_wind_speed()) { + status = derive_wind_speed(uwnd_dpa[i], vwnd_dpa[i], dp); + } + else { + status = derive_wind_direction(uwnd_dpa[i], vwnd_dpa[i], dp); + } + + // Store the result + dpa.add(dp, uwnd_dpa.lower(i), uwnd_dpa.upper(i)); + } +} + + // + // Derive U and V from wind speed and direction + // + +else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { + DataPlaneArray wspd_dpa; + DataPlaneArray wdir_dpa; + status = read_wind_data_plane_array(vinfo, vinfo->wind_info().wind_speed, wspd_dpa) && + read_wind_data_plane_array(vinfo, vinfo->wind_info().wind_direction, wdir_dpa); + + if(!status) return status; + + if(wspd_dpa.n_planes() != wdir_dpa.n_planes()) { + mlog << Warning << "\nMet2dDataFile::derive_data_plane_array() -> " + << "when deriving winds, the number of wind speed records (" + << wspd_dpa.n_planes() + << ") does not match the number of wind direction records (" + << wdir_dpa.n_planes() + << ") for file '" << filename() << "'\n\n"; + return false; + } + + // + // Loop through each of the data planes + // + for(int i=0; i " + << "when deriving winds for level " << i+1 + << ", the wind speed levels (" << wspd_dpa.lower(i) + << ", " << wspd_dpa.upper(i) + << ") do not match the wind direction levels (" + << wdir_dpa.lower(i) << ", " << wdir_dpa.upper(i) + << ") in file '" << filename() << "'\n\n"; + return false; + } + + // Do the derivation + DataPlane dp; + if(vinfo->is_u_wind()) { + status = derive_u_wind(wspd_dpa[i], wdir_dpa[i], dp); + } + else { + status = derive_v_wind(wspd_dpa[i], wdir_dpa[i], dp); + } + + // Store the result + dpa.add(dp, wspd_dpa.lower(i), wspd_dpa.upper(i)); + } +} + +return status; + +} + + +//////////////////////////////////////////////////////////////////////// + + +bool Met2dDataFile::read_wind_data_plane(VarInfo *vinfo, + const StringArray &names, + DataPlane &dp) + +{ + +if(!vinfo) return false; + +bool status = false; + + // Copy input VarInfo + +VarInfo * vinfo_cur = vinfo->clone(); + + // Try each of the possible names + +for(int i=0; iset_name(names[i]); + vinfo_cur->set_magic(names[i], vinfo_cur->level_name()); + if(data_plane(*vinfo_cur, dp, false)) { + status = true; + break; + } +} + + // Cleanup + +if(vinfo_cur) { delete vinfo_cur; vinfo_cur = nullptr; } + +return status; + +} + + +//////////////////////////////////////////////////////////////////////// + + +bool Met2dDataFile::read_wind_data_plane_array(VarInfo *vinfo, + const StringArray &names, + DataPlaneArray &dpa) + +{ + +if(!vinfo) return false; + +bool status = false; + + // Copy input VarInfo + +VarInfo * vinfo_cur = vinfo->clone(); + + // Try each of the possible names + +for(int i=0; iset_name(names[i]); + vinfo_cur->set_magic(names[i], vinfo_cur->level_name()); + if(data_plane_array(*vinfo_cur, dpa, false)) { + status = true; + break; + } +} + + // Cleanup + +if(vinfo_cur) { delete vinfo_cur; vinfo_cur = nullptr; } + +return status; + +} + + +//////////////////////////////////////////////////////////////////////// + + bool Met2dDataFile::process_data_plane(VarInfo *vinfo, DataPlane &dp) { diff --git a/src/libcode/vx_data2d/data_class.h b/src/libcode/vx_data2d/data_class.h index 1b8cd6493d..f7db6009bb 100644 --- a/src/libcode/vx_data2d/data_class.h +++ b/src/libcode/vx_data2d/data_class.h @@ -141,11 +141,11 @@ class Met2dDataFile : public Met2dData { // retrieve the first matching data plane - virtual bool data_plane(VarInfo &, DataPlane &) = 0; + virtual bool data_plane(VarInfo &, DataPlane &, bool do_derive = true) = 0; // retrieve all matching data planes - virtual int data_plane_array(VarInfo &, DataPlaneArray &) = 0; + virtual int data_plane_array(VarInfo &, DataPlaneArray &, bool do_derive = true) = 0; // retrieve the indexes of the first matching data plane @@ -156,6 +156,14 @@ class Met2dDataFile : public Met2dData { int data_planes(std::vector&, std::vector&); + bool derive_data_plane(VarInfo *, DataPlane &); + + bool derive_data_plane_array(VarInfo *, DataPlaneArray &); + + bool read_wind_data_plane(VarInfo *, const StringArray &, DataPlane &); + + bool read_wind_data_plane_array(VarInfo *, const StringArray &, DataPlaneArray &); + // post-process data after reading it bool process_data_plane(VarInfo *, DataPlane &); diff --git a/src/libcode/vx_data2d/var_info.h b/src/libcode/vx_data2d/var_info.h index 21f7747704..bcb48ce074 100644 --- a/src/libcode/vx_data2d/var_info.h +++ b/src/libcode/vx_data2d/var_info.h @@ -148,6 +148,7 @@ class VarInfo NumArray range() const; RegridInfo regrid() const; + WindMetadata wind_info() const; ConcatString magic_str_attr() const; ConcatString name_attr() const; @@ -254,6 +255,7 @@ inline int VarInfo::n_bins() const { return nBins; } inline NumArray VarInfo::range() const { return Range; } inline RegridInfo VarInfo::regrid() const { return Regrid; } +inline WindMetadata VarInfo::wind_info() const { return WindInfo; } inline ConcatString VarInfo::name_attr() const { return(SetAttrName.empty() ? name() : SetAttrName); } inline ConcatString VarInfo::units_attr() const { return(SetAttrUnits.empty() ? units() : SetAttrUnits); } diff --git a/src/libcode/vx_data2d_grib/data2d_grib.cc b/src/libcode/vx_data2d_grib/data2d_grib.cc index 7c881c0a92..040942a13f 100644 --- a/src/libcode/vx_data2d_grib/data2d_grib.cc +++ b/src/libcode/vx_data2d_grib/data2d_grib.cc @@ -404,7 +404,8 @@ return count; //////////////////////////////////////////////////////////////////////// -bool MetGrib1DataFile::data_plane(VarInfo &vinfo, DataPlane &plane) { +bool MetGrib1DataFile::data_plane(VarInfo &vinfo, DataPlane &plane, + bool do_derive) { bool status = false; int n_planes = 0; DataPlaneArray plane_array; @@ -412,7 +413,7 @@ bool MetGrib1DataFile::data_plane(VarInfo &vinfo, DataPlane &plane) { int j; // Call data_plane_array() to retrieve all matching records - n_planes = data_plane_array(*vinfo_grib, plane_array); + n_planes = data_plane_array(*vinfo_grib, plane_array, do_derive); // Process multiple matches if ( n_planes > 0 ) { @@ -464,7 +465,8 @@ bool MetGrib1DataFile::data_plane(VarInfo &vinfo, DataPlane &plane) { //////////////////////////////////////////////////////////////////////// int MetGrib1DataFile::data_plane_array(VarInfo &vinfo, - DataPlaneArray &plane_array) { + DataPlaneArray &plane_array, + bool do_derive) { bool status = false; bool exact; int i, lower, upper, type_num; @@ -540,75 +542,10 @@ int MetGrib1DataFile::data_plane_array(VarInfo &vinfo, } } // end for loop - // If no matches were found, check for wind records to be derived. - if(plane_array.n_planes() == 0) { - - // Derive wind speed and direction - if(vinfo_grib->code() == wdir_grib_code || - vinfo_grib->code() == wind_grib_code) { - - mlog << Debug(3) << "MetGrib1DataFile::data_plane_array() -> " - << "Attempt to derive winds from U and V components.\n"; - - // Initialize the current VarInfo object - vinfo_grib_winds = *vinfo_grib; - - // Retrieve U-wind, doing a rotation if necessary - mlog << Debug(3) << "MetGrib1DataFile::data_plane_array() -> " - << "Reading U-wind records.\n"; - vinfo_grib_winds.set_name(ugrd_abbr_str); - data_plane_array(vinfo_grib_winds, u_plane_array); - - // Retrieve V-wind, doing a rotation if necessary - mlog << Debug(3) << "MetGrib1DataFile::data_plane_array() -> " - << "Reading V-wind records.\n"; - vinfo_grib_winds.set_name(vgrd_abbr_str); - data_plane_array(vinfo_grib_winds, v_plane_array); - - // Derive wind speed or direction - if(u_plane_array.n_planes() != v_plane_array.n_planes()) { - mlog << Warning << "\nMetGrib1DataFile::data_plane_array() -> " - << "when deriving winds, the number of U-wind records (" - << u_plane_array.n_planes() << ") does not match the " - << "number of V-wind records (" << v_plane_array.n_planes() - << ") for GRIB file \"" << filename() << "\".\n\n"; - return 0; - } - - // Loop through each of the data planes - for(i=0; i " - << "when deriving winds for level " << i+1 - << ", the U-wind levels (" - << u_plane_array.lower(i) << ", " << u_plane_array.upper(i) - << ") do not match the V-wind levels (" - << v_plane_array.lower(i) << ", " << v_plane_array.upper(i) - << ") in GRIB file \"" << filename() << "\".\n\n"; - plane_array.clear(); - return 0; - } - - // Derive wind direction - if(vinfo_grib->code() == wdir_grib_code) { - derive_wind_direction(u_plane_array[i], v_plane_array[i], cur_plane); - } - // Derive wind speed - else { - derive_wind_speed(u_plane_array[i], v_plane_array[i], cur_plane); - } - - // Add the current data plane - plane_array.add(cur_plane, u_plane_array.lower(i), u_plane_array.upper(i)); - - } // end for - - } // end if wdir or wind - } // end if n_planes == 0 + // If nothing was found, try to build derived records + if(plane_array.n_planes() == 0 && do_derive) { + derive_data_plane_array(&vinfo, plane_array); + } mlog << Debug(3) << "MetGrib1DataFile::data_plane_array() -> " << "Found " << plane_array.n_planes() diff --git a/src/libcode/vx_data2d_grib/data2d_grib.h b/src/libcode/vx_data2d_grib/data2d_grib.h index fedc99b8d7..80f4f24e1e 100644 --- a/src/libcode/vx_data2d_grib/data2d_grib.h +++ b/src/libcode/vx_data2d_grib/data2d_grib.h @@ -86,11 +86,11 @@ class MetGrib1DataFile : public Met2dDataFile { // retrieve the first matching data plane - bool data_plane(VarInfo &, DataPlane &); + bool data_plane(VarInfo &, DataPlane &, bool do_derive = true); // retrieve all matching data planes - int data_plane_array(VarInfo &, DataPlaneArray &); + int data_plane_array(VarInfo &, DataPlaneArray &, bool do_derive = true); // retrieve the index of the first matching record diff --git a/src/libcode/vx_data2d_grib2/data2d_grib2.cc b/src/libcode/vx_data2d_grib2/data2d_grib2.cc index 103c0bbf1e..71990c561b 100644 --- a/src/libcode/vx_data2d_grib2/data2d_grib2.cc +++ b/src/libcode/vx_data2d_grib2/data2d_grib2.cc @@ -148,7 +148,8 @@ void MetGrib2DataFile::dump(ostream & out, int depth) const { //////////////////////////////////////////////////////////////////////// -bool MetGrib2DataFile::data_plane(VarInfo &vinfo, DataPlane &plane) { +bool MetGrib2DataFile::data_plane(VarInfo &vinfo, DataPlane &plane, + bool do_derive) { // narrow the vinfo pointer auto vinfo_g2 = (VarInfoGrib2*)(&vinfo); @@ -159,26 +160,24 @@ bool MetGrib2DataFile::data_plane(VarInfo &vinfo, DataPlane &plane) { find_record_matches(vinfo_g2, listMatch, listMatchRange); // if no matches were found, check for derived records - if( 1 > listMatch.size() ){ - - DataPlaneArray plane_array = check_derived(vinfo_g2); + if(listMatch.empty() && do_derive) { + DataPlaneArray plane_array; + derive_data_plane_array(vinfo_g2, plane_array); // verify that only a single data_plane was found - if( 1 > plane_array.n_planes() ){ + if(plane_array.n_planes() < 1){ mlog << Warning << "\nMetGrib2DataFile::data_plane() -> " << "No matching record found for '" << vinfo_g2->magic_str() << "'\n\n"; return false; - } else if( 1 < plane_array.n_planes() ){ + } else if(plane_array.n_planes() > 1) { mlog << Warning << "\nMetGrib2DataFile::data_plane() -> " - << "Wind speed/direction derivation found " - << plane_array.n_planes() - << " matching records found for '" + << "found " << plane_array.n_planes() + << " matching derived records for '" << vinfo_g2->magic_str() << "'\n\n"; - } // report the matched record @@ -240,7 +239,8 @@ bool MetGrib2DataFile::data_plane(VarInfo &vinfo, DataPlane &plane) { //////////////////////////////////////////////////////////////////////// int MetGrib2DataFile::data_plane_array(VarInfo &vinfo, - DataPlaneArray &plane_array) { + DataPlaneArray &plane_array, + bool do_derive) { // Initialize plane_array.clear(); @@ -307,12 +307,12 @@ int MetGrib2DataFile::data_plane_array(VarInfo &vinfo, } // if nothing was found, try to build derived records - else { + else if(do_derive) { - plane_array = check_derived(vinfo_g2); + derive_data_plane_array(vinfo_g2, plane_array); // if no matches were found, bail - if( 1 > plane_array.n_planes() ){ + if(plane_array.n_planes() < 1) { mlog << Warning << "\nMetGrib2DataFile::data_plane_array() -> " << "No matching records found for '" << vinfo_g2->magic_str() << "'\n\n"; @@ -321,9 +321,8 @@ int MetGrib2DataFile::data_plane_array(VarInfo &vinfo, // report the matched record mlog << Debug(3) << "\nMetGrib2DataFile::data_plane_array() -> " - << "Wind speed/direction derivation " << "found " << plane_array.n_planes() - << " matching records found for '" + << " matching derived records for '" << vinfo_g2->magic_str() << "'\n\n"; return plane_array.n_planes(); @@ -624,72 +623,6 @@ DataPlane MetGrib2DataFile::check_uv_rotation(const VarInfoGrib2 *vinfo, Grib2Re //////////////////////////////////////////////////////////////////////// -DataPlaneArray MetGrib2DataFile::check_derived( const VarInfoGrib2 *vinfo ){ - DataPlaneArray array_ret; - - // if the requested field cannot be derived, bail - if( vinfo->name() != "WIND" && - vinfo->name() != "WDIR" ) { - return array_ret; - } - - // read the data_plane objects for each constituent - DataPlaneArray array_u, array_v; - VarInfoGrib2 vinfo_cons(*vinfo); - vinfo_cons.set_name( ugrd_abbr_str ); - data_plane_array(vinfo_cons, array_u); - vinfo_cons.set_name( vgrd_abbr_str ); - data_plane_array(vinfo_cons, array_v); - - // derive wind speed or direction - if( array_u.n_planes() != array_v.n_planes() ){ - mlog << Warning << "\nMetGrib2DataFile::data_plane_array() -> " - << "when deriving winds, the number of U-wind records (" - << array_u.n_planes() - << ") does not match the number of V-wind record (" - << array_v.n_planes() - << ") for GRIB2 file '" << filename() << "'\n\n"; - - return array_ret; - } - - // loop through each of the data planes - for(int i=0; i < array_u.n_planes(); i++) { - - // check that the current level values match - if( !is_eq(array_u.lower(i), array_v.lower(i)) || - !is_eq(array_u.upper(i), array_v.upper(i)) ){ - - mlog << Warning << "\nMetGrib1DataFile::data_plane_array() -> " - << "when deriving winds for level " << i+1 - << ", the U-wind levels (" << array_u.lower(i) - << ", " << array_u.upper(i) - << ") do not match the V-wind levels (" - << array_v.lower(i) << ", " << array_v.upper(i) - << ") in GRIB file '" << filename() << "'\n\n"; - - return array_ret; - } - - // perform the derivation - DataPlane plane_deriv; - if(vinfo->name() == "WIND") derive_wind_speed( - array_u[i], array_v[i], - plane_deriv); - else derive_wind_direction( - array_u[i], array_v[i], - plane_deriv); - - // add the current data plane - array_ret.add(plane_deriv, array_u.lower(i), array_u.upper(i)); - - } - - return array_ret; -} - -//////////////////////////////////////////////////////////////////////// - void MetGrib2DataFile::read_grib2_record_list() { gribfield *gfld; long offset = 0; diff --git a/src/libcode/vx_data2d_grib2/data2d_grib2.h b/src/libcode/vx_data2d_grib2/data2d_grib2.h index ddcc6ce8cc..65b8937669 100644 --- a/src/libcode/vx_data2d_grib2/data2d_grib2.h +++ b/src/libcode/vx_data2d_grib2/data2d_grib2.h @@ -111,14 +111,12 @@ class MetGrib2DataFile : public Met2dDataFile { void read_grib2_record_list(); + // JHG, move this to the base class DataPlane check_uv_rotation( const VarInfoGrib2 *vinfo, Grib2Record *rec, DataPlane plane ); - DataPlaneArray check_derived( const VarInfoGrib2 *vinfo ); - - public: MetGrib2DataFile(); @@ -136,11 +134,11 @@ class MetGrib2DataFile : public Met2dDataFile { // retrieve the first matching data plane - bool data_plane(VarInfo &, DataPlane &); + bool data_plane(VarInfo &, DataPlane &, bool do_derive = true); // retrieve all matching data planes - int data_plane_array(VarInfo &, DataPlaneArray &); + int data_plane_array(VarInfo &, DataPlaneArray &, bool do_derive = true); // retrieve the index of the first matching record diff --git a/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc b/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc index 1b42a8f5c2..33e5036a50 100644 --- a/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc +++ b/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc @@ -270,53 +270,54 @@ Grid MetNcCFDataFile::build_grid_from_lat_lon_vars(NcVar *lat_var, NcVar *lon_va //////////////////////////////////////////////////////////////////////// -bool MetNcCFDataFile::data_plane(VarInfo &vinfo, DataPlane &plane) -{ - // Not sure why we do this - - auto vinfo_nc = (VarInfoNcCF *)&vinfo; - static const string method_name +bool MetNcCFDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, + bool do_derive) { + auto vinfo_nc = (VarInfoNcCF *) &vinfo; + static const string method_name = "MetNcCFDataFile::data_plane(VarInfo &, DataPlane &) -> "; - LongArray dimension = vinfo_nc->dimension(); - NcVarInfo *data_var = get_data_var(vinfo); - if (nullptr != data_var) { - int time_dim_slot = data_var->t_slot; - int zdim_slot = data_var->z_slot; - - // set vlevels if needed - _file->set_vlevels(data_var); + LongArray dimension = vinfo_nc->dimension(); + NcVarInfo *data_var = get_data_var(vinfo); + if (nullptr != data_var) { + int time_dim_slot = data_var->t_slot; + int zdim_slot = data_var->z_slot; + + // set vlevels if needed + _file->set_vlevels(data_var); + + for (int idx=0; idxdimension(), plane, info); + // Attempt to derive the data + if(!status && do_derive) { + status = derive_data_plane(vinfo_nc, plane); + } + // Check that the times match those requested if(status) { @@ -293,7 +299,8 @@ bool MetNcMetDataFile::data_plane(VarInfo &vinfo, DataPlane &plane) { //////////////////////////////////////////////////////////////////////// int MetNcMetDataFile::data_plane_array(VarInfo &vinfo, - DataPlaneArray &plane_array) { + DataPlaneArray &plane_array, + bool do_derive) { bool status = false; int n_rec = 0; DataPlane plane; @@ -302,7 +309,7 @@ int MetNcMetDataFile::data_plane_array(VarInfo &vinfo, plane_array.clear(); // Can only read a single 2D data plane from a MET NetCDF file - status = data_plane(vinfo, plane); + status = data_plane(vinfo, plane, do_derive); // Add the data plane to the DataPlaneArray with no level values if(status) { diff --git a/src/libcode/vx_data2d_nc_met/data2d_nc_met.h b/src/libcode/vx_data2d_nc_met/data2d_nc_met.h index 4174f58e4e..9e503d8954 100644 --- a/src/libcode/vx_data2d_nc_met/data2d_nc_met.h +++ b/src/libcode/vx_data2d_nc_met/data2d_nc_met.h @@ -62,11 +62,11 @@ class MetNcMetDataFile : public Met2dDataFile { // retrieve the first matching data plane - bool data_plane(VarInfo &, DataPlane &); + bool data_plane(VarInfo &, DataPlane &, bool do_derive = true); // retrieve all matching data planes - int data_plane_array(VarInfo &, DataPlaneArray &); + int data_plane_array(VarInfo &, DataPlaneArray &, bool do_derive = true); // retrieve the index of the first matching record diff --git a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc index 037d3dc489..10672278c0 100644 --- a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc +++ b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc @@ -121,7 +121,8 @@ void MetNcWrfDataFile::dump(ostream & out, int depth) const { //////////////////////////////////////////////////////////////////////// -bool MetNcWrfDataFile::data_plane(VarInfo &vinfo, DataPlane &plane) { +bool MetNcWrfDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, + bool do_derive) { bool status = false; double pressure; ConcatString level_str; @@ -152,6 +153,11 @@ bool MetNcWrfDataFile::data_plane(VarInfo &vinfo, DataPlane &plane) { status = WrfNc->data(vinfo_nc->req_name().c_str(), dimension, plane, pressure, info); + // Attempt to derive the data + if(!status && do_derive) { + status = derive_data_plane(vinfo_nc, plane); + } + // Check that the times match those requested if(status) { @@ -180,10 +186,13 @@ bool MetNcWrfDataFile::data_plane(VarInfo &vinfo, DataPlane &plane) { status = process_data_plane(&vinfo, plane); // Set the VarInfo object's name, long_name, and units strings - if(info->name_att.length() > 0) vinfo.set_name(info->name_att); - else vinfo.set_name(info->name); - if(info->long_name_att.length() > 0) vinfo.set_long_name(info->long_name_att.c_str()); - if(info->units_att.length() > 0) vinfo.set_units(info->units_att.c_str()); + // Note that info is null for derived fields + if(info) { + if(info->name_att.length() > 0) vinfo.set_name(info->name_att); + else vinfo.set_name(info->name); + if(info->long_name_att.length() > 0) vinfo.set_long_name(info->long_name_att.c_str()); + if(info->units_att.length() > 0) vinfo.set_units(info->units_att.c_str()); + } // Set the VarInfo object's level string for pressure levels if(!is_bad_data(pressure)) { @@ -198,7 +207,8 @@ bool MetNcWrfDataFile::data_plane(VarInfo &vinfo, DataPlane &plane) { //////////////////////////////////////////////////////////////////////// int MetNcWrfDataFile::data_plane_array(VarInfo &vinfo, - DataPlaneArray &plane_array) { + DataPlaneArray &plane_array, + bool do_derive) { int i, i_dim, n_level, status, lower, upper; ConcatString level_str; double pressure, min_level, max_level; @@ -245,6 +255,11 @@ int MetNcWrfDataFile::data_plane_array(VarInfo &vinfo, status = WrfNc->data(vinfo_nc->req_name().c_str(), cur_dim, cur_plane, pressure, info); + // Attempt to derive the data + if(!status && do_derive) { + status = derive_data_plane(vinfo_nc, cur_plane); + } + // Check that the times match those requested if(status) { @@ -283,7 +298,8 @@ int MetNcWrfDataFile::data_plane_array(VarInfo &vinfo, plane_array.add(cur_plane, pressure, pressure); // Set the VarInfo object's name, long_name, and units strings - if(i==0) { + // Note that info is null for derived fields + if(i==0 && info) { if(info->name_att.length() > 0) vinfo.set_name(info->name_att); else vinfo.set_name(info->name); if(info->long_name_att.length() > 0) vinfo.set_long_name(info->long_name_att.c_str()); diff --git a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.h b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.h index b23e8f6447..d26bf1a68a 100644 --- a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.h +++ b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.h @@ -61,11 +61,11 @@ class MetNcWrfDataFile : public Met2dDataFile { // retrieve the first matching data plane - bool data_plane(VarInfo &, DataPlane &); + bool data_plane(VarInfo &, DataPlane &, bool do_derive = true); // retrieve all matching data planes - int data_plane_array(VarInfo &, DataPlaneArray &); + int data_plane_array(VarInfo &, DataPlaneArray &, bool do_derive = true); // retrieve the index of the first matching record diff --git a/src/libcode/vx_data2d_python/data2d_python.cc b/src/libcode/vx_data2d_python/data2d_python.cc index b585ee2c60..69209c0f5d 100644 --- a/src/libcode/vx_data2d_python/data2d_python.cc +++ b/src/libcode/vx_data2d_python/data2d_python.cc @@ -295,7 +295,7 @@ return; //////////////////////////////////////////////////////////////////////// -bool MetPythonDataFile::data_plane(VarInfo &vinfo, DataPlane &plane) +bool MetPythonDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, bool) { @@ -360,7 +360,9 @@ return true; //////////////////////////////////////////////////////////////////////// -int MetPythonDataFile::data_plane_array(VarInfo &vinfo, DataPlaneArray &plane_array) +int MetPythonDataFile::data_plane_array(VarInfo &vinfo, + DataPlaneArray &plane_array, + bool) { diff --git a/src/libcode/vx_data2d_python/data2d_python.h b/src/libcode/vx_data2d_python/data2d_python.h index 623967fd49..1e7d05bca9 100644 --- a/src/libcode/vx_data2d_python/data2d_python.h +++ b/src/libcode/vx_data2d_python/data2d_python.h @@ -86,9 +86,9 @@ class MetPythonDataFile : public Met2dDataFile { void dump (std::ostream &, int depth = 0) const; - bool data_plane(VarInfo &, DataPlane &); + bool data_plane(VarInfo &, DataPlane &, bool do_derive = true); - int data_plane_array(VarInfo &, DataPlaneArray &); + int data_plane_array(VarInfo &, DataPlaneArray &, bool do_derive = true); int index(VarInfo &); diff --git a/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc b/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc index a8c75a83dc..8e4d5e8830 100644 --- a/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc +++ b/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc @@ -163,8 +163,8 @@ void MetUGridDataFile::dump(ostream & out, int depth) const { //////////////////////////////////////////////////////////////////////// -bool MetUGridDataFile::data_plane(VarInfo &vinfo, DataPlane &plane) -{ +bool MetUGridDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, + bool do_derive) { bool status = false; auto data_var = (NcVarInfo *)nullptr; static const string method_name @@ -179,6 +179,11 @@ bool MetUGridDataFile::data_plane(VarInfo &vinfo, DataPlane &plane) if (nullptr != data_var) { // Read the data status = data_plane(vinfo, plane, data_var); + + // Attempt to derive the data + if(!status && do_derive) { + status = derive_data_plane(&vinfo, plane); + } } else { LevelInfo level = vinfo.level(); @@ -309,7 +314,8 @@ bool MetUGridDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, const NcVarI //////////////////////////////////////////////////////////////////////// int MetUGridDataFile::data_plane_array(VarInfo &vinfo, - DataPlaneArray &plane_array) { + DataPlaneArray &plane_array, + bool do_derive) { int n_rec = 0; DataPlane plane; static const string method_name @@ -322,7 +328,7 @@ int MetUGridDataFile::data_plane_array(VarInfo &vinfo, long lvl_lower = level.lower(); long lvl_upper = level.upper(); ConcatString req_name = vinfo.req_name(); - NcVarInfo *data_vinfo = _file->find_by_name(req_name.c_str()); + NcVarInfo *data_vinfo = _file->find_by_name(req_name.c_str()); if (level.type() == LevelType_Time) { mlog << Error << "\n" << method_name << "LevelType_Time for unstructured grid is not enabled\n\n"; @@ -375,7 +381,7 @@ int MetUGridDataFile::data_plane_array(VarInfo &vinfo, } } } - else if (data_plane(vinfo, plane)) { + else if (data_plane(vinfo, plane, do_derive)) { plane_array.add(plane, lvl_lower, lvl_upper); n_rec++; } diff --git a/src/libcode/vx_data2d_ugrid/data2d_ugrid.h b/src/libcode/vx_data2d_ugrid/data2d_ugrid.h index 6f9ab51ff3..6e081a2902 100644 --- a/src/libcode/vx_data2d_ugrid/data2d_ugrid.h +++ b/src/libcode/vx_data2d_ugrid/data2d_ugrid.h @@ -86,12 +86,12 @@ class MetUGridDataFile : public Met2dDataFile { // retrieve the first matching data plane - bool data_plane(VarInfo &, DataPlane &); + bool data_plane(VarInfo &, DataPlane &, bool do_derive = true); bool data_plane(VarInfo &, DataPlane &, const NcVarInfo *); // retrieve all matching data planes - int data_plane_array(VarInfo &, DataPlaneArray &); + int data_plane_array(VarInfo &, DataPlaneArray &, bool do_derive = true); // retrieve the index of the first matching record From e597d98435c799b006252ac9a6a6de8609469052 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 11 Jun 2026 16:41:14 +0000 Subject: [PATCH 07/63] Per #1518, update function names, add a hook for rotate_winds(), and add long names and units for derived wind fields. --- src/libcode/vx_data2d/data_class.cc | 146 ++++++++++++++---- src/libcode/vx_data2d/data_class.h | 15 +- src/libcode/vx_data2d/var_info.cc | 9 +- src/libcode/vx_data2d/var_info.h | 3 +- src/libcode/vx_data2d_grib/data2d_grib.cc | 2 +- src/libcode/vx_data2d_grib2/data2d_grib2.cc | 4 +- src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc | 4 +- src/libcode/vx_data2d_nc_met/data2d_nc_met.cc | 2 +- src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc | 4 +- src/libcode/vx_data2d_ugrid/data2d_ugrid.cc | 2 +- 10 files changed, 144 insertions(+), 47 deletions(-) diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index f0f76c35bd..fa0bc08202 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -362,7 +362,7 @@ return n_valid; //////////////////////////////////////////////////////////////////////// -bool Met2dDataFile::derive_data_plane(VarInfo *vinfo, DataPlane &dp) +bool Met2dDataFile::derive_winds(VarInfo *vinfo, DataPlane &dp) { @@ -375,17 +375,25 @@ bool status = false; // if(vinfo->is_wind_speed() || vinfo->is_wind_direction()) { - DataPlane u_dp; - DataPlane v_dp; - status = read_wind_data_plane(vinfo, vinfo->wind_info().u_wind, u_dp) && - read_wind_data_plane(vinfo, vinfo->wind_info().v_wind, v_dp); + DataPlane uwnd_dp; + DataPlane vwnd_dp; + ConcatString uwnd_units; + ConcatString vwnd_units; + status = read_wind_data(vinfo, vinfo->wind_info().u_wind, + uwnd_dp, uwnd_units) && + read_wind_data(vinfo, vinfo->wind_info().v_wind, + vwnd_dp, vwnd_units); if(status) { if(vinfo->is_wind_speed()) { - status = derive_wind_speed(u_dp, v_dp, dp); + status = derive_wind_speed(uwnd_dp, vwnd_dp, dp); + vinfo->set_long_name("Wind Speed"); + vinfo->set_units(uwnd_units); } else { - status = derive_wind_direction(u_dp, v_dp, dp); + status = derive_wind_direction(uwnd_dp, vwnd_dp, dp); + vinfo->set_long_name("Wind Direction"); + vinfo->set_units("deg"); } } } @@ -395,17 +403,25 @@ if(vinfo->is_wind_speed() || vinfo->is_wind_direction()) { // else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { - DataPlane spd_dp; - DataPlane dir_dp; - status = read_wind_data_plane(vinfo, vinfo->wind_info().wind_speed, spd_dp) && - read_wind_data_plane(vinfo, vinfo->wind_info().wind_direction, dir_dp); + DataPlane wspd_dp; + DataPlane wdir_dp; + ConcatString wspd_units; + ConcatString wdir_units; + status = read_wind_data(vinfo, vinfo->wind_info().wind_speed, + wspd_dp, wspd_units) && + read_wind_data(vinfo, vinfo->wind_info().wind_direction, + wdir_dp, wdir_units); if(status) { - if(vinfo->is_wind_speed()) { - status = derive_u_wind(spd_dp, dir_dp, dp); + if(vinfo->is_u_wind()) { + status = derive_u_wind(wspd_dp, wdir_dp, dp); + vinfo->set_long_name("U-Component of Wind"); + vinfo->set_units(wspd_units); } else { - status = derive_v_wind(spd_dp, dir_dp, dp); + status = derive_v_wind(wspd_dp, wdir_dp, dp); + vinfo->set_long_name("V-Component of Wind"); + vinfo->set_units(wspd_units); } } } @@ -418,11 +434,12 @@ return status; //////////////////////////////////////////////////////////////////////// -bool Met2dDataFile::derive_data_plane_array(VarInfo *vinfo, - DataPlaneArray &dpa) +bool Met2dDataFile::derive_winds(VarInfo *vinfo, DataPlaneArray &dpa) { +static const char *method_name = "Met2dDataFile::derive_winds() -> "; + if(!vinfo) return false; bool status = false; @@ -434,13 +451,26 @@ bool status = false; if(vinfo->is_wind_speed() || vinfo->is_wind_direction()) { DataPlaneArray uwnd_dpa; DataPlaneArray vwnd_dpa; - status = read_wind_data_plane_array(vinfo, vinfo->wind_info().u_wind, uwnd_dpa) && - read_wind_data_plane_array(vinfo, vinfo->wind_info().v_wind, vwnd_dpa); - + ConcatString uwnd_units; + ConcatString vwnd_units; + status = read_wind_data(vinfo, vinfo->wind_info().u_wind, + uwnd_dpa, uwnd_units) && + read_wind_data(vinfo, vinfo->wind_info().v_wind, + vwnd_dpa, vwnd_units); if(!status) return status; + // Store the long name and units + if(vinfo->is_wind_speed()) { + vinfo->set_long_name("Wind Speed"); + vinfo->set_units(uwnd_units); + } + else { + vinfo->set_long_name("Wind Direction"); + vinfo->set_units("deg"); + } + if(uwnd_dpa.n_planes() != vwnd_dpa.n_planes()) { - mlog << Warning << "\nMet2dDataFile::derive_data_plane_array() -> " + mlog << Warning << "\n" << method_name << "when deriving winds, the number of U-wind records (" << uwnd_dpa.n_planes() << ") does not match the number of V-wind records (" @@ -457,7 +487,7 @@ if(vinfo->is_wind_speed() || vinfo->is_wind_direction()) { // Levels must match if(!is_eq(uwnd_dpa.lower(i), vwnd_dpa.lower(i)) || !is_eq(uwnd_dpa.upper(i), vwnd_dpa.upper(i)) ){ - mlog << Warning << "\nMet2dDataFile::derive_data_plane_array() -> " + mlog << Warning << "\n" << method_name << "when deriving winds for level " << i+1 << ", the U-wind levels (" << uwnd_dpa.lower(i) << ", " << uwnd_dpa.upper(i) @@ -488,13 +518,27 @@ if(vinfo->is_wind_speed() || vinfo->is_wind_direction()) { else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { DataPlaneArray wspd_dpa; DataPlaneArray wdir_dpa; - status = read_wind_data_plane_array(vinfo, vinfo->wind_info().wind_speed, wspd_dpa) && - read_wind_data_plane_array(vinfo, vinfo->wind_info().wind_direction, wdir_dpa); + ConcatString wspd_units; + ConcatString wdir_units; + status = read_wind_data(vinfo, vinfo->wind_info().wind_speed, + wspd_dpa, wspd_units) && + read_wind_data(vinfo, vinfo->wind_info().wind_direction, + wdir_dpa, wdir_units); if(!status) return status; + // Store the long name and units + if(vinfo->is_u_wind()) { + vinfo->set_long_name("U-Component of Wind"); + vinfo->set_units(wspd_units); + } + else { + vinfo->set_long_name("V-Component of Wind"); + vinfo->set_units(wspd_units); + } + if(wspd_dpa.n_planes() != wdir_dpa.n_planes()) { - mlog << Warning << "\nMet2dDataFile::derive_data_plane_array() -> " + mlog << Warning << "\n" << method_name << "when deriving winds, the number of wind speed records (" << wspd_dpa.n_planes() << ") does not match the number of wind direction records (" @@ -511,7 +555,7 @@ else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { // Levels must match if(!is_eq(wspd_dpa.lower(i), wdir_dpa.lower(i)) || !is_eq(wspd_dpa.upper(i), wdir_dpa.upper(i)) ){ - mlog << Warning << "\nMet2dDataFile::derive_data_plane_array() -> " + mlog << Warning << "\n" << method_name << "when deriving winds for level " << i+1 << ", the wind speed levels (" << wspd_dpa.lower(i) << ", " << wspd_dpa.upper(i) @@ -543,9 +587,46 @@ return status; //////////////////////////////////////////////////////////////////////// -bool Met2dDataFile::read_wind_data_plane(VarInfo *vinfo, - const StringArray &names, - DataPlane &dp) +bool Met2dDataFile::rotate_winds(VarInfo *vinfo, DataPlane &dp) + +{ + +if(!vinfo) return false; + +bool status = false; + +// JHG work here + +return status; + +} + + +//////////////////////////////////////////////////////////////////////// + + +bool Met2dDataFile::rotate_winds(VarInfo *vinfo, DataPlaneArray &dpa) + +{ + +if(!vinfo) return false; + +bool status = false; + +// JHG work here + +return status; + +} + + +//////////////////////////////////////////////////////////////////////// + + +bool Met2dDataFile::read_wind_data(VarInfo *vinfo, + const StringArray &names, + DataPlane &dp, + ConcatString &units) { @@ -564,6 +645,7 @@ for(int i=0; iset_magic(names[i], vinfo_cur->level_name()); if(data_plane(*vinfo_cur, dp, false)) { status = true; + units = vinfo_cur->units(); break; } } @@ -580,9 +662,10 @@ return status; //////////////////////////////////////////////////////////////////////// -bool Met2dDataFile::read_wind_data_plane_array(VarInfo *vinfo, - const StringArray &names, - DataPlaneArray &dpa) +bool Met2dDataFile::read_wind_data(VarInfo *vinfo, + const StringArray &names, + DataPlaneArray &dpa, + ConcatString &units) { @@ -601,6 +684,7 @@ for(int i=0; iset_magic(names[i], vinfo_cur->level_name()); if(data_plane_array(*vinfo_cur, dpa, false)) { status = true; + units = vinfo_cur->units(); break; } } diff --git a/src/libcode/vx_data2d/data_class.h b/src/libcode/vx_data2d/data_class.h index f7db6009bb..f2ca9d7285 100644 --- a/src/libcode/vx_data2d/data_class.h +++ b/src/libcode/vx_data2d/data_class.h @@ -83,6 +83,11 @@ class Met2dDataFile : public Met2dData { void mtddf_init_from_scratch(); + bool read_wind_data(VarInfo *, const StringArray &, + DataPlane &, ConcatString &); + bool read_wind_data(VarInfo *, const StringArray &, + DataPlaneArray &, ConcatString &); + bool GridShifted; protected: @@ -156,13 +161,13 @@ class Met2dDataFile : public Met2dData { int data_planes(std::vector&, std::vector&); - bool derive_data_plane(VarInfo *, DataPlane &); - - bool derive_data_plane_array(VarInfo *, DataPlaneArray &); + // derive and rotate wind fields - bool read_wind_data_plane(VarInfo *, const StringArray &, DataPlane &); + bool derive_winds(VarInfo *, DataPlane &); + bool derive_winds(VarInfo *, DataPlaneArray &); - bool read_wind_data_plane_array(VarInfo *, const StringArray &, DataPlaneArray &); + bool rotate_winds(VarInfo *, DataPlane &); + bool rotate_winds(VarInfo *, DataPlaneArray &); // post-process data after reading it diff --git a/src/libcode/vx_data2d/var_info.cc b/src/libcode/vx_data2d/var_info.cc index b67d18ab13..02e190beb8 100644 --- a/src/libcode/vx_data2d/var_info.cc +++ b/src/libcode/vx_data2d/var_info.cc @@ -300,7 +300,7 @@ void VarInfo::set_name(const char *str) { /////////////////////////////////////////////////////////////////////////////// -void VarInfo::set_name(const string str) { +void VarInfo::set_name(const string &str) { Name = str; return; } @@ -328,6 +328,13 @@ void VarInfo::set_units(const char *str) { /////////////////////////////////////////////////////////////////////////////// +void VarInfo::set_units(const string &str) { + Units = str; + return; +} + +/////////////////////////////////////////////////////////////////////////////// + void VarInfo::set_level_info(const LevelInfo &l) { Level = l; return; diff --git a/src/libcode/vx_data2d/var_info.h b/src/libcode/vx_data2d/var_info.h index bcb48ce074..dd984e534e 100644 --- a/src/libcode/vx_data2d/var_info.h +++ b/src/libcode/vx_data2d/var_info.h @@ -173,8 +173,9 @@ class VarInfo void set_req_name(const char *); void set_name(const char *); - void set_name(const std::string); + void set_name(const std::string &); void set_units(const char *); + void set_units(const std::string &); void set_level_info(const LevelInfo &); void set_req_level_name(const char *); void set_level_name(const char *); diff --git a/src/libcode/vx_data2d_grib/data2d_grib.cc b/src/libcode/vx_data2d_grib/data2d_grib.cc index 040942a13f..5eea2f1424 100644 --- a/src/libcode/vx_data2d_grib/data2d_grib.cc +++ b/src/libcode/vx_data2d_grib/data2d_grib.cc @@ -544,7 +544,7 @@ int MetGrib1DataFile::data_plane_array(VarInfo &vinfo, // If nothing was found, try to build derived records if(plane_array.n_planes() == 0 && do_derive) { - derive_data_plane_array(&vinfo, plane_array); + derive_winds(&vinfo, plane_array); } mlog << Debug(3) << "MetGrib1DataFile::data_plane_array() -> " diff --git a/src/libcode/vx_data2d_grib2/data2d_grib2.cc b/src/libcode/vx_data2d_grib2/data2d_grib2.cc index 71990c561b..d43d026a7d 100644 --- a/src/libcode/vx_data2d_grib2/data2d_grib2.cc +++ b/src/libcode/vx_data2d_grib2/data2d_grib2.cc @@ -162,7 +162,7 @@ bool MetGrib2DataFile::data_plane(VarInfo &vinfo, DataPlane &plane, // if no matches were found, check for derived records if(listMatch.empty() && do_derive) { DataPlaneArray plane_array; - derive_data_plane_array(vinfo_g2, plane_array); + derive_winds(vinfo_g2, plane_array); // verify that only a single data_plane was found if(plane_array.n_planes() < 1){ @@ -309,7 +309,7 @@ int MetGrib2DataFile::data_plane_array(VarInfo &vinfo, // if nothing was found, try to build derived records else if(do_derive) { - derive_data_plane_array(vinfo_g2, plane_array); + derive_winds(vinfo_g2, plane_array); // if no matches were found, bail if(plane_array.n_planes() < 1) { diff --git a/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc b/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc index 33e5036a50..81e83d0406 100644 --- a/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc +++ b/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc @@ -308,7 +308,7 @@ bool MetNcCFDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, // Attempt to derive the data if(!status && do_derive) { - status = derive_data_plane(vinfo_nc, plane); + status = derive_winds(vinfo_nc, plane); } return status; @@ -434,7 +434,7 @@ int MetNcCFDataFile::data_plane_array(VarInfo &vinfo, // Attempt to derive the data if(n_rec == 0 && do_derive) { - status = derive_data_plane_array(vinfo_nc, plane_array); + status = derive_winds(vinfo_nc, plane_array); } return n_rec; diff --git a/src/libcode/vx_data2d_nc_met/data2d_nc_met.cc b/src/libcode/vx_data2d_nc_met/data2d_nc_met.cc index 885d9b178d..2dd2534bb5 100644 --- a/src/libcode/vx_data2d_nc_met/data2d_nc_met.cc +++ b/src/libcode/vx_data2d_nc_met/data2d_nc_met.cc @@ -240,7 +240,7 @@ bool MetNcMetDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, // Attempt to derive the data if(!status && do_derive) { - status = derive_data_plane(vinfo_nc, plane); + status = derive_winds(vinfo_nc, plane); } // Check that the times match those requested diff --git a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc index 10672278c0..3b97c76bd8 100644 --- a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc +++ b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc @@ -155,7 +155,7 @@ bool MetNcWrfDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, // Attempt to derive the data if(!status && do_derive) { - status = derive_data_plane(vinfo_nc, plane); + status = derive_winds(vinfo_nc, plane); } // Check that the times match those requested @@ -257,7 +257,7 @@ int MetNcWrfDataFile::data_plane_array(VarInfo &vinfo, // Attempt to derive the data if(!status && do_derive) { - status = derive_data_plane(vinfo_nc, cur_plane); + status = derive_winds(vinfo_nc, cur_plane); } // Check that the times match those requested diff --git a/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc b/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc index 8e4d5e8830..b989629ab8 100644 --- a/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc +++ b/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc @@ -182,7 +182,7 @@ bool MetUGridDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, // Attempt to derive the data if(!status && do_derive) { - status = derive_data_plane(&vinfo, plane); + status = derive_winds(&vinfo, plane); } } else { From 197dde9b7b2e521fcddc43f547ee6d23eced78e8 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 11 Jun 2026 18:10:57 +0000 Subject: [PATCH 08/63] Per #1518, improve level string handling for NetCDF files. When deriving winds, the level string needs to be wrapped in parenthesis based on the existing parsing logic. --- src/libcode/vx_data2d/data_class.cc | 22 +++++++++++++++++-- src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc | 2 +- src/libcode/vx_data2d_nc_wrf/wrf_file.cc | 10 ++++----- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index fa0bc08202..df669b4a54 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -642,7 +642,16 @@ VarInfo * vinfo_cur = vinfo->clone(); for(int i=0; iset_name(names[i]); - vinfo_cur->set_magic(names[i], vinfo_cur->level_name()); + + // Wrap level in parenthesis, if needed + string lstr = vinfo_cur->level_name(); + if(lstr.find(',') != string::npos && + lstr.find('(') == string::npos) { + lstr.insert(0, "("); + lstr.append(")"); + } + vinfo_cur->set_magic(names[i], lstr); + if(data_plane(*vinfo_cur, dp, false)) { status = true; units = vinfo_cur->units(); @@ -681,7 +690,16 @@ VarInfo * vinfo_cur = vinfo->clone(); for(int i=0; iset_name(names[i]); - vinfo_cur->set_magic(names[i], vinfo_cur->level_name()); + + // Wrap level in parenthesis, if needed + string lstr = vinfo_cur->level_name(); + if(lstr.find(',') != string::npos && + lstr.find('(') == string::npos) { + lstr.insert(0, "("); + lstr.append(")"); + } + vinfo_cur->set_magic(names[i], lstr); + if(data_plane_array(*vinfo_cur, dpa, false)) { status = true; units = vinfo_cur->units(); diff --git a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc index 3b97c76bd8..54dd75e0b9 100644 --- a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc +++ b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc @@ -124,7 +124,7 @@ void MetNcWrfDataFile::dump(ostream & out, int depth) const { bool MetNcWrfDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, bool do_derive) { bool status = false; - double pressure; + double pressure = bad_data_double; ConcatString level_str; VarInfoNcWrf * vinfo_nc = (VarInfoNcWrf *) &vinfo; NcVarInfo *info = (NcVarInfo *) nullptr; diff --git a/src/libcode/vx_data2d_nc_wrf/wrf_file.cc b/src/libcode/vx_data2d_nc_wrf/wrf_file.cc index 3eb71979fc..9c2901333e 100644 --- a/src/libcode/vx_data2d_nc_wrf/wrf_file.cc +++ b/src/libcode/vx_data2d_nc_wrf/wrf_file.cc @@ -537,20 +537,20 @@ if ( !args_ok(a) ) { int dim_count = var->getDimCount(); if ( dim_count != a.n_elements() ) { - mlog << Error << "\n" << method_name + mlog << Warning << "\n" << method_name << "needed " << dim_count << " arguments for variable " << (GET_NC_NAME_P(var)) << ", got " << (a.n_elements()) << "\n\n"; - exit ( 1 ); + return bad_data_double; } if (dim_count >= max_wrf_args ) { - mlog << Error << "\n" << method_name + mlog << Warning << "\n" << method_name << " too may arguments for variable \"" << (GET_NC_NAME_P(var)) << "\"\n\n"; - exit ( 1 ); + return bad_data_double; } @@ -604,7 +604,7 @@ if ( dim_count != a.n_elements() ) { << "needed " << dim_count << " arguments for variable " << var_name << ", got " << a.n_elements() << "\n\n"; - exit ( 1 ); + return false; } From 96e9e72144f1bb89a5d7ac37e7fb51fa34555294 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 12 Jun 2026 19:56:37 +0000 Subject: [PATCH 09/63] Per #1518, handle wind rotation in the Met2dDataFile base class rather than just the derived classes for GRIB1 and GRIB2. --- src/basic/vx_config/config_constants.h | 1 - src/libcode/vx_data2d/data_class.cc | 117 +++++++++++++--- src/libcode/vx_data2d/data_class.h | 8 +- src/libcode/vx_data2d/var_info.cc | 20 ++- src/libcode/vx_data2d/var_info.h | 8 +- src/libcode/vx_data2d_grib/data2d_grib.cc | 131 ++---------------- src/libcode/vx_data2d_grib/data2d_grib.h | 8 +- src/libcode/vx_data2d_grib2/data2d_grib2.cc | 98 ++++--------- src/libcode/vx_data2d_grib2/data2d_grib2.h | 15 +- src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc | 31 +++-- src/libcode/vx_data2d_nc_cf/data2d_nc_cf.h | 10 +- src/libcode/vx_data2d_nc_met/data2d_nc_met.cc | 10 +- src/libcode/vx_data2d_nc_met/data2d_nc_met.h | 4 +- src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc | 30 ++-- src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.h | 4 +- .../vx_data2d_nc_wrf/var_info_nc_wrf.cc | 20 --- .../vx_data2d_nc_wrf/var_info_nc_wrf.h | 1 - src/libcode/vx_data2d_python/data2d_python.cc | 9 +- src/libcode/vx_data2d_python/data2d_python.h | 4 +- src/libcode/vx_data2d_ugrid/data2d_ugrid.cc | 30 ++-- src/libcode/vx_data2d_ugrid/data2d_ugrid.h | 8 +- 21 files changed, 240 insertions(+), 327 deletions(-) diff --git a/src/basic/vx_config/config_constants.h b/src/basic/vx_config/config_constants.h index 0ae2b4ac20..1dba37e8e8 100644 --- a/src/basic/vx_config/config_constants.h +++ b/src/basic/vx_config/config_constants.h @@ -465,7 +465,6 @@ struct WindMetadata { StringArray v_wind; // V-wind field names StringArray wind_speed; // Wind speed field names StringArray wind_direction; // Wind direction field names - ConcatString standard_name; // Standard field name, optional WindMetadata() { clear(); } ~WindMetadata() { clear(); } diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index df669b4a54..0a0169b037 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -110,7 +110,7 @@ void Met2dDataFile::mtddf_init_from_scratch() Raw_Grid = (Grid *) nullptr; Dest_Grid = (Grid *) nullptr; -ShiftRight = 0; +ShiftRight = 0; GridShifted = false; return; @@ -130,7 +130,7 @@ if ( Dest_Grid ) { delete Dest_Grid; Dest_Grid = (Grid *) nullptr; } Filename.clear(); -ShiftRight = 0; +ShiftRight = 0; GridShifted = false; return; @@ -360,7 +360,7 @@ return n_valid; //////////////////////////////////////////////////////////////////////// - +// JHG enhance to add support for kinetic energy, vorticity, and divergence bool Met2dDataFile::derive_winds(VarInfo *vinfo, DataPlane &dp) @@ -391,6 +391,16 @@ if(vinfo->is_wind_speed() || vinfo->is_wind_direction()) { vinfo->set_units(uwnd_units); } else { + + // Rotate U/V winds, if needed + if(vinfo->need_rotation()) { + DataPlane uwnd_dp_orig(uwnd_dp); + DataPlane vwnd_dp_orig(vwnd_dp); + rotate_uv_grid_to_earth(uwnd_dp_orig, vwnd_dp_orig, + *Raw_Grid, uwnd_dp, vwnd_dp); + vinfo->set_grid_relative_flag(false); + } + status = derive_wind_direction(uwnd_dp, vwnd_dp, dp); vinfo->set_long_name("Wind Direction"); vinfo->set_units("deg"); @@ -412,6 +422,14 @@ else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { read_wind_data(vinfo, vinfo->wind_info().wind_direction, wdir_dp, wdir_units); + // Rotate wind direction, if needed + if(vinfo->need_rotation()) { + DataPlane wdir_dp_orig(wdir_dp); + rotate_wind_direction_grid_to_earth(wdir_dp_orig, + *Raw_Grid, wdir_dp); + vinfo->set_grid_relative_flag(false); + } + if(status) { if(vinfo->is_u_wind()) { status = derive_u_wind(wspd_dp, wdir_dp, dp); @@ -459,6 +477,18 @@ if(vinfo->is_wind_speed() || vinfo->is_wind_direction()) { vwnd_dpa, vwnd_units); if(!status) return status; + // Rotate U/V winds, if needed + if(vinfo->need_rotation()) { + for(int i=0; iset_grid_relative_flag(false); + } + // Store the long name and units if(vinfo->is_wind_speed()) { vinfo->set_long_name("Wind Speed"); @@ -527,6 +557,16 @@ else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { if(!status) return status; + // Rotate wind direction, if needed + if(vinfo->need_rotation()) { + for(int i=0; iset_grid_relative_flag(false); + } + } + // Store the long name and units if(vinfo->is_u_wind()) { vinfo->set_long_name("U-Component of Wind"); @@ -591,29 +631,51 @@ bool Met2dDataFile::rotate_winds(VarInfo *vinfo, DataPlane &dp) { -if(!vinfo) return false; - -bool status = false; +static const char *method_name = "Met2dDataFile::rotate_winds() -> "; -// JHG work here +if(!vinfo || !vinfo->need_rotation()) return false; -return status; +bool status = false; +DataPlane uwnd_dp; +DataPlane vwnd_dp; +DataPlane tmp_dp; +ConcatString units; + +// Rotate U-Wind +if(vinfo->is_u_wind()) { + uwnd_dp = dp; + status = read_wind_data(vinfo, vinfo->wind_info().v_wind, + vwnd_dp, units); + if(status) status = rotate_uv_grid_to_earth(uwnd_dp, vwnd_dp, + *Raw_Grid, + dp, tmp_dp); +} +// Rotate V-Wind +else if(vinfo->is_v_wind()) { + vwnd_dp = dp; + status = read_wind_data(vinfo, vinfo->wind_info().u_wind, + uwnd_dp, units); + if(status) status = rotate_uv_grid_to_earth(uwnd_dp, vwnd_dp, + *Raw_Grid, + tmp_dp, dp); +} +// Rotate Wind Direction +else if(vinfo->is_wind_direction()) { + tmp_dp = dp; + if(status) rotate_wind_direction_grid_to_earth( + tmp_dp, *Raw_Grid, dp); } - -//////////////////////////////////////////////////////////////////////// - - -bool Met2dDataFile::rotate_winds(VarInfo *vinfo, DataPlaneArray &dpa) - -{ - -if(!vinfo) return false; - -bool status = false; - -// JHG work here +if(!status) { + mlog << Warning << "\n" << method_name + << "Trouble rotating wind field (" << vinfo->magic_str() + << ") from grid to earth relative.\n\n"; +} +// Update flag for a successful rotation +else { + vinfo->set_grid_relative_flag(false); +} return status; @@ -652,9 +714,11 @@ for(int i=0; iset_magic(names[i], lstr); + // Retrieve units and grid-relative status if(data_plane(*vinfo_cur, dp, false)) { status = true; units = vinfo_cur->units(); + vinfo->set_grid_relative_flag(vinfo_cur->is_grid_relative()); break; } } @@ -700,9 +764,11 @@ for(int i=0; iset_magic(names[i], lstr); + // Retrieve units and grid-relative status if(data_plane_array(*vinfo_cur, dpa, false)) { status = true; units = vinfo_cur->units(); + vinfo->set_grid_relative_flag(vinfo_cur->is_grid_relative()); break; } } @@ -719,12 +785,19 @@ return status; //////////////////////////////////////////////////////////////////////// -bool Met2dDataFile::process_data_plane(VarInfo *vinfo, DataPlane &dp) +bool Met2dDataFile::process_data_plane(VarInfo *vinfo, DataPlane &dp, + bool do_winds) { if ( ! vinfo ) return false; + // + // Rotate winds, if requested and needed + // + +if(do_winds && vinfo->need_rotation()) rotate_winds(vinfo, dp); + // // Apply conversion logic // diff --git a/src/libcode/vx_data2d/data_class.h b/src/libcode/vx_data2d/data_class.h index f2ca9d7285..b26edf1086 100644 --- a/src/libcode/vx_data2d/data_class.h +++ b/src/libcode/vx_data2d/data_class.h @@ -146,11 +146,11 @@ class Met2dDataFile : public Met2dData { // retrieve the first matching data plane - virtual bool data_plane(VarInfo &, DataPlane &, bool do_derive = true) = 0; + virtual bool data_plane(VarInfo &, DataPlane &, bool do_winds = true) = 0; // retrieve all matching data planes - virtual int data_plane_array(VarInfo &, DataPlaneArray &, bool do_derive = true) = 0; + virtual int data_plane_array(VarInfo &, DataPlaneArray &, bool do_winds = true) = 0; // retrieve the indexes of the first matching data plane @@ -165,13 +165,11 @@ class Met2dDataFile : public Met2dData { bool derive_winds(VarInfo *, DataPlane &); bool derive_winds(VarInfo *, DataPlaneArray &); - bool rotate_winds(VarInfo *, DataPlane &); - bool rotate_winds(VarInfo *, DataPlaneArray &); // post-process data after reading it - bool process_data_plane(VarInfo *, DataPlane &); + bool process_data_plane(VarInfo *, DataPlane &, bool do_winds = true); }; diff --git a/src/libcode/vx_data2d/var_info.cc b/src/libcode/vx_data2d/var_info.cc index 02e190beb8..221f3cc438 100644 --- a/src/libcode/vx_data2d/var_info.cc +++ b/src/libcode/vx_data2d/var_info.cc @@ -119,6 +119,7 @@ void VarInfo::assign(const VarInfo &v) { DefaultRegrid = v.DefaultRegrid; Regrid = v.Regrid; + GridRelativeFlag = v.GridRelativeFlag; WindInfo = v.WindInfo; SetAttrName = v.SetAttrName; @@ -182,6 +183,7 @@ void VarInfo::clear() { DefaultRegrid.clear(); Regrid.clear(); + GridRelativeFlag = false; WindInfo.clear(); SetAttrName.clear(); @@ -468,6 +470,13 @@ void VarInfo::set_regrid(const RegridInfo &ri) { /////////////////////////////////////////////////////////////////////////////// +void VarInfo::set_grid_relative_flag(bool f) { + GridRelativeFlag = f; + return; +} + +/////////////////////////////////////////////////////////////////////////////// + void VarInfo::set_magic(const ConcatString &nstr, const ConcatString &lstr) { // Check for embedded whitespace @@ -844,7 +853,16 @@ bool VarInfo::is_wind_direction() const { /////////////////////////////////////////////////////////////////////////////// bool VarInfo::is_grid_relative() const { - return is_flag_set(SetAttrIsGridRelative); + return (!is_bad_data(SetAttrIsGridRelative) ? + SetAttrIsGridRelative != 0 : + GridRelativeFlag); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool VarInfo::need_rotation() const { + return (is_u_wind() || is_v_wind() || is_wind_direction()) && + is_grid_relative(); } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_data2d/var_info.h b/src/libcode/vx_data2d/var_info.h index dd984e534e..0b4595ea8c 100644 --- a/src/libcode/vx_data2d/var_info.h +++ b/src/libcode/vx_data2d/var_info.h @@ -60,7 +60,8 @@ class VarInfo RegridInfo DefaultRegrid; // Default regridding logic RegridInfo Regrid; // Regridding logic - WindMetadata WindInfo; // Wind variable metadata + bool GridRelativeFlag; // Wind data is grid relative + WindMetadata WindInfo; // Wind variable metadata // Options to override metadata ConcatString SetAttrName; @@ -204,6 +205,8 @@ class VarInfo void set_default_regrid(const RegridInfo &); void set_regrid(const RegridInfo &); + void set_grid_relative_flag(bool); + void set_level_info_grib(Dictionary & dict); void set_prob_info_grib(ConcatString prob_name, double thresh_lo, double thresh_hi); @@ -218,7 +221,8 @@ class VarInfo virtual bool is_v_wind() const; virtual bool is_wind_speed() const; virtual bool is_wind_direction() const; - virtual bool is_grid_relative() const; + bool is_grid_relative() const; + bool need_rotation() const; bool is_prob() const; }; diff --git a/src/libcode/vx_data2d_grib/data2d_grib.cc b/src/libcode/vx_data2d_grib/data2d_grib.cc index 5eea2f1424..22856b6628 100644 --- a/src/libcode/vx_data2d_grib/data2d_grib.cc +++ b/src/libcode/vx_data2d_grib/data2d_grib.cc @@ -405,7 +405,7 @@ return count; //////////////////////////////////////////////////////////////////////// bool MetGrib1DataFile::data_plane(VarInfo &vinfo, DataPlane &plane, - bool do_derive) { + bool do_winds) { bool status = false; int n_planes = 0; DataPlaneArray plane_array; @@ -413,7 +413,7 @@ bool MetGrib1DataFile::data_plane(VarInfo &vinfo, DataPlane &plane, int j; // Call data_plane_array() to retrieve all matching records - n_planes = data_plane_array(*vinfo_grib, plane_array, do_derive); + n_planes = data_plane_array(*vinfo_grib, plane_array, do_winds); // Process multiple matches if ( n_planes > 0 ) { @@ -466,7 +466,7 @@ bool MetGrib1DataFile::data_plane(VarInfo &vinfo, DataPlane &plane, int MetGrib1DataFile::data_plane_array(VarInfo &vinfo, DataPlaneArray &plane_array, - bool do_derive) { + bool do_winds) { bool status = false; bool exact; int i, lower, upper, type_num; @@ -503,30 +503,12 @@ int MetGrib1DataFile::data_plane_array(VarInfo &vinfo, // Read current record status = get_data_plane(r, cur_plane); - // Check if these are winds that should be rotated - if(status && - is_grid_relative(r) && - (vinfo_grib->is_u_wind() || - vinfo_grib->is_v_wind() || - vinfo_grib->is_wind_direction())) { - - // Initialize the current VarInfo object - vinfo_grib_winds = *vinfo_grib; - cur_level = vinfo_grib_winds.level(); - - // Reset the level range for pressure and vertical levels - if(cur_level.type() == LevelType_Pres || - cur_level.type() == LevelType_Vert) { - cur_level.set_range(lower, upper); - vinfo_grib_winds.set_level_info(cur_level); - } - - // Rotate the winds - rotate_winds(vinfo_grib_winds, cur_plane); + if(status) { + // Store whether winds are grid relative + vinfo.set_grid_relative_flag(is_grid_relative(r)); + status = process_data_plane(&vinfo, cur_plane, do_winds); } - if(status) status = process_data_plane(&vinfo, cur_plane); - if(!status) { cur_plane.clear(); lower = upper = bad_data_int; @@ -543,7 +525,7 @@ int MetGrib1DataFile::data_plane_array(VarInfo &vinfo, } // end for loop // If nothing was found, try to build derived records - if(plane_array.n_planes() == 0 && do_derive) { + if(plane_array.n_planes() == 0 && do_winds) { derive_winds(&vinfo, plane_array); } @@ -556,101 +538,6 @@ int MetGrib1DataFile::data_plane_array(VarInfo &vinfo, return plane_array.n_planes(); } -//////////////////////////////////////////////////////////////////////// -// -// This function rotates the wind data that's passed in from -// grid-relative to earth-relative. -// -//////////////////////////////////////////////////////////////////////// - -void MetGrib1DataFile::rotate_winds(VarInfoGrib &vinfo_grib, DataPlane &plane) { - VarInfoGrib vinfo_grib_winds = vinfo_grib; - DataPlane u2d, v2d, u2d_rot, v2d_rot; - - // For U-wind, retrieve the corresponding V-wind, and rotate - if(vinfo_grib.is_u_wind()) { - - mlog << Debug(3) << "MetGrib1DataFile::rotate_winds() -> " - << "Have U-wind record, reading V-wind record.\n"; - vinfo_grib_winds.set_name(vgrd_abbr_str); - data_plane_scalar(vinfo_grib_winds, v2d); - rotate_uv_grid_to_earth(plane, v2d, grid(), u2d_rot, v2d_rot); - plane = u2d_rot; - } - - // For V-wind, retrieve the corresponding U-wind, and rotate - else if(vinfo_grib.is_v_wind()) { - - mlog << Debug(3) << "MetGrib1DataFile::rotate_winds() -> " - << "Have V-wind record, reading U-wind record.\n"; - vinfo_grib_winds.set_name(ugrd_abbr_str); - data_plane_scalar(vinfo_grib_winds, u2d); - rotate_uv_grid_to_earth(u2d, plane, grid(), u2d_rot, v2d_rot); - plane = v2d_rot; - } - - // For wind direction, rotate - else if(vinfo_grib.is_wind_direction()) { - mlog << Debug(3) << "MetGrib1DataFile::rotate_winds() -> " - << "Have wind direction, calling rotate.\n"; - rotate_wind_direction_grid_to_earth(plane, grid(), u2d); - plane = u2d; - } - - return; -} - -//////////////////////////////////////////////////////////////////////// -// -// This function retrieves a single data plane as reqested in the -// VarInfo object but does not attempt to rotate or derive winds. -// -//////////////////////////////////////////////////////////////////////// - -bool MetGrib1DataFile::data_plane_scalar(VarInfoGrib &vinfo_grib, - DataPlane &plane) { - int i; - GribRecord r; - bool status = false; - - // Initialize the data plane - plane.clear(); - - // Loop through the records in the GRIB file looking for a match - for(i=0; in_records(); i++) { - - // Read the current record. - GF->seek_record(i); - (*GF) >> r; - - // Check for an exact match - if(is_exact_match(vinfo_grib, r)) { - - mlog << Debug(3) << "MetGrib1DataFile::data_plane_scalar() -> " - << "Found exact match for VarInfo \"" - << vinfo_grib.magic_str() << "\" in GRIB record " - << i+1 << " of GRIB file \"" << filename() - << "\".\n"; - - // Read current record - status = get_data_plane(r, plane); - - if(status) status = process_data_plane(&vinfo_grib, plane); - - break; - } - } // end for loop - - if(!status) { - mlog << Warning << "\nMetGrib1DataFile::data_plane_scalar() -> " - << "No exact match found for VarInfo \"" - << vinfo_grib.magic_str() << "\" in GRIB file \"" - << filename() << "\".\n\n"; - } - - return status; -} - /////////////////////////////////////////////////////////////////////////////// // // Check whether or not the res_flag indicates that the vectors are defined @@ -658,7 +545,7 @@ bool MetGrib1DataFile::data_plane_scalar(VarInfoGrib &vinfo_grib, // ////////////////////////////////////////////////////////////////////////////// -bool is_grid_relative(const GribRecord &r) { +static bool is_grid_relative(const GribRecord &r) { unsigned char res_flag = 0; // LatLon diff --git a/src/libcode/vx_data2d_grib/data2d_grib.h b/src/libcode/vx_data2d_grib/data2d_grib.h index 80f4f24e1e..4d1e3569e1 100644 --- a/src/libcode/vx_data2d_grib/data2d_grib.h +++ b/src/libcode/vx_data2d_grib/data2d_grib.h @@ -42,10 +42,6 @@ class MetGrib1DataFile : public Met2dDataFile { DataPlane Plane; - void rotate_winds(VarInfoGrib &, DataPlane &); - - bool data_plane_scalar(VarInfoGrib &, DataPlane &); - public: MetGrib1DataFile(); @@ -86,11 +82,11 @@ class MetGrib1DataFile : public Met2dDataFile { // retrieve the first matching data plane - bool data_plane(VarInfo &, DataPlane &, bool do_derive = true); + bool data_plane(VarInfo &, DataPlane &, bool do_winds = true); // retrieve all matching data planes - int data_plane_array(VarInfo &, DataPlaneArray &, bool do_derive = true); + int data_plane_array(VarInfo &, DataPlaneArray &, bool do_winds = true); // retrieve the index of the first matching record diff --git a/src/libcode/vx_data2d_grib2/data2d_grib2.cc b/src/libcode/vx_data2d_grib2/data2d_grib2.cc index d43d026a7d..36b5d8bd50 100644 --- a/src/libcode/vx_data2d_grib2/data2d_grib2.cc +++ b/src/libcode/vx_data2d_grib2/data2d_grib2.cc @@ -38,8 +38,9 @@ using namespace std; //////////////////////////////////////////////////////////////////////// -double scaled2dbl(int scale_factor, int scale_value); -int parse_int4(g2int); +static bool is_grid_relative(const Grib2Record *); +static double scaled2dbl(int scale_factor, int scale_value); +static int parse_int4(g2int); //////////////////////////////////////////////////////////////////////// // @@ -82,19 +83,12 @@ MetGrib2DataFile & MetGrib2DataFile::operator=(const MetGrib2DataFile &) { void MetGrib2DataFile::grib2_init_from_scratch() { ScanMode = -1; - - PairMap[ugrd_abbr_str] = vgrd_abbr_str; - PairMap[vgrd_abbr_str] = ugrd_abbr_str; - - return; } //////////////////////////////////////////////////////////////////////// void MetGrib2DataFile::close() { fclose(FileGrib2); - - return; } //////////////////////////////////////////////////////////////////////// @@ -149,7 +143,7 @@ void MetGrib2DataFile::dump(ostream & out, int depth) const { //////////////////////////////////////////////////////////////////////// bool MetGrib2DataFile::data_plane(VarInfo &vinfo, DataPlane &plane, - bool do_derive) { + bool do_winds) { // narrow the vinfo pointer auto vinfo_g2 = (VarInfoGrib2*)(&vinfo); @@ -160,7 +154,7 @@ bool MetGrib2DataFile::data_plane(VarInfo &vinfo, DataPlane &plane, find_record_matches(vinfo_g2, listMatch, listMatchRange); // if no matches were found, check for derived records - if(listMatch.empty() && do_derive) { + if(listMatch.empty() && do_winds) { DataPlaneArray plane_array; derive_winds(vinfo_g2, plane_array); @@ -188,7 +182,7 @@ bool MetGrib2DataFile::data_plane(VarInfo &vinfo, DataPlane &plane, plane = plane_array[0]; - return process_data_plane(vinfo_g2, plane); + return process_data_plane(vinfo_g2, plane, do_winds); } // END: if( 1 > listMatch.size() ) @@ -228,10 +222,11 @@ bool MetGrib2DataFile::data_plane(VarInfo &vinfo, DataPlane &plane, bool read_success = read_grib2_record_data_plane(listMatch[0], plane); - // check the data plane for wind rotation - plane = check_uv_rotation(vinfo_g2, listMatch[0], plane); - - if(read_success) read_success = process_data_plane(vinfo_g2, plane); + if(read_success) { + // store whether winds are grid relative + vinfo_g2->set_grid_relative_flag(is_grid_relative(listMatch[0])); + read_success = process_data_plane(vinfo_g2, plane, do_winds); + } return read_success; } @@ -240,7 +235,7 @@ bool MetGrib2DataFile::data_plane(VarInfo &vinfo, DataPlane &plane, int MetGrib2DataFile::data_plane_array(VarInfo &vinfo, DataPlaneArray &plane_array, - bool do_derive) { + bool do_winds) { // Initialize plane_array.clear(); @@ -307,7 +302,7 @@ int MetGrib2DataFile::data_plane_array(VarInfo &vinfo, } // if nothing was found, try to build derived records - else if(do_derive) { + else if(do_winds) { derive_winds(vinfo_g2, plane_array); @@ -336,9 +331,6 @@ int MetGrib2DataFile::data_plane_array(VarInfo &vinfo, DataPlane plane; num_read += ( read_grib2_record_data_plane(*it, plane) ? 1 : 0 ); - // check the data plane for wind rotation - plane = check_uv_rotation(vinfo_g2, *it, plane); - // add the data plane to the array at the specified level(s) double lvl_lower = (double)(*it)->LvlVal1; double lvl_upper = (double)(*it)->LvlVal2; @@ -347,7 +339,10 @@ int MetGrib2DataFile::data_plane_array(VarInfo &vinfo, lvl_upper = ( (double)(*it)->LvlVal2 ) / 100.0; } - if(process_data_plane(vinfo_g2, plane)) { + // store whether winds are grid relative + vinfo_g2->set_grid_relative_flag(is_grid_relative(*it)); + + if(process_data_plane(vinfo_g2, plane, do_winds)) { plane_array.add(plane, lvl_lower, lvl_upper); } } @@ -578,51 +573,6 @@ void MetGrib2DataFile::find_record_matches(const VarInfoGrib2* vinfo, //////////////////////////////////////////////////////////////////////// -DataPlane MetGrib2DataFile::check_uv_rotation(const VarInfoGrib2 *vinfo, Grib2Record *rec, DataPlane plane){ - - // check that the field is present in the pair map - string parm_name = vinfo->name().text(); - if( 0 == PairMap.count( parm_name ) || - 0 == (rec->ResCompFlag & 8) ) { - return plane; - } - - // build the magic string of the pair field, and check it - ConcatString pair_mag = build_magic( rec ); - pair_mag.replace(parm_name.data(), PairMap[parm_name].data()); - if( 0 == NameRecMap.count( string(pair_mag.text()) ) ){ - mlog << Debug(3) << "MetGrib2DataFile::check_uv_rotation -> " - << "UV rotation pair record not found: '" << pair_mag - << "'\n"; - return plane; - } - - // read the data plane for the pair record - Grib2Record *rec_pair = NameRecMap[pair_mag.text()]; - DataPlane plane_pair; - read_grib2_record_data_plane(NameRecMap[pair_mag.text()], - plane_pair); - - mlog << Debug(3) << "MetGrib2DataFile::check_uv_rotation() -> " - << "Found pair match \"" << pair_mag << "\" in GRIB2 record " - << rec_pair->RecNum << " field " << rec_pair->FieldNum << "\n"; - - // rotate the winds - DataPlane u2d; - DataPlane v2d; - DataPlane u2d_rot; - DataPlane v2d_rot; - if( 'U' == parm_name.at(0) ){ u2d = plane; v2d = plane_pair; } - else { v2d = plane; u2d = plane_pair; } - rotate_uv_grid_to_earth(u2d, v2d, *Raw_Grid, u2d_rot, v2d_rot); - if( 'U' == parm_name.at(0) ){ plane = u2d_rot; } - else { plane = v2d_rot; } - - return plane; -} - -//////////////////////////////////////////////////////////////////////// - void MetGrib2DataFile::read_grib2_record_list() { gribfield *gfld; long offset = 0; @@ -897,10 +847,6 @@ void MetGrib2DataFile::read_grib2_record_list() { // add the record to the list RecList.emplace_back(rec); - // build data structure for U/V wind pairs - string rec_mag = build_magic(rec).text(); - NameRecMap[rec_mag] = rec; - g2_free(gfld); // if there are more fields in the current record, read the next one @@ -1617,7 +1563,13 @@ int MetGrib2DataFile::index( VarInfo &vinfo ){ // //////////////////////////////////////////////////////////////////////// -double scaled2dbl(int scale_factor, int scale_value) { +static bool is_grid_relative(const Grib2Record *r) { + return (r->ResCompFlag & 8) != 0; +} + +//////////////////////////////////////////////////////////////////////// + +static double scaled2dbl(int scale_factor, int scale_value) { if (scale_factor == 0) return (double) scale_value; if (scale_factor < 0) return ( scale_value * pow(10.0, -scale_factor) ); return ( scale_value / pow(10.0, scale_factor) ); @@ -1625,7 +1577,7 @@ double scaled2dbl(int scale_factor, int scale_value) { //////////////////////////////////////////////////////////////////////// -int parse_int4(g2int i) { +static int parse_int4(g2int i) { unsigned char c[4]; unsigned long n = i; diff --git a/src/libcode/vx_data2d_grib2/data2d_grib2.h b/src/libcode/vx_data2d_grib2/data2d_grib2.h index 65b8937669..5e35583a6c 100644 --- a/src/libcode/vx_data2d_grib2/data2d_grib2.h +++ b/src/libcode/vx_data2d_grib2/data2d_grib2.h @@ -86,17 +86,12 @@ class MetGrib2DataFile : public Met2dDataFile { std::vector RecList; - std::map PairMap; - std::map NameRecMap; - int ScanMode; - // // utilities to read a GRIB2 information // - void find_record_matches( const VarInfoGrib2* vinfo, std::vector &listMatchExact, std::vector &listMatchRange @@ -111,12 +106,6 @@ class MetGrib2DataFile : public Met2dDataFile { void read_grib2_record_list(); - // JHG, move this to the base class - DataPlane check_uv_rotation( const VarInfoGrib2 *vinfo, - Grib2Record *rec, - DataPlane plane - ); - public: MetGrib2DataFile(); @@ -134,11 +123,11 @@ class MetGrib2DataFile : public Met2dDataFile { // retrieve the first matching data plane - bool data_plane(VarInfo &, DataPlane &, bool do_derive = true); + bool data_plane(VarInfo &, DataPlane &, bool do_winds = true); // retrieve all matching data planes - int data_plane_array(VarInfo &, DataPlaneArray &, bool do_derive = true); + int data_plane_array(VarInfo &, DataPlaneArray &, bool do_winds = true); // retrieve the index of the first matching record diff --git a/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc b/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc index 81e83d0406..30f81acde4 100644 --- a/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc +++ b/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc @@ -159,7 +159,7 @@ void MetNcCFDataFile::dump(ostream & out, int depth) const { //////////////////////////////////////////////////////////////////////// int MetNcCFDataFile::add_data_planes_by_time(VarInfo &vinfo, const LevelInfo &level, - DataPlaneArray &plane_array) { + DataPlaneArray &plane_array, bool do_winds) { int n_rec = 0; const auto *vinfo_nc = (VarInfoNcCF *)&vinfo; const NcVarInfo *data_var = get_data_var(vinfo); @@ -192,7 +192,7 @@ int MetNcCFDataFile::add_data_planes_by_time(VarInfo &vinfo, const LevelInfo &le auto time_idx = time_offsets[idx]; if (time_idx < time_cnt) { dimension[t_slot] = time_offsets[idx]; - if (data_plane(vinfo, plane, dimension)) { + if (read_data_plane(vinfo, plane, dimension, do_winds)) { plane_array.add(plane, (double)time_lower, (double)time_upper); n_rec++; if (mlog.verbosity_level() >= nc_cf_debug_level) { @@ -210,7 +210,7 @@ int MetNcCFDataFile::add_data_planes_by_time(VarInfo &vinfo, const LevelInfo &le //////////////////////////////////////////////////////////////////////// int MetNcCFDataFile::add_data_planes_by_z(VarInfo &vinfo, const LevelInfo &level, - DataPlaneArray &plane_array) { + DataPlaneArray &plane_array, bool do_winds) { int n_rec = 0; const auto *vinfo_nc = (VarInfoNcCF *)&vinfo; const NcVarInfo *data_var = get_data_var(vinfo); @@ -242,7 +242,7 @@ int MetNcCFDataFile::add_data_planes_by_z(VarInfo &vinfo, const LevelInfo &level auto z_idx = (int)z_offsets[idx]; if (z_idx < z_cnt) { dimension[z_slot] = z_offsets[idx]; - if (data_plane(vinfo, plane, dimension)) { + if (read_data_plane(vinfo, plane, dimension, do_winds)) { plane_array.add(plane, z_lower, z_upper); n_rec++; } @@ -271,10 +271,10 @@ Grid MetNcCFDataFile::build_grid_from_lat_lon_vars(NcVar *lat_var, NcVar *lon_va //////////////////////////////////////////////////////////////////////// bool MetNcCFDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, - bool do_derive) { + bool do_winds) { auto vinfo_nc = (VarInfoNcCF *) &vinfo; static const string method_name - = "MetNcCFDataFile::data_plane(VarInfo &, DataPlane &) -> "; + = "MetNcCFDataFile::data_plane() -> "; LongArray dimension = vinfo_nc->dimension(); NcVarInfo *data_var = get_data_var(vinfo); @@ -307,7 +307,7 @@ bool MetNcCFDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, bool status = data_plane(vinfo, plane, dimension); // Attempt to derive the data - if(!status && do_derive) { + if(!status && do_winds) { status = derive_winds(vinfo_nc, plane); } @@ -316,11 +316,12 @@ bool MetNcCFDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, //////////////////////////////////////////////////////////////////////// -bool MetNcCFDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, const LongArray &dimension) +bool MetNcCFDataFile::read_data_plane(VarInfo &vinfo, DataPlane &plane, + const LongArray &dimension, bool do_winds) { auto vinfo_nc = (VarInfoNcCF *)&vinfo; static const string method_name - = "MetNcCFDataFile::data_plane(VarInfo &, DataPlane &, LongArray &) -> "; + = "MetNcCFDataFile::read_data_plane() -> "; Grid grid_attr = vinfo.grid_attr(); _file->update_grid(grid_attr); @@ -369,7 +370,7 @@ bool MetNcCFDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, const LongArr } } - status = process_data_plane(&vinfo, plane); + status = process_data_plane(&vinfo, plane, do_winds); // Set the VarInfo object's name, long_name, level, and units strings @@ -395,7 +396,7 @@ bool MetNcCFDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, const LongArr int MetNcCFDataFile::data_plane_array(VarInfo &vinfo, DataPlaneArray &plane_array, - bool do_derive) { + bool do_winds) { int n_rec = 0; DataPlane plane; bool status = false; @@ -422,18 +423,18 @@ int MetNcCFDataFile::data_plane_array(VarInfo &vinfo, cur_time_index = cur_z_index = 0; if (0 <= t_dim_slot && range_flag == dimension[t_dim_slot] && level.type() == LevelType_Time) { - n_rec = add_data_planes_by_time(vinfo, level, plane_array); + n_rec = add_data_planes_by_time(vinfo, level, plane_array, do_winds); } else if (0 <= z_dim_slot && range_flag == dimension[z_dim_slot] && level.type() == LevelType_Pres) { - n_rec = add_data_planes_by_z(vinfo, level, plane_array); + n_rec = add_data_planes_by_z(vinfo, level, plane_array, do_winds); } - else if (data_plane(vinfo, plane)) { + else if (data_plane(vinfo, plane, do_winds)) { plane_array.add(plane, bad_data_int, bad_data_int); n_rec++; } // Attempt to derive the data - if(n_rec == 0 && do_derive) { + if(n_rec == 0 && do_winds) { status = derive_winds(vinfo_nc, plane_array); } diff --git a/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.h b/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.h index 8b7192186a..d4dd7b3439 100644 --- a/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.h +++ b/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.h @@ -35,16 +35,16 @@ class MetNcCFDataFile : public Met2dDataFile { MetNcCFDataFile & operator=(const MetNcCFDataFile &); int add_data_planes_by_time(VarInfo &vinfo, const LevelInfo &level, - DataPlaneArray &plane_array); + DataPlaneArray &plane_array, bool do_winds); int add_data_planes_by_z(VarInfo &vinfo, const LevelInfo &level, - DataPlaneArray &plane_array); + DataPlaneArray &plane_array, bool do_winds); LongArray collect_time_offsets(VarInfo &vinfo); LongArray collect_z_offsets(VarInfo &vinfo); long convert_generic_to_offset(double value, const std::string& dim_name, std::vector values); long convert_time_to_offset(double time_value) const; long convert_z_to_offset(double z_value, const NcVarInfo* data_var); - bool data_plane(VarInfo &, DataPlane &, const LongArray &dimension); + bool read_data_plane(VarInfo &, DataPlane &, const LongArray &dimension, bool do_winds); void error_message(const bool is_dim_time, const int error_code, const double _lower, const double _upper, const long _value, const ConcatString &var_name, @@ -99,11 +99,11 @@ class MetNcCFDataFile : public Met2dDataFile { // retrieve the first matching data plane - bool data_plane(VarInfo &, DataPlane &, bool do_derive = true); + bool data_plane(VarInfo &, DataPlane &, bool do_winds = true); // retrieve all matching data planes - int data_plane_array(VarInfo &, DataPlaneArray &, bool do_derive = true); + int data_plane_array(VarInfo &, DataPlaneArray &, bool do_winds = true); // retrieve the index of the first matching record diff --git a/src/libcode/vx_data2d_nc_met/data2d_nc_met.cc b/src/libcode/vx_data2d_nc_met/data2d_nc_met.cc index 2dd2534bb5..540bdc83bd 100644 --- a/src/libcode/vx_data2d_nc_met/data2d_nc_met.cc +++ b/src/libcode/vx_data2d_nc_met/data2d_nc_met.cc @@ -210,7 +210,7 @@ void MetNcMetDataFile::set_range_azimuth_times(int i_track_point, DataPlane &pla //////////////////////////////////////////////////////////////////////// bool MetNcMetDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, - bool do_derive) { + bool do_winds) { bool status = false; ConcatString req_time_str, data_time_str; VarInfoNcMet * vinfo_nc = (VarInfoNcMet *) &vinfo; @@ -239,7 +239,7 @@ bool MetNcMetDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, plane, info); // Attempt to derive the data - if(!status && do_derive) { + if(!status && do_winds) { status = derive_winds(vinfo_nc, plane); } @@ -283,7 +283,7 @@ bool MetNcMetDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, status = false; } - status = process_data_plane(&vinfo, plane); + status = process_data_plane(&vinfo, plane, do_winds); // Set the VarInfo object's name, long_name, level, and units strings if(info->name_att.length() > 0) vinfo.set_name(info->name_att); @@ -300,7 +300,7 @@ bool MetNcMetDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, int MetNcMetDataFile::data_plane_array(VarInfo &vinfo, DataPlaneArray &plane_array, - bool do_derive) { + bool do_winds) { bool status = false; int n_rec = 0; DataPlane plane; @@ -309,7 +309,7 @@ int MetNcMetDataFile::data_plane_array(VarInfo &vinfo, plane_array.clear(); // Can only read a single 2D data plane from a MET NetCDF file - status = data_plane(vinfo, plane, do_derive); + status = data_plane(vinfo, plane, do_winds); // Add the data plane to the DataPlaneArray with no level values if(status) { diff --git a/src/libcode/vx_data2d_nc_met/data2d_nc_met.h b/src/libcode/vx_data2d_nc_met/data2d_nc_met.h index 9e503d8954..c020912209 100644 --- a/src/libcode/vx_data2d_nc_met/data2d_nc_met.h +++ b/src/libcode/vx_data2d_nc_met/data2d_nc_met.h @@ -62,11 +62,11 @@ class MetNcMetDataFile : public Met2dDataFile { // retrieve the first matching data plane - bool data_plane(VarInfo &, DataPlane &, bool do_derive = true); + bool data_plane(VarInfo &, DataPlane &, bool do_winds = true); // retrieve all matching data planes - int data_plane_array(VarInfo &, DataPlaneArray &, bool do_derive = true); + int data_plane_array(VarInfo &, DataPlaneArray &, bool do_winds = true); // retrieve the index of the first matching record diff --git a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc index 54dd75e0b9..be9bcb8186 100644 --- a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc +++ b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc @@ -6,10 +6,8 @@ // ** P.O.Box 3000, Boulder, Colorado, 80307-3000, USA // *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* - //////////////////////////////////////////////////////////////////////// - #include #include #include @@ -23,6 +21,9 @@ using namespace std; +//////////////////////////////////////////////////////////////////////// + +static bool is_grid_relative(const char *); //////////////////////////////////////////////////////////////////////// // @@ -122,7 +123,7 @@ void MetNcWrfDataFile::dump(ostream & out, int depth) const { //////////////////////////////////////////////////////////////////////// bool MetNcWrfDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, - bool do_derive) { + bool do_winds) { bool status = false; double pressure = bad_data_double; ConcatString level_str; @@ -153,8 +154,11 @@ bool MetNcWrfDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, status = WrfNc->data(vinfo_nc->req_name().c_str(), dimension, plane, pressure, info); + // Store whether winds are grid relative + vinfo_nc->set_grid_relative_flag(is_grid_relative(vinfo_nc->req_name().c_str())); + // Attempt to derive the data - if(!status && do_derive) { + if(!status && do_winds) { status = derive_winds(vinfo_nc, plane); } @@ -183,7 +187,7 @@ bool MetNcWrfDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, status = false; } - status = process_data_plane(&vinfo, plane); + status = process_data_plane(&vinfo, plane, do_winds); // Set the VarInfo object's name, long_name, and units strings // Note that info is null for derived fields @@ -208,7 +212,7 @@ bool MetNcWrfDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, int MetNcWrfDataFile::data_plane_array(VarInfo &vinfo, DataPlaneArray &plane_array, - bool do_derive) { + bool do_winds) { int i, i_dim, n_level, status, lower, upper; ConcatString level_str; double pressure, min_level, max_level; @@ -255,8 +259,11 @@ int MetNcWrfDataFile::data_plane_array(VarInfo &vinfo, status = WrfNc->data(vinfo_nc->req_name().c_str(), cur_dim, cur_plane, pressure, info); + // Store whether winds are grid relative + vinfo_nc->set_grid_relative_flag(is_grid_relative(vinfo_nc->req_name().c_str())); + // Attempt to derive the data - if(!status && do_derive) { + if(!status && do_winds) { status = derive_winds(vinfo_nc, cur_plane); } @@ -285,7 +292,7 @@ int MetNcWrfDataFile::data_plane_array(VarInfo &vinfo, status = false; } - status = process_data_plane(&vinfo, cur_plane); + status = process_data_plane(&vinfo, cur_plane, do_winds); // Add current plane to the data plane array plane_array.add(cur_plane, pressure, pressure); @@ -329,3 +336,10 @@ int MetNcWrfDataFile::index(VarInfo &vinfo){ } //////////////////////////////////////////////////////////////////////// + +static bool is_grid_relative(const char *name) { + return has_prefix(pinterp_grid_relative_names, + n_pinterp_grid_relative_names, name); +} + +//////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.h b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.h index d26bf1a68a..1f031df1fb 100644 --- a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.h +++ b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.h @@ -61,11 +61,11 @@ class MetNcWrfDataFile : public Met2dDataFile { // retrieve the first matching data plane - bool data_plane(VarInfo &, DataPlane &, bool do_derive = true); + bool data_plane(VarInfo &, DataPlane &, bool do_winds = true); // retrieve all matching data planes - int data_plane_array(VarInfo &, DataPlaneArray &, bool do_derive = true); + int data_plane_array(VarInfo &, DataPlaneArray &, bool do_winds = true); // retrieve the index of the first matching record diff --git a/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.cc b/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.cc index 41b6fdd73f..abb5feae5b 100644 --- a/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.cc +++ b/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.cc @@ -410,24 +410,4 @@ bool VarInfoNcWrf::is_wind_direction() const { return false; } - -/////////////////////////////////////////////////////////////////////////////// - -bool VarInfoNcWrf::is_grid_relative() const { - - // - // Check set_attrs entry - // - int flag = SetAttrIsGridRelative; - if(!is_bad_data(flag)) return is_flag_set(flag); - - // - // Check to see if the VarInfo name matches any of expected Pinterp - // variables that should be rotated from grid-relative to earth-relative. - // - return has_prefix(pinterp_grid_relative_names, - n_pinterp_grid_relative_names, - Name.c_str()); -} - /////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.h b/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.h index bc55f426c0..314009600b 100644 --- a/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.h +++ b/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.h @@ -242,7 +242,6 @@ class VarInfoNcWrf : public VarInfo bool is_v_wind() const override; bool is_wind_speed() const override; bool is_wind_direction() const override; - bool is_grid_relative() const override; }; /////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_data2d_python/data2d_python.cc b/src/libcode/vx_data2d_python/data2d_python.cc index 69209c0f5d..35226d4fe1 100644 --- a/src/libcode/vx_data2d_python/data2d_python.cc +++ b/src/libcode/vx_data2d_python/data2d_python.cc @@ -295,7 +295,8 @@ return; //////////////////////////////////////////////////////////////////////// -bool MetPythonDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, bool) +bool MetPythonDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, + bool do_winds) { @@ -332,7 +333,7 @@ if ( status ) { plane = Plane; - status = process_data_plane(&vinfo, plane); + status = process_data_plane(&vinfo, plane, do_winds); } @@ -362,7 +363,7 @@ return true; int MetPythonDataFile::data_plane_array(VarInfo &vinfo, DataPlaneArray &plane_array, - bool) + bool do_winds) { @@ -400,7 +401,7 @@ if ( status ) { plane = Plane; - status = process_data_plane(&vinfo, plane); + status = process_data_plane(&vinfo, plane, do_winds); } diff --git a/src/libcode/vx_data2d_python/data2d_python.h b/src/libcode/vx_data2d_python/data2d_python.h index 1e7d05bca9..6c32d63d5f 100644 --- a/src/libcode/vx_data2d_python/data2d_python.h +++ b/src/libcode/vx_data2d_python/data2d_python.h @@ -86,9 +86,9 @@ class MetPythonDataFile : public Met2dDataFile { void dump (std::ostream &, int depth = 0) const; - bool data_plane(VarInfo &, DataPlane &, bool do_derive = true); + bool data_plane(VarInfo &, DataPlane &, bool do_winds = true); - int data_plane_array(VarInfo &, DataPlaneArray &, bool do_derive = true); + int data_plane_array(VarInfo &, DataPlaneArray &, bool do_winds = true); int index(VarInfo &); diff --git a/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc b/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc index b989629ab8..7babaa60bb 100644 --- a/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc +++ b/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc @@ -164,11 +164,11 @@ void MetUGridDataFile::dump(ostream & out, int depth) const { //////////////////////////////////////////////////////////////////////// bool MetUGridDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, - bool do_derive) { + bool do_winds) { bool status = false; auto data_var = (NcVarInfo *)nullptr; static const string method_name - = "MetUGridDataFile::data_plane(VarInfo &, DataPlane &) -> "; + = "MetUGridDataFile::data_plane(VarInfo &, DataPlane &, bool) -> "; // Initialize the data plane @@ -178,10 +178,10 @@ bool MetUGridDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, data_var = _file->find_by_name(req_name.c_str()); if (nullptr != data_var) { // Read the data - status = data_plane(vinfo, plane, data_var); + status = data_plane(vinfo, plane, data_var, do_winds); // Attempt to derive the data - if(!status && do_derive) { + if(!status && do_winds) { status = derive_winds(&vinfo, plane); } } @@ -196,7 +196,7 @@ bool MetUGridDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, int vlevel = extract_vlevels(req_name, nc_var_info->name.c_str()); if (vlevel >= lvl_lower && vlevel <= lvl_upper) { vinfo.set_req_name(nc_var_info->name.c_str()); - status = data_plane(vinfo, plane, nc_var_info); + status = data_plane(vinfo, plane, nc_var_info, do_winds); if (status) { mlog << Debug(5) << method_name << "Found range match for VarInfo \"" << req_name @@ -218,7 +218,8 @@ bool MetUGridDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, // The requested variable name is the prefix of the actual variable name. // -bool MetUGridDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, const NcVarInfo *data_var) +bool MetUGridDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, + const NcVarInfo *data_var, bool do_winds) { // Not sure why we do this bool status = false; @@ -226,7 +227,7 @@ bool MetUGridDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, const NcVarI VarInfoUGrid *vinfo_nc = (VarInfoUGrid *)&vinfo; static const string method_name_s = "MetUGridDataFile::data_plane() -> "; static const string method_name - = "MetUGridDataFile::data_plane(VarInfo &, DataPlane &, const NcVarInfo *) -> "; + = "MetUGridDataFile::data_plane(VarInfo &, DataPlane &, const NcVarInfo *, bool) -> "; // Initialize the data plane @@ -305,7 +306,7 @@ bool MetUGridDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, const NcVarI } // Read the data - status = read_data_plane(data_var->name, vinfo, plane, dimension); + status = read_data_plane(data_var->name, vinfo, plane, dimension, do_winds); } return status; @@ -315,7 +316,7 @@ bool MetUGridDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, const NcVarI int MetUGridDataFile::data_plane_array(VarInfo &vinfo, DataPlaneArray &plane_array, - bool do_derive) { + bool do_winds) { int n_rec = 0; DataPlane plane; static const string method_name @@ -342,7 +343,7 @@ int MetUGridDataFile::data_plane_array(VarInfo &vinfo, int vlevel = extract_vlevels(req_name, nc_var_info->name.c_str()); if (vlevel >= lvl_lower && vlevel <= lvl_upper) { vinfo.set_req_name(nc_var_info->name.c_str()); - if (data_plane(vinfo, plane, nc_var_info)) { + if (data_plane(vinfo, plane, nc_var_info, do_winds)) { plane_array.add(plane, vlevel, vlevel); n_rec++; } @@ -375,13 +376,13 @@ int MetUGridDataFile::data_plane_array(VarInfo &vinfo, } for (int idx=tmp_lower; idx<=tmp_upper; idx++) { _cur_vert_index = idx; - if (data_plane(vinfo, plane, data_vinfo)) { + if (data_plane(vinfo, plane, data_vinfo, do_winds)) { plane_array.add(plane, lvl_lower, lvl_upper); n_rec++; } } } - else if (data_plane(vinfo, plane, do_derive)) { + else if (data_plane(vinfo, plane, do_winds)) { plane_array.add(plane, lvl_lower, lvl_upper); n_rec++; } @@ -747,7 +748,8 @@ int MetUGridDataFile::index(VarInfo &vinfo){ //////////////////////////////////////////////////////////////////////// bool MetUGridDataFile::read_data_plane(ConcatString var_name, VarInfo &vinfo, - DataPlane &plane, LongArray &dimension) { + DataPlane &plane, LongArray &dimension, + bool do_winds) { static const string method_name = "MetUGridDataFile::read_data_plane() -> "; // Read the data @@ -793,7 +795,7 @@ bool MetUGridDataFile::read_data_plane(ConcatString var_name, VarInfo &vinfo, status = false; } - if (status) status = process_data_plane(&vinfo, plane); + if (status) status = process_data_plane(&vinfo, plane, do_winds); else { mlog << Debug(2) << "\n" << method_name << "not processed data_plane\n"; } diff --git a/src/libcode/vx_data2d_ugrid/data2d_ugrid.h b/src/libcode/vx_data2d_ugrid/data2d_ugrid.h index 6e081a2902..7244e97788 100644 --- a/src/libcode/vx_data2d_ugrid/data2d_ugrid.h +++ b/src/libcode/vx_data2d_ugrid/data2d_ugrid.h @@ -86,12 +86,12 @@ class MetUGridDataFile : public Met2dDataFile { // retrieve the first matching data plane - bool data_plane(VarInfo &, DataPlane &, bool do_derive = true); - bool data_plane(VarInfo &, DataPlane &, const NcVarInfo *); + bool data_plane(VarInfo &, DataPlane &, bool do_winds = true); + bool data_plane(VarInfo &, DataPlane &, const NcVarInfo *, bool do_winds); // retrieve all matching data planes - int data_plane_array(VarInfo &, DataPlaneArray &, bool do_derive = true); + int data_plane_array(VarInfo &, DataPlaneArray &, bool do_winds = true); // retrieve the index of the first matching record @@ -100,7 +100,7 @@ class MetUGridDataFile : public Met2dDataFile { int index(VarInfo &); bool read_data_plane(ConcatString var_name, VarInfo &vinfo, - DataPlane &plane, LongArray &dimension); + DataPlane &plane, LongArray &dimension, bool do_winds); // // do stuff From 78c8808c59a9b0f863d546b430122bcda7e73e08 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Sat, 13 Jun 2026 05:35:58 +0000 Subject: [PATCH 10/63] Per #1518, add hooks to derive kinetic energy, vorticity, and divergence. Still need to add the vorticity and divergence derivations and add new unit tests. --- src/libcode/vx_data2d/data2d_utils.cc | 91 +++++++++++++++++++ src/libcode/vx_data2d/data2d_utils.h | 12 +++ src/libcode/vx_data2d/data_class.cc | 84 +++++++++++++---- src/libcode/vx_data2d/var_info.cc | 34 ++++++- src/libcode/vx_data2d/var_info.h | 4 + src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc | 15 +-- .../vx_data2d_nc_wrf/var_info_nc_wrf.h | 26 ------ 7 files changed, 215 insertions(+), 51 deletions(-) diff --git a/src/libcode/vx_data2d/data2d_utils.cc b/src/libcode/vx_data2d/data2d_utils.cc index bfeb9da72e..1181462235 100644 --- a/src/libcode/vx_data2d/data2d_utils.cc +++ b/src/libcode/vx_data2d/data2d_utils.cc @@ -178,6 +178,97 @@ static bool derive_wind_speed_and_direction( //////////////////////////////////////////////////////////////////////// +bool derive_kinetic_energy( + const DataPlane &uwnd, const DataPlane &vwnd, + DataPlane &keng) { + + mlog << Debug(3) + << "Deriving kinetic energy from U and V wind components.\n"; + + // + // Check that the dimensions match + // + if(uwnd.nx() != vwnd.nx() || uwnd.ny() != vwnd.ny()) { + mlog << Warning << "\nderive_kinetic_energy() -> " + << "the dimensions for U and V do not match: (" + << uwnd.nx() << ", " << uwnd.ny() << ") != (" + << vwnd.nx() << ", " << vwnd.ny() << ")\n\n"; + return false; + } + + // + // Initialize output + // + keng = uwnd; + keng.set_constant(bad_data_double); + + const int nx = uwnd.nx(); + const int ny = uwnd.ny(); + +#pragma omp parallel default(shared) \ + shared(uwnd, vwnd, keng) + { + +#pragma omp for schedule(static) \ + collapse(2) + for(int x=0; xis_wind_speed() || vinfo->is_wind_direction()) { +if(vinfo->need_uv_wind()) { DataPlane uwnd_dp; DataPlane vwnd_dp; ConcatString uwnd_units; @@ -385,26 +384,46 @@ if(vinfo->is_wind_speed() || vinfo->is_wind_direction()) { vwnd_dp, vwnd_units); if(status) { + + // Rotate U/V winds, if needed + if(vinfo->need_rotation()) { + DataPlane uwnd_dp_orig(uwnd_dp); + DataPlane vwnd_dp_orig(vwnd_dp); + rotate_uv_grid_to_earth(uwnd_dp_orig, vwnd_dp_orig, + *Raw_Grid, uwnd_dp, vwnd_dp); + vinfo->set_grid_relative_flag(false); + } + + // Derive wind speed if(vinfo->is_wind_speed()) { status = derive_wind_speed(uwnd_dp, vwnd_dp, dp); vinfo->set_long_name("Wind Speed"); vinfo->set_units(uwnd_units); } - else { - - // Rotate U/V winds, if needed - if(vinfo->need_rotation()) { - DataPlane uwnd_dp_orig(uwnd_dp); - DataPlane vwnd_dp_orig(vwnd_dp); - rotate_uv_grid_to_earth(uwnd_dp_orig, vwnd_dp_orig, - *Raw_Grid, uwnd_dp, vwnd_dp); - vinfo->set_grid_relative_flag(false); - } - + // Derive wind direction + else if(vinfo->is_wind_direction()) { status = derive_wind_direction(uwnd_dp, vwnd_dp, dp); vinfo->set_long_name("Wind Direction"); vinfo->set_units("deg"); } + // Derive kinetic energy + else if(vinfo->is_kinetic_energy()) { + status = derive_kinetic_energy(uwnd_dp, vwnd_dp, dp); + vinfo->set_long_name("Kinetic Energy"); + vinfo->set_units("J/kg"); + } + // Derive vorticity + else if(vinfo->is_vorticity()) { + status = derive_vorticity(uwnd_dp, vwnd_dp, dp); + vinfo->set_long_name("Absolute Vorticity"); + vinfo->set_units("1/s"); + } + // Derive divergence + else if(vinfo->is_divergence()) { + status = derive_divergence(uwnd_dp, vwnd_dp, dp); + vinfo->set_long_name("Absolute Divergence"); + vinfo->set_units("1/s"); + } } } @@ -463,10 +482,10 @@ if(!vinfo) return false; bool status = false; // - // Derive wind speed and direction from U and V + // Derive wind fields from U and V // -if(vinfo->is_wind_speed() || vinfo->is_wind_direction()) { +if(vinfo->need_uv_wind()) { DataPlaneArray uwnd_dpa; DataPlaneArray vwnd_dpa; ConcatString uwnd_units; @@ -475,6 +494,7 @@ if(vinfo->is_wind_speed() || vinfo->is_wind_direction()) { uwnd_dpa, uwnd_units) && read_wind_data(vinfo, vinfo->wind_info().v_wind, vwnd_dpa, vwnd_units); + if(!status) return status; // Rotate U/V winds, if needed @@ -494,11 +514,24 @@ if(vinfo->is_wind_speed() || vinfo->is_wind_direction()) { vinfo->set_long_name("Wind Speed"); vinfo->set_units(uwnd_units); } - else { + else if(vinfo->is_wind_direction()) { vinfo->set_long_name("Wind Direction"); vinfo->set_units("deg"); } + else if(vinfo->is_kinetic_energy()) { + vinfo->set_long_name("Kinetic Energy"); + vinfo->set_units("J/kg"); + } + else if(vinfo->is_vorticity()) { + vinfo->set_long_name("Absolute Vorticity"); + vinfo->set_units("1/s"); + } + else if(vinfo->is_divergence()) { + vinfo->set_long_name("Absolute Divergence"); + vinfo->set_units("1/s"); + } + // Check for matching dimensions if(uwnd_dpa.n_planes() != vwnd_dpa.n_planes()) { mlog << Warning << "\n" << method_name << "when deriving winds, the number of U-wind records (" @@ -529,12 +562,27 @@ if(vinfo->is_wind_speed() || vinfo->is_wind_direction()) { // Do the derivation DataPlane dp; + + // Derive wind speed if(vinfo->is_wind_speed()) { status = derive_wind_speed(uwnd_dpa[i], vwnd_dpa[i], dp); } - else { + // Derive wind direction + else if(vinfo->is_wind_direction()) { status = derive_wind_direction(uwnd_dpa[i], vwnd_dpa[i], dp); } + // Derive kinetic energy + else if(vinfo->is_kinetic_energy()) { + status = derive_kinetic_energy(uwnd_dpa[i], vwnd_dpa[i], dp); + } + // Derive vorticity + else if(vinfo->is_vorticity()) { + status = derive_vorticity(uwnd_dpa[i], vwnd_dpa[i], dp); + } + // Derive divergence + else if(vinfo->is_divergence()) { + status = derive_divergence(uwnd_dpa[i], vwnd_dpa[i], dp); + } // Store the result dpa.add(dp, uwnd_dpa.lower(i), uwnd_dpa.upper(i)); diff --git a/src/libcode/vx_data2d/var_info.cc b/src/libcode/vx_data2d/var_info.cc index 221f3cc438..6e2227655d 100644 --- a/src/libcode/vx_data2d/var_info.cc +++ b/src/libcode/vx_data2d/var_info.cc @@ -852,6 +852,24 @@ bool VarInfo::is_wind_direction() const { /////////////////////////////////////////////////////////////////////////////// +bool VarInfo::is_kinetic_energy() const { + return WindInfo.is_kinetic_energy(Name); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool VarInfo::is_vorticity() const { + return WindInfo.is_vorticity(Name); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool VarInfo::is_divergence() const { + return WindInfo.is_divergence(Name); +} + +/////////////////////////////////////////////////////////////////////////////// + bool VarInfo::is_grid_relative() const { return (!is_bad_data(SetAttrIsGridRelative) ? SetAttrIsGridRelative != 0 : @@ -860,8 +878,22 @@ bool VarInfo::is_grid_relative() const { /////////////////////////////////////////////////////////////////////////////// +bool VarInfo::need_uv_wind() const { + return(is_wind_speed() || + is_wind_direction() || + is_kinetic_energy() || + is_vorticity() || + is_divergence()); +} + +/////////////////////////////////////////////////////////////////////////////// + bool VarInfo::need_rotation() const { - return (is_u_wind() || is_v_wind() || is_wind_direction()) && + return (is_u_wind() || + is_v_wind() || + is_wind_direction() || + is_vorticity() || + is_divergence()) && is_grid_relative(); } diff --git a/src/libcode/vx_data2d/var_info.h b/src/libcode/vx_data2d/var_info.h index 0b4595ea8c..0e0ffa3737 100644 --- a/src/libcode/vx_data2d/var_info.h +++ b/src/libcode/vx_data2d/var_info.h @@ -221,7 +221,11 @@ class VarInfo virtual bool is_v_wind() const; virtual bool is_wind_speed() const; virtual bool is_wind_direction() const; + bool is_kinetic_energy() const; + bool is_vorticity() const; + bool is_divergence() const; bool is_grid_relative() const; + bool need_uv_wind() const; bool need_rotation() const; bool is_prob() const; }; diff --git a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc index be9bcb8186..25c8a2c839 100644 --- a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc +++ b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc @@ -23,7 +23,7 @@ using namespace std; //////////////////////////////////////////////////////////////////////// -static bool is_grid_relative(const char *); +static bool is_grid_relative(VarInfo *); //////////////////////////////////////////////////////////////////////// // @@ -155,7 +155,7 @@ bool MetNcWrfDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, dimension, plane, pressure, info); // Store whether winds are grid relative - vinfo_nc->set_grid_relative_flag(is_grid_relative(vinfo_nc->req_name().c_str())); + vinfo_nc->set_grid_relative_flag(is_grid_relative(vinfo_nc)); // Attempt to derive the data if(!status && do_winds) { @@ -260,7 +260,7 @@ int MetNcWrfDataFile::data_plane_array(VarInfo &vinfo, cur_dim, cur_plane, pressure, info); // Store whether winds are grid relative - vinfo_nc->set_grid_relative_flag(is_grid_relative(vinfo_nc->req_name().c_str())); + vinfo_nc->set_grid_relative_flag(is_grid_relative(vinfo_nc)); // Attempt to derive the data if(!status && do_winds) { @@ -337,9 +337,12 @@ int MetNcWrfDataFile::index(VarInfo &vinfo){ //////////////////////////////////////////////////////////////////////// -static bool is_grid_relative(const char *name) { - return has_prefix(pinterp_grid_relative_names, - n_pinterp_grid_relative_names, name); +static bool is_grid_relative(VarInfo *vinfo) { + + // All WRF winds are grid relative + return vinfo->is_u_wind() || + vinfo->is_v_wind() || + vinfo->is_wind_direction(); } //////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.h b/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.h index 314009600b..e46be4d0dc 100644 --- a/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.h +++ b/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.h @@ -138,32 +138,6 @@ static const int n_pinterp_v_wind_names = /////////////////////////////////////////////////////////////////////////////// -// -// List of wind variable names that should be rotated from grid-relative -// to earth-relative. MET is not able to read winds from Pinterp files since -// they are defined on a staggered grid. If the code is enhanced to do so, -// the data in these variables should be rotated from grid-relative to -// earth-relative prior to verifying. -// Taken from the WRF version 3.2 Registry.EM file -// - -static const char *pinterp_grid_relative_names[] = { - "UU", // x-wind component, m s-1 - "UZ0", // U WIND COMPONENT AT ZNT, m s-1 - "VV", // y-wind component, m s-1 - "VZ0" // V WIND COMPONENT AT ZNT, m s-1 -}; - -// -// Number of Pinterp grid relative variable names -// - -static const int n_pinterp_grid_relative_names = - sizeof(pinterp_grid_relative_names)/ - sizeof(*pinterp_grid_relative_names); - -/////////////////////////////////////////////////////////////////////////////// - // // List of wind speed variable names // Taken from the WRF version 3.2 Registry.EM file From f6e22bc8a59e27bd2d7bb758e3c2e0bcbb910395 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Mon, 15 Jun 2026 16:56:19 +0000 Subject: [PATCH 11/63] Per #1518, back out hooks for deriving divergence and vorticity since they're non-trivial. --- src/basic/vx_config/config_constants.h | 2 -- src/libcode/vx_data2d/data2d_utils.cc | 30 -------------------------- src/libcode/vx_data2d/data2d_utils.h | 8 ------- src/libcode/vx_data2d/data_class.cc | 28 ------------------------ src/libcode/vx_data2d/var_info.cc | 24 ++++----------------- src/libcode/vx_data2d/var_info.h | 2 -- 6 files changed, 4 insertions(+), 90 deletions(-) diff --git a/src/basic/vx_config/config_constants.h b/src/basic/vx_config/config_constants.h index 1dba37e8e8..ca67556191 100644 --- a/src/basic/vx_config/config_constants.h +++ b/src/basic/vx_config/config_constants.h @@ -480,8 +480,6 @@ struct WindMetadata { // Supported derivations bool is_kinetic_energy(const std::string &s) const { return s == "KENG"; } - bool is_vorticity(const std::string &s) const { return s == "ABSV"; } - bool is_divergence(const std::string &s) const { return s == "ABSD"; } }; //////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_data2d/data2d_utils.cc b/src/libcode/vx_data2d/data2d_utils.cc index 1181462235..8dc3dfff30 100644 --- a/src/libcode/vx_data2d/data2d_utils.cc +++ b/src/libcode/vx_data2d/data2d_utils.cc @@ -239,36 +239,6 @@ bool derive_kinetic_energy( //////////////////////////////////////////////////////////////////////// -bool derive_vorticity( - const DataPlane &uwnd, const DataPlane &vwnd, - DataPlane &absv) { - - mlog << Debug(3) - << "Deriving absolute vorticity from U and V wind components.\n"; - - // JHG work here - absv = uwnd; - - return true; -} - -//////////////////////////////////////////////////////////////////////// - -bool derive_divergence( - const DataPlane &uwnd, const DataPlane &vwnd, - DataPlane &absd) { - - mlog << Debug(3) - << "Deriving absolute divergence from U and V wind components.\n"; - - // JHG work here - absd = uwnd; - - return true; -} - -//////////////////////////////////////////////////////////////////////// - bool derive_u_wind( const DataPlane &wspd, const DataPlane &wdir, DataPlane &uwnd) { diff --git a/src/libcode/vx_data2d/data2d_utils.h b/src/libcode/vx_data2d/data2d_utils.h index 6067a054af..ecab2c7396 100644 --- a/src/libcode/vx_data2d/data2d_utils.h +++ b/src/libcode/vx_data2d/data2d_utils.h @@ -42,14 +42,6 @@ extern bool derive_kinetic_energy( const DataPlane &uwnd, const DataPlane &vwnd, DataPlane &keng); -extern bool derive_vorticity( - const DataPlane &uwnd, const DataPlane &vwnd, - DataPlane &absv); - -extern bool derive_divergence( - const DataPlane &uwnd, const DataPlane &vwnd, - DataPlane &absd); - extern bool derive_u_wind( const DataPlane &wspd, const DataPlane &wdir, DataPlane &uwnd); diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index 5351752b78..ec946adf6e 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -412,18 +412,6 @@ if(vinfo->need_uv_wind()) { vinfo->set_long_name("Kinetic Energy"); vinfo->set_units("J/kg"); } - // Derive vorticity - else if(vinfo->is_vorticity()) { - status = derive_vorticity(uwnd_dp, vwnd_dp, dp); - vinfo->set_long_name("Absolute Vorticity"); - vinfo->set_units("1/s"); - } - // Derive divergence - else if(vinfo->is_divergence()) { - status = derive_divergence(uwnd_dp, vwnd_dp, dp); - vinfo->set_long_name("Absolute Divergence"); - vinfo->set_units("1/s"); - } } } @@ -522,14 +510,6 @@ if(vinfo->need_uv_wind()) { vinfo->set_long_name("Kinetic Energy"); vinfo->set_units("J/kg"); } - else if(vinfo->is_vorticity()) { - vinfo->set_long_name("Absolute Vorticity"); - vinfo->set_units("1/s"); - } - else if(vinfo->is_divergence()) { - vinfo->set_long_name("Absolute Divergence"); - vinfo->set_units("1/s"); - } // Check for matching dimensions if(uwnd_dpa.n_planes() != vwnd_dpa.n_planes()) { @@ -575,14 +555,6 @@ if(vinfo->need_uv_wind()) { else if(vinfo->is_kinetic_energy()) { status = derive_kinetic_energy(uwnd_dpa[i], vwnd_dpa[i], dp); } - // Derive vorticity - else if(vinfo->is_vorticity()) { - status = derive_vorticity(uwnd_dpa[i], vwnd_dpa[i], dp); - } - // Derive divergence - else if(vinfo->is_divergence()) { - status = derive_divergence(uwnd_dpa[i], vwnd_dpa[i], dp); - } // Store the result dpa.add(dp, uwnd_dpa.lower(i), uwnd_dpa.upper(i)); diff --git a/src/libcode/vx_data2d/var_info.cc b/src/libcode/vx_data2d/var_info.cc index 6e2227655d..d2a3e76347 100644 --- a/src/libcode/vx_data2d/var_info.cc +++ b/src/libcode/vx_data2d/var_info.cc @@ -858,18 +858,6 @@ bool VarInfo::is_kinetic_energy() const { /////////////////////////////////////////////////////////////////////////////// -bool VarInfo::is_vorticity() const { - return WindInfo.is_vorticity(Name); -} - -/////////////////////////////////////////////////////////////////////////////// - -bool VarInfo::is_divergence() const { - return WindInfo.is_divergence(Name); -} - -/////////////////////////////////////////////////////////////////////////////// - bool VarInfo::is_grid_relative() const { return (!is_bad_data(SetAttrIsGridRelative) ? SetAttrIsGridRelative != 0 : @@ -881,19 +869,15 @@ bool VarInfo::is_grid_relative() const { bool VarInfo::need_uv_wind() const { return(is_wind_speed() || is_wind_direction() || - is_kinetic_energy() || - is_vorticity() || - is_divergence()); + is_kinetic_energy()); } /////////////////////////////////////////////////////////////////////////////// bool VarInfo::need_rotation() const { - return (is_u_wind() || - is_v_wind() || - is_wind_direction() || - is_vorticity() || - is_divergence()) && + return (is_u_wind() || + is_v_wind() || + is_wind_direction()) && is_grid_relative(); } diff --git a/src/libcode/vx_data2d/var_info.h b/src/libcode/vx_data2d/var_info.h index 0e0ffa3737..c2c8779945 100644 --- a/src/libcode/vx_data2d/var_info.h +++ b/src/libcode/vx_data2d/var_info.h @@ -222,8 +222,6 @@ class VarInfo virtual bool is_wind_speed() const; virtual bool is_wind_direction() const; bool is_kinetic_energy() const; - bool is_vorticity() const; - bool is_divergence() const; bool is_grid_relative() const; bool need_uv_wind() const; bool need_rotation() const; From 662ee419f9e97ee2c8afe5d099ff83ef820f628e Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Mon, 15 Jun 2026 20:09:57 +0000 Subject: [PATCH 12/63] Per #1518, refine logic slightly. --- src/libcode/vx_data2d/data_class.cc | 25 ++++++++++++++------- src/libcode/vx_data2d/var_info.cc | 20 ++++++++++++++--- src/libcode/vx_data2d/var_info.h | 2 ++ src/libcode/vx_data2d_grib2/data2d_grib2.cc | 12 +++++----- 4 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index ec946adf6e..a3f04b3bdc 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -391,7 +391,7 @@ if(vinfo->need_uv_wind()) { DataPlane vwnd_dp_orig(vwnd_dp); rotate_uv_grid_to_earth(uwnd_dp_orig, vwnd_dp_orig, *Raw_Grid, uwnd_dp, vwnd_dp); - vinfo->set_grid_relative_flag(false); + vinfo->set_earth_relative(); } // Derive wind speed @@ -434,7 +434,7 @@ else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { DataPlane wdir_dp_orig(wdir_dp); rotate_wind_direction_grid_to_earth(wdir_dp_orig, *Raw_Grid, wdir_dp); - vinfo->set_grid_relative_flag(false); + vinfo->set_earth_relative(); } if(status) { @@ -494,7 +494,7 @@ if(vinfo->need_uv_wind()) { *Raw_Grid, uwnd_dpa.at(i), vwnd_dpa.at(i)); } - vinfo->set_grid_relative_flag(false); + vinfo->set_earth_relative(); } // Store the long name and units @@ -583,7 +583,7 @@ else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { DataPlane wdir_dp_orig(wdir_dpa[i]); rotate_wind_direction_grid_to_earth(wdir_dp_orig, *Raw_Grid, wdir_dpa.at(i)); - vinfo->set_grid_relative_flag(false); + vinfo->set_earth_relative(); } } @@ -683,8 +683,8 @@ else if(vinfo->is_v_wind()) { // Rotate Wind Direction else if(vinfo->is_wind_direction()) { tmp_dp = dp; - if(status) rotate_wind_direction_grid_to_earth( - tmp_dp, *Raw_Grid, dp); + rotate_wind_direction_grid_to_earth(tmp_dp, *Raw_Grid, dp); + status = true; } if(!status) { @@ -694,7 +694,7 @@ if(!status) { } // Update flag for a successful rotation else { - vinfo->set_grid_relative_flag(false); + vinfo->set_earth_relative(); } return status; @@ -816,7 +816,16 @@ if ( ! vinfo ) return false; // Rotate winds, if requested and needed // -if(do_winds && vinfo->need_rotation()) rotate_winds(vinfo, dp); +if(do_winds && vinfo->is_wind_rotation()) { + + if(vinfo->need_rotation()) { + rotate_winds(vinfo, dp); + } + else { + mlog << Debug(3) << "Wind field \"" << vinfo->magic_str() + << "\" is defined as earth-relative.\n"; + } +} // // Apply conversion logic diff --git a/src/libcode/vx_data2d/var_info.cc b/src/libcode/vx_data2d/var_info.cc index d2a3e76347..feff0f9fe7 100644 --- a/src/libcode/vx_data2d/var_info.cc +++ b/src/libcode/vx_data2d/var_info.cc @@ -477,6 +477,14 @@ void VarInfo::set_grid_relative_flag(bool f) { /////////////////////////////////////////////////////////////////////////////// +void VarInfo::set_earth_relative() { + GridRelativeFlag = false; + SetAttrIsGridRelative = 0; + return; +} + +/////////////////////////////////////////////////////////////////////////////// + void VarInfo::set_magic(const ConcatString &nstr, const ConcatString &lstr) { // Check for embedded whitespace @@ -858,6 +866,14 @@ bool VarInfo::is_kinetic_energy() const { /////////////////////////////////////////////////////////////////////////////// +bool VarInfo::is_wind_rotation() const { + return (is_u_wind() || + is_v_wind() || + is_wind_direction()); +} + +/////////////////////////////////////////////////////////////////////////////// + bool VarInfo::is_grid_relative() const { return (!is_bad_data(SetAttrIsGridRelative) ? SetAttrIsGridRelative != 0 : @@ -875,9 +891,7 @@ bool VarInfo::need_uv_wind() const { /////////////////////////////////////////////////////////////////////////////// bool VarInfo::need_rotation() const { - return (is_u_wind() || - is_v_wind() || - is_wind_direction()) && + return is_wind_rotation() && is_grid_relative(); } diff --git a/src/libcode/vx_data2d/var_info.h b/src/libcode/vx_data2d/var_info.h index c2c8779945..c5716bac2f 100644 --- a/src/libcode/vx_data2d/var_info.h +++ b/src/libcode/vx_data2d/var_info.h @@ -206,6 +206,7 @@ class VarInfo void set_regrid(const RegridInfo &); void set_grid_relative_flag(bool); + void set_earth_relative(); void set_level_info_grib(Dictionary & dict); void set_prob_info_grib(ConcatString prob_name, @@ -222,6 +223,7 @@ class VarInfo virtual bool is_wind_speed() const; virtual bool is_wind_direction() const; bool is_kinetic_energy() const; + bool is_wind_rotation() const; bool is_grid_relative() const; bool need_uv_wind() const; bool need_rotation() const; diff --git a/src/libcode/vx_data2d_grib2/data2d_grib2.cc b/src/libcode/vx_data2d_grib2/data2d_grib2.cc index 36b5d8bd50..2c66680952 100644 --- a/src/libcode/vx_data2d_grib2/data2d_grib2.cc +++ b/src/libcode/vx_data2d_grib2/data2d_grib2.cc @@ -477,12 +477,12 @@ void MetGrib2DataFile::find_record_matches(const VarInfoGrib2* vinfo, } // test for an index or field name match - else if( - ( vinfo->discipline() == (*it)->Discipline && - vinfo->parm_cat() == (*it)->ParmCat && - vinfo->parm() == (*it)->Parm ) || - vinfo->name().text() == (*it)->ParmName - ){ + else if( ( vinfo->name().empty() && + vinfo->discipline() == (*it)->Discipline && + vinfo->parm_cat() == (*it)->ParmCat && + vinfo->parm() == (*it)->Parm ) || + ( vinfo->name().nonempty() && + vinfo->name().text() == (*it)->ParmName ) ){ // test the level type number, if specified if ( !is_bad_data(vinfo->level().type_num()) && From 6affc2c15bb2f97b9814ac62d44873d7c7d0c4c4 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Mon, 15 Jun 2026 20:43:54 +0000 Subject: [PATCH 13/63] Per #1518, update library code to assume NetCDF files (MET, WRF, and CF) contain earth-relative winds. --- src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc | 6 +++++ src/libcode/vx_data2d_nc_met/data2d_nc_met.cc | 3 +++ src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc | 22 ++++--------------- src/libcode/vx_data2d_ugrid/data2d_ugrid.cc | 4 ++++ 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc b/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc index 30f81acde4..c6a093105b 100644 --- a/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc +++ b/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc @@ -306,6 +306,9 @@ bool MetNcCFDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, // Read the data bool status = data_plane(vinfo, plane, dimension); + // Assume that CF-compliant NetCDF winds are earth-relative + vinfo_nc->set_grid_relative_flag(false); + // Attempt to derive the data if(!status && do_winds) { status = derive_winds(vinfo_nc, plane); @@ -433,6 +436,9 @@ int MetNcCFDataFile::data_plane_array(VarInfo &vinfo, n_rec++; } + // Assume that CF-compliant NetCDF winds are earth-relative + vinfo_nc->set_grid_relative_flag(true); + // Attempt to derive the data if(n_rec == 0 && do_winds) { status = derive_winds(vinfo_nc, plane_array); diff --git a/src/libcode/vx_data2d_nc_met/data2d_nc_met.cc b/src/libcode/vx_data2d_nc_met/data2d_nc_met.cc index 540bdc83bd..aaa25eb35a 100644 --- a/src/libcode/vx_data2d_nc_met/data2d_nc_met.cc +++ b/src/libcode/vx_data2d_nc_met/data2d_nc_met.cc @@ -238,6 +238,9 @@ bool MetNcMetDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, vinfo_nc->dimension(), plane, info); + // Assume that winds in MET output files are earth-relative + vinfo_nc->set_grid_relative_flag(false); + // Attempt to derive the data if(!status && do_winds) { status = derive_winds(vinfo_nc, plane); diff --git a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc index 25c8a2c839..be4b05c792 100644 --- a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc +++ b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc @@ -21,10 +21,6 @@ using namespace std; -//////////////////////////////////////////////////////////////////////// - -static bool is_grid_relative(VarInfo *); - //////////////////////////////////////////////////////////////////////// // // Code for class MetNcWrfDataFile @@ -154,8 +150,8 @@ bool MetNcWrfDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, status = WrfNc->data(vinfo_nc->req_name().c_str(), dimension, plane, pressure, info); - // Store whether winds are grid relative - vinfo_nc->set_grid_relative_flag(is_grid_relative(vinfo_nc)); + // Assume that WRF winds are grid-relative + vinfo_nc->set_grid_relative_flag(true); // Attempt to derive the data if(!status && do_winds) { @@ -259,8 +255,8 @@ int MetNcWrfDataFile::data_plane_array(VarInfo &vinfo, status = WrfNc->data(vinfo_nc->req_name().c_str(), cur_dim, cur_plane, pressure, info); - // Store whether winds are grid relative - vinfo_nc->set_grid_relative_flag(is_grid_relative(vinfo_nc)); + // Assume that WRF winds are grid-relative + vinfo_nc->set_grid_relative_flag(true); // Attempt to derive the data if(!status && do_winds) { @@ -336,13 +332,3 @@ int MetNcWrfDataFile::index(VarInfo &vinfo){ } //////////////////////////////////////////////////////////////////////// - -static bool is_grid_relative(VarInfo *vinfo) { - - // All WRF winds are grid relative - return vinfo->is_u_wind() || - vinfo->is_v_wind() || - vinfo->is_wind_direction(); -} - -//////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc b/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc index 7babaa60bb..236bf8a73c 100644 --- a/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc +++ b/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc @@ -177,9 +177,13 @@ bool MetUGridDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, ConcatString req_name = vinfo.req_name(); data_var = _file->find_by_name(req_name.c_str()); if (nullptr != data_var) { + // Read the data status = data_plane(vinfo, plane, data_var, do_winds); + // Assume that UGRID winds are earth-relative + vinfo.set_grid_relative_flag(false); + // Attempt to derive the data if(!status && do_winds) { status = derive_winds(&vinfo, plane); From f365616c0b74dae847657a72dfc65f0911dce739 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Mon, 15 Jun 2026 21:18:45 +0000 Subject: [PATCH 14/63] Per #1518, patch logic in GRIB2 find_record_matches() to enable the pcp_combine -sum command to work again on precip data where name = APCP_03 while req_name = APCP. --- src/libcode/vx_data2d/data_class.cc | 2 ++ src/libcode/vx_data2d/var_info.cc | 7 +++++++ src/libcode/vx_data2d/var_info.h | 1 + src/libcode/vx_data2d_grib2/data2d_grib2.cc | 12 ++++++------ 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index a3f04b3bdc..edb7785679 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -723,6 +723,7 @@ VarInfo * vinfo_cur = vinfo->clone(); // Try each of the possible names for(int i=0; iset_req_name(names[i]); vinfo_cur->set_name(names[i]); // Wrap level in parenthesis, if needed @@ -773,6 +774,7 @@ VarInfo * vinfo_cur = vinfo->clone(); // Try each of the possible names for(int i=0; iset_req_name(names[i]); vinfo_cur->set_name(names[i]); // Wrap level in parenthesis, if needed diff --git a/src/libcode/vx_data2d/var_info.cc b/src/libcode/vx_data2d/var_info.cc index feff0f9fe7..7cb73051eb 100644 --- a/src/libcode/vx_data2d/var_info.cc +++ b/src/libcode/vx_data2d/var_info.cc @@ -295,6 +295,13 @@ void VarInfo::set_req_name(const char *str) { /////////////////////////////////////////////////////////////////////////////// +void VarInfo::set_req_name(const string &str) { + ReqName = str; + return; +} + +/////////////////////////////////////////////////////////////////////////////// + void VarInfo::set_name(const char *str) { Name = str; return; diff --git a/src/libcode/vx_data2d/var_info.h b/src/libcode/vx_data2d/var_info.h index c5716bac2f..38b457c457 100644 --- a/src/libcode/vx_data2d/var_info.h +++ b/src/libcode/vx_data2d/var_info.h @@ -173,6 +173,7 @@ class VarInfo virtual void add_grib_code(Dictionary &); void set_req_name(const char *); + void set_req_name(const std::string &); void set_name(const char *); void set_name(const std::string &); void set_units(const char *); diff --git a/src/libcode/vx_data2d_grib2/data2d_grib2.cc b/src/libcode/vx_data2d_grib2/data2d_grib2.cc index 2c66680952..afc60b9596 100644 --- a/src/libcode/vx_data2d_grib2/data2d_grib2.cc +++ b/src/libcode/vx_data2d_grib2/data2d_grib2.cc @@ -477,12 +477,12 @@ void MetGrib2DataFile::find_record_matches(const VarInfoGrib2* vinfo, } // test for an index or field name match - else if( ( vinfo->name().empty() && - vinfo->discipline() == (*it)->Discipline && - vinfo->parm_cat() == (*it)->ParmCat && - vinfo->parm() == (*it)->Parm ) || - ( vinfo->name().nonempty() && - vinfo->name().text() == (*it)->ParmName ) ){ + else if( ( vinfo->req_name().empty() && + vinfo->discipline() == (*it)->Discipline && + vinfo->parm_cat() == (*it)->ParmCat && + vinfo->parm() == (*it)->Parm ) || + ( vinfo->req_name().nonempty() && + vinfo->req_name().text() == (*it)->ParmName ) ){ // test the level type number, if specified if ( !is_bad_data(vinfo->level().type_num()) && From 2fc474cf6588344f51c7431e884a8678fa57832c Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Mon, 15 Jun 2026 22:14:45 +0000 Subject: [PATCH 15/63] Per #1518, update call to read_data_plane() ci-run-unit --- src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc b/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc index c6a093105b..79ebcc6e0c 100644 --- a/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc +++ b/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc @@ -304,7 +304,7 @@ bool MetNcCFDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, } // Read the data - bool status = data_plane(vinfo, plane, dimension); + bool status = read_data_plane(vinfo, plane, dimension, do_winds); // Assume that CF-compliant NetCDF winds are earth-relative vinfo_nc->set_grid_relative_flag(false); From a16afd2f9fa86f2afdc4240b2547de3723ea7a9a Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 16 Jun 2026 17:33:16 +0000 Subject: [PATCH 16/63] Per #1518, siwitchtch from index_a/index_b/index_c to the more descriptive disc/pcat/pnum. --- src/libcode/vx_data2d/table_lookup.cc | 97 ++++++++++++++------------- src/libcode/vx_data2d/table_lookup.h | 8 +-- 2 files changed, 53 insertions(+), 52 deletions(-) diff --git a/src/libcode/vx_data2d/table_lookup.cc b/src/libcode/vx_data2d/table_lookup.cc index b51bb40610..fc59898e8f 100644 --- a/src/libcode/vx_data2d/table_lookup.cc +++ b/src/libcode/vx_data2d/table_lookup.cc @@ -333,7 +333,7 @@ void Grib2TableEntry::clear() { -index_a = index_b = index_c = mtab_set = mtab_low = mtab_high = cntr = ltab = -1; +disc = pcat = pnum = mtab_set = mtab_low = mtab_high = cntr = ltab = -1; parm_name.clear(); @@ -355,9 +355,9 @@ void Grib2TableEntry::assign(const Grib2TableEntry & e) clear(); -index_a = e.index_a; -index_b = e.index_b; -index_c = e.index_c; +disc = e.disc; +pcat = e.pcat; +pnum = e.pnum; mtab_high = e.mtab_high; mtab_low = e.mtab_low; mtab_set = e.mtab_set; @@ -385,14 +385,14 @@ void Grib2TableEntry::dump(ostream & out, int depth) const Indent prefix(depth); out << prefix << "Index values = (" - << index_a << ", " + << disc << ", " << mtab_set << ", " << mtab_low << ", " << mtab_high << ", " << cntr << ", " << ltab << ", " - << index_b << ", " - << index_c << ")\n"; + << pcat << ", " + << pnum << ")\n"; out << prefix << "parm_name = " << parm_name.contents() << "\n"; @@ -410,9 +410,9 @@ return; bool Grib2TableEntry::is_eq(const Grib2TableEntry &e) const { - return (index_a == e.index_a) && - (index_b == e.index_b) && - (index_c == e.index_c) && + return (disc == e.disc) && + (pcat == e.pcat) && + (pnum == e.pnum) && (parm_name == e.parm_name) && (mtab_set == e.mtab_set) && (mtab_low == e.mtab_low) && @@ -468,14 +468,14 @@ for (int j=0; j<8; ++j) { if(!is_number(tok[j].c_str())) return false; } -index_a = atoi(tok[0].c_str()); +disc = atoi(tok[0].c_str()); mtab_set = atoi(tok[1].c_str()); mtab_low = atoi(tok[2].c_str()); mtab_high = atoi(tok[3].c_str()); cntr = atoi(tok[4].c_str()); ltab = atoi(tok[5].c_str()); -index_b = atoi(tok[6].c_str()); -index_c = atoi(tok[7].c_str()); +pcat = atoi(tok[6].c_str()); +pnum = atoi(tok[7].c_str()); // // grab the 3 strings separated by double quotes @@ -807,19 +807,20 @@ return status; //////////////////////////////////////////////////////////////////////// + ConcatString TableFlatFile::log_arguments(const char * parm_name, - int a, int b, int c, + int disc, int pcat, int pnum, int mtab, int cntr, int ltab) const { ConcatString msg; msg << "parm_name = " << parm_name; -if( bad_data_int != a ) msg << ", index_a = " << a; +if( bad_data_int != disc ) msg << ", disc = " << disc; if( bad_data_int != mtab ) msg << ", grib2_mtab = " << mtab; if( bad_data_int != cntr ) msg << ", grib2_cntr = " << cntr; if( bad_data_int != ltab ) msg << ", grib2_ltab = " << ltab; -if( bad_data_int != b ) msg << ", index_b = " << b; -if( bad_data_int != c ) msg << ", index_c = " << c; +if( bad_data_int != pcat ) msg << ", pcat = " << pcat; +if( bad_data_int != pnum ) msg << ", pnum = " << pnum; return msg; @@ -1251,7 +1252,7 @@ bool TableFlatFile::lookup_grib1(const char * parm_name, Grib1TableEntry & e) //////////////////////////////////////////////////////////////////////// -bool TableFlatFile::lookup_grib2(int a, int b, int c, Grib2TableEntry & e) +bool TableFlatFile::lookup_grib2(int disc, int pcat, int pnum, Grib2TableEntry & e) { @@ -1259,7 +1260,7 @@ e.clear(); for (int j=0; jparm_name - << ", index_a = " << it->index_a - << ", index_b = " << it->index_b - << ", index_c = " << it->index_c << "\n"; + << ", disc = " << it->disc + << ", pcat = " << it->pcat + << ", pnum = " << it->pnum << "\n"; mlog << Debug(3) << "Using the first match found: " << " parm_name: " << e.parm_name - << ", index_a = " << e.index_a - << ", index_b = " << e.index_b - << ", index_c = " << e.index_c << "\n\n"; + << ", disc = " << e.disc + << ", pcat = " << e.pcat + << ", pnum = " << e.pnum << "\n\n"; } @@ -1384,7 +1385,7 @@ bool TableFlatFile::lookup_grib2(const char * parm_name, int a, int b, int c, bool TableFlatFile::lookup_grib2(const char * parm_name, - int a, int b, int c, + int disc, int pcat, int pnum, int mtab, int cntr, int ltab, Grib2TableEntry & e, int & n_matches) @@ -1399,9 +1400,9 @@ bool TableFlatFile::lookup_grib2(const char * parm_name, for(int j=0; jparm_name - << ", index_a = " << it->index_a + << ", disc = " << it->disc << ", grib2_mtab = " << it->mtab_set << ", grib2_cntr = " << it->cntr << ", grib2_ltab = " << it->ltab - << ", index_b = " << it->index_b - << ", index_c = " << it->index_c + << ", pcat = " << it->pcat + << ", pnum = " << it->pnum << "\n"; mlog << Debug(3) << "Using the first match found: " << " parm_name: " << e.parm_name - << ", index_a = " << e.index_a + << ", disc = " << e.disc << ", grib2_mtab = " << e.mtab_set << ", grib2_cntr = " << e.cntr << ", grib2_ltab = " << e.ltab - << ", index_b = " << e.index_b - << ", index_c = " << e.index_c + << ", pcat = " << e.pcat + << ", pnum = " << e.pnum << "\n\n"; } else if( 0 == n_matches ){ mlog << Debug(3) << "No match, lookup criteria (" - << log_arguments(parm_name, a, b, c, mtab, cntr, ltab) + << log_arguments(parm_name, disc, pcat, pnum, mtab, cntr, ltab) << ")\n"; } diff --git a/src/libcode/vx_data2d/table_lookup.h b/src/libcode/vx_data2d/table_lookup.h index ae330ee1eb..2e55bc78db 100644 --- a/src/libcode/vx_data2d/table_lookup.h +++ b/src/libcode/vx_data2d/table_lookup.h @@ -109,14 +109,14 @@ class Grib2TableEntry { bool is_eq(const Grib2TableEntry &) const; GribEntryMatch match(const int &mtab, const int &_cntr, const int &_ltab) const; - int index_a; // Section 0 Discipline + int disc; // Section 0 Discipline int mtab_set; // Section 1 Master Tables Version Number used by set_var int mtab_low; // Section 1 Master Tables Version Number low range of tables int mtab_high; // Section 1 Master Tables Version Number high range of tables - int cntr; // Section 1 originating centre, used for local tables + int cntr; // Section 1 originating center, used for local tables int ltab; // Section 1 Local Tables Version Number - int index_b; // Section 4 Template 4.0 Parameter category - int index_c; // Section 4 Template 4.0 Parameter number + int pcat; // Section 4 Template 4.0 Parameter category + int pnum; // Section 4 Template 4.0 Parameter number ConcatString parm_name; From b883eea154ecc625309e1816171c27dca1482c28 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 16 Jun 2026 20:01:22 +0000 Subject: [PATCH 17/63] Per #1518, update the grib table lookup to return a vector of matches. --- src/libcode/vx_data2d/table_lookup.cc | 472 +++++------------- src/libcode/vx_data2d/table_lookup.h | 42 +- .../vx_data2d_grib/data2d_grib_utils.cc | 35 +- src/libcode/vx_data2d_grib/grib_strings.cc | 22 +- src/libcode/vx_data2d_grib/var_info_grib.cc | 77 +-- src/libcode/vx_data2d_grib/var_info_grib.h | 5 +- src/libcode/vx_data2d_grib2/data2d_grib2.cc | 9 +- src/libcode/vx_data2d_grib2/var_info_grib2.cc | 38 +- 8 files changed, 241 insertions(+), 459 deletions(-) diff --git a/src/libcode/vx_data2d/table_lookup.cc b/src/libcode/vx_data2d/table_lookup.cc index fc59898e8f..3d62fb8f80 100644 --- a/src/libcode/vx_data2d/table_lookup.cc +++ b/src/libcode/vx_data2d/table_lookup.cc @@ -1044,435 +1044,211 @@ return true; } - //////////////////////////////////////////////////////////////////////// +int TableFlatFile::lookup_grib1(int code, int table_number, + vector &matches) { + matches.clear(); -bool TableFlatFile::lookup_grib1(int code, int table_number, Grib1TableEntry & e) - -{ - -e.clear(); - -for (int j=0; j &matches) { + matches.clear(); + + for(const auto &e : g1e) { + if((e.code == code ) && + (e.table_number == table_number) && + (e.center == center ) && + (e.subcenter == -1 || + e.subcenter == subcenter)) { + matches.emplace_back(e); } } - return false; -} + return (int) matches.size(); +} //////////////////////////////////////////////////////////////////////// +int TableFlatFile::lookup_grib1(int code, + vector &matches) { -bool TableFlatFile::lookup_grib1(int code, Grib1TableEntry & e) // assumes table_number = 2; - -{ - -const int table_number = 2; -bool status = false; - -status = lookup_grib1(code, table_number, e); - -return status; + // Assume default table_number = 2 + return lookup_grib1(code, 2, matches); } - //////////////////////////////////////////////////////////////////////// +int TableFlatFile::lookup_grib1(const char * parm_name, int table_number, int code, + vector &matches) { + matches.clear(); -bool TableFlatFile::lookup_grib1(const char * parm_name, int table_number, int code, - Grib1TableEntry & e, int & n_matches) - -{ - - // clear the by-reference arguments - e.clear(); - n_matches = 0; - - // build a list of matches - vector matches; - for(int j=0; j < N_grib1_elements; j++){ - - if( g1e[j].parm_name != parm_name || - (bad_data_int != table_number && g1e[j].table_number != table_number) || - (bad_data_int != code && g1e[j].code != code) ) - continue; - - if( n_matches++ == 0 ) e = g1e[j]; - matches.emplace_back( g1e[j] ); - - } - - // if there are multiple matches, print a descriptive message - if( 1 < n_matches ){ - - ConcatString msg; - msg << "Multiple GRIB1 table entries match lookup criteria (" - << "parm_name = " << parm_name; - if( bad_data_int != table_number ) msg << ", table_number = " << table_number; - if( bad_data_int != code ) msg << ", code = " << code; - msg << "):\n"; - mlog << Debug(3) << "\n" << msg; - - for(auto it = matches.begin(); it < matches.end(); it++) - mlog << Debug(3) << " parm_name: " << it->parm_name - << ", table_number = " << it->table_number - << ", code = " << it->code << "\n"; - - mlog << Debug(3) << "Using the first match found: " - << " parm_name: " << e.parm_name - << ", table_number = " << e.table_number - << ", code = " << e.code << "\n\n"; - + for(const auto &e : g1e) { + if((e.parm_name == parm_name ) && + (is_bad_data(table_number) || e.table_number == table_number) && + (is_bad_data(code) || e.code == code )) { + matches.emplace_back(e); + } } - return (n_matches > 0); - + return (int) matches.size(); } - //////////////////////////////////////////////////////////////////////// - -bool TableFlatFile::lookup_grib1(const char * parm_name, int table_number, int code,int center, int subcenter, - Grib1TableEntry & e, int & n_matches) - -{ - - // clear the by-reference arguments - e.clear(); - n_matches = 0; - - // build a list of matches - vector matches; - int matching_subsenter; - for(int j=0; j < N_grib1_elements; j++){ - matching_subsenter = subcenter; - if( g1e[j].subcenter == -1){ - matching_subsenter = -1; +int TableFlatFile::lookup_grib1(const char *parm_name, int table_number, + int code,int center, int subcenter, + vector &matches) { + matches.clear(); + + for(const auto &e : g1e) { + if((e.parm_name == parm_name ) && + (is_bad_data(table_number) || e.table_number == table_number) && + (is_bad_data(code) || e.code == code ) && + (is_bad_data(center) || e.center == center ) && + (e.subcenter == -1 || + is_bad_data(subcenter) || e.subcenter == subcenter )) { + matches.emplace_back(e); } - - if( g1e[j].parm_name != parm_name || - (bad_data_int != table_number && g1e[j].table_number != table_number) || - (bad_data_int != code && g1e[j].code != code) || - (bad_data_int != center && g1e[j].center != center) || - (bad_data_int != matching_subsenter && g1e[j].subcenter != matching_subsenter) ) - continue; - - if( n_matches++ == 0 ) e = g1e[j]; - matches.emplace_back( g1e[j] ); - } - // if there are multiple matches, print a descriptive message - if( 1 < n_matches ){ - - ConcatString msg; - msg << "Multiple GRIB1 table entries match lookup criteria (" - << "parm_name = " << parm_name; - if( bad_data_int != table_number ) msg << ", table_number = " << table_number; - if( bad_data_int != code ) msg << ", code = " << code; - msg << "):\n"; - mlog << Debug(3) << "\n" << msg; - - for(auto it = matches.begin(); it < matches.end(); it++) - { - mlog << Debug(3) << " parm_name: " << it->parm_name - << ", table_number = " << it->table_number - << ", code = " << it->code - << ", center = " << it->center - << ", subcenter = " << it->subcenter << "\n"; - } - - mlog << Debug(3) << "Using the first match found: " - << " parm_name: " << e.parm_name - << ", table_number = " << e.table_number - << ", code = " << e.code << "\n\n"; - - } - - return (n_matches > 0); - + return (int) matches.size(); } - //////////////////////////////////////////////////////////////////////// +int TableFlatFile::lookup_grib1(const char * parm_name, + vector &matches) { -bool TableFlatFile::lookup_grib1(const char * parm_name, Grib1TableEntry & e) // assumes table number is 2 - -{ - - int n_matches = -1; - return lookup_grib1(parm_name, 2, bad_data_int, e, n_matches); - + // Assume default table_number = 2 + return lookup_grib1(parm_name, 2, bad_data_int, matches); } - //////////////////////////////////////////////////////////////////////// +int TableFlatFile::lookup_grib2(int disc, int pcat, int pnum, + vector &matches) { + matches.clear(); -bool TableFlatFile::lookup_grib2(int disc, int pcat, int pnum, Grib2TableEntry & e) - -{ - -e.clear(); - -for (int j=0; j &matches) { + vector exact_matches; + vector partial_matches; -bool TableFlatFile::lookup_grib2(int disc, int pcat, int pnum, - int mtab, int cntr, int ltab, - Grib2TableEntry & e) - -{ - - bool has_def_entry = false; - Grib2TableEntry e_def_match; + for(const auto &e : g2e) { - e.clear(); + // Check discipline, parm_cat, and cat + if((e.disc != disc) || + (e.pcat != pcat) || + (e.pnum != pnum)) continue; - for (int j=0; j &matches) { + matches.clear(); -bool TableFlatFile::lookup_grib2(const char * parm_name, int disc, int pcat, int pnum, - Grib2TableEntry & e, int & n_matches) - -{ + for(const auto &e : g2e) { - // clear the by-reference arguments - e.clear(); - n_matches = 0; - - // build a list of matches - vector matches; - for(int j=0; jparm_name - << ", disc = " << it->disc - << ", pcat = " << it->pcat - << ", pnum = " << it->pnum << "\n"; - - mlog << Debug(3) << "Using the first match found: " - << " parm_name: " << e.parm_name - << ", disc = " << e.disc - << ", pcat = " << e.pcat - << ", pnum = " << e.pnum << "\n\n"; - - } - - return (n_matches > 0); - + return (int) matches.size(); } - //////////////////////////////////////////////////////////////////////// +int TableFlatFile::lookup_grib2(const char * parm_name, + int disc, int pcat, int pnum, + int mtab, int cntr, int ltab, + vector &matches) { + vector exact_matches; + vector partial_matches; -bool TableFlatFile::lookup_grib2(const char * parm_name, - int disc, int pcat, int pnum, - int mtab, int cntr, int ltab, - Grib2TableEntry & e, int & n_matches) + for(const auto &e : g2e) { -{ - // clear the by-reference arguments - e.clear(); - n_matches = 0; + if((e.parm_name == parm_name ) && + (is_bad_data(disc) || e.disc == disc) && + (is_bad_data(pcat) || e.pcat == pcat) && + (is_bad_data(pnum) || e.pnum == pnum)) { - // build a list of matches - vector matches; - vector partial_matches; - for(int j=0; jparm_name - << ", disc = " << it->disc - << ", grib2_mtab = " << it->mtab_set - << ", grib2_cntr = " << it->cntr - << ", grib2_ltab = " << it->ltab - << ", pcat = " << it->pcat - << ", pnum = " << it->pnum - << "\n"; - - mlog << Debug(3) << "Using the first match found: " - << " parm_name: " << e.parm_name - << ", disc = " << e.disc - << ", grib2_mtab = " << e.mtab_set - << ", grib2_cntr = " << e.cntr - << ", grib2_ltab = " << e.ltab - << ", pcat = " << e.pcat - << ", pnum = " << e.pnum - << "\n\n"; - - } - else if( 0 == n_matches ){ - mlog << Debug(3) << "No match, lookup criteria (" - << log_arguments(parm_name, disc, pcat, pnum, mtab, cntr, ltab) - << ")\n"; - } + // Prefer exact matches + if(!exact_matches.empty()) matches = exact_matches; + else matches = partial_matches; - return (n_matches > 0); + return (int) matches.size(); } - //////////////////////////////////////////////////////////////////////// - -bool TableFlatFile::lookup_grib2(const char * parm_name, Grib2TableEntry & e, int & n_matches) - -{ - - return lookup_grib2(parm_name, bad_data_int, bad_data_int, bad_data_int, e, n_matches); - +int TableFlatFile::lookup_grib2(const char * parm_name, + vector &matches) { + return lookup_grib2(parm_name, bad_data_int, bad_data_int, bad_data_int, + matches); } - //////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_data2d/table_lookup.h b/src/libcode/vx_data2d/table_lookup.h index 2e55bc78db..506d895a51 100644 --- a/src/libcode/vx_data2d/table_lookup.h +++ b/src/libcode/vx_data2d/table_lookup.h @@ -201,22 +201,32 @@ class TableFlatFile { bool read(const char * filename); - bool lookup_grib1(int code, int table_number, Grib1TableEntry &); - bool lookup_grib1(int code, int table_number, int center, int subcenter, Grib1TableEntry &); - - bool lookup_grib1(int code, Grib1TableEntry &); // assumes table_number is 2 - bool lookup_grib1(const char * parm_name, Grib1TableEntry &); // assumes table_number is 2 - - bool lookup_grib1(const char * parm_name, int table_number, int code, - Grib1TableEntry &, int & n_matches); - bool lookup_grib1(const char * parm_name, int table_number, int code,int center, int subcenter, - Grib1TableEntry &, int & n_matches); - - bool lookup_grib2(int a, int b, int c, Grib2TableEntry &); - bool lookup_grib2(int a, int b, int c, int mtab, int cntr, int ltab, Grib2TableEntry &); - bool lookup_grib2(const char * parm_name, Grib2TableEntry &, int & n_matches); - bool lookup_grib2(const char * parm_name, int a, int b, int c, Grib2TableEntry &, int & n_matches); - bool lookup_grib2(const char * parm_name, int a, int b, int c, int mtab, int cntr, int ltab, Grib2TableEntry &, int & n_matches); + int lookup_grib1(int code, int table_number, + std::vector &); + int lookup_grib1(int code, int table_number, int center, int subcenter, + std::vector &); + + // Assumes table_number = 2 by default + int lookup_grib1(int code, + std::vector &); + int lookup_grib1(const char * parm_name, + std::vector &); + + int lookup_grib1(const char * parm_name, int table_number, int code, + std::vector &); + int lookup_grib1(const char * parm_name, int table_number, int code,int center, int subcenter, + std::vector &); + + int lookup_grib2(int disc, int pcat, int pnum, + std::vector &); + int lookup_grib2(int disc, int pcat, int pnum, int mtab, int cntr, int ltab, + std::vector &); + int lookup_grib2(const char * parm_name, + std::vector &); + int lookup_grib2(const char * parm_name, int disc, int pcat, int pnum, + std::vector &); + int lookup_grib2(const char * parm_name, int disc, int pcat, int pnum, int mtab, int cntr, int ltab, + std::vector &); void readUserGribTables(const char * table_type); diff --git a/src/libcode/vx_data2d_grib/data2d_grib_utils.cc b/src/libcode/vx_data2d_grib/data2d_grib_utils.cc index 938d390282..2170975445 100644 --- a/src/libcode/vx_data2d_grib/data2d_grib_utils.cc +++ b/src/libcode/vx_data2d_grib/data2d_grib_utils.cc @@ -43,7 +43,8 @@ bool is_prelim_match( VarInfoGrib & vinfo, const GribRecord & g) unixtime ut, init_ut, valid_ut; const char *method_name = "is_prelim_match() -> "; - int p_code, code_for_lookup= vinfo.field_rec (); + int p_code; + int code_for_lookup = vinfo.field_rec(); double p_thresh_lo, p_thresh_hi; Section1_Header *pds = (Section1_Header *) g.pds; @@ -53,8 +54,8 @@ bool is_prelim_match( VarInfoGrib & vinfo, const GribRecord & g) // clean up the code - except for code 33 and 34 (UGRID and VGRID) // and name WIND when we derive wind speed and direction bool is_lookup_for_wind_components = - ( vinfo.code () == ugrd_grib_code || \ - vinfo.code () == vgrd_grib_code ) && \ + ( vinfo.code () == ugrd_grib_code || + vinfo.code () == vgrd_grib_code ) && field_name == "WIND"; if ( is_lookup_for_wind_components) { @@ -62,9 +63,9 @@ bool is_prelim_match( VarInfoGrib & vinfo, const GribRecord & g) field_name.clear (); code_for_lookup = vinfo.code (); } - vinfo.set_code (bad_data_int); - vinfo.units ().clear (); - vinfo.long_name ().clear (); + vinfo.set_code(bad_data_int); + vinfo.units().clear(); + vinfo.long_name().clear(); // // check ptv @@ -155,17 +156,19 @@ bool is_prelim_match( VarInfoGrib & vinfo, const GribRecord & g) // if it is one of APCP names - (APCP_Z0) - use 'APCP' only if ( check_reg_exp("^APCP_[0-9]*$", field_name.c_str()) ) field_name = "APCP"; - Grib1TableEntry tab; - int tab_match = -1; + vector matches; // if the name is specified, use it if( !field_name.empty() ) { // look up the name in the grib tables - if( !GribTable.lookup_grib1(field_name.c_str(), vinfo_ptv, code_for_lookup, vinfo_center, vinfo_subcenter, tab, tab_match) ) + + if(GribTable.lookup_grib1(field_name.c_str(), vinfo_ptv, code_for_lookup, + vinfo_center, vinfo_subcenter, matches) == 0) { // if did not find with params from the header - try default - if( !GribTable.lookup_grib1(field_name.c_str(), default_grib1_ptv, code_for_lookup, default_grib1_center, default_grib1_subcenter, tab, tab_match) ) + if(GribTable.lookup_grib1(field_name.c_str(), default_grib1_ptv, code_for_lookup, + default_grib1_center, default_grib1_subcenter, matches) == 0) { // if the lookup still fails, then it's not a match return false; @@ -187,9 +190,11 @@ bool is_prelim_match( VarInfoGrib & vinfo, const GribRecord & g) } // use the specified indexes to look up the field name - if( !GribTable.lookup_grib1(code_for_lookup, vinfo_ptv, vinfo_center, vinfo_subcenter,tab) ) { + if(GribTable.lookup_grib1(code_for_lookup, vinfo_ptv, + vinfo_center, vinfo_subcenter, matches) == 0 ) { //if did not find with params from the header - try default - if( !GribTable.lookup_grib1(code_for_lookup, default_grib1_ptv, default_grib1_center, default_grib1_subcenter, tab) ) + if(GribTable.lookup_grib1(code_for_lookup, default_grib1_ptv, + default_grib1_center, default_grib1_subcenter, matches) == 0) { mlog << Error << "\n" << method_name << "no parameter found with matching GRIB1_ptv (" @@ -200,9 +205,9 @@ bool is_prelim_match( VarInfoGrib & vinfo, const GribRecord & g) } } } - vinfo.set_code ( tab.code ); - vinfo.set_units ( tab.units.c_str()); - vinfo.set_long_name ( tab.full_name.c_str() ); + vinfo.set_code ( matches[0].code); + vinfo.set_units ( matches[0].units.c_str()); + vinfo.set_long_name ( matches[0].full_name.c_str()); // // test the level type number, if specified diff --git a/src/libcode/vx_data2d_grib/grib_strings.cc b/src/libcode/vx_data2d_grib/grib_strings.cc index c6d68de13c..44a277a7aa 100644 --- a/src/libcode/vx_data2d_grib/grib_strings.cc +++ b/src/libcode/vx_data2d_grib/grib_strings.cc @@ -36,8 +36,8 @@ ConcatString get_grib_code_list_str(int k, int grib_code, int ptv) { // look up the name in the grib tables - Grib1TableEntry tab; - if( !GribTable.lookup_grib1(grib_code, ptv, tab) ){ + vector matches; + if(GribTable.lookup_grib1(grib_code, ptv, matches) == 0){ mlog << Error << "\nget_grib_code_list_str() - unrecognized GRIB1 code " << grib_code << " and/or table version " << ptv << "\n\n"; exit(1); @@ -45,9 +45,9 @@ ConcatString get_grib_code_list_str(int k, int grib_code, int ptv) // return the requested field switch(k) { - case 0: return tab.full_name; // GRIB Code Name - case 1: return tab.units; // GRIB Code Unit - case 2: return tab.parm_name; // GRIB Code Abbreviation + case 0: return matches[0].full_name; // GRIB Code Name + case 1: return matches[0].units; // GRIB Code Unit + case 2: return matches[0].parm_name; // GRIB Code Abbreviation default: mlog << Error << "\nget_grib_code_list_str() - unexpected value for k: " << k << "\n\n"; @@ -246,14 +246,14 @@ int str_to_grib_code(const char *c, int ptv) if( check_reg_exp("[0-9]+", c) ) return atoi(c); // look up the name in the grib tables - int n_matches; - Grib1TableEntry tab; - if( !GribTable.lookup_grib1(c, ptv, bad_data_int, - default_grib1_center, default_grib1_subcenter, - tab, n_matches) ) + vector matches; + if(GribTable.lookup_grib1(c, ptv, bad_data_int, + default_grib1_center, default_grib1_subcenter, + matches) == 0) { return bad_data_int; + } - return tab.code; + return matches[0].code; } diff --git a/src/libcode/vx_data2d_grib/var_info_grib.cc b/src/libcode/vx_data2d_grib/var_info_grib.cc index 2cb7622d7a..991e89543a 100644 --- a/src/libcode/vx_data2d_grib/var_info_grib.cc +++ b/src/libcode/vx_data2d_grib/var_info_grib.cc @@ -102,14 +102,14 @@ void VarInfoGrib::assign(const VarInfoGrib &v) { VarInfo::assign(v); // Copy - PTV = v.ptv(); - Code = v.code(); - LvlType = v.lvl_type(); - PCode = v.p_code(); - Center = v.center (); - Subcenter = v.subcenter (); - FieldRec = v.field_rec (); - TRI = v.tri(); + PTV = v.PTV; + Code = v.Code; + LvlType = v.LvlType; + PCode = v.PCode; + Center = v.Center; + Subcenter = v.Subcenter; + FieldRec = v.FieldRec; + TRI = v.TRI; return; } @@ -122,13 +122,13 @@ void VarInfoGrib::clear() { VarInfo::clear(); // Initialize - PTV = bad_data_int; - Code = bad_data_int; - LvlType = bad_data_int; - PCode = bad_data_int; - Center = bad_data_int; - Subcenter = bad_data_int; - FieldRec = bad_data_int; + PTV = bad_data_int; + Code = bad_data_int; + LvlType = bad_data_int; + PCode = bad_data_int; + Center = bad_data_int; + Subcenter = bad_data_int; + FieldRec = bad_data_int; return; } @@ -139,12 +139,12 @@ void VarInfoGrib::dump(ostream &out) const { // Dump out the contents out << "VarInfoGrib::dump():\n" - << " PTV = " << PTV << "\n" - << " Code = " << Code << "\n" - << " LvlType = " << LvlType << "\n" - << " PCode = " << PCode << "\n" - << " Center = " << Center << "\n" - << " Subcenter = " << Subcenter << "\n"; + << " PTV = " << PTV << "\n" + << " Code = " << Code << "\n" + << " LvlType = " << LvlType << "\n" + << " PCode = " << PCode << "\n" + << " Center = " << Center << "\n" + << " Subcenter = " << Subcenter << "\n"; return; } @@ -210,7 +210,6 @@ void VarInfoGrib::set_tri(int v) { void VarInfoGrib::add_grib_code (Dictionary &dict) { ConcatString field_name = dict.lookup_string(conf_key_name, false); - int tab_match = -1; int field_ptv = dict.lookup_int (conf_key_GRIB1_ptv, false); int field_code = dict.lookup_int (conf_key_GRIB1_code, false); @@ -221,16 +220,21 @@ void VarInfoGrib::add_grib_code (Dictionary &dict) } int field_center = dict.lookup_int (conf_key_GRIB1_center, false); int field_subcenter = dict.lookup_int (conf_key_GRIB1_subcenter, false); - Grib1TableEntry tab; + + vector matches; // if the name is specified, use it if( !field_name.empty() ){ // look up the name in the grib tables - if( !GribTable.lookup_grib1(field_name.c_str(), field_ptv, field_code, field_center, field_subcenter, tab, tab_match) ) + if(GribTable.lookup_grib1(field_name.c_str(), field_ptv, field_code, + field_center, field_subcenter, + matches) == 0) { // if did not find with params from the header - try default - if( !GribTable.lookup_grib1(field_name.c_str(), default_grib1_ptv, field_code, default_grib1_center, default_grib1_subcenter, tab, tab_match) ) + if(GribTable.lookup_grib1(field_name.c_str(), default_grib1_ptv, field_code, + default_grib1_center, default_grib1_subcenter, + matches) == 0) { mlog << Error << "\nVarInfoGrib::add_grib_code() -> " << "unrecognized GRIB1 field abbreviation '" << field_name @@ -257,9 +261,13 @@ void VarInfoGrib::add_grib_code (Dictionary &dict) } // use the specified indexes to look up the field name - if( !GribTable.lookup_grib1(field_code, field_ptv, field_center, field_subcenter,tab) ){ + if(GribTable.lookup_grib1(field_code, field_ptv, + field_center, field_subcenter, + matches) == 0 ){ //if did not find with params from the header - try default - if( !GribTable.lookup_grib1(field_code, default_grib1_ptv, default_grib1_center, default_grib1_subcenter,tab) ) + if(GribTable.lookup_grib1(field_code, default_grib1_ptv, + default_grib1_center, default_grib1_subcenter, + matches) == 0) { mlog << Error << "\nVarInfoGrib::add_grib_code() -> " << "no parameter found with matching GRIB1_ptv (" @@ -270,9 +278,6 @@ void VarInfoGrib::add_grib_code (Dictionary &dict) } } } - set_code ( tab.code ); - set_long_name ( tab.full_name.c_str() ); - set_units ( tab.units.c_str() ); } /////////////////////////////////////////////////////////////////////////////// @@ -281,8 +286,6 @@ bool VarInfoGrib::set_dict(Dictionary & dict, bool do_exit) { VarInfo::set_dict(dict); - int tab_match = -1; - Grib1TableEntry tab; ConcatString field_name = dict.lookup_string(conf_key_name, false); int field_ptv = dict.lookup_int (conf_key_GRIB1_ptv, false); int field_code = dict.lookup_int (conf_key_GRIB1_code, false); @@ -327,8 +330,11 @@ bool VarInfoGrib::set_dict(Dictionary & dict, bool do_exit) { double thresh_lo = dict_prob->lookup_double(conf_key_thresh_lo, false); double thresh_hi = dict_prob->lookup_double(conf_key_thresh_hi, false); + vector matches; + // look up the probability field abbreviation - if( !GribTable.lookup_grib1(prob_name.c_str(), field_ptv, field_code, tab, tab_match) ){ + if(GribTable.lookup_grib1(prob_name.c_str(), field_ptv, field_code, + matches) == 0){ ConcatString msg; msg << "\nVarInfoGrib::set_dict() -> " << "unrecognized GRIB1 probability field abbreviation '" @@ -337,10 +343,7 @@ bool VarInfoGrib::set_dict(Dictionary & dict, bool do_exit) { return false; } - set_p_flag ( true ); - set_p_code ( tab.code ); - set_p_units ( tab.units.c_str() ); - + set_p_flag(true); set_prob_info_grib(prob_name, thresh_lo, thresh_hi); return true; diff --git a/src/libcode/vx_data2d_grib/var_info_grib.h b/src/libcode/vx_data2d_grib/var_info_grib.h index f3f0f49f96..17de4e8365 100644 --- a/src/libcode/vx_data2d_grib/var_info_grib.h +++ b/src/libcode/vx_data2d_grib/var_info_grib.h @@ -18,6 +18,7 @@ #include "vx_config.h" #include "data_file_type.h" +#include "table_lookup.h" /////////////////////////////////////////////////////////////////////////////// // @@ -31,10 +32,6 @@ static const char * const CONFIG_GRIB_Code = "GRIB_Code"; static const char * const CONFIG_GRIB_LvlType = "GRIB_Level"; static const char * const CONFIG_GRIB_PCode = "GRIB_Prob_Code"; -/////////////////////////////////////////////////////////////////////////////// - - - /////////////////////////////////////////////////////////////////////////////// class VarInfoGrib : public VarInfo diff --git a/src/libcode/vx_data2d_grib2/data2d_grib2.cc b/src/libcode/vx_data2d_grib2/data2d_grib2.cc index afc60b9596..90ba2fcb0e 100644 --- a/src/libcode/vx_data2d_grib2/data2d_grib2.cc +++ b/src/libcode/vx_data2d_grib2/data2d_grib2.cc @@ -832,16 +832,17 @@ void MetGrib2DataFile::read_grib2_record_list() { id << rec->Discipline << "_" << rec->ParmCat << "_" << rec->Parm; // use the index to look up the parameter name - Grib2TableEntry tab; - if( !GribTable.lookup_grib2(rec->Discipline, rec->ParmCat, rec->Parm, - gfld->idsect[2], gfld->idsect[0], gfld->idsect[3], tab) ){ + vector matches; + if(GribTable.lookup_grib2(rec->Discipline, rec->ParmCat, rec->Parm, + gfld->idsect[2], gfld->idsect[0], gfld->idsect[3], + matches) == 0){ mlog << Debug(4) << "MetGrib2DataFile::read_grib2_record_list() - unrecognized GRIB2 " << "field indexes - disc: " << rec->Discipline << ", master table: " << gfld->idsect[2] << ", center: " << gfld->idsect[0] << ", local table: " << gfld->idsect[3] << ", parm_cat: " << rec->ParmCat << ", parm: " << rec->Parm << "\n"; rec->ParmName = str_format("DISC%d_CAT%d_PARM%d", rec->Discipline, rec->ParmCat, rec->Parm); } else { - rec->ParmName = tab.parm_name.text(); + rec->ParmName = matches[0].parm_name.text(); } // add the record to the list diff --git a/src/libcode/vx_data2d_grib2/var_info_grib2.cc b/src/libcode/vx_data2d_grib2/var_info_grib2.cc index d63c7d1b46..6b5d6ade0b 100644 --- a/src/libcode/vx_data2d_grib2/var_info_grib2.cc +++ b/src/libcode/vx_data2d_grib2/var_info_grib2.cc @@ -324,8 +324,6 @@ bool VarInfoGrib2::set_dict(Dictionary & dict, bool do_exit) { VarInfo::set_dict(dict); - int tab_match = -1; - Grib2TableEntry tab; ConcatString field_name = dict.lookup_string(conf_key_name, false); ConcatString ens_str = dict.lookup_string(conf_key_GRIB_ens, false); int field_disc = dict.lookup_int (conf_key_GRIB2_disc, false); @@ -362,6 +360,8 @@ bool VarInfoGrib2::set_dict(Dictionary & dict, bool do_exit) { handle_config_error(msg, do_exit); } + vector matches; + // if the name is specified, use it if( !field_name.empty() ){ @@ -369,9 +369,10 @@ bool VarInfoGrib2::set_dict(Dictionary & dict, bool do_exit) { set_req_name( field_name.c_str() ); // look up the name in the grib tables - if( !GribTable.lookup_grib2(field_name.c_str(), field_disc, field_parm_cat, field_parm, mtab, cntr, ltab, - tab, tab_match) && - field_name != "PROB" ){ + if(GribTable.lookup_grib2(field_name.c_str(), + field_disc, field_parm_cat, field_parm, + mtab, cntr, ltab, matches) == 0 && + field_name != "PROB"){ ConcatString msg; msg << "\nVarInfoGrib2::set_dict() -> " << "unrecognized GRIB2 field abbreviation '" << field_name @@ -395,8 +396,8 @@ bool VarInfoGrib2::set_dict(Dictionary & dict, bool do_exit) { } // use the specified indexes to look up the field name - if( !GribTable.lookup_grib2(field_disc, field_parm_cat, - field_parm, mtab, cntr, ltab, tab) ){ + if(GribTable.lookup_grib2(field_disc, field_parm_cat, field_parm, + mtab, cntr, ltab, matches) == 0){ ConcatString msg; msg << "\nVarInfoGrib2::set_dict() -> " << "no parameter found with matching " @@ -408,21 +409,14 @@ bool VarInfoGrib2::set_dict(Dictionary & dict, bool do_exit) { handle_config_error(msg, do_exit); } - // use the lookup parameter name - field_name = tab.parm_name; + // use the first lookup parameter name + field_name = matches[0].parm_name; } set_ens (ens_str.c_str()); // set the matched parameter lookup information set_name ( field_name ); set_req_name ( field_name.c_str() ); - if( field_name != "PROB" ){ - set_discipline( tab.index_a ); - set_parm_cat ( tab.index_b ); - set_parm ( tab.index_c ); - set_units ( tab.units.c_str() ); - set_long_name ( tab.full_name.c_str() ); - } // call the parent to set the level information set_level_info_grib(dict); @@ -453,8 +447,8 @@ bool VarInfoGrib2::set_dict(Dictionary & dict, bool do_exit) { double thresh_hi = dict_prob->lookup_double(conf_key_thresh_hi, false); // look up the probability field abbreviation - if(!GribTable.lookup_grib2(prob_name.c_str(), field_disc, field_parm_cat, - field_parm, mtab, cntr, ltab, tab, tab_match)){ + if(GribTable.lookup_grib2(prob_name.c_str(), field_disc, field_parm_cat, + field_parm, mtab, cntr, ltab, matches) == 0){ ConcatString msg; msg << "\nVarInfoGrib2::set_dict() -> " << "unrecognized GRIB2 probability field abbreviation '" @@ -463,12 +457,8 @@ bool VarInfoGrib2::set_dict(Dictionary & dict, bool do_exit) { return false; } - set_discipline ( tab.index_a ); - set_parm_cat ( tab.index_b ); - set_parm ( tab.index_c ); - set_p_flag ( true ); - set_p_units ( tab.units.c_str() ); - set_units ( "%" ); + set_p_flag(true); + set_units("%"); set_prob_info_grib(prob_name, thresh_lo, thresh_hi); From a0e1978cbdde0410732b30d047ade7b0416384f1 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 16 Jun 2026 20:19:25 +0000 Subject: [PATCH 18/63] Correct TCDC to be TCC for GALWEM. --- internal/test_unit/xml/unit_grib_tables.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/test_unit/xml/unit_grib_tables.xml b/internal/test_unit/xml/unit_grib_tables.xml index 88e8370e23..5430a1ea12 100644 --- a/internal/test_unit/xml/unit_grib_tables.xml +++ b/internal/test_unit/xml/unit_grib_tables.xml @@ -36,8 +36,8 @@ \ &DATA_DIR_MODEL;/grib2/um_raw/PS.557WW_SC.U_DI.F_GP.GALWEM-GD_GR.C17KM_AR.GLOBAL_DD.20160424_CY.00_FH.000_DF.GR2 \ &OUTPUT_DIR;/grib_tables/um_raw/PS.557WW_SC.U_DI.F_GP.GALWEM-GD_GR.C17KM_AR.GLOBAL_DD.20160424_CY.00_FH.000_DF.ps \ - 'name = "TCDC"; level = "L0";' \ - -title "GRIB2 um_raw L0 TCDC" \ + 'name = "TCC"; level = "L0";' \ + -title "GRIB2 um_raw L0 TCC" \ -v 1 From b55cfeaec900cb9fe66b4d7a4d3e71eafe624488 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Wed, 17 Jun 2026 17:30:03 +0000 Subject: [PATCH 19/63] Per #1518, add logic to check whether DataPlaneArray level values match. --- src/basic/vx_util/data_plane.cc | 18 ++++++++++++++++++ src/basic/vx_util/data_plane.h | 1 + 2 files changed, 19 insertions(+) diff --git a/src/basic/vx_util/data_plane.cc b/src/basic/vx_util/data_plane.cc index 7809864905..67912013fc 100644 --- a/src/basic/vx_util/data_plane.cc +++ b/src/basic/vx_util/data_plane.cc @@ -1332,6 +1332,24 @@ void DataPlaneArray::levels(int n, double & _low, double & _up) const { /////////////////////////////////////////////////////////////////////////////// +bool DataPlaneArray::levels_match(const DataPlaneArray &d) const { + + // Check for matching number of levels + if(Nplanes != d.Nplanes) return false; + + for(int i=0; i Date: Wed, 17 Jun 2026 17:35:14 +0000 Subject: [PATCH 20/63] Per #1518, move call to rotate_winds() outside of process_data_plane(). We now have rotate_winds() for both DataPlane and DataPlaneArray inputs. And wind rotation is now handled AFTER the calls to process_data_plane(). --- src/libcode/vx_data2d/data_class.cc | 119 +++++++++++++++--- src/libcode/vx_data2d/data_class.h | 3 +- src/libcode/vx_data2d_grib/data2d_grib.cc | 5 +- src/libcode/vx_data2d_grib2/data2d_grib2.cc | 32 +++-- src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc | 5 +- src/libcode/vx_data2d_nc_met/data2d_nc_met.cc | 5 +- src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc | 10 +- src/libcode/vx_data2d_python/data2d_python.cc | 8 +- src/libcode/vx_data2d_ugrid/data2d_ugrid.cc | 5 +- 9 files changed, 154 insertions(+), 38 deletions(-) diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index edb7785679..dcee9edf9c 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -651,9 +651,18 @@ bool Met2dDataFile::rotate_winds(VarInfo *vinfo, DataPlane &dp) { -static const char *method_name = "Met2dDataFile::rotate_winds() -> "; +static const char *method_name = "Met2dDataFile::rotate_winds(DataPlane) -> "; -if(!vinfo || !vinfo->need_rotation()) return false; +if(!vinfo || !vinfo->is_wind_rotation()) return false; + +if(vinfo->is_wind_rotation() && !vinfo->is_grid_relative()) { + mlog << Debug(3) << "Wind field \"" << vinfo->magic_str() + << "\" is already defined as earth-relative.\n"; + return true; +} + + // + // Apply conversion logic bool status = false; @@ -705,6 +714,94 @@ return status; //////////////////////////////////////////////////////////////////////// +bool Met2dDataFile::rotate_winds(VarInfo *vinfo, DataPlaneArray &dpa) + +{ + +static const char *method_name = "Met2dDataFile::rotate_winds(DataPlaneArray) -> "; + +if(!vinfo || !vinfo->is_wind_rotation()) return false; + +if(vinfo->is_wind_rotation() && !vinfo->is_grid_relative()) { + mlog << Debug(3) << "Wind field \"" << vinfo->magic_str() + << "\" is already defined as earth-relative.\n"; + return true; +} + +bool status = false; + +DataPlaneArray uwnd_dpa; +DataPlaneArray vwnd_dpa; +DataPlaneArray tmp_dpa; +ConcatString units; +DataPlaneArray *uwnd_out; +DataPlaneArray *vwnd_out; + +// Rotate U-Wind and V-Wind +if(vinfo->is_u_wind() || vinfo->is_v_wind()) { + + if(vinfo->is_u_wind()) { + uwnd_dpa = dpa; + uwnd_out = &dpa; + vwnd_out = &tmp_dpa; + status = read_wind_data(vinfo, vinfo->wind_info().v_wind, + vwnd_dpa, units); + } + else { + vwnd_dpa = dpa; + uwnd_out = &tmp_dpa; + vwnd_out = &dpa; + status = read_wind_data(vinfo, vinfo->wind_info().u_wind, + uwnd_dpa, units); + } + + // Check for matching levels + if(!uwnd_dpa.levels_match(vwnd_dpa)) { + mlog << Warning << "\n" << method_name + << "The U-wind and V-wind levels do not match.\n\n"; + status = false; + } + + // Rotate each plane + if(status) { + for(int i=0; iat(i), vwnd_out->at(i)); + if(!status) break; + } + } +} +// Rotate Wind Direction +else if(vinfo->is_wind_direction()) { + tmp_dpa = dpa; + + // Rotate each plane + for(int i=0; imagic_str() + << ") from grid to earth relative.\n\n"; +} +// Update flag for a successful rotation +else { + vinfo->set_earth_relative(); +} + +return status; + +} + + +//////////////////////////////////////////////////////////////////////// + + bool Met2dDataFile::read_wind_data(VarInfo *vinfo, const StringArray &names, DataPlane &dp, @@ -807,28 +904,12 @@ return status; //////////////////////////////////////////////////////////////////////// -bool Met2dDataFile::process_data_plane(VarInfo *vinfo, DataPlane &dp, - bool do_winds) +bool Met2dDataFile::process_data_plane(VarInfo *vinfo, DataPlane &dp) { if ( ! vinfo ) return false; - // - // Rotate winds, if requested and needed - // - -if(do_winds && vinfo->is_wind_rotation()) { - - if(vinfo->need_rotation()) { - rotate_winds(vinfo, dp); - } - else { - mlog << Debug(3) << "Wind field \"" << vinfo->magic_str() - << "\" is defined as earth-relative.\n"; - } -} - // // Apply conversion logic // diff --git a/src/libcode/vx_data2d/data_class.h b/src/libcode/vx_data2d/data_class.h index b26edf1086..f7a91662a6 100644 --- a/src/libcode/vx_data2d/data_class.h +++ b/src/libcode/vx_data2d/data_class.h @@ -166,10 +166,11 @@ class Met2dDataFile : public Met2dData { bool derive_winds(VarInfo *, DataPlane &); bool derive_winds(VarInfo *, DataPlaneArray &); bool rotate_winds(VarInfo *, DataPlane &); + bool rotate_winds(VarInfo *, DataPlaneArray &); // post-process data after reading it - bool process_data_plane(VarInfo *, DataPlane &, bool do_winds = true); + bool process_data_plane(VarInfo *, DataPlane &); }; diff --git a/src/libcode/vx_data2d_grib/data2d_grib.cc b/src/libcode/vx_data2d_grib/data2d_grib.cc index 22856b6628..b67afed071 100644 --- a/src/libcode/vx_data2d_grib/data2d_grib.cc +++ b/src/libcode/vx_data2d_grib/data2d_grib.cc @@ -506,7 +506,7 @@ int MetGrib1DataFile::data_plane_array(VarInfo &vinfo, if(status) { // Store whether winds are grid relative vinfo.set_grid_relative_flag(is_grid_relative(r)); - status = process_data_plane(&vinfo, cur_plane, do_winds); + status = process_data_plane(&vinfo, cur_plane); } if(!status) { @@ -524,6 +524,9 @@ int MetGrib1DataFile::data_plane_array(VarInfo &vinfo, } } // end for loop + // Handle wind rotation + if(do_winds) rotate_winds(&vinfo, plane_array); + // If nothing was found, try to build derived records if(plane_array.n_planes() == 0 && do_winds) { derive_winds(&vinfo, plane_array); diff --git a/src/libcode/vx_data2d_grib2/data2d_grib2.cc b/src/libcode/vx_data2d_grib2/data2d_grib2.cc index 90ba2fcb0e..349416d98a 100644 --- a/src/libcode/vx_data2d_grib2/data2d_grib2.cc +++ b/src/libcode/vx_data2d_grib2/data2d_grib2.cc @@ -182,12 +182,20 @@ bool MetGrib2DataFile::data_plane(VarInfo &vinfo, DataPlane &plane, plane = plane_array[0]; - return process_data_plane(vinfo_g2, plane, do_winds); + bool status = process_data_plane(vinfo_g2, plane); + + // handle wind rotation + if(status && do_winds) status = rotate_winds(vinfo_g2, plane); + + return status; } // END: if( 1 > listMatch.size() ) // verify that a only single record was found - if( 1 < listMatch.size() ){ + if(listMatch.empty()) { + return false; + } + else if( 1 < listMatch.size() ){ ConcatString msg; for(size_t i=0; i < listMatch.size(); i++) { msg << " Record " << listMatch[i]->RecNum @@ -219,16 +227,16 @@ bool MetGrib2DataFile::data_plane(VarInfo &vinfo, DataPlane &plane, << Filename << "'\n"; // read the data plane for the matched record - bool read_success = read_grib2_record_data_plane(listMatch[0], - plane); + bool status = read_grib2_record_data_plane(listMatch[0], plane); - if(read_success) { - // store whether winds are grid relative + if(status) { vinfo_g2->set_grid_relative_flag(is_grid_relative(listMatch[0])); - read_success = process_data_plane(vinfo_g2, plane, do_winds); + status = process_data_plane(vinfo_g2, plane); + // handle wind rotation + if(status && do_winds) status = rotate_winds(vinfo_g2, plane); } - return read_success; + return status; } //////////////////////////////////////////////////////////////////////// @@ -339,14 +347,18 @@ int MetGrib2DataFile::data_plane_array(VarInfo &vinfo, lvl_upper = ( (double)(*it)->LvlVal2 ) / 100.0; } - // store whether winds are grid relative + // store grid relative status vinfo_g2->set_grid_relative_flag(is_grid_relative(*it)); - if(process_data_plane(vinfo_g2, plane, do_winds)) { + // add current plane to the data plane array + if(process_data_plane(vinfo_g2, plane)) { plane_array.add(plane, lvl_lower, lvl_upper); } } + // handle wind rotation + if(do_winds) rotate_winds(vinfo_g2, plane_array); + return num_read; } diff --git a/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc b/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc index 79ebcc6e0c..fbb42eb889 100644 --- a/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc +++ b/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc @@ -373,7 +373,10 @@ bool MetNcCFDataFile::read_data_plane(VarInfo &vinfo, DataPlane &plane, } } - status = process_data_plane(&vinfo, plane, do_winds); + status = process_data_plane(&vinfo, plane); + + // Handle wind rotation + if(status && do_winds) status = rotate_winds(&vinfo, plane); // Set the VarInfo object's name, long_name, level, and units strings diff --git a/src/libcode/vx_data2d_nc_met/data2d_nc_met.cc b/src/libcode/vx_data2d_nc_met/data2d_nc_met.cc index aaa25eb35a..3623354898 100644 --- a/src/libcode/vx_data2d_nc_met/data2d_nc_met.cc +++ b/src/libcode/vx_data2d_nc_met/data2d_nc_met.cc @@ -286,7 +286,10 @@ bool MetNcMetDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, status = false; } - status = process_data_plane(&vinfo, plane, do_winds); + status = process_data_plane(&vinfo, plane); + + // Handle wind rotation + if(status && do_winds) status = rotate_winds(&vinfo, plane); // Set the VarInfo object's name, long_name, level, and units strings if(info->name_att.length() > 0) vinfo.set_name(info->name_att); diff --git a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc index be4b05c792..f23870db2b 100644 --- a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc +++ b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc @@ -183,7 +183,10 @@ bool MetNcWrfDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, status = false; } - status = process_data_plane(&vinfo, plane, do_winds); + status = process_data_plane(&vinfo, plane); + + // Handle wind rotation + if(status && do_winds) status = rotate_winds(&vinfo, plane); // Set the VarInfo object's name, long_name, and units strings // Note that info is null for derived fields @@ -288,12 +291,15 @@ int MetNcWrfDataFile::data_plane_array(VarInfo &vinfo, status = false; } - status = process_data_plane(&vinfo, cur_plane, do_winds); + status = process_data_plane(&vinfo, cur_plane); // Add current plane to the data plane array plane_array.add(cur_plane, pressure, pressure); } + // Handle wind rotation + if(do_winds) rotate_winds(&vinfo, plane_array); + // Check for bad status if(!status) return 0; diff --git a/src/libcode/vx_data2d_python/data2d_python.cc b/src/libcode/vx_data2d_python/data2d_python.cc index 35226d4fe1..64cd19d891 100644 --- a/src/libcode/vx_data2d_python/data2d_python.cc +++ b/src/libcode/vx_data2d_python/data2d_python.cc @@ -333,7 +333,9 @@ if ( status ) { plane = Plane; - status = process_data_plane(&vinfo, plane, do_winds); + status = process_data_plane(&vinfo, plane); + + if(status && do_winds) status = rotate_winds(&vinfo, plane); } @@ -401,7 +403,9 @@ if ( status ) { plane = Plane; - status = process_data_plane(&vinfo, plane, do_winds); + status = process_data_plane(&vinfo, plane); + + if(status && do_winds) status = rotate_winds(&vinfo, plane); } diff --git a/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc b/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc index 236bf8a73c..55daace6eb 100644 --- a/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc +++ b/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc @@ -799,11 +799,14 @@ bool MetUGridDataFile::read_data_plane(ConcatString var_name, VarInfo &vinfo, status = false; } - if (status) status = process_data_plane(&vinfo, plane, do_winds); + if (status) status = process_data_plane(&vinfo, plane); else { mlog << Debug(2) << "\n" << method_name << "not processed data_plane\n"; } + // Handle wind rotation + if(status && do_winds) status = rotate_winds(&vinfo, plane); + // Set the VarInfo object's name, long_name, level, and units strings if (!info->name_att.empty()) From a9b3b0c0c6bf17e94603a3148eb3cc4f83ef0619 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Wed, 17 Jun 2026 17:52:28 +0000 Subject: [PATCH 21/63] Per #1518, rotate_winds() should return true for non-wind vars. --- src/libcode/vx_data2d/data_class.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index dcee9edf9c..74e4295e44 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -653,7 +653,9 @@ bool Met2dDataFile::rotate_winds(VarInfo *vinfo, DataPlane &dp) static const char *method_name = "Met2dDataFile::rotate_winds(DataPlane) -> "; -if(!vinfo || !vinfo->is_wind_rotation()) return false; +if(!vinfo) return false; + +if(!vinfo->is_wind_rotation()) return true; if(vinfo->is_wind_rotation() && !vinfo->is_grid_relative()) { mlog << Debug(3) << "Wind field \"" << vinfo->magic_str() @@ -720,7 +722,9 @@ bool Met2dDataFile::rotate_winds(VarInfo *vinfo, DataPlaneArray &dpa) static const char *method_name = "Met2dDataFile::rotate_winds(DataPlaneArray) -> "; -if(!vinfo || !vinfo->is_wind_rotation()) return false; +if(!vinfo) return false; + +if(!vinfo->is_wind_rotation()) return true; if(vinfo->is_wind_rotation() && !vinfo->is_grid_relative()) { mlog << Debug(3) << "Wind field \"" << vinfo->magic_str() From 6bb618db416d63b124ae07576d0655f9313fdcb3 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Wed, 17 Jun 2026 19:09:02 +0000 Subject: [PATCH 22/63] Per #1518, patch rotate_winds() logic for DataPlaneArray. ci-run-unit --- src/libcode/vx_data2d/data_class.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index 74e4295e44..ac046c97f5 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -492,7 +492,7 @@ if(vinfo->need_uv_wind()) { DataPlane vwnd_dp_orig(vwnd_dpa[i]); rotate_uv_grid_to_earth(uwnd_dp_orig, vwnd_dp_orig, *Raw_Grid, - uwnd_dpa.at(i), vwnd_dpa.at(i)); + uwnd_dpa.at(i), vwnd_dpa.at(i)); } vinfo->set_earth_relative(); } @@ -736,7 +736,7 @@ bool status = false; DataPlaneArray uwnd_dpa; DataPlaneArray vwnd_dpa; -DataPlaneArray tmp_dpa; +DataPlaneArray tmp_dpa(dpa); ConcatString units; DataPlaneArray *uwnd_out; DataPlaneArray *vwnd_out; @@ -770,7 +770,7 @@ if(vinfo->is_u_wind() || vinfo->is_v_wind()) { if(status) { for(int i=0; iat(i), vwnd_out->at(i)); if(!status) break; } @@ -783,7 +783,7 @@ else if(vinfo->is_wind_direction()) { // Rotate each plane for(int i=0; i Date: Wed, 17 Jun 2026 20:23:09 +0000 Subject: [PATCH 23/63] Per #1518, add back in calls to set the GRIB code after doing a table lookup. --- src/libcode/vx_data2d_grib/var_info_grib.cc | 27 +++++++++++++-------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/libcode/vx_data2d_grib/var_info_grib.cc b/src/libcode/vx_data2d_grib/var_info_grib.cc index 991e89543a..c5221cd0f9 100644 --- a/src/libcode/vx_data2d_grib/var_info_grib.cc +++ b/src/libcode/vx_data2d_grib/var_info_grib.cc @@ -102,14 +102,14 @@ void VarInfoGrib::assign(const VarInfoGrib &v) { VarInfo::assign(v); // Copy - PTV = v.PTV; - Code = v.Code; - LvlType = v.LvlType; - PCode = v.PCode; - Center = v.Center; - Subcenter = v.Subcenter; - FieldRec = v.FieldRec; - TRI = v.TRI; + PTV = v.PTV; + Code = v.Code; + LvlType = v.LvlType; + PCode = v.PCode; + Center = v.Center; + Subcenter = v.Subcenter; + FieldRec = v.FieldRec; + TRI = v.TRI; return; } @@ -129,6 +129,7 @@ void VarInfoGrib::clear() { Center = bad_data_int; Subcenter = bad_data_int; FieldRec = bad_data_int; + TRI = bad_data_int; return; } @@ -144,7 +145,8 @@ void VarInfoGrib::dump(ostream &out) const { << " LvlType = " << LvlType << "\n" << " PCode = " << PCode << "\n" << " Center = " << Center << "\n" - << " Subcenter = " << Subcenter << "\n"; + << " Subcenter = " << Subcenter << "\n" + << " TRI = " << TRI << "\n"; return; } @@ -278,6 +280,9 @@ void VarInfoGrib::add_grib_code (Dictionary &dict) } } } + set_code ( matches[0].code ); + set_long_name ( matches[0].full_name.c_str() ); + set_units ( matches[0].units.c_str() ); } /////////////////////////////////////////////////////////////////////////////// @@ -343,7 +348,9 @@ bool VarInfoGrib::set_dict(Dictionary & dict, bool do_exit) { return false; } - set_p_flag(true); + set_p_flag ( true ); + set_p_code ( matches[0].code ); + set_p_units ( matches[0].units.c_str() ); set_prob_info_grib(prob_name, thresh_lo, thresh_hi); return true; From 9b603fd2780c2612a2e79b1e08cee1c14c5cb032 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Wed, 17 Jun 2026 22:15:05 +0000 Subject: [PATCH 24/63] Per #1518, need to store the units parsed from the GRIB tables. --- .../vx_data2d_grib2/.var_info_grib2.cc.swp | Bin 0 -> 16384 bytes src/libcode/vx_data2d_grib2/var_info_grib2.cc | 6 +++++- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 src/libcode/vx_data2d_grib2/.var_info_grib2.cc.swp diff --git a/src/libcode/vx_data2d_grib2/.var_info_grib2.cc.swp b/src/libcode/vx_data2d_grib2/.var_info_grib2.cc.swp new file mode 100644 index 0000000000000000000000000000000000000000..6d77b4d0f17372092456564adb2af167eb805fbd GIT binary patch literal 16384 zcmeI3UyK_^9mj_>34hv@C?FLYS`7)LzH822+sP&IaiLBwDTnTk=q?EmA(^?|vAtov zv+Rz2xu&!fA<-95BLPB4pj06GhLk|_0Ej;Dz(Y_)Aa5W61<~?^#0!5~0^gb0wRaug zB`Uc-l-=la&dhJ-x4-$#{Khl0>t*Zo>^wbGvG>o_hAdm#5f?t$C`xd(C&;C^r)*a9|zYugC92)+g8!5o+d4}<%_ zX7Ja02>C7e4R`_k6nqyv4IPzDxw?d^oT3jPRQ0@uN>z%}p`_&j(7d>HHm_k(-D-QZtu zBjg|8@8CJ`J@6!W0xW=ePz7aRf#1KCkl%qT;Cb*gXn`g;13n3kgJYlu4uS*V<*kJL z8TMfM0GVHaHN!l9W7f^dX&jE>du{H%O2OYN8ERQUFnP)*>2#uJ|AV( zBDY28tfjeBqO-m$UFNxuaY9h+Gz(|(mP)N=dz^)ZG2L(!JMM;&q&D+BD%+d}EX0d3 z4@FcLLvIP!N$NhT-goIMpy%!}(fYDsxV(j4Z74(}ib!$-^G=POb*3t9r#) zNjg7WUYAo=s4G=oelGL&p9wxe#EKX|CF+WO+;-nU3 zVxw1#lSY&d42X2nNYX(836lN%emIzXB(*3L3%#OAYDp#zdPS4el1vPsMg5S_(o78W ziYBQg7}!Teu$mqDEQ;KgU+CR(?3;ok2Y;-?7CxdTjwu}%bWd;WjR}c?6EHX|Ghq5b zO)#YTq3&V|Xf#97X+(C&q}{%C*sCgf)?m^V{zw;$(7MqLr-ispbbJi6gK2Zd`{T%l zJAA&9G+*~hVO+M|2pvxP3ewfoWF~xG7^9{`&u{FMMzuA@`gkBUm2K!Vw@C|_fZd2r zPt!e3I+jd>{W@v8>7Gn0Yc+v+jY$zs7ejNqo*Dz)n*;iJR+pm~3YYsvLE< zNHSkWSy>Bfokk=>SgR#zTe2_w!p?#4Lm_YRbH(=IR90V0Hq&v%a5)F>7!T(u3(^%k zEI54UXQ_BN&-?u0KR!-R6hBrxBF@pOWm$Xa5z+M= z9_~d{c_L(v*h>#uRqMcn5uaMB$JG{jgf+O`ru6{pds~0iMs$uX)52nXZY(afp!2ct zJ&F}MR-!6Q>#`%Fpv^x}`q_*pIdra;B|A{^0U$Dni`~T$m`ep3*p9KL}1V=y}JOEzA zKK~MU7F+~fums)wfU7|5|9=903_|c(Z~#n# zSFne_3VsAauot|HJ^Mv)2J8SYU?1KC6W~wSV}BDY0=4(v57hp<0#qAcQSHpH+yl7> zau4Jl$UX4?;(;sTm7DY=H*Sk=I9{#{v<~!?D^y9NjHdGXnkEN|=s?rt2u0TV zity9Leme(>sy8b-fTeZP80AIyC`meOb-X&czi5q@ElcSeD6+Bm?1ro9rcK_CqN>)D zQsj%UgT-v2YSC4!extFp%Kf*avOKKP!H+>5p4PMPHuNOk8njW_lh%U4)OXD&PZ>L? zz6M%4!k6u|8jPiN)FfsMt3h9+m0%dHr9_RnjFy2dN|e@uF|?MJj_Y?NPw5$GF(RcW zT5;9!A$|<2PDYU7h^~6Dkqn^NOB3ZOB}8aZb?jK9Z7G9VskE}PQuJ*Bcu@2OW5t%} zm4eQ4$q{x`Qk(6H`P-1{fyus!eZ{CPJ02nNjnXF~wOXsvkZy-JLgu%)o)Q{TG++!Y zlr**y+m$y zO}`dmW>C$hbx*od9SoTo^PKr~bPFuwm$ge!YD$>9Qf#KPev6w5_pRS0Cqf=2{b{^x z9n?mfrr}ZGpwX&qgx`|W8MoQwc(R5QFBKSZ)2S3A`oc1uHXDg$ruO+s$KI}ib=&Tm whcRf2wvbX|;etR!V-7wk0xFvNd0+oPK@Xfb%&8~om=1IF#s3<~`{PLdFJM!%s{jB1 literal 0 HcmV?d00001 diff --git a/src/libcode/vx_data2d_grib2/var_info_grib2.cc b/src/libcode/vx_data2d_grib2/var_info_grib2.cc index 6b5d6ade0b..fecc0c4339 100644 --- a/src/libcode/vx_data2d_grib2/var_info_grib2.cc +++ b/src/libcode/vx_data2d_grib2/var_info_grib2.cc @@ -417,6 +417,10 @@ bool VarInfoGrib2::set_dict(Dictionary & dict, bool do_exit) { // set the matched parameter lookup information set_name ( field_name ); set_req_name ( field_name.c_str() ); + if( field_name != "PROB" ){ + set_units ( matches[0].units.c_str() ); + set_long_name ( matches[0].full_name.c_str() ); + } // call the parent to set the level information set_level_info_grib(dict); @@ -458,7 +462,7 @@ bool VarInfoGrib2::set_dict(Dictionary & dict, bool do_exit) { } set_p_flag(true); - set_units("%"); + set_units(matches[0].units.c_str()); set_prob_info_grib(prob_name, thresh_lo, thresh_hi); From 76f27ca587f1430424c87fbe9536d055534ab206 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Wed, 17 Jun 2026 22:16:43 +0000 Subject: [PATCH 25/63] Per #1518, delete accidentally committed swap file. ci-run-unit --- .../vx_data2d_grib2/.var_info_grib2.cc.swp | Bin 16384 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/libcode/vx_data2d_grib2/.var_info_grib2.cc.swp diff --git a/src/libcode/vx_data2d_grib2/.var_info_grib2.cc.swp b/src/libcode/vx_data2d_grib2/.var_info_grib2.cc.swp deleted file mode 100644 index 6d77b4d0f17372092456564adb2af167eb805fbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 zcmeI3UyK_^9mj_>34hv@C?FLYS`7)LzH822+sP&IaiLBwDTnTk=q?EmA(^?|vAtov zv+Rz2xu&!fA<-95BLPB4pj06GhLk|_0Ej;Dz(Y_)Aa5W61<~?^#0!5~0^gb0wRaug zB`Uc-l-=la&dhJ-x4-$#{Khl0>t*Zo>^wbGvG>o_hAdm#5f?t$C`xd(C&;C^r)*a9|zYugC92)+g8!5o+d4}<%_ zX7Ja02>C7e4R`_k6nqyv4IPzDxw?d^oT3jPRQ0@uN>z%}p`_&j(7d>HHm_k(-D-QZtu zBjg|8@8CJ`J@6!W0xW=ePz7aRf#1KCkl%qT;Cb*gXn`g;13n3kgJYlu4uS*V<*kJL z8TMfM0GVHaHN!l9W7f^dX&jE>du{H%O2OYN8ERQUFnP)*>2#uJ|AV( zBDY28tfjeBqO-m$UFNxuaY9h+Gz(|(mP)N=dz^)ZG2L(!JMM;&q&D+BD%+d}EX0d3 z4@FcLLvIP!N$NhT-goIMpy%!}(fYDsxV(j4Z74(}ib!$-^G=POb*3t9r#) zNjg7WUYAo=s4G=oelGL&p9wxe#EKX|CF+WO+;-nU3 zVxw1#lSY&d42X2nNYX(836lN%emIzXB(*3L3%#OAYDp#zdPS4el1vPsMg5S_(o78W ziYBQg7}!Teu$mqDEQ;KgU+CR(?3;ok2Y;-?7CxdTjwu}%bWd;WjR}c?6EHX|Ghq5b zO)#YTq3&V|Xf#97X+(C&q}{%C*sCgf)?m^V{zw;$(7MqLr-ispbbJi6gK2Zd`{T%l zJAA&9G+*~hVO+M|2pvxP3ewfoWF~xG7^9{`&u{FMMzuA@`gkBUm2K!Vw@C|_fZd2r zPt!e3I+jd>{W@v8>7Gn0Yc+v+jY$zs7ejNqo*Dz)n*;iJR+pm~3YYsvLE< zNHSkWSy>Bfokk=>SgR#zTe2_w!p?#4Lm_YRbH(=IR90V0Hq&v%a5)F>7!T(u3(^%k zEI54UXQ_BN&-?u0KR!-R6hBrxBF@pOWm$Xa5z+M= z9_~d{c_L(v*h>#uRqMcn5uaMB$JG{jgf+O`ru6{pds~0iMs$uX)52nXZY(afp!2ct zJ&F}MR-!6Q>#`%Fpv^x}`q_*pIdra;B|A{^0U$Dni`~T$m`ep3*p9KL}1V=y}JOEzA zKK~MU7F+~fums)wfU7|5|9=903_|c(Z~#n# zSFne_3VsAauot|HJ^Mv)2J8SYU?1KC6W~wSV}BDY0=4(v57hp<0#qAcQSHpH+yl7> zau4Jl$UX4?;(;sTm7DY=H*Sk=I9{#{v<~!?D^y9NjHdGXnkEN|=s?rt2u0TV zity9Leme(>sy8b-fTeZP80AIyC`meOb-X&czi5q@ElcSeD6+Bm?1ro9rcK_CqN>)D zQsj%UgT-v2YSC4!extFp%Kf*avOKKP!H+>5p4PMPHuNOk8njW_lh%U4)OXD&PZ>L? zz6M%4!k6u|8jPiN)FfsMt3h9+m0%dHr9_RnjFy2dN|e@uF|?MJj_Y?NPw5$GF(RcW zT5;9!A$|<2PDYU7h^~6Dkqn^NOB3ZOB}8aZb?jK9Z7G9VskE}PQuJ*Bcu@2OW5t%} zm4eQ4$q{x`Qk(6H`P-1{fyus!eZ{CPJ02nNjnXF~wOXsvkZy-JLgu%)o)Q{TG++!Y zlr**y+m$y zO}`dmW>C$hbx*od9SoTo^PKr~bPFuwm$ge!YD$>9Qf#KPev6w5_pRS0Cqf=2{b{^x z9n?mfrr}ZGpwX&qgx`|W8MoQwc(R5QFBKSZ)2S3A`oc1uHXDg$ruO+s$KI}ib=&Tm whcRf2wvbX|;etR!V-7wk0xFvNd0+oPK@Xfb%&8~om=1IF#s3<~`{PLdFJM!%s{jB1 From 4487321eb3926c461145278b69120f4c7d095119 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Wed, 17 Jun 2026 23:20:38 +0000 Subject: [PATCH 26/63] Per #1518, reverting logic in find_record_matches() back to what it was to make the unit tests happier. ci-run-unit --- src/libcode/vx_data2d_grib2/data2d_grib2.cc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/libcode/vx_data2d_grib2/data2d_grib2.cc b/src/libcode/vx_data2d_grib2/data2d_grib2.cc index 349416d98a..9bc5e7317c 100644 --- a/src/libcode/vx_data2d_grib2/data2d_grib2.cc +++ b/src/libcode/vx_data2d_grib2/data2d_grib2.cc @@ -489,12 +489,10 @@ void MetGrib2DataFile::find_record_matches(const VarInfoGrib2* vinfo, } // test for an index or field name match - else if( ( vinfo->req_name().empty() && - vinfo->discipline() == (*it)->Discipline && - vinfo->parm_cat() == (*it)->ParmCat && - vinfo->parm() == (*it)->Parm ) || - ( vinfo->req_name().nonempty() && - vinfo->req_name().text() == (*it)->ParmName ) ){ + else if ( ( vinfo->discipline() == (*it)->Discipline && + vinfo->parm_cat() == (*it)->ParmCat && + vinfo->parm() == (*it)->Parm ) || + ( vinfo->req_name().text() == (*it)->ParmName ) ){ // test the level type number, if specified if ( !is_bad_data(vinfo->level().type_num()) && From 9112064b22e717dce3e57c6b9fea0574ca34b9c0 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 18 Jun 2026 18:08:12 +0000 Subject: [PATCH 27/63] Trying to eliminate testing workflow failures ci-run-unit --- src/libcode/vx_data2d_grib2/var_info_grib2.cc | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/libcode/vx_data2d_grib2/var_info_grib2.cc b/src/libcode/vx_data2d_grib2/var_info_grib2.cc index fecc0c4339..217b73c97f 100644 --- a/src/libcode/vx_data2d_grib2/var_info_grib2.cc +++ b/src/libcode/vx_data2d_grib2/var_info_grib2.cc @@ -415,10 +415,13 @@ bool VarInfoGrib2::set_dict(Dictionary & dict, bool do_exit) { set_ens (ens_str.c_str()); // set the matched parameter lookup information - set_name ( field_name ); - set_req_name ( field_name.c_str() ); + set_name ( field_name ); + set_req_name ( field_name.c_str() ); if( field_name != "PROB" ){ - set_units ( matches[0].units.c_str() ); + set_discipline( matches[0].disc ); + set_parm_cat ( matches[0].pcat ); + set_parm ( matches[0].pnum ); + set_units ( matches[0].units.c_str() ); set_long_name ( matches[0].full_name.c_str() ); } @@ -461,8 +464,12 @@ bool VarInfoGrib2::set_dict(Dictionary & dict, bool do_exit) { return false; } - set_p_flag(true); - set_units(matches[0].units.c_str()); + set_discipline ( matches[0].disc ); + set_parm_cat ( matches[0].pcat ); + set_parm ( matches[0].pnum ); + set_p_flag ( true ); + set_p_units ( matches[0].units.c_str() ); + set_units ( "%" ); set_prob_info_grib(prob_name, thresh_lo, thresh_hi); From b088d62fdcb2c221a79809add29436fec3ed56a6 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 18 Jun 2026 19:10:57 +0000 Subject: [PATCH 28/63] Per #1518, always read ConfigConstants before reading a config string. --- src/tools/other/point2grid/point2grid.cc | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/tools/other/point2grid/point2grid.cc b/src/tools/other/point2grid/point2grid.cc index ac8278c6a3..0cd1adeffc 100644 --- a/src/tools/other/point2grid/point2grid.cc +++ b/src/tools/other/point2grid/point2grid.cc @@ -360,10 +360,15 @@ static void process_command_line(int argc, char **argv) { StringArray var_names; auto vinfo = VarInfoFactory::new_var_info(FileType_NcMet); for(int i=0; iclear(); + // Populate the VarInfo object using the config string + config.read(replace_path(config_const_filename).c_str()); config.read_string(FieldSA[i].c_str()); vinfo->set_dict(config); + vname = vinfo->name(); if (var_names.has(vname)) { mlog << Error << "\n" << method_name @@ -628,10 +633,15 @@ static int get_obs_type(NcFile *nc) { bool has_attr_grid = false; auto vinfo = VarInfoFactory::new_var_info(FileType_NcCF); for(int i=0; iclear(); + // Populate the VarInfo object using the config string + config.read(replace_path(config_const_filename).c_str()); config.read_string(FieldSA[i].c_str()); vinfo->set_dict(config); + if (vinfo->grid_attr().is_set()) { has_attr_grid = true; break; @@ -816,6 +826,7 @@ void process_point_met_data(MetPointData *met_point_obs, MetConfig &config, VarI vinfo->clear(); // Populate the VarInfo object using the config string + config.read(replace_path(config_const_filename).c_str()); config.read_string(FieldSA[i].c_str()); vinfo->set_dict(config); @@ -1316,11 +1327,15 @@ static void process_point_nccf_file(NcFile *nc_in, MetConfig &config, if (0 < FieldSA.n() && !user_defined_latlon) { ConcatString coordinates_value; auto var_info = VarInfoNcCF(*(VarInfoNcCF *)vinfo); + // Initialize var_info.clear(); + // Populate the VarInfo object using the config string + config.read(replace_path(config_const_filename).c_str()); config.read_string(FieldSA[0].c_str()); var_info.set_dict(config); + NcVar var_data = get_nc_var(nc_in, var_info.name().c_str()); if (get_nc_att_value(&var_data, coordinates_att_name, coordinates_value)) { StringArray sa = coordinates_value.split(" "); @@ -1408,6 +1423,7 @@ static void process_point_nccf_file(NcFile *nc_in, MetConfig &config, var_cell_mapping.clear(); // Populate the VarInfo object using the config string + config.read(replace_path(config_const_filename).c_str()); config.read_string(FieldSA[i].c_str()); vinfo->set_dict(config); @@ -1819,6 +1835,7 @@ static void process_goes_file(NcFile *nc_in, MetConfig &config, VarInfo *vinfo, vinfo->clear(); // Populate the VarInfo object using the config string + config.read(replace_path(config_const_filename).c_str()); config.read_string(FieldSA[i].c_str()); vinfo->set_dict(config); From b7f25d68afff8ce871f3322dabe5840755f33e24 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 18 Jun 2026 22:12:57 +0000 Subject: [PATCH 29/63] Per #1518, more tweaks to try get the unit tests to pass ci-run-unit --- internal/test_unit/config/GridStatConfig_WRF_pres | 3 +++ src/libcode/vx_data2d/data_class.cc | 4 ++++ src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc | 1 + 3 files changed, 8 insertions(+) diff --git a/internal/test_unit/config/GridStatConfig_WRF_pres b/internal/test_unit/config/GridStatConfig_WRF_pres index f94ae7d04d..550cd0e469 100644 --- a/internal/test_unit/config/GridStatConfig_WRF_pres +++ b/internal/test_unit/config/GridStatConfig_WRF_pres @@ -56,6 +56,9 @@ nc_pairs_var_suffix = ""; hss_ec_value = NA; rank_corr_flag = FALSE; +u_wind_field_name = "U_PL"; +v_wind_field_name = "V_PL"; + // // Forecast and observation fields to be verified // diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index ac046c97f5..1e02e3679d 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -841,6 +841,8 @@ for(int i=0; iunits(); vinfo->set_grid_relative_flag(vinfo_cur->is_grid_relative()); + mlog << "Found matching wind field \"" + << vinfo_cur->magic_str() << "\".\n"; break; } } @@ -892,6 +894,8 @@ for(int i=0; iunits(); vinfo->set_grid_relative_flag(vinfo_cur->is_grid_relative()); + mlog << "Found matching wind field(s) \"" + << vinfo_cur->magic_str() << "\".\n"; break; } } diff --git a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc index f23870db2b..73f0c598e7 100644 --- a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc +++ b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc @@ -131,6 +131,7 @@ bool MetNcWrfDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, // Read the data WrfNc->get_nc_var_info(vinfo_nc->req_name().c_str(), info); + if(!info) return false; LongArray dimension = vinfo_nc->dimension(); int dim_count = dimension.n_elements(); for (int k=0; k Date: Mon, 22 Jun 2026 17:38:21 +0000 Subject: [PATCH 30/63] Minor tweak --- src/libcode/vx_data2d/var_info.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcode/vx_data2d/var_info.cc b/src/libcode/vx_data2d/var_info.cc index 7cb73051eb..c4caf2c231 100644 --- a/src/libcode/vx_data2d/var_info.cc +++ b/src/libcode/vx_data2d/var_info.cc @@ -296,7 +296,7 @@ void VarInfo::set_req_name(const char *str) { /////////////////////////////////////////////////////////////////////////////// void VarInfo::set_req_name(const string &str) { - ReqName = str; + set_req_name(str.c_str()); return; } @@ -310,7 +310,7 @@ void VarInfo::set_name(const char *str) { /////////////////////////////////////////////////////////////////////////////// void VarInfo::set_name(const string &str) { - Name = str; + set_name(str.c_str()); return; } @@ -338,7 +338,7 @@ void VarInfo::set_units(const char *str) { /////////////////////////////////////////////////////////////////////////////// void VarInfo::set_units(const string &str) { - Units = str; + set_units(str.c_str()); return; } From d5316c5e6b0e46f653d98600d926262d71bbbccc Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Mon, 22 Jun 2026 19:00:23 +0000 Subject: [PATCH 31/63] Per #1518, add VarInfo::reset_dict_with_name() function and update read_wind_data() to call it. Hopefully that'll parse the wind component data better. ci-run-unit --- src/libcode/vx_data2d/data_class.cc | 48 +++++++++++++---------------- src/libcode/vx_data2d/var_info.cc | 17 ++++++++-- src/libcode/vx_data2d/var_info.h | 4 ++- 3 files changed, 40 insertions(+), 29 deletions(-) diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index 1e02e3679d..cbf9ae5257 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -813,6 +813,8 @@ bool Met2dDataFile::read_wind_data(VarInfo *vinfo, { +static const char *method_name = "Met2dDataFile::read_wind_data(DataPlane) -> "; + if(!vinfo) return false; bool status = false; @@ -824,20 +826,10 @@ VarInfo * vinfo_cur = vinfo->clone(); // Try each of the possible names for(int i=0; iset_req_name(names[i]); - vinfo_cur->set_name(names[i]); - - // Wrap level in parenthesis, if needed - string lstr = vinfo_cur->level_name(); - if(lstr.find(',') != string::npos && - lstr.find('(') == string::npos) { - lstr.insert(0, "("); - lstr.append(")"); - } - vinfo_cur->set_magic(names[i], lstr); - // Retrieve units and grid-relative status - if(data_plane(*vinfo_cur, dp, false)) { + // Check for a match + if(vinfo_cur->reset_dict_with_name(names[i].c_str()) && + data_plane(*vinfo_cur, dp, false)) { status = true; units = vinfo_cur->units(); vinfo->set_grid_relative_flag(vinfo_cur->is_grid_relative()); @@ -851,6 +843,12 @@ for(int i=0; iclone(); // Try each of the possible names for(int i=0; iset_req_name(names[i]); - vinfo_cur->set_name(names[i]); - - // Wrap level in parenthesis, if needed - string lstr = vinfo_cur->level_name(); - if(lstr.find(',') != string::npos && - lstr.find('(') == string::npos) { - lstr.insert(0, "("); - lstr.append(")"); - } - vinfo_cur->set_magic(names[i], lstr); - // Retrieve units and grid-relative status - if(data_plane_array(*vinfo_cur, dpa, false)) { + // Check for a match + if(vinfo_cur->reset_dict_with_name(names[i].c_str()) && + data_plane_array(*vinfo_cur, dpa, false)) { status = true; units = vinfo_cur->units(); vinfo->set_grid_relative_flag(vinfo_cur->is_grid_relative()); @@ -904,6 +894,12 @@ for(int i=0; i Date: Mon, 22 Jun 2026 19:39:13 +0000 Subject: [PATCH 32/63] Per #1518, improve the read_wind_data() warning messages. ci-run-unit --- src/libcode/vx_data2d/data_class.cc | 76 ++++++++++++++++++++--------- src/libcode/vx_data2d/data_class.h | 6 ++- 2 files changed, 56 insertions(+), 26 deletions(-) diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index cbf9ae5257..c1d6b14dd4 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -378,9 +378,13 @@ if(vinfo->need_uv_wind()) { DataPlane vwnd_dp; ConcatString uwnd_units; ConcatString vwnd_units; - status = read_wind_data(vinfo, vinfo->wind_info().u_wind, + status = read_wind_data(vinfo, + conf_key_u_wind_field_name, + vinfo->wind_info().u_wind, uwnd_dp, uwnd_units) && - read_wind_data(vinfo, vinfo->wind_info().v_wind, + read_wind_data(vinfo, + conf_key_v_wind_field_name, + vinfo->wind_info().v_wind, vwnd_dp, vwnd_units); if(status) { @@ -424,9 +428,13 @@ else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { DataPlane wdir_dp; ConcatString wspd_units; ConcatString wdir_units; - status = read_wind_data(vinfo, vinfo->wind_info().wind_speed, + status = read_wind_data(vinfo, + conf_key_wind_speed_field_name, + vinfo->wind_info().wind_speed, wspd_dp, wspd_units) && - read_wind_data(vinfo, vinfo->wind_info().wind_direction, + read_wind_data(vinfo, + conf_key_wind_direction_field_name, + vinfo->wind_info().wind_direction, wdir_dp, wdir_units); // Rotate wind direction, if needed @@ -478,9 +486,13 @@ if(vinfo->need_uv_wind()) { DataPlaneArray vwnd_dpa; ConcatString uwnd_units; ConcatString vwnd_units; - status = read_wind_data(vinfo, vinfo->wind_info().u_wind, + status = read_wind_data(vinfo, + conf_key_u_wind_field_name, + vinfo->wind_info().u_wind, uwnd_dpa, uwnd_units) && - read_wind_data(vinfo, vinfo->wind_info().v_wind, + read_wind_data(vinfo, + conf_key_v_wind_field_name, + vinfo->wind_info().v_wind, vwnd_dpa, vwnd_units); if(!status) return status; @@ -570,9 +582,13 @@ else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { DataPlaneArray wdir_dpa; ConcatString wspd_units; ConcatString wdir_units; - status = read_wind_data(vinfo, vinfo->wind_info().wind_speed, + status = read_wind_data(vinfo, + conf_key_wind_speed_field_name, + vinfo->wind_info().wind_speed, wspd_dpa, wspd_units) && - read_wind_data(vinfo, vinfo->wind_info().wind_direction, + read_wind_data(vinfo, + conf_key_wind_direction_field_name, + vinfo->wind_info().wind_direction, wdir_dpa, wdir_units); if(!status) return status; @@ -676,7 +692,9 @@ ConcatString units; // Rotate U-Wind if(vinfo->is_u_wind()) { uwnd_dp = dp; - status = read_wind_data(vinfo, vinfo->wind_info().v_wind, + status = read_wind_data(vinfo, + conf_key_v_wind_field_name, + vinfo->wind_info().v_wind, vwnd_dp, units); if(status) status = rotate_uv_grid_to_earth(uwnd_dp, vwnd_dp, *Raw_Grid, @@ -685,7 +703,9 @@ if(vinfo->is_u_wind()) { // Rotate V-Wind else if(vinfo->is_v_wind()) { vwnd_dp = dp; - status = read_wind_data(vinfo, vinfo->wind_info().u_wind, + status = read_wind_data(vinfo, + conf_key_u_wind_field_name, + vinfo->wind_info().u_wind, uwnd_dp, units); if(status) status = rotate_uv_grid_to_earth(uwnd_dp, vwnd_dp, *Raw_Grid, @@ -748,14 +768,18 @@ if(vinfo->is_u_wind() || vinfo->is_v_wind()) { uwnd_dpa = dpa; uwnd_out = &dpa; vwnd_out = &tmp_dpa; - status = read_wind_data(vinfo, vinfo->wind_info().v_wind, + status = read_wind_data(vinfo, + conf_key_v_wind_field_name, + vinfo->wind_info().v_wind, vwnd_dpa, units); } else { vwnd_dpa = dpa; uwnd_out = &tmp_dpa; vwnd_out = &dpa; - status = read_wind_data(vinfo, vinfo->wind_info().u_wind, + status = read_wind_data(vinfo, + conf_key_u_wind_field_name, + vinfo->wind_info().u_wind, uwnd_dpa, units); } @@ -807,6 +831,7 @@ return status; bool Met2dDataFile::read_wind_data(VarInfo *vinfo, + const char *conf_key_name, const StringArray &names, DataPlane &dp, ConcatString &units) @@ -839,16 +864,17 @@ for(int i=0; i Date: Mon, 22 Jun 2026 20:38:39 +0000 Subject: [PATCH 33/63] Per #1518, refined wind rotation log messages #ci-run-unit --- src/libcode/vx_data2d/data2d_utils.cc | 6 ------ src/libcode/vx_data2d/data_class.cc | 27 ++++++++++++++++++--------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/libcode/vx_data2d/data2d_utils.cc b/src/libcode/vx_data2d/data2d_utils.cc index 8dc3dfff30..efecb12efa 100644 --- a/src/libcode/vx_data2d/data2d_utils.cc +++ b/src/libcode/vx_data2d/data2d_utils.cc @@ -333,9 +333,6 @@ void rotate_wind_direction_grid_to_earth( const int nx = wdir2d.nx(); const int ny = wdir2d.ny(); - mlog << Debug(3) - << "Rotating wind direction from grid-relative to earth-relative.\n"; - // // Initialize by setting to u2d // @@ -394,9 +391,6 @@ bool rotate_uv_grid_to_earth( const int nx = u2d.nx(); const int ny = u2d.ny(); - mlog << Debug(3) - << "Rotating U and V wind components from grid-relative to earth-relative.\n"; - // // Check that the dimensions match // diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index c1d6b14dd4..531b8b90a2 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -673,15 +673,18 @@ if(!vinfo) return false; if(!vinfo->is_wind_rotation()) return true; -if(vinfo->is_wind_rotation() && !vinfo->is_grid_relative()) { - mlog << Debug(3) << "Wind field \"" << vinfo->magic_str() - << "\" is already defined as earth-relative.\n"; +if(vinfo->is_grid_relative()) { + mlog << Debug(3) << "Rotating wind field \"" + << vinfo->magic_str() + << "\" from grid-relative to earth-relative.\n"; +} +else { + mlog << Debug(3) << "Identified wind field \"" + << vinfo->magic_str() + << "\" as being earth-relative.\n"; return true; } - // - // Apply conversion logic - bool status = false; DataPlane uwnd_dp; @@ -746,9 +749,15 @@ if(!vinfo) return false; if(!vinfo->is_wind_rotation()) return true; -if(vinfo->is_wind_rotation() && !vinfo->is_grid_relative()) { - mlog << Debug(3) << "Wind field \"" << vinfo->magic_str() - << "\" is already defined as earth-relative.\n"; +if(vinfo->is_grid_relative()) { + mlog << Debug(3) << "Rotating " << dpa.n_planes() + << " wind field(s) for \"" << vinfo->magic_str() + << "\" from grid-relative to earth-relative.\n"; +} +else { + mlog << Debug(3) << "Identified " << dpa.n_planes() + << " wind field(s) for \"" << vinfo->magic_str() + << "\" as being earth-relative.\n"; return true; } From 4d675b0c9f8cf318e750870b2875ecdf03d636e6 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Mon, 22 Jun 2026 21:17:57 +0000 Subject: [PATCH 34/63] Per #1518, handle wind rotation before calling process_data_plane(). That's the order of the logic in the develop branch and changing it caused differences in the unit test output. --- src/libcode/vx_data2d_grib/data2d_grib.cc | 14 +++++++----- src/libcode/vx_data2d_grib2/data2d_grib2.cc | 22 ++++++++++++------- src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc | 4 ++-- src/libcode/vx_data2d_nc_met/data2d_nc_met.cc | 4 ++-- src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc | 11 ++++++---- src/libcode/vx_data2d_python/data2d_python.cc | 8 +++---- src/libcode/vx_data2d_ugrid/data2d_ugrid.cc | 7 ++---- 7 files changed, 39 insertions(+), 31 deletions(-) diff --git a/src/libcode/vx_data2d_grib/data2d_grib.cc b/src/libcode/vx_data2d_grib/data2d_grib.cc index b67afed071..e0c7e2ad17 100644 --- a/src/libcode/vx_data2d_grib/data2d_grib.cc +++ b/src/libcode/vx_data2d_grib/data2d_grib.cc @@ -503,12 +503,6 @@ int MetGrib1DataFile::data_plane_array(VarInfo &vinfo, // Read current record status = get_data_plane(r, cur_plane); - if(status) { - // Store whether winds are grid relative - vinfo.set_grid_relative_flag(is_grid_relative(r)); - status = process_data_plane(&vinfo, cur_plane); - } - if(!status) { cur_plane.clear(); lower = upper = bad_data_int; @@ -518,6 +512,9 @@ int MetGrib1DataFile::data_plane_array(VarInfo &vinfo, continue; } + // Store whether winds are grid relative + vinfo.set_grid_relative_flag(is_grid_relative(r)); + // Add current record to the data plane array plane_array.add(cur_plane, (double) lower, (double) upper); @@ -532,6 +529,11 @@ int MetGrib1DataFile::data_plane_array(VarInfo &vinfo, derive_winds(&vinfo, plane_array); } + // Post-process each data plane + for(int i=0; i " << "Found " << plane_array.n_planes() << " GRIB records matching VarInfo \"" diff --git a/src/libcode/vx_data2d_grib2/data2d_grib2.cc b/src/libcode/vx_data2d_grib2/data2d_grib2.cc index 9bc5e7317c..5a68564a5d 100644 --- a/src/libcode/vx_data2d_grib2/data2d_grib2.cc +++ b/src/libcode/vx_data2d_grib2/data2d_grib2.cc @@ -182,10 +182,11 @@ bool MetGrib2DataFile::data_plane(VarInfo &vinfo, DataPlane &plane, plane = plane_array[0]; - bool status = process_data_plane(vinfo_g2, plane); - // handle wind rotation - if(status && do_winds) status = rotate_winds(vinfo_g2, plane); + bool status = true; + if(do_winds) status = rotate_winds(vinfo_g2, plane); + + if(status) status = process_data_plane(vinfo_g2, plane); return status; @@ -230,10 +231,12 @@ bool MetGrib2DataFile::data_plane(VarInfo &vinfo, DataPlane &plane, bool status = read_grib2_record_data_plane(listMatch[0], plane); if(status) { - vinfo_g2->set_grid_relative_flag(is_grid_relative(listMatch[0])); - status = process_data_plane(vinfo_g2, plane); + // handle wind rotation + vinfo_g2->set_grid_relative_flag(is_grid_relative(listMatch[0])); if(status && do_winds) status = rotate_winds(vinfo_g2, plane); + + if(status) status = process_data_plane(vinfo_g2, plane); } return status; @@ -351,14 +354,17 @@ int MetGrib2DataFile::data_plane_array(VarInfo &vinfo, vinfo_g2->set_grid_relative_flag(is_grid_relative(*it)); // add current plane to the data plane array - if(process_data_plane(vinfo_g2, plane)) { - plane_array.add(plane, lvl_lower, lvl_upper); - } + plane_array.add(plane, lvl_lower, lvl_upper); } // handle wind rotation if(do_winds) rotate_winds(vinfo_g2, plane_array); + // post-process each data plane + for(int i=0; iname_att.empty()) diff --git a/src/libcode/vx_data2d_nc_met/data2d_nc_met.cc b/src/libcode/vx_data2d_nc_met/data2d_nc_met.cc index 3623354898..6a1a72fc48 100644 --- a/src/libcode/vx_data2d_nc_met/data2d_nc_met.cc +++ b/src/libcode/vx_data2d_nc_met/data2d_nc_met.cc @@ -286,11 +286,11 @@ bool MetNcMetDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, status = false; } - status = process_data_plane(&vinfo, plane); - // Handle wind rotation if(status && do_winds) status = rotate_winds(&vinfo, plane); + if(status) status = process_data_plane(&vinfo, plane); + // Set the VarInfo object's name, long_name, level, and units strings if(info->name_att.length() > 0) vinfo.set_name(info->name_att); else vinfo.set_name(info->name); diff --git a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc index 73f0c598e7..ea47f513e1 100644 --- a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc +++ b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc @@ -184,11 +184,11 @@ bool MetNcWrfDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, status = false; } - status = process_data_plane(&vinfo, plane); - // Handle wind rotation if(status && do_winds) status = rotate_winds(&vinfo, plane); + if(status) status = process_data_plane(&vinfo, plane); + // Set the VarInfo object's name, long_name, and units strings // Note that info is null for derived fields if(info) { @@ -292,8 +292,6 @@ int MetNcWrfDataFile::data_plane_array(VarInfo &vinfo, status = false; } - status = process_data_plane(&vinfo, cur_plane); - // Add current plane to the data plane array plane_array.add(cur_plane, pressure, pressure); } @@ -301,6 +299,11 @@ int MetNcWrfDataFile::data_plane_array(VarInfo &vinfo, // Handle wind rotation if(do_winds) rotate_winds(&vinfo, plane_array); + // post-process each data plane + for(int i=0; iname_att.empty()) From a200bdc19c6727d9f22c8d7acaad20967098a85e Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Mon, 22 Jun 2026 21:49:00 +0000 Subject: [PATCH 35/63] Per #1518, update gen_ens_prod and ensemble_stat to clone the VarInfo object prior to reading data since deriving/rotating winds can affect the contents of the VarInfo object. ci-run-unit --- src/tools/core/ensemble_stat/ensemble_stat.cc | 27 ++++++++++++++----- src/tools/other/gen_ens_prod/gen_ens_prod.cc | 12 ++++++--- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/tools/core/ensemble_stat/ensemble_stat.cc b/src/tools/core/ensemble_stat/ensemble_stat.cc index 550975473b..32ff10acb5 100644 --- a/src/tools/core/ensemble_stat/ensemble_stat.cc +++ b/src/tools/core/ensemble_stat/ensemble_stat.cc @@ -629,9 +629,15 @@ static void process_n_vld() { //////////////////////////////////////////////////////////////////////// static bool get_data_plane(const char *infile, GrdFileType ftype, - VarInfo *info, DataPlane &dp, bool do_regrid) { + VarInfo *in_var_info, DataPlane &dp, + bool do_regrid) { bool found; + if(!in_var_info) return false; + + // Clone local copy since reading data can affect contents + VarInfo *info = in_var_info->clone(); + // Read the current ensemble file auto mtddf = Met2dDataFileFactory::new_met_2d_data_file(infile, ftype); if(!mtddf) { @@ -673,8 +679,9 @@ static bool get_data_plane(const char *infile, GrdFileType ftype, } // end if found - // Deallocate the data file pointer, if necessary - if(mtddf) { delete mtddf; mtddf = (Met2dDataFile *) nullptr; } + // Cleanup + if(info) { delete info; info = nullptr; } + if(mtddf) { delete mtddf; mtddf = nullptr; } return found; } @@ -682,12 +689,17 @@ static bool get_data_plane(const char *infile, GrdFileType ftype, //////////////////////////////////////////////////////////////////////// static bool get_data_plane_array(const char *infile, GrdFileType ftype, - VarInfo *info, DataPlaneArray &dpa, + VarInfo *in_var_info, DataPlaneArray &dpa, bool do_regrid) { bool found; - auto mtddf = Met2dDataFileFactory::new_met_2d_data_file(infile, ftype); + + if(!in_var_info) return false; + + // Clone local copy since reading data can affect contents + VarInfo *info = in_var_info->clone(); // Read the current ensemble file + auto mtddf = Met2dDataFileFactory::new_met_2d_data_file(infile, ftype); if(!mtddf) { mlog << Error << "\nget_data_plane_array() -> " << "trouble reading file \"" << infile << "\"\n\n"; @@ -740,8 +752,9 @@ static bool get_data_plane_array(const char *infile, GrdFileType ftype, } // end if found - // Deallocate the data file pointer, if necessary - if(mtddf) { delete mtddf; mtddf = (Met2dDataFile *) nullptr; } + // Cleanup + if(info) { delete info; info = nullptr; } + if(mtddf) { delete mtddf; mtddf = nullptr; } return found; } diff --git a/src/tools/other/gen_ens_prod/gen_ens_prod.cc b/src/tools/other/gen_ens_prod/gen_ens_prod.cc index 7dd034c144..8c3dd6859e 100644 --- a/src/tools/other/gen_ens_prod/gen_ens_prod.cc +++ b/src/tools/other/gen_ens_prod/gen_ens_prod.cc @@ -656,10 +656,15 @@ static void get_ens_mean_stdev(GenEnsProdVarInfo *ens_info, //////////////////////////////////////////////////////////////////////// static bool get_data_plane(const char *infile, GrdFileType ftype, - VarInfo *info, DataPlane &dp) { + VarInfo *in_var_info, DataPlane &dp) { bool found; Met2dDataFile *mtddf = nullptr; + if(!in_var_info) return false; + + // Clone local copy since reading data can affect contents + VarInfo *info = in_var_info->clone(); + // Read the current ensemble file if(!(mtddf = Met2dDataFileFactory::new_met_2d_data_file(infile, ftype))) { mlog << Error << "\nget_data_plane() -> " @@ -700,8 +705,9 @@ static bool get_data_plane(const char *infile, GrdFileType ftype, } // end if found - // Deallocate the data file pointer, if necessary - if(mtddf) { delete mtddf; mtddf = (Met2dDataFile *) nullptr; } + // Cleanup + if(info) { delete info; info = nullptr; } + if(mtddf) { delete mtddf; mtddf = nullptr; } return found; } From a49227f8c17c8e3f9c55466f3cc7c7f8f9409f86 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 23 Jun 2026 14:13:17 +0000 Subject: [PATCH 36/63] Per #1518, abandon VarInfo::set_earth_relative() since that logic wreaks havoc when processing paired VL1L2 winds. Use a VarInfo::clone() in read_wind_data() and nowhere else. --- src/libcode/vx_data2d/data_class.cc | 42 +++++++------------ src/libcode/vx_data2d/var_info.cc | 8 ---- src/libcode/vx_data2d/var_info.h | 1 - src/tools/core/ensemble_stat/ensemble_stat.cc | 16 ++----- src/tools/other/gen_ens_prod/gen_ens_prod.cc | 12 ++---- 5 files changed, 22 insertions(+), 57 deletions(-) diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index 531b8b90a2..a5e214e485 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -395,7 +395,6 @@ if(vinfo->need_uv_wind()) { DataPlane vwnd_dp_orig(vwnd_dp); rotate_uv_grid_to_earth(uwnd_dp_orig, vwnd_dp_orig, *Raw_Grid, uwnd_dp, vwnd_dp); - vinfo->set_earth_relative(); } // Derive wind speed @@ -442,7 +441,6 @@ else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { DataPlane wdir_dp_orig(wdir_dp); rotate_wind_direction_grid_to_earth(wdir_dp_orig, *Raw_Grid, wdir_dp); - vinfo->set_earth_relative(); } if(status) { @@ -506,7 +504,6 @@ if(vinfo->need_uv_wind()) { *Raw_Grid, uwnd_dpa.at(i), vwnd_dpa.at(i)); } - vinfo->set_earth_relative(); } // Store the long name and units @@ -599,7 +596,6 @@ else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { DataPlane wdir_dp_orig(wdir_dpa[i]); rotate_wind_direction_grid_to_earth(wdir_dp_orig, *Raw_Grid, wdir_dpa.at(i)); - vinfo->set_earth_relative(); } } @@ -726,10 +722,6 @@ if(!status) { << "Trouble rotating wind field (" << vinfo->magic_str() << ") from grid to earth relative.\n\n"; } -// Update flag for a successful rotation -else { - vinfo->set_earth_relative(); -} return status; @@ -826,10 +818,6 @@ if(!status) { << "Trouble rotating wind fields (" << vinfo->magic_str() << ") from grid to earth relative.\n\n"; } -// Update flag for a successful rotation -else { - vinfo->set_earth_relative(); -} return status; @@ -855,20 +843,19 @@ bool status = false; // Copy input VarInfo -VarInfo * vinfo_cur = vinfo->clone(); +VarInfo * vinfo_copy = vinfo->clone(); // Try each of the possible names for(int i=0; ireset_dict_with_name(names[i].c_str()) && - data_plane(*vinfo_cur, dp, false)) { + // Find matching data with no more wind processing + if(vinfo_copy->reset_dict_with_name(names[i].c_str()) && + data_plane(*vinfo_copy, dp, false)) { status = true; - units = vinfo_cur->units(); - vinfo->set_grid_relative_flag(vinfo_cur->is_grid_relative()); + units = vinfo_copy->units(); mlog << "Found matching wind field \"" - << vinfo_cur->magic_str() << "\".\n"; + << vinfo_copy->magic_str() << "\".\n"; break; } } @@ -882,7 +869,7 @@ if(!status) { // Cleanup -if(vinfo_cur) { delete vinfo_cur; vinfo_cur = nullptr; } +if(vinfo_copy) { delete vinfo_copy; vinfo_copy = nullptr; } return status; @@ -908,20 +895,19 @@ bool status = false; // Copy input VarInfo -VarInfo * vinfo_cur = vinfo->clone(); +VarInfo * vinfo_copy = vinfo->clone(); // Try each of the possible names for(int i=0; ireset_dict_with_name(names[i].c_str()) && - data_plane_array(*vinfo_cur, dpa, false)) { + // Find matching data with no more wind processing + if(vinfo_copy->reset_dict_with_name(names[i].c_str()) && + data_plane_array(*vinfo_copy, dpa, false)) { status = true; - units = vinfo_cur->units(); - vinfo->set_grid_relative_flag(vinfo_cur->is_grid_relative()); + units = vinfo_copy->units(); mlog << "Found matching wind field(s) \"" - << vinfo_cur->magic_str() << "\".\n"; + << vinfo_copy->magic_str() << "\".\n"; break; } } @@ -935,7 +921,7 @@ if(!status) { // Cleanup -if(vinfo_cur) { delete vinfo_cur; vinfo_cur = nullptr; } +if(vinfo_copy) { delete vinfo_copy; vinfo_copy = nullptr; } return status; diff --git a/src/libcode/vx_data2d/var_info.cc b/src/libcode/vx_data2d/var_info.cc index 4adfd013f1..15a7daaaa2 100644 --- a/src/libcode/vx_data2d/var_info.cc +++ b/src/libcode/vx_data2d/var_info.cc @@ -486,14 +486,6 @@ void VarInfo::set_grid_relative_flag(bool f) { /////////////////////////////////////////////////////////////////////////////// -void VarInfo::set_earth_relative() { - GridRelativeFlag = false; - SetAttrIsGridRelative = 0; - return; -} - -/////////////////////////////////////////////////////////////////////////////// - void VarInfo::set_magic(const ConcatString &nstr, const ConcatString &lstr) { // Check for embedded whitespace diff --git a/src/libcode/vx_data2d/var_info.h b/src/libcode/vx_data2d/var_info.h index 236bbbd0ce..726606077b 100644 --- a/src/libcode/vx_data2d/var_info.h +++ b/src/libcode/vx_data2d/var_info.h @@ -209,7 +209,6 @@ class VarInfo void set_regrid(const RegridInfo &); void set_grid_relative_flag(bool); - void set_earth_relative(); void set_level_info_grib(Dictionary & dict); void set_prob_info_grib(ConcatString prob_name, diff --git a/src/tools/core/ensemble_stat/ensemble_stat.cc b/src/tools/core/ensemble_stat/ensemble_stat.cc index 32ff10acb5..789db67454 100644 --- a/src/tools/core/ensemble_stat/ensemble_stat.cc +++ b/src/tools/core/ensemble_stat/ensemble_stat.cc @@ -629,14 +629,11 @@ static void process_n_vld() { //////////////////////////////////////////////////////////////////////// static bool get_data_plane(const char *infile, GrdFileType ftype, - VarInfo *in_var_info, DataPlane &dp, + VarInfo *info, DataPlane &dp, bool do_regrid) { bool found; - if(!in_var_info) return false; - - // Clone local copy since reading data can affect contents - VarInfo *info = in_var_info->clone(); + if(!info) return false; // Read the current ensemble file auto mtddf = Met2dDataFileFactory::new_met_2d_data_file(infile, ftype); @@ -680,7 +677,6 @@ static bool get_data_plane(const char *infile, GrdFileType ftype, } // end if found // Cleanup - if(info) { delete info; info = nullptr; } if(mtddf) { delete mtddf; mtddf = nullptr; } return found; @@ -689,14 +685,11 @@ static bool get_data_plane(const char *infile, GrdFileType ftype, //////////////////////////////////////////////////////////////////////// static bool get_data_plane_array(const char *infile, GrdFileType ftype, - VarInfo *in_var_info, DataPlaneArray &dpa, + VarInfo *info, DataPlaneArray &dpa, bool do_regrid) { bool found; - if(!in_var_info) return false; - - // Clone local copy since reading data can affect contents - VarInfo *info = in_var_info->clone(); + if(!info) return false; // Read the current ensemble file auto mtddf = Met2dDataFileFactory::new_met_2d_data_file(infile, ftype); @@ -753,7 +746,6 @@ static bool get_data_plane_array(const char *infile, GrdFileType ftype, } // end if found // Cleanup - if(info) { delete info; info = nullptr; } if(mtddf) { delete mtddf; mtddf = nullptr; } return found; diff --git a/src/tools/other/gen_ens_prod/gen_ens_prod.cc b/src/tools/other/gen_ens_prod/gen_ens_prod.cc index 8c3dd6859e..bd9bb974fb 100644 --- a/src/tools/other/gen_ens_prod/gen_ens_prod.cc +++ b/src/tools/other/gen_ens_prod/gen_ens_prod.cc @@ -656,17 +656,14 @@ static void get_ens_mean_stdev(GenEnsProdVarInfo *ens_info, //////////////////////////////////////////////////////////////////////// static bool get_data_plane(const char *infile, GrdFileType ftype, - VarInfo *in_var_info, DataPlane &dp) { + VarInfo *info, DataPlane &dp) { bool found; - Met2dDataFile *mtddf = nullptr; - if(!in_var_info) return false; - - // Clone local copy since reading data can affect contents - VarInfo *info = in_var_info->clone(); + if(!info) return false; // Read the current ensemble file - if(!(mtddf = Met2dDataFileFactory::new_met_2d_data_file(infile, ftype))) { + auto mtddf = Met2dDataFileFactory::new_met_2d_data_file(infile, ftype); + if(!mtddf) { mlog << Error << "\nget_data_plane() -> " << "trouble reading file \"" << infile << "\"\n\n"; exit(1); @@ -706,7 +703,6 @@ static bool get_data_plane(const char *infile, GrdFileType ftype, } // end if found // Cleanup - if(info) { delete info; info = nullptr; } if(mtddf) { delete mtddf; mtddf = nullptr; } return found; From 746b667a8fb4c7dc31a997b1fc0c07f3156591b8 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 23 Jun 2026 15:32:30 +0000 Subject: [PATCH 37/63] Per #1518, refine log message formatting and update existing plots of U-wind from WRF to demonstrate use is_grid_relative=false and produce the same output as before. --- internal/test_unit/xml/unit_plot_data_plane.xml | 4 ++-- src/libcode/vx_data2d/data_class.cc | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/internal/test_unit/xml/unit_plot_data_plane.xml b/internal/test_unit/xml/unit_plot_data_plane.xml index e42b275e41..999773a57d 100644 --- a/internal/test_unit/xml/unit_plot_data_plane.xml +++ b/internal/test_unit/xml/unit_plot_data_plane.xml @@ -615,7 +615,7 @@ \ &DATA_DIR_MODEL;/wrf/wrfout_solarwind_d02_2019-08-31_12:00:00 \ &OUTPUT_DIR;/plot_data_plane/wrf_west_east_stag.ps \ - 'name="U"; level="(0,0,*,*)";' \ + 'name="U"; level="(0,0,*,*)"; is_grid_relative=false;' \ -title "X-wind component (staggered)" \ -v 1 @@ -629,7 +629,7 @@ \ &DATA_DIR_MODEL;/wrf/wrfout_solarwind_d02_2019-08-31_12:00:00 \ &OUTPUT_DIR;/plot_data_plane/wrf_south_north_stag.ps \ - 'name="V"; level="(0,0,*,*)";' \ + 'name="V"; level="(0,0,*,*)"; is_grid_relative=false;' \ -title "Y-wind component (staggered)" \ -v 1 diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index a5e214e485..ed5587e611 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -863,7 +863,8 @@ for(int i=0; i Date: Tue, 23 Jun 2026 17:11:55 +0000 Subject: [PATCH 38/63] Per #1518, patch pcp_combine.cc read_field to read the -field config strings into a copy of the MetConfig object to avoid settings from one -field option from being passed along to the next one. --- src/tools/core/pcp_combine/pcp_combine.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/tools/core/pcp_combine/pcp_combine.cc b/src/tools/core/pcp_combine/pcp_combine.cc index 5cee4ab207..0e580490ad 100644 --- a/src/tools/core/pcp_combine/pcp_combine.cc +++ b/src/tools/core/pcp_combine/pcp_combine.cc @@ -1308,18 +1308,19 @@ static bool get_field(const char *filename, ConcatString config_str = parse_config_str(cur_field); mlog << Debug(1) - << "Reading data (" << config_str + << "\nReading data (" << config_str << ") from input file: " << filename << "\n"; // - // Parse the config string. + // Parse the config string into a local copy. // - config.read_string(config_str.c_str()); + MetConfig cur_config = config; + cur_config.read_string(config_str.c_str()); // // Get the gridded file type from config string, if present. // - ftype = parse_conf_file_type(&config); + ftype = parse_conf_file_type(&cur_config); // // If not set by the config string, use the file list type. @@ -1368,7 +1369,7 @@ static bool get_field(const char *filename, // // Initialize the VarInfo object with a config. // - cur_var->set_dict(config); + cur_var->set_dict(cur_config); // // Set the VarInfo timing object. From 5b070cb1d7dd955409d8ce1aff87ff0260c3d4b6 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 23 Jun 2026 17:15:30 +0000 Subject: [PATCH 39/63] Per #1518, log each wind rotation operation. --- src/libcode/vx_data2d/data_class.cc | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index ed5587e611..32cf1d029e 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -393,6 +393,8 @@ if(vinfo->need_uv_wind()) { if(vinfo->need_rotation()) { DataPlane uwnd_dp_orig(uwnd_dp); DataPlane vwnd_dp_orig(vwnd_dp); + mlog << Debug(3) << "Rotating U and V wind fields " + << "from grid-relative to earth-relative.\n"; rotate_uv_grid_to_earth(uwnd_dp_orig, vwnd_dp_orig, *Raw_Grid, uwnd_dp, vwnd_dp); } @@ -439,6 +441,8 @@ else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { // Rotate wind direction, if needed if(vinfo->need_rotation()) { DataPlane wdir_dp_orig(wdir_dp); + mlog << Debug(3) << "Rotating wind direction field " + << "from grid-relative to earth-relative.\n"; rotate_wind_direction_grid_to_earth(wdir_dp_orig, *Raw_Grid, wdir_dp); } @@ -497,6 +501,9 @@ if(vinfo->need_uv_wind()) { // Rotate U/V winds, if needed if(vinfo->need_rotation()) { + mlog << Debug(3) << "Rotating " << uwnd_dpa.n_planes() + << " U and V wind fields from grid-relative " + << "to earth-relative.\n"; for(int i=0; iis_u_wind() || vinfo->is_v_wind()) { // Rotate wind direction, if needed if(vinfo->need_rotation()) { + mlog << Debug(3) << "Rotating " << wdir_dpa.n_planes() + << " wind direction field(s) from grid-relative" + << "to earth-relative.\n"; for(int i=0; i Date: Tue, 23 Jun 2026 18:13:33 +0000 Subject: [PATCH 40/63] Per #1518, move clone() operation up in the logic from read_wind_data() to the upstream derive_winds() and rotate_winds() functions. When deriving wind_direction, we need to know if the U and V components are grid or earth relative. --- src/libcode/vx_data2d/data_class.cc | 164 ++++++++++++++++------------ src/libcode/vx_data2d/data_class.h | 4 +- 2 files changed, 94 insertions(+), 74 deletions(-) diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index 32cf1d029e..6ffa1ba7ef 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -374,23 +374,27 @@ bool status = false; // if(vinfo->need_uv_wind()) { + + // Create local copies + VarInfo * vinfo_uwnd = vinfo->clone(); + VarInfo * vinfo_vwnd = vinfo->clone(); + DataPlane uwnd_dp; DataPlane vwnd_dp; - ConcatString uwnd_units; - ConcatString vwnd_units; - status = read_wind_data(vinfo, + status = read_wind_data(vinfo_uwnd, conf_key_u_wind_field_name, vinfo->wind_info().u_wind, - uwnd_dp, uwnd_units) && - read_wind_data(vinfo, + uwnd_dp) && + read_wind_data(vinfo_vwnd, conf_key_v_wind_field_name, vinfo->wind_info().v_wind, - vwnd_dp, vwnd_units); + vwnd_dp); if(status) { // Rotate U/V winds, if needed - if(vinfo->need_rotation()) { + if(vinfo_uwnd->need_rotation() && + vinfo_vwnd->need_rotation()) { DataPlane uwnd_dp_orig(uwnd_dp); DataPlane vwnd_dp_orig(vwnd_dp); mlog << Debug(3) << "Rotating U and V wind fields " @@ -403,7 +407,7 @@ if(vinfo->need_uv_wind()) { if(vinfo->is_wind_speed()) { status = derive_wind_speed(uwnd_dp, vwnd_dp, dp); vinfo->set_long_name("Wind Speed"); - vinfo->set_units(uwnd_units); + vinfo->set_units(vinfo_uwnd->units()); } // Derive wind direction else if(vinfo->is_wind_direction()) { @@ -418,6 +422,10 @@ if(vinfo->need_uv_wind()) { vinfo->set_units("J/kg"); } } + + // Cleanup + if(vinfo_uwnd) { delete vinfo_uwnd; vinfo_uwnd = nullptr; } + if(vinfo_vwnd) { delete vinfo_vwnd; vinfo_vwnd = nullptr; } } // @@ -425,21 +433,24 @@ if(vinfo->need_uv_wind()) { // else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { + + // Create local copies + VarInfo * vinfo_wspd = vinfo->clone(); + VarInfo * vinfo_wdir = vinfo->clone(); + DataPlane wspd_dp; DataPlane wdir_dp; - ConcatString wspd_units; - ConcatString wdir_units; - status = read_wind_data(vinfo, + status = read_wind_data(vinfo_wspd, conf_key_wind_speed_field_name, vinfo->wind_info().wind_speed, - wspd_dp, wspd_units) && - read_wind_data(vinfo, + wspd_dp) && + read_wind_data(vinfo_wdir, conf_key_wind_direction_field_name, vinfo->wind_info().wind_direction, - wdir_dp, wdir_units); + wdir_dp); // Rotate wind direction, if needed - if(vinfo->need_rotation()) { + if(vinfo_wdir->need_rotation()) { DataPlane wdir_dp_orig(wdir_dp); mlog << Debug(3) << "Rotating wind direction field " << "from grid-relative to earth-relative.\n"; @@ -451,14 +462,18 @@ else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { if(vinfo->is_u_wind()) { status = derive_u_wind(wspd_dp, wdir_dp, dp); vinfo->set_long_name("U-Component of Wind"); - vinfo->set_units(wspd_units); + vinfo->set_units(vinfo_wspd->units()); } else { status = derive_v_wind(wspd_dp, wdir_dp, dp); vinfo->set_long_name("V-Component of Wind"); - vinfo->set_units(wspd_units); + vinfo->set_units(vinfo_wspd->units()); } } + + // Cleanup + if(vinfo_wspd) { delete vinfo_wspd; vinfo_wspd = nullptr; } + if(vinfo_wdir) { delete vinfo_wdir; vinfo_wdir = nullptr; } } return status; @@ -484,23 +499,27 @@ bool status = false; // if(vinfo->need_uv_wind()) { + + // Create local copies + VarInfo * vinfo_uwnd = vinfo->clone(); + VarInfo * vinfo_vwnd = vinfo->clone(); + DataPlaneArray uwnd_dpa; DataPlaneArray vwnd_dpa; - ConcatString uwnd_units; - ConcatString vwnd_units; - status = read_wind_data(vinfo, + status = read_wind_data(vinfo_uwnd, conf_key_u_wind_field_name, vinfo->wind_info().u_wind, - uwnd_dpa, uwnd_units) && - read_wind_data(vinfo, + uwnd_dpa) && + read_wind_data(vinfo_vwnd, conf_key_v_wind_field_name, vinfo->wind_info().v_wind, - vwnd_dpa, vwnd_units); + vwnd_dpa); if(!status) return status; // Rotate U/V winds, if needed - if(vinfo->need_rotation()) { + if(vinfo_uwnd->need_rotation() && + vinfo_vwnd->need_rotation()) { mlog << Debug(3) << "Rotating " << uwnd_dpa.n_planes() << " U and V wind fields from grid-relative " << "to earth-relative.\n"; @@ -516,7 +535,7 @@ if(vinfo->need_uv_wind()) { // Store the long name and units if(vinfo->is_wind_speed()) { vinfo->set_long_name("Wind Speed"); - vinfo->set_units(uwnd_units); + vinfo->set_units(vinfo_uwnd->units()); } else if(vinfo->is_wind_direction()) { vinfo->set_long_name("Wind Direction"); @@ -575,6 +594,10 @@ if(vinfo->need_uv_wind()) { // Store the result dpa.add(dp, uwnd_dpa.lower(i), uwnd_dpa.upper(i)); } + + // Cleanup + if(vinfo_uwnd) { delete vinfo_uwnd; vinfo_uwnd = nullptr; } + if(vinfo_vwnd) { delete vinfo_vwnd; vinfo_vwnd = nullptr; } } // @@ -582,23 +605,26 @@ if(vinfo->need_uv_wind()) { // else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { + + // Create local copies + VarInfo * vinfo_wspd = vinfo->clone(); + VarInfo * vinfo_wdir = vinfo->clone(); + DataPlaneArray wspd_dpa; DataPlaneArray wdir_dpa; - ConcatString wspd_units; - ConcatString wdir_units; - status = read_wind_data(vinfo, + status = read_wind_data(vinfo_wspd, conf_key_wind_speed_field_name, vinfo->wind_info().wind_speed, - wspd_dpa, wspd_units) && - read_wind_data(vinfo, + wspd_dpa) && + read_wind_data(vinfo_wdir, conf_key_wind_direction_field_name, vinfo->wind_info().wind_direction, - wdir_dpa, wdir_units); + wdir_dpa); if(!status) return status; // Rotate wind direction, if needed - if(vinfo->need_rotation()) { + if(vinfo_wdir->need_rotation()) { mlog << Debug(3) << "Rotating " << wdir_dpa.n_planes() << " wind direction field(s) from grid-relative" << "to earth-relative.\n"; @@ -612,11 +638,11 @@ else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { // Store the long name and units if(vinfo->is_u_wind()) { vinfo->set_long_name("U-Component of Wind"); - vinfo->set_units(wspd_units); + vinfo->set_units(vinfo_wspd->units()); } else { vinfo->set_long_name("V-Component of Wind"); - vinfo->set_units(wspd_units); + vinfo->set_units(vinfo_wspd->units()); } if(wspd_dpa.n_planes() != wdir_dpa.n_planes()) { @@ -659,6 +685,10 @@ else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { // Store the result dpa.add(dp, wspd_dpa.lower(i), wspd_dpa.upper(i)); } + + // Cleanup + if(vinfo_wspd) { delete vinfo_wspd; vinfo_wspd = nullptr; } + if(vinfo_wdir) { delete vinfo_wdir; vinfo_wdir = nullptr; } } return status; @@ -693,18 +723,20 @@ else { bool status = false; +// Create local copy +VarInfo * vinfo_wind = vinfo->clone(); + DataPlane uwnd_dp; DataPlane vwnd_dp; DataPlane tmp_dp; -ConcatString units; // Rotate U-Wind if(vinfo->is_u_wind()) { uwnd_dp = dp; - status = read_wind_data(vinfo, + status = read_wind_data(vinfo_wind, conf_key_v_wind_field_name, vinfo->wind_info().v_wind, - vwnd_dp, units); + vwnd_dp); if(status) status = rotate_uv_grid_to_earth(uwnd_dp, vwnd_dp, *Raw_Grid, dp, tmp_dp); @@ -712,10 +744,10 @@ if(vinfo->is_u_wind()) { // Rotate V-Wind else if(vinfo->is_v_wind()) { vwnd_dp = dp; - status = read_wind_data(vinfo, + status = read_wind_data(vinfo_wind, conf_key_u_wind_field_name, vinfo->wind_info().u_wind, - uwnd_dp, units); + uwnd_dp); if(status) status = rotate_uv_grid_to_earth(uwnd_dp, vwnd_dp, *Raw_Grid, tmp_dp, dp); @@ -733,6 +765,9 @@ if(!status) { << ") from grid to earth relative.\n\n"; } +// Cleanup +if(vinfo_wind) { delete vinfo_wind; vinfo_wind = nullptr; } + return status; } @@ -765,10 +800,12 @@ else { bool status = false; +// Create local copy +VarInfo * vinfo_wind = vinfo->clone(); + DataPlaneArray uwnd_dpa; DataPlaneArray vwnd_dpa; DataPlaneArray tmp_dpa(dpa); -ConcatString units; DataPlaneArray *uwnd_out; DataPlaneArray *vwnd_out; @@ -779,19 +816,19 @@ if(vinfo->is_u_wind() || vinfo->is_v_wind()) { uwnd_dpa = dpa; uwnd_out = &dpa; vwnd_out = &tmp_dpa; - status = read_wind_data(vinfo, + status = read_wind_data(vinfo_wind, conf_key_v_wind_field_name, vinfo->wind_info().v_wind, - vwnd_dpa, units); + vwnd_dpa); } else { vwnd_dpa = dpa; uwnd_out = &tmp_dpa; vwnd_out = &dpa; - status = read_wind_data(vinfo, + status = read_wind_data(vinfo_wind, conf_key_u_wind_field_name, vinfo->wind_info().u_wind, - uwnd_dpa, units); + uwnd_dpa); } // Check for matching levels @@ -829,6 +866,9 @@ if(!status) { << ") from grid to earth relative.\n\n"; } +// Cleanup +if(vinfo_wind) { delete vinfo_wind; vinfo_wind = nullptr; } + return status; } @@ -840,8 +880,7 @@ return status; bool Met2dDataFile::read_wind_data(VarInfo *vinfo, const char *conf_key_name, const StringArray &names, - DataPlane &dp, - ConcatString &units) + DataPlane &dp) { @@ -851,21 +890,16 @@ if(!vinfo) return false; bool status = false; - // Copy input VarInfo - -VarInfo * vinfo_copy = vinfo->clone(); - // Try each of the possible names for(int i=0; ireset_dict_with_name(names[i].c_str()) && - data_plane(*vinfo_copy, dp, false)) { + if(vinfo->reset_dict_with_name(names[i].c_str()) && + data_plane(*vinfo, dp, false)) { status = true; - units = vinfo_copy->units(); mlog << "Found matching wind field \"" - << vinfo_copy->magic_str() << "\".\n"; + << vinfo->magic_str() << "\".\n"; break; } } @@ -878,10 +912,6 @@ if(!status) { << "\" to specify the matching variable name.\n\n"; } - // Cleanup - -if(vinfo_copy) { delete vinfo_copy; vinfo_copy = nullptr; } - return status; } @@ -893,8 +923,7 @@ return status; bool Met2dDataFile::read_wind_data(VarInfo *vinfo, const char *conf_key_name, const StringArray &names, - DataPlaneArray &dpa, - ConcatString &units) + DataPlaneArray &dpa) { @@ -904,21 +933,16 @@ if(!vinfo) return false; bool status = false; - // Copy input VarInfo - -VarInfo * vinfo_copy = vinfo->clone(); - // Try each of the possible names for(int i=0; ireset_dict_with_name(names[i].c_str()) && - data_plane_array(*vinfo_copy, dpa, false)) { + if(vinfo->reset_dict_with_name(names[i].c_str()) && + data_plane_array(*vinfo, dpa, false)) { status = true; - units = vinfo_copy->units(); mlog << "Found matching wind field(s) \"" - << vinfo_copy->magic_str() << "\".\n"; + << vinfo->magic_str() << "\".\n"; break; } } @@ -931,10 +955,6 @@ if(!status) { << "\" to specify the matching variable name.\n\n"; } - // Cleanup - -if(vinfo_copy) { delete vinfo_copy; vinfo_copy = nullptr; } - return status; } diff --git a/src/libcode/vx_data2d/data_class.h b/src/libcode/vx_data2d/data_class.h index 8484439cb2..cde545a3e2 100644 --- a/src/libcode/vx_data2d/data_class.h +++ b/src/libcode/vx_data2d/data_class.h @@ -85,10 +85,10 @@ class Met2dDataFile : public Met2dData { bool read_wind_data(VarInfo *, const char *, const StringArray &, - DataPlane &, ConcatString &); + DataPlane &); bool read_wind_data(VarInfo *, const char *, const StringArray &, - DataPlaneArray &, ConcatString &); + DataPlaneArray &); bool GridShifted; From f605d9099bca715de9a663e2bf83f505daf1b1c8 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 23 Jun 2026 20:47:15 +0000 Subject: [PATCH 41/63] More tweaks --- src/libcode/vx_data2d/data_class.cc | 12 ++++-- src/libcode/vx_data2d/var_info.cc | 8 ++++ src/libcode/vx_data2d/var_info.h | 1 + src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc | 41 ++++++++++--------- 4 files changed, 39 insertions(+), 23 deletions(-) diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index 6ffa1ba7ef..975dc26f23 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -393,7 +393,8 @@ if(vinfo->need_uv_wind()) { if(status) { // Rotate U/V winds, if needed - if(vinfo_uwnd->need_rotation() && + if(vinfo->is_wind_rotation() && + vinfo_uwnd->need_rotation() && vinfo_vwnd->need_rotation()) { DataPlane uwnd_dp_orig(uwnd_dp); DataPlane vwnd_dp_orig(vwnd_dp); @@ -412,6 +413,7 @@ if(vinfo->need_uv_wind()) { // Derive wind direction else if(vinfo->is_wind_direction()) { status = derive_wind_direction(uwnd_dp, vwnd_dp, dp); + vinfo->set_earth_relative(); vinfo->set_long_name("Wind Direction"); vinfo->set_units("deg"); } @@ -456,6 +458,7 @@ else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { << "from grid-relative to earth-relative.\n"; rotate_wind_direction_grid_to_earth(wdir_dp_orig, *Raw_Grid, wdir_dp); + vinfo->set_earth_relative(); } if(status) { @@ -518,7 +521,8 @@ if(vinfo->need_uv_wind()) { if(!status) return status; // Rotate U/V winds, if needed - if(vinfo_uwnd->need_rotation() && + if(vinfo->is_wind_rotation() && + vinfo_uwnd->need_rotation() && vinfo_vwnd->need_rotation()) { mlog << Debug(3) << "Rotating " << uwnd_dpa.n_planes() << " U and V wind fields from grid-relative " @@ -538,6 +542,7 @@ if(vinfo->need_uv_wind()) { vinfo->set_units(vinfo_uwnd->units()); } else if(vinfo->is_wind_direction()) { + vinfo->set_earth_relative(); vinfo->set_long_name("Wind Direction"); vinfo->set_units("deg"); } @@ -626,13 +631,14 @@ else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { // Rotate wind direction, if needed if(vinfo_wdir->need_rotation()) { mlog << Debug(3) << "Rotating " << wdir_dpa.n_planes() - << " wind direction field(s) from grid-relative" + << " wind direction field(s) from grid-relative " << "to earth-relative.\n"; for(int i=0; iset_earth_relative(); } // Store the long name and units diff --git a/src/libcode/vx_data2d/var_info.cc b/src/libcode/vx_data2d/var_info.cc index 15a7daaaa2..4adfd013f1 100644 --- a/src/libcode/vx_data2d/var_info.cc +++ b/src/libcode/vx_data2d/var_info.cc @@ -486,6 +486,14 @@ void VarInfo::set_grid_relative_flag(bool f) { /////////////////////////////////////////////////////////////////////////////// +void VarInfo::set_earth_relative() { + GridRelativeFlag = false; + SetAttrIsGridRelative = 0; + return; +} + +/////////////////////////////////////////////////////////////////////////////// + void VarInfo::set_magic(const ConcatString &nstr, const ConcatString &lstr) { // Check for embedded whitespace diff --git a/src/libcode/vx_data2d/var_info.h b/src/libcode/vx_data2d/var_info.h index 726606077b..236bbbd0ce 100644 --- a/src/libcode/vx_data2d/var_info.h +++ b/src/libcode/vx_data2d/var_info.h @@ -209,6 +209,7 @@ class VarInfo void set_regrid(const RegridInfo &); void set_grid_relative_flag(bool); + void set_earth_relative(); void set_level_info_grib(Dictionary & dict); void set_prob_info_grib(ConcatString prob_name, diff --git a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc index ea47f513e1..e8e1926a13 100644 --- a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc +++ b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc @@ -129,30 +129,31 @@ bool MetNcWrfDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, // Initialize the data plane plane.clear(); - // Read the data + // Assume that all WRF winds are grid-relative + vinfo_nc->set_grid_relative_flag(true); + + // Read the data if found WrfNc->get_nc_var_info(vinfo_nc->req_name().c_str(), info); - if(!info) return false; - LongArray dimension = vinfo_nc->dimension(); - int dim_count = dimension.n_elements(); - for (int k=0; kvar, k)); - NcVarInfo *var_info = find_var_info_by_dim_name(WrfNc->Var, dim_name, - WrfNc->Nvars); - if (var_info) { - long new_offset = get_index_at_nc_data(var_info->var, - vinfo_nc->dim_value(k), - dim_name, (k == info->t_slot)); - if (new_offset != bad_data_int) dimension[k] = new_offset; + if(info) { + LongArray dimension = vinfo_nc->dimension(); + int dim_count = dimension.n_elements(); + for (int k=0; kvar, k)); + NcVarInfo *var_info = find_var_info_by_dim_name(WrfNc->Var, dim_name, + WrfNc->Nvars); + if (var_info) { + long new_offset = get_index_at_nc_data(var_info->var, + vinfo_nc->dim_value(k), + dim_name, (k == info->t_slot)); + if (new_offset != bad_data_int) dimension[k] = new_offset; + } } } - } - - status = WrfNc->data(vinfo_nc->req_name().c_str(), - dimension, plane, pressure, info); - // Assume that WRF winds are grid-relative - vinfo_nc->set_grid_relative_flag(true); + status = WrfNc->data(vinfo_nc->req_name().c_str(), + dimension, plane, pressure, info); + } // Attempt to derive the data if(!status && do_winds) { From c7b147a57200e3e2aa77943092d0fe07b270d5a4 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 23 Jun 2026 20:52:20 +0000 Subject: [PATCH 42/63] Per #1518, add unit_winds.xml to demonstrate the new functionality. ci-run-unit --- .github/workflows/testing.yml | 2 +- internal/test_unit/bin/unit_test.sh | 1 + internal/test_unit/xml/unit_winds.xml | 90 +++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 internal/test_unit/xml/unit_winds.xml diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 1e9bf089f3..ed3dbd6496 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -148,7 +148,7 @@ jobs: - jobid: 'job1' tests: 'ascii2nc' - jobid: 'job2' - tests: 'pb2nc madis2nc pcp_combine gen_ens_prod regrid' + tests: 'pb2nc madis2nc pcp_combine gen_ens_prod regrid winds' fail-fast: false steps: - uses: actions/checkout@v6 diff --git a/internal/test_unit/bin/unit_test.sh b/internal/test_unit/bin/unit_test.sh index 5679f26bdc..bb0ebb8f73 100755 --- a/internal/test_unit/bin/unit_test.sh +++ b/internal/test_unit/bin/unit_test.sh @@ -41,6 +41,7 @@ UNIT_XML="unit_ascii2nc.xml \ unit_gen_ens_prod.xml \ unit_pcp_combine.xml \ unit_regrid.xml \ + unit_winds.xml \ unit_wwmca_regrid.xml \ unit_point_stat.xml \ unit_stat_analysis_ps.xml \ diff --git a/internal/test_unit/xml/unit_winds.xml b/internal/test_unit/xml/unit_winds.xml new file mode 100644 index 0000000000..7bfea78d0c --- /dev/null +++ b/internal/test_unit/xml/unit_winds.xml @@ -0,0 +1,90 @@ + + + + + + + + + +]> + + + + + + &TEST_DIR; + true + + + + + + + + &MET_BIN;/pcp_combine + \ + -add &DATA_DIR_MODEL;/grib1/nam/nam_2012040900_F012.grib \ + -field 'name="UGRD"; level="Z10"; set_attr_name="UWIND_GRID"; is_grid_relative=false;' \ + -field 'name="UGRD"; level="Z10"; set_attr_name="UWIND_EARTH";' \ + -field 'name="VGRD"; level="Z10"; set_attr_name="VWIND_GRID"; is_grid_relative=false;' \ + -field 'name="VGRD"; level="Z10"; set_attr_name="VWIND_EARTH";' \ + -field 'name="WDIR"; level="Z10"; set_attr_name="D_WDIR_GRID"; is_grid_relative=false;' \ + -field 'name="WDIR"; level="Z10"; set_attr_name="D_WDIR_EARTH";' \ + -field 'name="WIND"; level="Z10"; set_attr_name="D_WIND";' \ + -field 'name="KENG"; level="Z10"; set_attr_name="D_KENG";' \ + &OUTPUT_DIR;/winds/pcp_combine_nam_winds_GRIB1.nc \ + -v 3 + + + &OUTPUT_DIR;/winds/pcp_combine_nam_winds_GRIB1.nc + + + + + + + + + + &MET_BIN;/pcp_combine + \ + -add &DATA_DIR_MODEL;/grib2/nbm/blend.t13z.core.f119.co.grib2 \ + -field 'name="UGRD"; level="Z10"; set_attr_name="D_UWIND";' \ + -field 'name="VGRD"; level="Z10"; set_attr_name="D_VWIND";' \ + -field 'name="WDIR"; level="Z10"; set_attr_name="WDIR";' \ + -field 'name="WDIR"; level="Z10"; set_attr_name="WDIR_ROTATE"; is_grid_relative=true;' \ + -field 'name="WIND"; level="Z10"; set_attr_name="WIND";' \ + &OUTPUT_DIR;/winds/pcp_combine_nbm_winds_GRIB2.nc \ + -v 3 + + + &OUTPUT_DIR;/winds/pcp_combine_nbm_winds_GRIB2.nc + + + + + + + + + &MET_BIN;/pcp_combine + \ + -add &DATA_DIR_MODEL;/wrf/wrfout_solarwind_d02_2019-08-31_12:00:00 \ + -field 'name="U10"; level="(0,*,*)"; set_attr_name="U10_GRID"; v_wind_field_name="V10"; is_grid_relative=false;' \ + -field 'name="U10"; level="(0,*,*)"; set_attr_name="U10_EARTH"; v_wind_field_name="V10";' \ + -field 'name="V10"; level="(0,*,*)"; set_attr_name="V10_GRID"; u_wind_field_name="U10"; is_grid_relative=false;' \ + -field 'name="V10"; level="(0,*,*)"; set_attr_name="V10_EARTH"; u_wind_field_name="U10";' \ + -field 'name="WDIR10"; level="(0,*,*)"; set_attr_name="WDIR10_GRID"; is_wind_direction=true; u_wind_field_name="U10"; v_wind_field_name="V10"; is_grid_relative=false;' \ + -field 'name="WDIR10"; level="(0,*,*)"; set_attr_name="WDIR10_EARTH"; is_wind_direction=true; u_wind_field_name="U10"; v_wind_field_name="V10";' \ + -field 'name="WIND10"; level="(0,*,*)"; is_wind_speed=true; u_wind_field_name="U10"; v_wind_field_name="V10";' \ + &OUTPUT_DIR;/winds/pcp_combine_winds_NETCDF_WRF.nc \ + -v 3 + + + &OUTPUT_DIR;/winds/pcp_combine_winds_NETCDF_WRF.nc + + + + From 99a7f69eae1e7e0f66498018c22f4c39d38d1312 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 23 Jun 2026 21:18:03 +0000 Subject: [PATCH 43/63] Start doc updates --- docs/Users_Guide/config_options.rst | 34 +++++++++++++++++++++++++++++ docs/Users_Guide/point-stat.rst | 8 +++++++ 2 files changed, 42 insertions(+) diff --git a/docs/Users_Guide/config_options.rst b/docs/Users_Guide/config_options.rst index 3b0d1cc264..d55addc1a3 100644 --- a/docs/Users_Guide/config_options.rst +++ b/docs/Users_Guide/config_options.rst @@ -661,6 +661,40 @@ Some tools override the temporary directory by the command line argument A description of the use of temporary files in MET can be found in :numref:`Contributor's Guide Section %s `. +.. _config_wind_field_names: + +wind_field_names +---------------- + +As described in :numref:`PS_wind_rotation_derivation`, MET can automatically +derive wind variables and also rotate them from being grid-relative to earth-relative. +Logic is provided for each supported input file type to identify input wind components +and determine whether they are defined as being grid-relative or earth-relative. + +The following configuration options can be set to refine the metadata, when needed: + +.. code-block:: none + + is_u_wind = boolean; + is_v_wind = boolean; + is_grid_relative = boolean; + is_wind_speed = boolean; + is_wind_direction = boolean; + +When deriving and rotating winds, MET searches the input file for matching wind +components. That search is driven by the following configuration options: + +.. code-block:: none + + u_wind_field_name = "UGRD,U"; + v_wind_field_name = "VGRD,V"; + wind_speed_field_name = "WIND,SP"; + wind_direction_field_name = "WDIR,DD"; + +Each is a comma-separated list of wind variable names to be searched. Users can +explicity set these options to configure what data should be used in the wind +derivation and rotation logic. + message_type_group_map ---------------------- diff --git a/docs/Users_Guide/point-stat.rst b/docs/Users_Guide/point-stat.rst index 50a80be722..e3d99607ba 100644 --- a/docs/Users_Guide/point-stat.rst +++ b/docs/Users_Guide/point-stat.rst @@ -117,6 +117,14 @@ _______________________ The forecast value at P is chosen as the grid point inside the interpolation area whose value most closely matches the observation value. +.. _PS_wind_rotation_derivation: + +Wind Rotation and Derivation +---------------------------- + +JHG work here + + .. _PS_HiRA_framework: HiRA Framework From e0c2d45b193df798d2d6023002794368a293eced Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Wed, 24 Jun 2026 04:09:59 +0000 Subject: [PATCH 44/63] Per #1518, add logic to read_wind_data() when converting U to V or vice-versa try swapping the U's and V's and searching for that string first. Also update unit_winds.xml to no longer set u_wind_field_name and v_wind_field_name for a couple of fields. --- internal/test_unit/xml/unit_winds.xml | 8 ++-- src/libcode/vx_data2d/data_class.cc | 61 ++++++++++++++++++++++++--- 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/internal/test_unit/xml/unit_winds.xml b/internal/test_unit/xml/unit_winds.xml index 7bfea78d0c..6638db36b9 100644 --- a/internal/test_unit/xml/unit_winds.xml +++ b/internal/test_unit/xml/unit_winds.xml @@ -72,10 +72,10 @@ &MET_BIN;/pcp_combine \ -add &DATA_DIR_MODEL;/wrf/wrfout_solarwind_d02_2019-08-31_12:00:00 \ - -field 'name="U10"; level="(0,*,*)"; set_attr_name="U10_GRID"; v_wind_field_name="V10"; is_grid_relative=false;' \ - -field 'name="U10"; level="(0,*,*)"; set_attr_name="U10_EARTH"; v_wind_field_name="V10";' \ - -field 'name="V10"; level="(0,*,*)"; set_attr_name="V10_GRID"; u_wind_field_name="U10"; is_grid_relative=false;' \ - -field 'name="V10"; level="(0,*,*)"; set_attr_name="V10_EARTH"; u_wind_field_name="U10";' \ + -field 'name="U10"; level="(0,*,*)"; set_attr_name="U10_GRID"; is_grid_relative=false;' \ + -field 'name="U10"; level="(0,*,*)"; set_attr_name="U10_EARTH";' \ + -field 'name="V10"; level="(0,*,*)"; set_attr_name="V10_GRID"; is_grid_relative=false;' \ + -field 'name="V10"; level="(0,*,*)"; set_attr_name="V10_EARTH";' \ -field 'name="WDIR10"; level="(0,*,*)"; set_attr_name="WDIR10_GRID"; is_wind_direction=true; u_wind_field_name="U10"; v_wind_field_name="V10"; is_grid_relative=false;' \ -field 'name="WDIR10"; level="(0,*,*)"; set_attr_name="WDIR10_EARTH"; is_wind_direction=true; u_wind_field_name="U10"; v_wind_field_name="V10";' \ -field 'name="WIND10"; level="(0,*,*)"; is_wind_speed=true; u_wind_field_name="U10"; v_wind_field_name="V10";' \ diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index 975dc26f23..81555e9791 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -24,6 +24,14 @@ using namespace std; +//////////////////////////////////////////////////////////////////////// + + +static StringArray swap_uv_name(VarInfo *, + const ConcatString &, + const StringArray &); + + //////////////////////////////////////////////////////////////////////// @@ -896,12 +904,16 @@ if(!vinfo) return false; bool status = false; + // Update search names, if needed + +StringArray search_names(swap_uv_name(vinfo, conf_key_name, names)); + // Try each of the possible names -for(int i=0; ireset_dict_with_name(names[i].c_str()) && + if(vinfo->reset_dict_with_name(search_names[i].c_str()) && data_plane(*vinfo, dp, false)) { status = true; mlog << "Found matching wind field \"" @@ -913,7 +925,7 @@ for(int i=0; ireset_dict_with_name(names[i].c_str()) && + if(vinfo->reset_dict_with_name(search_names[i].c_str()) && data_plane_array(*vinfo, dpa, false)) { status = true; mlog << "Found matching wind field(s) \"" @@ -956,7 +972,7 @@ for(int i=0; iname()); + StringArray sa(names); + + // Replace U with V + if(vinfo->is_u_wind() && + conf_key_name == conf_key_v_wind_field_name) { + cs.replace("U", "V", false); + cs.replace("u", "v", false); + if(cs != vinfo->name()) sa.insert(0, cs.c_str()); + } + // Replace V with U + else if(vinfo->is_v_wind() && + conf_key_name == conf_key_u_wind_field_name) { + cs.replace("V", "U", false); + cs.replace("v", "u", false); + if(cs != vinfo->name()) sa.insert(0, cs.c_str()); + } + + return sa; + +} + + //////////////////////////////////////////////////////////////////////// From 35b248228e5de4207746b765b71aae1e4e9aa779 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Wed, 24 Jun 2026 04:43:14 +0000 Subject: [PATCH 45/63] Per #1518, update docs about wind rotation. --- docs/Users_Guide/point-stat.rst | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/Users_Guide/point-stat.rst b/docs/Users_Guide/point-stat.rst index e3d99607ba..020d60070d 100644 --- a/docs/Users_Guide/point-stat.rst +++ b/docs/Users_Guide/point-stat.rst @@ -122,8 +122,27 @@ The forecast value at P is chosen as the grid point inside the interpolation are Wind Rotation and Derivation ---------------------------- -JHG work here +Numerical weather prediction model output often defines winds relative to the orientation of the model grid rather than true north-south and east-west directions on the earth. +However point observations typically define winds relative to true earth directions. Prior to comparing them, the model wind data must be rotated from grid-relative to +to earth-relative. While the degree of grid-to-earth rotation varies based on the projection type and location, failing to rotate the winds has a significant impact on +the verification results. +For simplicity, the MET library code attempts to rotate all wind components from being grid-relative to earth-relative regardless of whether they are being compared to point +observations or gridded analyses. Running the MET tools at verbosity level 3 (-v 3) prints log messages to describing the wind rotation process. + +Wind fields which must be rotated include wind direction and both the U and V components of the wind vector. While wind direction can be rotated by itself, both U and V are +required to rotate either component. When processing U-wind data, MET attempts to read corresponding V-wind data and vice-versa. + +The configuration options for wind rotation and derivation in MET are described in section :numref:`config_wind_field_names`. + +When reading V-wind data to rotate U-wind or U-wind data to rotate V-wind, MET first searches using the same field name, but with both upper and lowercase U's and V's +swapped (e.g. for "U_PL" search for "V_PL"). If the result is unsuccesful, it searches other common field names specified by the **u_wind_field_name** and **v_wind_field_name** +configuration options. If needed, users should set these configuration options to indicate how the U-wind and V-wind data should be paired. + +In addition to rotating winds, MET can also derive them. If U-wind and V-wind are present in the input file, request field names of **WDIR**, **WIND**, or **KENG** +to derive wind direction, wind speed, and kinetic engery from the U and V components, respectively. If wind speed and direction are present in the input file, request field +names of **UGRD** or **VGRD** for MET to derive the U and V components from them. Depending on the wind field naming conventions, the configuration options described in +:numref:`config_wind_field_names` may be required to configure this derivation logic. .. _PS_HiRA_framework: From 590df6b619a68964f906267fb71ba06a21f6e5f5 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Wed, 24 Jun 2026 04:58:36 +0000 Subject: [PATCH 46/63] Per #1518, note config changes in the upgrade instructions. --- docs/Users_Guide/release-notes.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/Users_Guide/release-notes.rst b/docs/Users_Guide/release-notes.rst index 1e4f1a4abb..5f1f129071 100644 --- a/docs/Users_Guide/release-notes.rst +++ b/docs/Users_Guide/release-notes.rst @@ -182,6 +182,14 @@ MET Version 13.0.0 Upgrade Instructions * The "ensemble_flag.eas" and "ensemble_flag.eas_width" entries are added to enable the writing of EAS output fields. + * ConfigConstanst configuration file + + * The "u_wind_field_name", "v_wind_field_name", "wind_speed_field_name", and "wind_direction_field_name" + entries are comma-separated lists of field names to search when read wind data needed to derive winds + or rotate them from being grid-relative to earth-relative. See :numref:`PS_wind_rotation_derivation` + for a description of wind rotation and derivation and :numref:`config_wind_field_names` for the + corresponding configuration options. + .. dropdown:: Output format changes - NONE .. dropdown:: Output format changes - NONE From 4cf02d2f8f21763990a67534130d157133afd14e Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Wed, 24 Jun 2026 16:02:33 +0000 Subject: [PATCH 47/63] Try reverting from METbaseimage 3.5-latest back to 3.4-latest. The TC-Diag unit test fails in GHA when using 3.4-latest. --- .github/jobs/set_job_controls.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/jobs/set_job_controls.sh b/.github/jobs/set_job_controls.sh index ba11b48b70..818c62c4f0 100755 --- a/.github/jobs/set_job_controls.sh +++ b/.github/jobs/set_job_controls.sh @@ -6,7 +6,8 @@ run_unit_tests=false run_diff=false run_update_truth=false met_base_repo=met-base -met_base_tag=3.5-latest +# TODO: Change 3.4 back to 3.5 after solving TC-Diag failure +met_base_tag=3.4-latest input_data_version=develop truth_data_version=develop From f46f15cb9f6f5fbb2b468e6eeea4239d947ef2fb Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 25 Jun 2026 17:46:01 +0000 Subject: [PATCH 48/63] Per #1518, don't need to specify u_wind_field and v_wind_field_name after adding the swap UV logic. --- internal/test_unit/config/GridStatConfig_WRF_pres | 3 --- 1 file changed, 3 deletions(-) diff --git a/internal/test_unit/config/GridStatConfig_WRF_pres b/internal/test_unit/config/GridStatConfig_WRF_pres index 550cd0e469..f94ae7d04d 100644 --- a/internal/test_unit/config/GridStatConfig_WRF_pres +++ b/internal/test_unit/config/GridStatConfig_WRF_pres @@ -56,9 +56,6 @@ nc_pairs_var_suffix = ""; hss_ec_value = NA; rank_corr_flag = FALSE; -u_wind_field_name = "U_PL"; -v_wind_field_name = "V_PL"; - // // Forecast and observation fields to be verified // From 4303156035453948e127d5e3fc40e59860ba54cf Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 25 Jun 2026 19:58:43 +0000 Subject: [PATCH 49/63] Per #1518, solve 3 SonarQube findings. --- src/basic/vx_config/config_constants.h | 6 ++--- src/basic/vx_config/config_util.cc | 32 +++++++++++++------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/basic/vx_config/config_constants.h b/src/basic/vx_config/config_constants.h index ca67556191..83539369ba 100644 --- a/src/basic/vx_config/config_constants.h +++ b/src/basic/vx_config/config_constants.h @@ -294,7 +294,7 @@ struct InterpInfo { ~InterpInfo() { clear(); } InterpInfo(InterpInfo const &i) { *this = i; } InterpInfo &operator=(const InterpInfo &a) noexcept; // SonarQube findings - bool operator==(const InterpInfo &) const; + friend bool operator==(const InterpInfo &lhs, const InterpInfo &rhs); void clear(); void validate(); // Ensure that width and method are accordant }; @@ -450,7 +450,7 @@ struct MaskLatLon { ~MaskLatLon() { clear(); } MaskLatLon(MaskLatLon const &i) { *this = i; } MaskLatLon &operator=(const MaskLatLon &a) noexcept; - bool operator==(const MaskLatLon &) const; + friend bool operator==(const MaskLatLon &lhs, const MaskLatLon &rhs); void clear(); }; @@ -470,7 +470,7 @@ struct WindMetadata { ~WindMetadata() { clear(); } WindMetadata(WindMetadata const &i) { *this = i; } WindMetadata &operator=(const WindMetadata &a) noexcept; - bool operator==(const WindMetadata &) const; + friend bool operator==(const WindMetadata &lhs, const WindMetadata &rhs); void clear(); bool is_u_wind(const std::string &s) const { return u_wind.has(s); } diff --git a/src/basic/vx_config/config_util.cc b/src/basic/vx_config/config_util.cc index 941ceac733..83b97ffb5d 100644 --- a/src/basic/vx_config/config_util.cc +++ b/src/basic/vx_config/config_util.cc @@ -743,12 +743,12 @@ void MaskLatLon::clear() { /////////////////////////////////////////////////////////////////////////////// -bool MaskLatLon::operator==(const MaskLatLon &v) const { +bool operator==(const MaskLatLon &lhs, const MaskLatLon &rhs) { bool match = true; - if(!(name == v.name ) || - !(lat_thresh == v.lat_thresh) || - !(lon_thresh == v.lon_thresh)) { + if(!(lhs.name == rhs.name ) || + !(lhs.lat_thresh == rhs.lat_thresh) || + !(lhs.lon_thresh == rhs.lon_thresh)) { match = false; } @@ -832,13 +832,13 @@ void WindMetadata::clear() { /////////////////////////////////////////////////////////////////////////////// -bool WindMetadata::operator==(const WindMetadata &v) const { +bool operator==(const WindMetadata &lhs, const WindMetadata &rhs) { bool match = true; - if(!(u_wind == v.u_wind ) || - !(v_wind == v.v_wind ) || - !(wind_speed == v.wind_speed ) || - !(wind_direction == v.wind_direction)) { + if(!(lhs.u_wind == rhs.u_wind ) || + !(lhs.v_wind == rhs.v_wind ) || + !(lhs.wind_speed == rhs.wind_speed ) || + !(lhs.wind_direction == rhs.wind_direction)) { match = false; } @@ -1802,15 +1802,15 @@ void InterpInfo::validate() { /////////////////////////////////////////////////////////////////////////////// -bool InterpInfo::operator==(const InterpInfo &v) const { +bool operator==(const InterpInfo &lhs, const InterpInfo &rhs) { bool match = true; - if(!(field == v.field ) || - !(vld_thresh == v.vld_thresh) || - !(n_interp == v.n_interp ) || - !(method == v.method ) || - !(width == v.width ) || - !(shape == v.shape )) { + if(!(lhs.field == rhs.field ) || + !(lhs.vld_thresh == rhs.vld_thresh) || + !(lhs.n_interp == rhs.n_interp ) || + !(lhs.method == rhs.method ) || + !(lhs.width == rhs.width ) || + !(lhs.shape == rhs.shape )) { match = false; } From a114fa963d04072433f1ad1d0c70cd3f4a9e7e79 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 25 Jun 2026 20:05:45 +0000 Subject: [PATCH 50/63] Per #1518, solve SonarQube findings in data_class.h/.cc. --- src/libcode/vx_data2d/data_class.cc | 22 +++++++++++----------- src/libcode/vx_data2d/data_class.h | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index 81555e9791..049f1d8e25 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -713,7 +713,7 @@ return status; //////////////////////////////////////////////////////////////////////// -bool Met2dDataFile::rotate_winds(VarInfo *vinfo, DataPlane &dp) +bool Met2dDataFile::rotate_winds(const VarInfo *vinfo, DataPlane &dp) { @@ -790,7 +790,7 @@ return status; //////////////////////////////////////////////////////////////////////// -bool Met2dDataFile::rotate_winds(VarInfo *vinfo, DataPlaneArray &dpa) +bool Met2dDataFile::rotate_winds(const VarInfo *vinfo, DataPlaneArray &dpa) { @@ -892,7 +892,7 @@ return status; bool Met2dDataFile::read_wind_data(VarInfo *vinfo, - const char *conf_key_name, + const char *conf_key, const StringArray &names, DataPlane &dp) @@ -906,7 +906,7 @@ bool status = false; // Update search names, if needed -StringArray search_names(swap_uv_name(vinfo, conf_key_name, names)); +StringArray search_names(swap_uv_name(vinfo, conf_key, names)); // Try each of the possible names @@ -926,7 +926,7 @@ if(!status) { mlog << Warning << "\n" << method_name << "No matching wind field found for name(s) \"" << write_css(search_names) << "\".\n" - << "Set \"" << conf_key_name + << "Set \"" << conf_key << "\" to specify the matching variable name.\n\n"; } @@ -939,7 +939,7 @@ return status; bool Met2dDataFile::read_wind_data(VarInfo *vinfo, - const char *conf_key_name, + const char *conf_key, const StringArray &names, DataPlaneArray &dpa) @@ -953,7 +953,7 @@ bool status = false; // Update search names, if needed -StringArray search_names(swap_uv_name(vinfo, conf_key_name, names)); +StringArray search_names(swap_uv_name(vinfo, conf_key, names)); // Try each of the possible names @@ -973,7 +973,7 @@ if(!status) { mlog << Warning << "\n" << method_name << "No matching wind field(s) found for name(s) \"" << write_css(search_names) << "\".\n" - << "Set \"" << conf_key_name + << "Set \"" << conf_key << "\" to specify the matching variable name.\n\n"; } @@ -1082,7 +1082,7 @@ return true; static StringArray swap_uv_name(VarInfo *vinfo, - const ConcatString &conf_key_name, + const ConcatString &conf_key, const StringArray &names) { @@ -1093,14 +1093,14 @@ static StringArray swap_uv_name(VarInfo *vinfo, // Replace U with V if(vinfo->is_u_wind() && - conf_key_name == conf_key_v_wind_field_name) { + conf_key == conf_key_v_wind_field_name) { cs.replace("U", "V", false); cs.replace("u", "v", false); if(cs != vinfo->name()) sa.insert(0, cs.c_str()); } // Replace V with U else if(vinfo->is_v_wind() && - conf_key_name == conf_key_u_wind_field_name) { + conf_key == conf_key_u_wind_field_name) { cs.replace("V", "U", false); cs.replace("v", "u", false); if(cs != vinfo->name()) sa.insert(0, cs.c_str()); diff --git a/src/libcode/vx_data2d/data_class.h b/src/libcode/vx_data2d/data_class.h index cde545a3e2..de36548069 100644 --- a/src/libcode/vx_data2d/data_class.h +++ b/src/libcode/vx_data2d/data_class.h @@ -167,8 +167,8 @@ class Met2dDataFile : public Met2dData { bool derive_winds(VarInfo *, DataPlane &); bool derive_winds(VarInfo *, DataPlaneArray &); - bool rotate_winds(VarInfo *, DataPlane &); - bool rotate_winds(VarInfo *, DataPlaneArray &); + bool rotate_winds(const VarInfo *, DataPlane &); + bool rotate_winds(const VarInfo *, DataPlaneArray &); // post-process data after reading it From 61bd643db502e8f2fede64f4fb90feb1e553d1ce Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 25 Jun 2026 20:10:52 +0000 Subject: [PATCH 51/63] Per #1518, make GRIB table lookup functions const to satisfy SonarQube. --- src/libcode/vx_data2d/table_lookup.cc | 22 +++++++++++----------- src/libcode/vx_data2d/table_lookup.h | 22 +++++++++++----------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/libcode/vx_data2d/table_lookup.cc b/src/libcode/vx_data2d/table_lookup.cc index 3d62fb8f80..1a87c4cd0a 100644 --- a/src/libcode/vx_data2d/table_lookup.cc +++ b/src/libcode/vx_data2d/table_lookup.cc @@ -1047,7 +1047,7 @@ return true; //////////////////////////////////////////////////////////////////////// int TableFlatFile::lookup_grib1(int code, int table_number, - vector &matches) { + vector &matches) const { matches.clear(); for(const auto &e : g1e) { @@ -1063,7 +1063,7 @@ int TableFlatFile::lookup_grib1(int code, int table_number, //////////////////////////////////////////////////////////////////////// int TableFlatFile::lookup_grib1(int code, int table_number, int center, int subcenter, - vector &matches) { + vector &matches) const { matches.clear(); for(const auto &e : g1e) { @@ -1082,7 +1082,7 @@ int TableFlatFile::lookup_grib1(int code, int table_number, int center, int subc //////////////////////////////////////////////////////////////////////// int TableFlatFile::lookup_grib1(int code, - vector &matches) { + vector &matches) const { // Assume default table_number = 2 return lookup_grib1(code, 2, matches); @@ -1092,7 +1092,7 @@ int TableFlatFile::lookup_grib1(int code, //////////////////////////////////////////////////////////////////////// int TableFlatFile::lookup_grib1(const char * parm_name, int table_number, int code, - vector &matches) { + vector &matches) const { matches.clear(); for(const auto &e : g1e) { @@ -1110,7 +1110,7 @@ int TableFlatFile::lookup_grib1(const char * parm_name, int table_number, int co int TableFlatFile::lookup_grib1(const char *parm_name, int table_number, int code,int center, int subcenter, - vector &matches) { + vector &matches) const { matches.clear(); for(const auto &e : g1e) { @@ -1130,7 +1130,7 @@ int TableFlatFile::lookup_grib1(const char *parm_name, int table_number, //////////////////////////////////////////////////////////////////////// int TableFlatFile::lookup_grib1(const char * parm_name, - vector &matches) { + vector &matches) const { // Assume default table_number = 2 return lookup_grib1(parm_name, 2, bad_data_int, matches); @@ -1139,7 +1139,7 @@ int TableFlatFile::lookup_grib1(const char * parm_name, //////////////////////////////////////////////////////////////////////// int TableFlatFile::lookup_grib2(int disc, int pcat, int pnum, - vector &matches) { + vector &matches) const { matches.clear(); for(const auto &e : g2e) { @@ -1157,7 +1157,7 @@ int TableFlatFile::lookup_grib2(int disc, int pcat, int pnum, int TableFlatFile::lookup_grib2(int disc, int pcat, int pnum, int mtab, int cntr, int ltab, - vector &matches) { + vector &matches) const { vector exact_matches; vector partial_matches; @@ -1189,7 +1189,7 @@ int TableFlatFile::lookup_grib2(int disc, int pcat, int pnum, int TableFlatFile::lookup_grib2(const char * parm_name, int disc, int pcat, int pnum, - vector &matches) { + vector &matches) const { matches.clear(); for(const auto &e : g2e) { @@ -1211,7 +1211,7 @@ int TableFlatFile::lookup_grib2(const char * parm_name, int TableFlatFile::lookup_grib2(const char * parm_name, int disc, int pcat, int pnum, int mtab, int cntr, int ltab, - vector &matches) { + vector &matches) const { vector exact_matches; vector partial_matches; @@ -1246,7 +1246,7 @@ int TableFlatFile::lookup_grib2(const char * parm_name, //////////////////////////////////////////////////////////////////////// int TableFlatFile::lookup_grib2(const char * parm_name, - vector &matches) { + vector &matches) const { return lookup_grib2(parm_name, bad_data_int, bad_data_int, bad_data_int, matches); } diff --git a/src/libcode/vx_data2d/table_lookup.h b/src/libcode/vx_data2d/table_lookup.h index 506d895a51..5d95002849 100644 --- a/src/libcode/vx_data2d/table_lookup.h +++ b/src/libcode/vx_data2d/table_lookup.h @@ -202,31 +202,31 @@ class TableFlatFile { int lookup_grib1(int code, int table_number, - std::vector &); + std::vector &) const; int lookup_grib1(int code, int table_number, int center, int subcenter, - std::vector &); + std::vector &) const; // Assumes table_number = 2 by default int lookup_grib1(int code, - std::vector &); + std::vector &) const; int lookup_grib1(const char * parm_name, - std::vector &); + std::vector &) const; int lookup_grib1(const char * parm_name, int table_number, int code, - std::vector &); + std::vector &) const; int lookup_grib1(const char * parm_name, int table_number, int code,int center, int subcenter, - std::vector &); + std::vector &) const; int lookup_grib2(int disc, int pcat, int pnum, - std::vector &); + std::vector &) const; int lookup_grib2(int disc, int pcat, int pnum, int mtab, int cntr, int ltab, - std::vector &); + std::vector &) const; int lookup_grib2(const char * parm_name, - std::vector &); + std::vector &) const; int lookup_grib2(const char * parm_name, int disc, int pcat, int pnum, - std::vector &); + std::vector &) const; int lookup_grib2(const char * parm_name, int disc, int pcat, int pnum, int mtab, int cntr, int ltab, - std::vector &); + std::vector &) const; void readUserGribTables(const char * table_type); From a4d3f034febce3033be81331e555133619622acf Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 25 Jun 2026 20:26:55 +0000 Subject: [PATCH 52/63] Per #1518, solve more SonarQube findings. --- src/libcode/vx_data2d/var_info.cc | 2 +- src/libcode/vx_data2d_grib/data2d_grib.cc | 12 +++-- src/libcode/vx_data2d_grib/data2d_grib.h | 4 +- .../vx_data2d_grib/data2d_grib_utils.cc | 38 ++++++------- src/libcode/vx_data2d_grib/var_info_grib.cc | 53 +++++++++---------- 5 files changed, 52 insertions(+), 57 deletions(-) diff --git a/src/libcode/vx_data2d/var_info.cc b/src/libcode/vx_data2d/var_info.cc index 4adfd013f1..309f61ef4c 100644 --- a/src/libcode/vx_data2d/var_info.cc +++ b/src/libcode/vx_data2d/var_info.cc @@ -827,7 +827,7 @@ bool VarInfo::is_flag_set(int flag) const { int VarInfo::get_wind_flag(const int set_attr_val, const StringArray &field_names) const { - int flag = bad_data_double; + int flag = bad_data_int; // Use explicit boolean definition, if provided if(!is_bad_data(set_attr_val)) flag = set_attr_val != 0; diff --git a/src/libcode/vx_data2d_grib/data2d_grib.cc b/src/libcode/vx_data2d_grib/data2d_grib.cc index e0c7e2ad17..13ded47942 100644 --- a/src/libcode/vx_data2d_grib/data2d_grib.cc +++ b/src/libcode/vx_data2d_grib/data2d_grib.cc @@ -468,20 +468,19 @@ int MetGrib1DataFile::data_plane_array(VarInfo &vinfo, DataPlaneArray &plane_array, bool do_winds) { bool status = false; - bool exact; - int i, lower, upper, type_num; GribRecord r; VarInfoGrib *vinfo_grib = (VarInfoGrib *) &vinfo; VarInfoGrib vinfo_grib_winds; LevelInfo cur_level; DataPlane cur_plane; - DataPlaneArray u_plane_array, v_plane_array; + DataPlaneArray u_plane_array; + DataPlaneArray v_plane_array; // Initialize plane_array.clear(); // Loop through the records in the GRIB file looking for matches - for(i=0; in_records(); i++) { + for(int i=0; in_records(); i++) { // Read the current record GF->seek_record(i); @@ -490,7 +489,7 @@ int MetGrib1DataFile::data_plane_array(VarInfo &vinfo, // Check for a range match if(is_range_match(*vinfo_grib, r)) { - exact = is_exact_match(*vinfo_grib, r); + bool exact = is_exact_match(*vinfo_grib, r); mlog << Debug(3) << "MetGrib1DataFile::data_plane_array() -> " << "Found " << ( exact ? "exact" : "range" ) << " match for VarInfo \"" << vinfo.magic_str() @@ -498,6 +497,9 @@ int MetGrib1DataFile::data_plane_array(VarInfo &vinfo, << filename() << "\".\n"; // Get the level information for this record + int lower; + int upper; + int type_num; read_pds_level(r, lower, upper, type_num); // Read current record diff --git a/src/libcode/vx_data2d_grib/data2d_grib.h b/src/libcode/vx_data2d_grib/data2d_grib.h index 4d1e3569e1..9391450f8d 100644 --- a/src/libcode/vx_data2d_grib/data2d_grib.h +++ b/src/libcode/vx_data2d_grib/data2d_grib.h @@ -82,11 +82,11 @@ class MetGrib1DataFile : public Met2dDataFile { // retrieve the first matching data plane - bool data_plane(VarInfo &, DataPlane &, bool do_winds = true); + bool data_plane(VarInfo &, DataPlane &, bool do_winds = true) override; // retrieve all matching data planes - int data_plane_array(VarInfo &, DataPlaneArray &, bool do_winds = true); + int data_plane_array(VarInfo &, DataPlaneArray &, bool do_winds = true) override; // retrieve the index of the first matching record diff --git a/src/libcode/vx_data2d_grib/data2d_grib_utils.cc b/src/libcode/vx_data2d_grib/data2d_grib_utils.cc index 2170975445..2afccda455 100644 --- a/src/libcode/vx_data2d_grib/data2d_grib_utils.cc +++ b/src/libcode/vx_data2d_grib/data2d_grib_utils.cc @@ -162,18 +162,15 @@ bool is_prelim_match( VarInfoGrib & vinfo, const GribRecord & g) if( !field_name.empty() ) { // look up the name in the grib tables + // if did not find with params from the header - try default if(GribTable.lookup_grib1(field_name.c_str(), vinfo_ptv, code_for_lookup, - vinfo_center, vinfo_subcenter, matches) == 0) + vinfo_center, vinfo_subcenter, matches) == 0 && + GribTable.lookup_grib1(field_name.c_str(), default_grib1_ptv, code_for_lookup, + default_grib1_center, default_grib1_subcenter, matches) == 0) { - // if did not find with params from the header - try default - if(GribTable.lookup_grib1(field_name.c_str(), default_grib1_ptv, code_for_lookup, - default_grib1_center, default_grib1_subcenter, matches) == 0) - { - // if the lookup still fails, then it's not a match - return false; - } - + // if both lookups fail, then it's not a match + return false; } } @@ -190,19 +187,18 @@ bool is_prelim_match( VarInfoGrib & vinfo, const GribRecord & g) } // use the specified indexes to look up the field name + // if did not find with params from the header - try default if(GribTable.lookup_grib1(code_for_lookup, vinfo_ptv, - vinfo_center, vinfo_subcenter, matches) == 0 ) { - //if did not find with params from the header - try default - if(GribTable.lookup_grib1(code_for_lookup, default_grib1_ptv, - default_grib1_center, default_grib1_subcenter, matches) == 0) - { - mlog << Error << "\n" << method_name - << "no parameter found with matching GRIB1_ptv (" - << vinfo_ptv << ") " << "GRIB1_code (" - << vinfo.field_rec() << "). Use the MET_GRIB_TABLES " - << "environment variable to define custom GRIB tables.\n\n"; - exit(1); - } + vinfo_center, vinfo_subcenter, matches) == 0 && + GribTable.lookup_grib1(code_for_lookup, default_grib1_ptv, + default_grib1_center, default_grib1_subcenter, matches) == 0) + { + mlog << Error << "\n" << method_name + << "no parameter found with matching GRIB1_ptv (" + << vinfo_ptv << ") " << "GRIB1_code (" + << vinfo.field_rec() << "). Use the MET_GRIB_TABLES " + << "environment variable to define custom GRIB tables.\n\n"; + exit(1); } } vinfo.set_code ( matches[0].code); diff --git a/src/libcode/vx_data2d_grib/var_info_grib.cc b/src/libcode/vx_data2d_grib/var_info_grib.cc index c5221cd0f9..80486a8e64 100644 --- a/src/libcode/vx_data2d_grib/var_info_grib.cc +++ b/src/libcode/vx_data2d_grib/var_info_grib.cc @@ -229,25 +229,23 @@ void VarInfoGrib::add_grib_code (Dictionary &dict) if( !field_name.empty() ){ // look up the name in the grib tables + // if did not find with params from the header - try default if(GribTable.lookup_grib1(field_name.c_str(), field_ptv, field_code, field_center, field_subcenter, + matches) == 0 && + GribTable.lookup_grib1(field_name.c_str(), default_grib1_ptv, field_code, + default_grib1_center, default_grib1_subcenter, matches) == 0) { - // if did not find with params from the header - try default - if(GribTable.lookup_grib1(field_name.c_str(), default_grib1_ptv, field_code, - default_grib1_center, default_grib1_subcenter, - matches) == 0) - { - mlog << Error << "\nVarInfoGrib::add_grib_code() -> " - << "unrecognized GRIB1 field abbreviation '" << field_name - << "' for table version (" << field_ptv - << "), center (" << field_center - << "), and subcenter (" << field_subcenter - << ") or default table version (" << default_grib1_ptv - << "), center (" << default_grib1_center - << "), and subcenter (" << default_grib1_subcenter << ").\n\n"; - exit(1); - } + mlog << Error << "\nVarInfoGrib::add_grib_code() -> " + << "unrecognized GRIB1 field abbreviation '" << field_name + << "' for table version (" << field_ptv + << "), center (" << field_center + << "), and subcenter (" << field_subcenter + << ") or default table version (" << default_grib1_ptv + << "), center (" << default_grib1_center + << "), and subcenter (" << default_grib1_subcenter << ").\n\n"; + exit(1); } } @@ -263,21 +261,20 @@ void VarInfoGrib::add_grib_code (Dictionary &dict) } // use the specified indexes to look up the field name + // if did not find with params from the header - try default if(GribTable.lookup_grib1(field_code, field_ptv, field_center, field_subcenter, - matches) == 0 ){ - //if did not find with params from the header - try default - if(GribTable.lookup_grib1(field_code, default_grib1_ptv, - default_grib1_center, default_grib1_subcenter, - matches) == 0) - { - mlog << Error << "\nVarInfoGrib::add_grib_code() -> " - << "no parameter found with matching GRIB1_ptv (" - << field_ptv << ") " << "GRIB1_code (" << field_code - << "). Use the MET_GRIB_TABLES environment variable " - << "to define custom GRIB tables.\n\n"; - exit(1); - } + matches) == 0 && + GribTable.lookup_grib1(field_code, default_grib1_ptv, + default_grib1_center, default_grib1_subcenter, + matches) == 0) + { + mlog << Error << "\nVarInfoGrib::add_grib_code() -> " + << "no parameter found with matching GRIB1_ptv (" + << field_ptv << ") " << "GRIB1_code (" << field_code + << "). Use the MET_GRIB_TABLES environment variable " + << "to define custom GRIB tables.\n\n"; + exit(1); } } set_code ( matches[0].code ); From eb9d144b7ca9d61eb4f802b55796d1e76df4dbda Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 25 Jun 2026 21:03:53 +0000 Subject: [PATCH 53/63] Per #1518, drive down more SonarQube findings to reduce the overall number of them relative to the develop branch. --- src/libcode/vx_data2d_grib/data2d_grib.h | 2 +- src/libcode/vx_data2d_grib2/data2d_grib2.cc | 2 +- src/libcode/vx_data2d_grib2/data2d_grib2.h | 6 +++--- src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc | 3 +-- src/libcode/vx_data2d_nc_cf/data2d_nc_cf.h | 6 +++--- src/libcode/vx_data2d_nc_met/data2d_nc_met.h | 6 +++--- src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc | 8 ++++---- src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.h | 6 +++--- src/libcode/vx_data2d_python/data2d_python.h | 6 +++--- src/libcode/vx_data2d_ugrid/data2d_ugrid.cc | 2 +- src/libcode/vx_data2d_ugrid/data2d_ugrid.h | 9 +++++---- 11 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/libcode/vx_data2d_grib/data2d_grib.h b/src/libcode/vx_data2d_grib/data2d_grib.h index 9391450f8d..5f5cafed0b 100644 --- a/src/libcode/vx_data2d_grib/data2d_grib.h +++ b/src/libcode/vx_data2d_grib/data2d_grib.h @@ -90,7 +90,7 @@ class MetGrib1DataFile : public Met2dDataFile { // retrieve the index of the first matching record - int index(VarInfo &); + int index(VarInfo &) override; }; diff --git a/src/libcode/vx_data2d_grib2/data2d_grib2.cc b/src/libcode/vx_data2d_grib2/data2d_grib2.cc index 5a68564a5d..4895d7f13f 100644 --- a/src/libcode/vx_data2d_grib2/data2d_grib2.cc +++ b/src/libcode/vx_data2d_grib2/data2d_grib2.cc @@ -850,7 +850,7 @@ void MetGrib2DataFile::read_grib2_record_list() { // use the index to look up the parameter name vector matches; if(GribTable.lookup_grib2(rec->Discipline, rec->ParmCat, rec->Parm, - gfld->idsect[2], gfld->idsect[0], gfld->idsect[3], + (int) gfld->idsect[2], (int) gfld->idsect[0], (int) gfld->idsect[3], matches) == 0){ mlog << Debug(4) << "MetGrib2DataFile::read_grib2_record_list() - unrecognized GRIB2 " << "field indexes - disc: " << rec->Discipline << ", master table: " << gfld->idsect[2] diff --git a/src/libcode/vx_data2d_grib2/data2d_grib2.h b/src/libcode/vx_data2d_grib2/data2d_grib2.h index 5e35583a6c..20c4aae5bc 100644 --- a/src/libcode/vx_data2d_grib2/data2d_grib2.h +++ b/src/libcode/vx_data2d_grib2/data2d_grib2.h @@ -123,15 +123,15 @@ class MetGrib2DataFile : public Met2dDataFile { // retrieve the first matching data plane - bool data_plane(VarInfo &, DataPlane &, bool do_winds = true); + bool data_plane(VarInfo &, DataPlane &, bool do_winds = true) override; // retrieve all matching data planes - int data_plane_array(VarInfo &, DataPlaneArray &, bool do_winds = true); + int data_plane_array(VarInfo &, DataPlaneArray &, bool do_winds = true) override; // retrieve the index of the first matching record - int index(VarInfo &); + int index(VarInfo &) override; // // do stuff diff --git a/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc b/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc index c1c05b0f86..c91443ab57 100644 --- a/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc +++ b/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc @@ -405,7 +405,6 @@ int MetNcCFDataFile::data_plane_array(VarInfo &vinfo, bool do_winds) { int n_rec = 0; DataPlane plane; - bool status = false; static const string method_name = "MetNcCFDataFile::data_plane_array(VarInfo &, DataPlaneArray &) -> "; @@ -444,7 +443,7 @@ int MetNcCFDataFile::data_plane_array(VarInfo &vinfo, // Attempt to derive the data if(n_rec == 0 && do_winds) { - status = derive_winds(vinfo_nc, plane_array); + derive_winds(vinfo_nc, plane_array); } return n_rec; diff --git a/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.h b/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.h index d4dd7b3439..eec2fa4585 100644 --- a/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.h +++ b/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.h @@ -99,15 +99,15 @@ class MetNcCFDataFile : public Met2dDataFile { // retrieve the first matching data plane - bool data_plane(VarInfo &, DataPlane &, bool do_winds = true); + bool data_plane(VarInfo &, DataPlane &, bool do_winds = true) override; // retrieve all matching data planes - int data_plane_array(VarInfo &, DataPlaneArray &, bool do_winds = true); + int data_plane_array(VarInfo &, DataPlaneArray &, bool do_winds = true) override; // retrieve the index of the first matching record - int index(VarInfo &); + int index(VarInfo &) override; // // do stuff diff --git a/src/libcode/vx_data2d_nc_met/data2d_nc_met.h b/src/libcode/vx_data2d_nc_met/data2d_nc_met.h index c020912209..da6e897983 100644 --- a/src/libcode/vx_data2d_nc_met/data2d_nc_met.h +++ b/src/libcode/vx_data2d_nc_met/data2d_nc_met.h @@ -62,15 +62,15 @@ class MetNcMetDataFile : public Met2dDataFile { // retrieve the first matching data plane - bool data_plane(VarInfo &, DataPlane &, bool do_winds = true); + bool data_plane(VarInfo &, DataPlane &, bool do_winds = true) override; // retrieve all matching data planes - int data_plane_array(VarInfo &, DataPlaneArray &, bool do_winds = true); + int data_plane_array(VarInfo &, DataPlaneArray &, bool do_winds = true) override; // retrieve the index of the first matching record - int index(VarInfo &); + int index(VarInfo &) override; // // do stuff diff --git a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc index e8e1926a13..b2a6bc146b 100644 --- a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc +++ b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc @@ -214,7 +214,7 @@ bool MetNcWrfDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, int MetNcWrfDataFile::data_plane_array(VarInfo &vinfo, DataPlaneArray &plane_array, bool do_winds) { - int i, i_dim, n_level, status, lower, upper; + int i_dim, n_level, status, lower, upper; ConcatString level_str; double pressure, min_level, max_level; bool found = false; @@ -251,7 +251,7 @@ int MetNcWrfDataFile::data_plane_array(VarInfo &vinfo, // Loop through each of levels specified in the range cur_dim = dim; - for(i=0; i Date: Thu, 25 Jun 2026 21:44:49 +0000 Subject: [PATCH 54/63] Per #1518, reduce 4 more SonarQube findings. --- src/basic/vx_config/config_constants.h | 25 ++++++++++++-- src/basic/vx_config/config_util.cc | 46 -------------------------- src/libcode/vx_data2d/data_class.cc | 4 +-- 3 files changed, 24 insertions(+), 51 deletions(-) diff --git a/src/basic/vx_config/config_constants.h b/src/basic/vx_config/config_constants.h index 83539369ba..4e3ee5b740 100644 --- a/src/basic/vx_config/config_constants.h +++ b/src/basic/vx_config/config_constants.h @@ -294,9 +294,17 @@ struct InterpInfo { ~InterpInfo() { clear(); } InterpInfo(InterpInfo const &i) { *this = i; } InterpInfo &operator=(const InterpInfo &a) noexcept; // SonarQube findings - friend bool operator==(const InterpInfo &lhs, const InterpInfo &rhs); void clear(); void validate(); // Ensure that width and method are accordant + + friend bool operator==(const InterpInfo &lhs, const InterpInfo &rhs) { + return(lhs.field == rhs.field && + lhs.vld_thresh == rhs.vld_thresh && + lhs.n_interp == rhs.n_interp && + lhs.method == rhs.method && + lhs.width == rhs.width && + lhs.shape == rhs.shape); + } }; //////////////////////////////////////////////////////////////////////// @@ -450,8 +458,13 @@ struct MaskLatLon { ~MaskLatLon() { clear(); } MaskLatLon(MaskLatLon const &i) { *this = i; } MaskLatLon &operator=(const MaskLatLon &a) noexcept; - friend bool operator==(const MaskLatLon &lhs, const MaskLatLon &rhs); void clear(); + + friend bool operator==(const MaskLatLon &lhs, const MaskLatLon &rhs) { + return(lhs.name == rhs.name && + lhs.lat_thresh == rhs.lat_thresh && + lhs.lon_thresh == rhs.lon_thresh); + } }; //////////////////////////////////////////////////////////////////////// @@ -470,7 +483,6 @@ struct WindMetadata { ~WindMetadata() { clear(); } WindMetadata(WindMetadata const &i) { *this = i; } WindMetadata &operator=(const WindMetadata &a) noexcept; - friend bool operator==(const WindMetadata &lhs, const WindMetadata &rhs); void clear(); bool is_u_wind(const std::string &s) const { return u_wind.has(s); } @@ -480,6 +492,13 @@ struct WindMetadata { // Supported derivations bool is_kinetic_energy(const std::string &s) const { return s == "KENG"; } + + friend bool operator==(const WindMetadata &lhs, const WindMetadata &rhs) { + return(lhs.u_wind == rhs.u_wind && + lhs.v_wind == rhs.v_wind && + lhs.wind_speed == rhs.wind_speed && + lhs.wind_direction == rhs.wind_direction); + } }; //////////////////////////////////////////////////////////////////////// diff --git a/src/basic/vx_config/config_util.cc b/src/basic/vx_config/config_util.cc index 83b97ffb5d..f4f17915a4 100644 --- a/src/basic/vx_config/config_util.cc +++ b/src/basic/vx_config/config_util.cc @@ -743,20 +743,6 @@ void MaskLatLon::clear() { /////////////////////////////////////////////////////////////////////////////// -bool operator==(const MaskLatLon &lhs, const MaskLatLon &rhs) { - bool match = true; - - if(!(lhs.name == rhs.name ) || - !(lhs.lat_thresh == rhs.lat_thresh) || - !(lhs.lon_thresh == rhs.lon_thresh)) { - match = false; - } - - return match; -} - -/////////////////////////////////////////////////////////////////////////////// - MaskLatLon &MaskLatLon::operator=(const MaskLatLon &a) noexcept { if(this != &a) { name = a.name; @@ -832,21 +818,6 @@ void WindMetadata::clear() { /////////////////////////////////////////////////////////////////////////////// -bool operator==(const WindMetadata &lhs, const WindMetadata &rhs) { - bool match = true; - - if(!(lhs.u_wind == rhs.u_wind ) || - !(lhs.v_wind == rhs.v_wind ) || - !(lhs.wind_speed == rhs.wind_speed ) || - !(lhs.wind_direction == rhs.wind_direction)) { - match = false; - } - - return match; -} - -/////////////////////////////////////////////////////////////////////////////// - WindMetadata &WindMetadata::operator=(const WindMetadata &a) noexcept { if(this != &a) { u_wind = a.u_wind; @@ -1802,23 +1773,6 @@ void InterpInfo::validate() { /////////////////////////////////////////////////////////////////////////////// -bool operator==(const InterpInfo &lhs, const InterpInfo &rhs) { - bool match = true; - - if(!(lhs.field == rhs.field ) || - !(lhs.vld_thresh == rhs.vld_thresh) || - !(lhs.n_interp == rhs.n_interp ) || - !(lhs.method == rhs.method ) || - !(lhs.width == rhs.width ) || - !(lhs.shape == rhs.shape )) { - match = false; - } - - return match; -} - -/////////////////////////////////////////////////////////////////////////////// - InterpInfo & InterpInfo::operator=(const InterpInfo &a) noexcept { if(this != &a) { field = a.field; diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index 049f1d8e25..8cc2580560 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -27,7 +27,7 @@ using namespace std; //////////////////////////////////////////////////////////////////////// -static StringArray swap_uv_name(VarInfo *, +static StringArray swap_uv_name(const VarInfo *, const ConcatString &, const StringArray &); @@ -1081,7 +1081,7 @@ return true; //////////////////////////////////////////////////////////////////////// -static StringArray swap_uv_name(VarInfo *vinfo, +static StringArray swap_uv_name(const VarInfo *vinfo, const ConcatString &conf_key, const StringArray &names) { From b0ebfd7bbd077108d4d7ef7547fe21a879b47b9c Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 30 Jun 2026 19:54:08 +0000 Subject: [PATCH 55/63] Per #1518, add missing references to Error or Debug for handful of calls to mlog throughout the MET repo. --- src/libcode/vx_data2d/data_class.cc | 4 ++-- src/libcode/vx_shapedata/mode_conf_info.cc | 9 ++++++--- src/tools/core/ensemble_stat/ensemble_stat.cc | 6 +++--- src/tools/dev_utils/gen_climo_bin.cc | 2 +- src/tools/other/gen_ens_prod/gen_ens_prod.cc | 2 +- src/tools/other/point2grid/point2grid.cc | 2 +- 6 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index 8cc2580560..3d964c6504 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -916,7 +916,7 @@ for(int i=0; ireset_dict_with_name(search_names[i].c_str()) && data_plane(*vinfo, dp, false)) { status = true; - mlog << "Found matching wind field \"" + mlog << Debug(3) << "Found matching wind field \"" << vinfo->magic_str() << "\".\n"; break; } @@ -963,7 +963,7 @@ for(int i=0; ireset_dict_with_name(search_names[i].c_str()) && data_plane_array(*vinfo, dpa, false)) { status = true; - mlog << "Found matching wind field(s) \"" + mlog << Debug(3) << "Found matching wind field(s) \"" << vinfo->magic_str() << "\".\n"; break; } diff --git a/src/libcode/vx_shapedata/mode_conf_info.cc b/src/libcode/vx_shapedata/mode_conf_info.cc index 571de92c08..3f229a4027 100644 --- a/src/libcode/vx_shapedata/mode_conf_info.cc +++ b/src/libcode/vx_shapedata/mode_conf_info.cc @@ -910,7 +910,8 @@ const DictionaryEntry * ee = dict->lookup(conf_key_field); if ( !ee ) { - mlog << "\nModeConfInfo::read_fields () -> \"field\" entry not found in dictionary!\n\n"; + mlog << Error << "\nModeConfInfo::read_fields () -> " + << "\"field\" entry not found in dictionary!\n\n"; exit ( 1 ); @@ -989,7 +990,8 @@ void ModeConfInfo::read_fields_1 (Mode_Field_Info * & info_array, Dictionary * d const DictionaryEntry * ee = dict->lookup(conf_key_field); if ( !ee ) { - mlog << "\nModeConfInfo::read_fields () -> \"field\" entry not found in dictionary!\n\n"; + mlog << Error << "\nModeConfInfo::read_fields () -> \"field\" " + << "entry not found in dictionary!\n\n"; exit ( 1 ); @@ -1668,7 +1670,8 @@ GrdFileType ModeConfInfo::file_type_for_field(bool isFcst, int field_index) const DictionaryEntry *e = dict->lookup(conf_key_field); if ( !e ) { - mlog << "\nModeConfInfo::read_fields () -> \"field\" entry not found in dictionary!\n\n"; + mlog << Error << "\nModeConfInfo::read_fields () -> \"field\" " + << "entry not found in dictionary!\n\n"; exit ( 1 ); } diff --git a/src/tools/core/ensemble_stat/ensemble_stat.cc b/src/tools/core/ensemble_stat/ensemble_stat.cc index 789db67454..57bb47f856 100644 --- a/src/tools/core/ensemble_stat/ensemble_stat.cc +++ b/src/tools/core/ensemble_stat/ensemble_stat.cc @@ -439,7 +439,7 @@ static void process_command_line(int argc, char **argv) { mlog << Debug(1) << "Ensemble Files[" << n_ens_files << "]:\n"; for(int i=0; iname() << " observations to populate " << to_count << " of " << to_grid.nxy() << " grid points.\n"; - if (0 < filtered_count ) mlog << log_msg << "\n"; + if (0 < filtered_count ) mlog << Debug(3) << log_msg << "\n"; } } // end for i From f2c4bfaddc26643f20e5168acb738a83c5ffcb02 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 30 Jun 2026 20:21:39 +0000 Subject: [PATCH 56/63] Per #1518, refine the swap UV name logic so that it's only employed when the current field name setting matches the contents of what's in ConfigConstants. That way, it is NOT used when the user explicitly sets the field name. --- src/libcode/vx_data2d/data_class.cc | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index 3d964c6504..0ae739c3a3 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -1086,21 +1086,31 @@ static StringArray swap_uv_name(const VarInfo *vinfo, const StringArray &names) { - // If converting between U-wind and V-wind, try swapping U and V - // Only add the search string if the substituion works - ConcatString cs(vinfo->name()); + // Try swapping U and V in the VarInfo name when: + // - Converting between U-wind and V-wind + // - The default setting has not be modified + // - The substitution produces an actual change + + // Lookup default setting from ConfigConstants + StringArray default_names; + static MetConfig conf_const(replace_path(config_const_filename).c_str()); + default_names.parse_css(conf_const.lookup_string(conf_key.c_str())); + StringArray sa(names); + ConcatString cs(vinfo->name()); // Replace U with V if(vinfo->is_u_wind() && - conf_key == conf_key_v_wind_field_name) { + conf_key == conf_key_v_wind_field_name && + names == default_names) { cs.replace("U", "V", false); cs.replace("u", "v", false); if(cs != vinfo->name()) sa.insert(0, cs.c_str()); } // Replace V with U else if(vinfo->is_v_wind() && - conf_key == conf_key_u_wind_field_name) { + conf_key == conf_key_u_wind_field_name && + names == default_names) { cs.replace("V", "U", false); cs.replace("v", "u", false); if(cs != vinfo->name()) sa.insert(0, cs.c_str()); From e19ca14acd82c34f0bbbd2761ea0a49649b7f120 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 30 Jun 2026 20:25:21 +0000 Subject: [PATCH 57/63] MetConfig doesn't need to be static --- src/libcode/vx_data2d/data_class.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index 0ae739c3a3..b82f6cc304 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -1093,7 +1093,7 @@ static StringArray swap_uv_name(const VarInfo *vinfo, // Lookup default setting from ConfigConstants StringArray default_names; - static MetConfig conf_const(replace_path(config_const_filename).c_str()); + MetConfig conf_const(replace_path(config_const_filename).c_str()); default_names.parse_css(conf_const.lookup_string(conf_key.c_str())); StringArray sa(names); From 4119f5a96e14e1be726459a8b97e4431bbd21d1f Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 30 Jun 2026 21:25:44 +0000 Subject: [PATCH 58/63] Per #1518, switch VarInfo::clone() to return an std::unique_ptr() to satisfy SonarQube's complaints about calling new and delete. --- src/libcode/vx_data2d/data_class.cc | 66 +++++++------------ src/libcode/vx_data2d/var_info.h | 2 +- src/libcode/vx_data2d/var_info_pairs.cc | 7 +- src/libcode/vx_data2d/var_info_pairs.h | 2 +- src/libcode/vx_data2d_grib/var_info_grib.cc | 7 +- src/libcode/vx_data2d_grib/var_info_grib.h | 2 +- src/libcode/vx_data2d_grib2/var_info_grib2.cc | 7 +- src/libcode/vx_data2d_grib2/var_info_grib2.h | 2 +- src/libcode/vx_data2d_nc_cf/var_info_nc_cf.cc | 7 +- src/libcode/vx_data2d_nc_cf/var_info_nc_cf.h | 2 +- .../vx_data2d_nc_met/var_info_nc_met.cc | 7 +- .../vx_data2d_nc_met/var_info_nc_met.h | 2 +- .../vx_data2d_nc_wrf/var_info_nc_wrf.cc | 7 +- .../vx_data2d_nc_wrf/var_info_nc_wrf.h | 2 +- .../vx_data2d_python/var_info_python.cc | 7 +- .../vx_data2d_python/var_info_python.h | 2 +- src/libcode/vx_data2d_ugrid/var_info_ugrid.cc | 7 +- src/libcode/vx_data2d_ugrid/var_info_ugrid.h | 2 +- src/libcode/vx_shapedata/mode_field_info.cc | 6 +- src/libcode/vx_shapedata/mode_field_info.h | 2 +- 20 files changed, 51 insertions(+), 97 deletions(-) diff --git a/src/libcode/vx_data2d/data_class.cc b/src/libcode/vx_data2d/data_class.cc index b82f6cc304..2a2462a419 100644 --- a/src/libcode/vx_data2d/data_class.cc +++ b/src/libcode/vx_data2d/data_class.cc @@ -384,16 +384,16 @@ bool status = false; if(vinfo->need_uv_wind()) { // Create local copies - VarInfo * vinfo_uwnd = vinfo->clone(); - VarInfo * vinfo_vwnd = vinfo->clone(); + auto vinfo_uwnd = vinfo->clone(); + auto vinfo_vwnd = vinfo->clone(); DataPlane uwnd_dp; DataPlane vwnd_dp; - status = read_wind_data(vinfo_uwnd, + status = read_wind_data(vinfo_uwnd.get(), conf_key_u_wind_field_name, vinfo->wind_info().u_wind, uwnd_dp) && - read_wind_data(vinfo_vwnd, + read_wind_data(vinfo_vwnd.get(), conf_key_v_wind_field_name, vinfo->wind_info().v_wind, vwnd_dp); @@ -432,10 +432,6 @@ if(vinfo->need_uv_wind()) { vinfo->set_units("J/kg"); } } - - // Cleanup - if(vinfo_uwnd) { delete vinfo_uwnd; vinfo_uwnd = nullptr; } - if(vinfo_vwnd) { delete vinfo_vwnd; vinfo_vwnd = nullptr; } } // @@ -445,16 +441,16 @@ if(vinfo->need_uv_wind()) { else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { // Create local copies - VarInfo * vinfo_wspd = vinfo->clone(); - VarInfo * vinfo_wdir = vinfo->clone(); + auto vinfo_wspd = vinfo->clone(); + auto vinfo_wdir = vinfo->clone(); DataPlane wspd_dp; DataPlane wdir_dp; - status = read_wind_data(vinfo_wspd, + status = read_wind_data(vinfo_wspd.get(), conf_key_wind_speed_field_name, vinfo->wind_info().wind_speed, wspd_dp) && - read_wind_data(vinfo_wdir, + read_wind_data(vinfo_wdir.get(), conf_key_wind_direction_field_name, vinfo->wind_info().wind_direction, wdir_dp); @@ -481,10 +477,6 @@ else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { vinfo->set_units(vinfo_wspd->units()); } } - - // Cleanup - if(vinfo_wspd) { delete vinfo_wspd; vinfo_wspd = nullptr; } - if(vinfo_wdir) { delete vinfo_wdir; vinfo_wdir = nullptr; } } return status; @@ -512,16 +504,16 @@ bool status = false; if(vinfo->need_uv_wind()) { // Create local copies - VarInfo * vinfo_uwnd = vinfo->clone(); - VarInfo * vinfo_vwnd = vinfo->clone(); + auto vinfo_uwnd = vinfo->clone(); + auto vinfo_vwnd = vinfo->clone(); DataPlaneArray uwnd_dpa; DataPlaneArray vwnd_dpa; - status = read_wind_data(vinfo_uwnd, + status = read_wind_data(vinfo_uwnd.get(), conf_key_u_wind_field_name, vinfo->wind_info().u_wind, uwnd_dpa) && - read_wind_data(vinfo_vwnd, + read_wind_data(vinfo_vwnd.get(), conf_key_v_wind_field_name, vinfo->wind_info().v_wind, vwnd_dpa); @@ -607,10 +599,6 @@ if(vinfo->need_uv_wind()) { // Store the result dpa.add(dp, uwnd_dpa.lower(i), uwnd_dpa.upper(i)); } - - // Cleanup - if(vinfo_uwnd) { delete vinfo_uwnd; vinfo_uwnd = nullptr; } - if(vinfo_vwnd) { delete vinfo_vwnd; vinfo_vwnd = nullptr; } } // @@ -620,16 +608,16 @@ if(vinfo->need_uv_wind()) { else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { // Create local copies - VarInfo * vinfo_wspd = vinfo->clone(); - VarInfo * vinfo_wdir = vinfo->clone(); + auto vinfo_wspd = vinfo->clone(); + auto vinfo_wdir = vinfo->clone(); DataPlaneArray wspd_dpa; DataPlaneArray wdir_dpa; - status = read_wind_data(vinfo_wspd, + status = read_wind_data(vinfo_wspd.get(), conf_key_wind_speed_field_name, vinfo->wind_info().wind_speed, wspd_dpa) && - read_wind_data(vinfo_wdir, + read_wind_data(vinfo_wdir.get(), conf_key_wind_direction_field_name, vinfo->wind_info().wind_direction, wdir_dpa); @@ -699,10 +687,6 @@ else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { // Store the result dpa.add(dp, wspd_dpa.lower(i), wspd_dpa.upper(i)); } - - // Cleanup - if(vinfo_wspd) { delete vinfo_wspd; vinfo_wspd = nullptr; } - if(vinfo_wdir) { delete vinfo_wdir; vinfo_wdir = nullptr; } } return status; @@ -738,7 +722,7 @@ else { bool status = false; // Create local copy -VarInfo * vinfo_wind = vinfo->clone(); +auto vinfo_wind = vinfo->clone(); DataPlane uwnd_dp; DataPlane vwnd_dp; @@ -747,7 +731,7 @@ DataPlane tmp_dp; // Rotate U-Wind if(vinfo->is_u_wind()) { uwnd_dp = dp; - status = read_wind_data(vinfo_wind, + status = read_wind_data(vinfo_wind.get(), conf_key_v_wind_field_name, vinfo->wind_info().v_wind, vwnd_dp); @@ -758,7 +742,7 @@ if(vinfo->is_u_wind()) { // Rotate V-Wind else if(vinfo->is_v_wind()) { vwnd_dp = dp; - status = read_wind_data(vinfo_wind, + status = read_wind_data(vinfo_wind.get(), conf_key_u_wind_field_name, vinfo->wind_info().u_wind, uwnd_dp); @@ -779,9 +763,6 @@ if(!status) { << ") from grid to earth relative.\n\n"; } -// Cleanup -if(vinfo_wind) { delete vinfo_wind; vinfo_wind = nullptr; } - return status; } @@ -815,7 +796,7 @@ else { bool status = false; // Create local copy -VarInfo * vinfo_wind = vinfo->clone(); +auto vinfo_wind = vinfo->clone(); DataPlaneArray uwnd_dpa; DataPlaneArray vwnd_dpa; @@ -830,7 +811,7 @@ if(vinfo->is_u_wind() || vinfo->is_v_wind()) { uwnd_dpa = dpa; uwnd_out = &dpa; vwnd_out = &tmp_dpa; - status = read_wind_data(vinfo_wind, + status = read_wind_data(vinfo_wind.get(), conf_key_v_wind_field_name, vinfo->wind_info().v_wind, vwnd_dpa); @@ -839,7 +820,7 @@ if(vinfo->is_u_wind() || vinfo->is_v_wind()) { vwnd_dpa = dpa; uwnd_out = &tmp_dpa; vwnd_out = &dpa; - status = read_wind_data(vinfo_wind, + status = read_wind_data(vinfo_wind.get(), conf_key_u_wind_field_name, vinfo->wind_info().u_wind, uwnd_dpa); @@ -880,9 +861,6 @@ if(!status) { << ") from grid to earth relative.\n\n"; } -// Cleanup -if(vinfo_wind) { delete vinfo_wind; vinfo_wind = nullptr; } - return status; } diff --git a/src/libcode/vx_data2d/var_info.h b/src/libcode/vx_data2d/var_info.h index 236bbbd0ce..0d327ec859 100644 --- a/src/libcode/vx_data2d/var_info.h +++ b/src/libcode/vx_data2d/var_info.h @@ -102,7 +102,7 @@ class VarInfo VarInfo(const VarInfo &); VarInfo & operator=(const VarInfo &); - virtual VarInfo *clone() const = 0; + virtual std::unique_ptr clone() const = 0; // Conversion function UserFunc_1Arg ConvertFx; diff --git a/src/libcode/vx_data2d/var_info_pairs.cc b/src/libcode/vx_data2d/var_info_pairs.cc index 631302b251..3cd685aa8b 100644 --- a/src/libcode/vx_data2d/var_info_pairs.cc +++ b/src/libcode/vx_data2d/var_info_pairs.cc @@ -74,11 +74,8 @@ VarInfoPairs & VarInfoPairs::operator=(const VarInfoPairs &f) { /////////////////////////////////////////////////////////////////////////////// -VarInfo *VarInfoPairs::clone() const { - - VarInfoPairs *ret = new VarInfoPairs(*this); - - return (VarInfo *)ret; +unique_ptr VarInfoPairs::clone() const { + return unique_ptr(new VarInfoPairs(*this)); } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_data2d/var_info_pairs.h b/src/libcode/vx_data2d/var_info_pairs.h index 51fe27a51f..01ea939cfb 100644 --- a/src/libcode/vx_data2d/var_info_pairs.h +++ b/src/libcode/vx_data2d/var_info_pairs.h @@ -33,7 +33,7 @@ class VarInfoPairs : public VarInfo { ~VarInfoPairs(); VarInfoPairs(const VarInfoPairs &); VarInfoPairs & operator=(const VarInfoPairs &); - VarInfo *clone() const; + std::unique_ptr clone() const; void dump(std::ostream &) const; void clear(); diff --git a/src/libcode/vx_data2d_grib/var_info_grib.cc b/src/libcode/vx_data2d_grib/var_info_grib.cc index 80486a8e64..9fe890b170 100644 --- a/src/libcode/vx_data2d_grib/var_info_grib.cc +++ b/src/libcode/vx_data2d_grib/var_info_grib.cc @@ -75,11 +75,8 @@ VarInfoGrib & VarInfoGrib::operator=(const VarInfoGrib &f) { /////////////////////////////////////////////////////////////////////////////// -VarInfo *VarInfoGrib::clone() const { - - VarInfoGrib *ret = new VarInfoGrib(*this); - - return (VarInfo *)ret; +unique_ptr VarInfoGrib::clone() const { + return unique_ptr(new VarInfoGrib(*this)); } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_data2d_grib/var_info_grib.h b/src/libcode/vx_data2d_grib/var_info_grib.h index 17de4e8365..c333924b39 100644 --- a/src/libcode/vx_data2d_grib/var_info_grib.h +++ b/src/libcode/vx_data2d_grib/var_info_grib.h @@ -64,7 +64,7 @@ class VarInfoGrib : public VarInfo ~VarInfoGrib() override; VarInfoGrib(const VarInfoGrib &); VarInfoGrib & operator=(const VarInfoGrib &); - VarInfo *clone() const override; + std::unique_ptr clone() const override; void dump(std::ostream &) const override; void clear(); diff --git a/src/libcode/vx_data2d_grib2/var_info_grib2.cc b/src/libcode/vx_data2d_grib2/var_info_grib2.cc index 217b73c97f..8d6b08d1b7 100644 --- a/src/libcode/vx_data2d_grib2/var_info_grib2.cc +++ b/src/libcode/vx_data2d_grib2/var_info_grib2.cc @@ -77,11 +77,8 @@ VarInfoGrib2 & VarInfoGrib2::operator=(const VarInfoGrib2 &f) { /////////////////////////////////////////////////////////////////////////////// -VarInfo *VarInfoGrib2::clone() const { - - VarInfoGrib2 *ret = new VarInfoGrib2(*this); - - return (VarInfo *)ret; +unique_ptr VarInfoGrib2::clone() const { + return unique_ptr(new VarInfoGrib2(*this)); } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_data2d_grib2/var_info_grib2.h b/src/libcode/vx_data2d_grib2/var_info_grib2.h index ad1a0f05b8..91f01b25f4 100644 --- a/src/libcode/vx_data2d_grib2/var_info_grib2.h +++ b/src/libcode/vx_data2d_grib2/var_info_grib2.h @@ -72,7 +72,7 @@ class VarInfoGrib2 : public VarInfo ~VarInfoGrib2() override; VarInfoGrib2(const VarInfoGrib2 &); VarInfoGrib2 & operator=(const VarInfoGrib2 &); - VarInfo *clone() const override; + std::unique_ptr clone() const override; void dump(std::ostream &) const override; void clear(); diff --git a/src/libcode/vx_data2d_nc_cf/var_info_nc_cf.cc b/src/libcode/vx_data2d_nc_cf/var_info_nc_cf.cc index a136425cd8..76ebc3adf9 100644 --- a/src/libcode/vx_data2d_nc_cf/var_info_nc_cf.cc +++ b/src/libcode/vx_data2d_nc_cf/var_info_nc_cf.cc @@ -76,11 +76,8 @@ VarInfoNcCF & VarInfoNcCF::operator=(const VarInfoNcCF &f) { /////////////////////////////////////////////////////////////////////////////// -VarInfo *VarInfoNcCF::clone() const { - - VarInfoNcCF *ret = new VarInfoNcCF(*this); - - return ret; +unique_ptr VarInfoNcCF::clone() const { + return unique_ptr(new VarInfoNcCF(*this)); } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_data2d_nc_cf/var_info_nc_cf.h b/src/libcode/vx_data2d_nc_cf/var_info_nc_cf.h index 81f33b7db6..514ad11356 100644 --- a/src/libcode/vx_data2d_nc_cf/var_info_nc_cf.h +++ b/src/libcode/vx_data2d_nc_cf/var_info_nc_cf.h @@ -45,7 +45,7 @@ class VarInfoNcCF : public VarInfo ~VarInfoNcCF() override; VarInfoNcCF(const VarInfoNcCF &); VarInfoNcCF & operator=(const VarInfoNcCF &); - VarInfo *clone() const override; + std::unique_ptr clone() const override; void dump(std::ostream &) const override; void clear(); diff --git a/src/libcode/vx_data2d_nc_met/var_info_nc_met.cc b/src/libcode/vx_data2d_nc_met/var_info_nc_met.cc index 4b7d96ecf9..2fa0e82c0c 100644 --- a/src/libcode/vx_data2d_nc_met/var_info_nc_met.cc +++ b/src/libcode/vx_data2d_nc_met/var_info_nc_met.cc @@ -72,11 +72,8 @@ VarInfoNcMet & VarInfoNcMet::operator=(const VarInfoNcMet &f) { /////////////////////////////////////////////////////////////////////////////// -VarInfo *VarInfoNcMet::clone() const { - - VarInfoNcMet *ret = new VarInfoNcMet(*this); - - return (VarInfo *)ret; +unique_ptr VarInfoNcMet::clone() const { + return unique_ptr(new VarInfoNcMet(*this)); } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_data2d_nc_met/var_info_nc_met.h b/src/libcode/vx_data2d_nc_met/var_info_nc_met.h index 4cdbb5948a..42dba7d00b 100644 --- a/src/libcode/vx_data2d_nc_met/var_info_nc_met.h +++ b/src/libcode/vx_data2d_nc_met/var_info_nc_met.h @@ -41,7 +41,7 @@ class VarInfoNcMet : public VarInfo ~VarInfoNcMet() override; VarInfoNcMet(const VarInfoNcMet &); VarInfoNcMet & operator=(const VarInfoNcMet &); - VarInfo *clone() const override; + std::unique_ptr clone() const override; void dump(std::ostream &) const override; void clear(); diff --git a/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.cc b/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.cc index abb5feae5b..2dfe83dcd1 100644 --- a/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.cc +++ b/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.cc @@ -72,11 +72,8 @@ VarInfoNcWrf & VarInfoNcWrf::operator=(const VarInfoNcWrf &f) { /////////////////////////////////////////////////////////////////////////////// -VarInfo *VarInfoNcWrf::clone() const { - - VarInfoNcWrf *ret = new VarInfoNcWrf(*this); - - return (VarInfo *)ret; +unique_ptr VarInfoNcWrf::clone() const { + return unique_ptr(new VarInfoNcWrf(*this)); } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.h b/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.h index e46be4d0dc..10b1f00178 100644 --- a/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.h +++ b/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.h @@ -178,7 +178,7 @@ class VarInfoNcWrf : public VarInfo ~VarInfoNcWrf() override; VarInfoNcWrf(const VarInfoNcWrf &); VarInfoNcWrf & operator=(const VarInfoNcWrf &); - VarInfo *clone() const override; + std::unique_ptr clone() const override; void dump(std::ostream &) const override; void clear(); diff --git a/src/libcode/vx_data2d_python/var_info_python.cc b/src/libcode/vx_data2d_python/var_info_python.cc index 5ad44b5737..cefa0bac8d 100644 --- a/src/libcode/vx_data2d_python/var_info_python.cc +++ b/src/libcode/vx_data2d_python/var_info_python.cc @@ -75,11 +75,8 @@ VarInfoPython & VarInfoPython::operator=(const VarInfoPython &f) { /////////////////////////////////////////////////////////////////////////////// -VarInfo *VarInfoPython::clone() const { - - VarInfoPython *ret = new VarInfoPython(*this); - - return (VarInfo *)ret; +unique_ptr VarInfoPython::clone() const { + return unique_ptr(new VarInfoPython(*this)); } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_data2d_python/var_info_python.h b/src/libcode/vx_data2d_python/var_info_python.h index 0bf98532e6..2c5f87b29a 100644 --- a/src/libcode/vx_data2d_python/var_info_python.h +++ b/src/libcode/vx_data2d_python/var_info_python.h @@ -41,7 +41,7 @@ class VarInfoPython : public VarInfo ~VarInfoPython(); VarInfoPython(const VarInfoPython &); VarInfoPython & operator=(const VarInfoPython &); - VarInfo *clone() const; + std::unique_ptr clone() const; void dump(std::ostream &) const; void clear(); diff --git a/src/libcode/vx_data2d_ugrid/var_info_ugrid.cc b/src/libcode/vx_data2d_ugrid/var_info_ugrid.cc index 51fe233880..f4d0178b86 100644 --- a/src/libcode/vx_data2d_ugrid/var_info_ugrid.cc +++ b/src/libcode/vx_data2d_ugrid/var_info_ugrid.cc @@ -72,11 +72,8 @@ VarInfoUGrid & VarInfoUGrid::operator=(const VarInfoUGrid &f) { /////////////////////////////////////////////////////////////////////////////// -VarInfo *VarInfoUGrid::clone() const { - - auto ret = new VarInfoUGrid(*this); - - return (VarInfo *)ret; +unique_ptr VarInfoUGrid::clone() const { + return unique_ptr(new VarInfoUGrid(*this)); } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_data2d_ugrid/var_info_ugrid.h b/src/libcode/vx_data2d_ugrid/var_info_ugrid.h index 0d96e2eac1..1725956fd5 100644 --- a/src/libcode/vx_data2d_ugrid/var_info_ugrid.h +++ b/src/libcode/vx_data2d_ugrid/var_info_ugrid.h @@ -45,7 +45,7 @@ class VarInfoUGrid : public VarInfo ~VarInfoUGrid() override; VarInfoUGrid(const VarInfoUGrid &); VarInfoUGrid & operator=(const VarInfoUGrid &); - VarInfo *clone() const override; + std::unique_ptr clone() const override; void dump(std::ostream &) const override; void clear(); diff --git a/src/libcode/vx_shapedata/mode_field_info.cc b/src/libcode/vx_shapedata/mode_field_info.cc index 5ff21bd6fe..d2f335b2c5 100644 --- a/src/libcode/vx_shapedata/mode_field_info.cc +++ b/src/libcode/vx_shapedata/mode_field_info.cc @@ -122,7 +122,7 @@ dict = 0; conf = 0; -var_info = 0; +var_info.reset(); clear(); @@ -155,7 +155,7 @@ conv_radius = 0; vld_thresh = 0.0; -if ( var_info ) { delete var_info; var_info = 0; } +var_info.reset(); conv_radius_array.clear(); @@ -207,7 +207,7 @@ dict = _dict; conf = _conf; -var_info = VarInfoFactory::new_var_info(type); +var_info = std::unique_ptr(VarInfoFactory::new_var_info(type)); if ( _multivar ) { diff --git a/src/libcode/vx_shapedata/mode_field_info.h b/src/libcode/vx_shapedata/mode_field_info.h index 3f73d6ecfa..93c3a67d85 100644 --- a/src/libcode/vx_shapedata/mode_field_info.h +++ b/src/libcode/vx_shapedata/mode_field_info.h @@ -73,7 +73,7 @@ class Mode_Field_Info { int conv_radius; // Convolution radius in grid squares double vld_thresh; // Minimum ratio of valid data points in the convolution area - VarInfo * var_info; // allocated + std::unique_ptr var_info; IntArray conv_radius_array; // List of convolution radii in grid squares ThreshArray conv_thresh_array; // List of conv thresholds to use From c030a4c04dcef4f869c6ae9cfdd94406171e8cf1 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 30 Jun 2026 21:31:37 +0000 Subject: [PATCH 59/63] Per #1518, solve another SonarQube finding. --- src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc index b2a6bc146b..33e7200db9 100644 --- a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc +++ b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc @@ -214,10 +214,7 @@ bool MetNcWrfDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, int MetNcWrfDataFile::data_plane_array(VarInfo &vinfo, DataPlaneArray &plane_array, bool do_winds) { - int i_dim, n_level, status, lower, upper; - ConcatString level_str; - double pressure, min_level, max_level; - bool found = false; + double pressure; VarInfoNcWrf *vinfo_nc = (VarInfoNcWrf *) &vinfo; LongArray dim = vinfo_nc->dimension(); NcVarInfo *info = (NcVarInfo *) nullptr; @@ -229,6 +226,8 @@ int MetNcWrfDataFile::data_plane_array(VarInfo &vinfo, plane_array.clear(); // Find the dimension that has the range flag set + int i_dim; + bool found = false; for(i_dim=0; i_dimdata(vinfo_nc->req_name().c_str(), - cur_dim, cur_plane, pressure, info); + double status = WrfNc->data(vinfo_nc->req_name().c_str(), + cur_dim, cur_plane, pressure, info); // Assume that WRF winds are grid-relative vinfo_nc->set_grid_relative_flag(true); @@ -325,7 +324,10 @@ int MetNcWrfDataFile::data_plane_array(VarInfo &vinfo, // Set the VarInfo object's level string for pressure levels // Check for a missing value, a single pressure level, or a range // of pressure levels + double min_level; + double max_level; plane_array.level_range(min_level, max_level); + ConcatString level_str; if(is_bad_data(min_level) || is_bad_data(max_level)) level_str << cs_erase << na_str; else if(is_eq(min_level, max_level)) level_str << cs_erase << "P" << nint(min_level); From 21cff9f04aa51d3a3deb3399e8444437817dec5b Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 30 Jun 2026 22:02:03 +0000 Subject: [PATCH 60/63] Switch double to bool --- src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc index 33e7200db9..20130822e3 100644 --- a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc +++ b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc @@ -256,8 +256,8 @@ int MetNcWrfDataFile::data_plane_array(VarInfo &vinfo, cur_dim[i_dim] = lower + i; // Read data for the current level - double status = WrfNc->data(vinfo_nc->req_name().c_str(), - cur_dim, cur_plane, pressure, info); + bool status = WrfNc->data(vinfo_nc->req_name().c_str(), + cur_dim, cur_plane, pressure, info); // Assume that WRF winds are grid-relative vinfo_nc->set_grid_relative_flag(true); From 933b89d8bbffe7a857eb258bf312688964b3d933 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 30 Jun 2026 22:34:10 +0000 Subject: [PATCH 61/63] More SonarQube cleanup --- src/libcode/vx_data2d/var_info.h | 1 - src/libcode/vx_data2d/var_info_pairs.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libcode/vx_data2d/var_info.h b/src/libcode/vx_data2d/var_info.h index 0d327ec859..d68e306058 100644 --- a/src/libcode/vx_data2d/var_info.h +++ b/src/libcode/vx_data2d/var_info.h @@ -108,7 +108,6 @@ class VarInfo UserFunc_1Arg ConvertFx; void clear(); - void clone_base() const; virtual void dump(std::ostream &) const; diff --git a/src/libcode/vx_data2d/var_info_pairs.h b/src/libcode/vx_data2d/var_info_pairs.h index 01ea939cfb..23121db1b7 100644 --- a/src/libcode/vx_data2d/var_info_pairs.h +++ b/src/libcode/vx_data2d/var_info_pairs.h @@ -33,7 +33,7 @@ class VarInfoPairs : public VarInfo { ~VarInfoPairs(); VarInfoPairs(const VarInfoPairs &); VarInfoPairs & operator=(const VarInfoPairs &); - std::unique_ptr clone() const; + std::unique_ptr clone() const override; void dump(std::ostream &) const; void clear(); From dae64dc203ee73ed35ea971d3c5f30e0a204f25e Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Wed, 1 Jul 2026 15:11:08 +0000 Subject: [PATCH 62/63] One more SonarQube issue --- src/libcode/vx_data2d_python/var_info_python.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcode/vx_data2d_python/var_info_python.h b/src/libcode/vx_data2d_python/var_info_python.h index 2c5f87b29a..52c1527def 100644 --- a/src/libcode/vx_data2d_python/var_info_python.h +++ b/src/libcode/vx_data2d_python/var_info_python.h @@ -41,7 +41,7 @@ class VarInfoPython : public VarInfo ~VarInfoPython(); VarInfoPython(const VarInfoPython &); VarInfoPython & operator=(const VarInfoPython &); - std::unique_ptr clone() const; + std::unique_ptr clone() const override; void dump(std::ostream &) const; void clear(); From b91fac466165efff0962813fcccb851a79d3199d Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 14 Jul 2026 18:49:01 +0000 Subject: [PATCH 63/63] Per #1518, update docs based on PR feedback. --- docs/Users_Guide/config_options.rst | 3 ++- docs/Users_Guide/point-stat.rst | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/Users_Guide/config_options.rst b/docs/Users_Guide/config_options.rst index 72dc71dd5f..d405ae2290 100644 --- a/docs/Users_Guide/config_options.rst +++ b/docs/Users_Guide/config_options.rst @@ -682,7 +682,8 @@ The following configuration options can be set to refine the metadata, when need is_wind_direction = boolean; When deriving and rotating winds, MET searches the input file for matching wind -components. That search is driven by the following configuration options: +components. That search is driven by the following configuration options and +default values found in the "data/config/ConfigConstants" file: .. code-block:: none diff --git a/docs/Users_Guide/point-stat.rst b/docs/Users_Guide/point-stat.rst index 084b8c7945..4442a6d565 100644 --- a/docs/Users_Guide/point-stat.rst +++ b/docs/Users_Guide/point-stat.rst @@ -124,11 +124,13 @@ Wind Rotation and Derivation Numerical weather prediction model output often defines winds relative to the orientation of the model grid rather than true north-south and east-west directions on the earth. However point observations typically define winds relative to true earth directions. Prior to comparing them, the model wind data must be rotated from grid-relative to -to earth-relative. While the degree of grid-to-earth rotation varies based on the projection type and location, failing to rotate the winds has a significant impact on +to earth-relative. While the degree of grid-to-earth rotation varies based on the projection type and location, failing to rotate the winds can have a significant impact on the verification results. For simplicity, the MET library code attempts to rotate all wind components from being grid-relative to earth-relative regardless of whether they are being compared to point -observations or gridded analyses. Running the MET tools at verbosity level 3 (-v 3) prints log messages to describing the wind rotation process. +observations with the Point-Stat tool or gridded analyses with the Grid-Stat tool. Running the MET tools at verbosity level 3 (-v 3) prints log messages to describing the wind +rotation process. While the logic to determine whether input winds are grid-relative varies by file type, specifying the **is_grid_relative = FALSE;** configuration option +manually overrides that logic and prevents winds from being rotated. Wind fields which must be rotated include wind direction and both the U and V components of the wind vector. While wind direction can be rotated by itself, both U and V are required to rotate either component. When processing U-wind data, MET attempts to read corresponding V-wind data and vice-versa.