diff --git a/.github/jobs/set_job_controls.sh b/.github/jobs/set_job_controls.sh index 8e3fb07da7..818c62c4f0 100755 --- a/.github/jobs/set_job_controls.sh +++ b/.github/jobs/set_job_controls.sh @@ -6,6 +6,7 @@ run_unit_tests=false run_diff=false run_update_truth=false met_base_repo=met-base +# 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 diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index caa120a0ce..b60635be02 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/data/config/ConfigConstants b/data/config/ConfigConstants index acf34b788a..f6edb9906a 100644 --- a/data/config/ConfigConstants +++ b/data/config/ConfigConstants @@ -22,6 +22,18 @@ 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"; + //////////////////////////////////////////////////////////////////////////////// // // Standard unit conversion functions. diff --git a/docs/Users_Guide/config_options.rst b/docs/Users_Guide/config_options.rst index d02d43eb7e..d405ae2290 100644 --- a/docs/Users_Guide/config_options.rst +++ b/docs/Users_Guide/config_options.rst @@ -661,6 +661,41 @@ 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 and +default values found in the "data/config/ConfigConstants" file: + +.. 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 fcfefeae85..4442a6d565 100644 --- a/docs/Users_Guide/point-stat.rst +++ b/docs/Users_Guide/point-stat.rst @@ -117,6 +117,35 @@ _______________________ 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 +---------------------------- + +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 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 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. + +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: HiRA Framework diff --git a/docs/Users_Guide/release-notes.rst b/docs/Users_Guide/release-notes.rst index c51d86da46..067a5c93bd 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 diff --git a/internal/test_unit/bin/unit_test.sh b/internal/test_unit/bin/unit_test.sh index ebca453449..8efc70ca2c 100755 --- a/internal/test_unit/bin/unit_test.sh +++ b/internal/test_unit/bin/unit_test.sh @@ -40,6 +40,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_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 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/internal/test_unit/xml/unit_winds.xml b/internal/test_unit/xml/unit_winds.xml new file mode 100644 index 0000000000..6638db36b9 --- /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"; 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";' \ + &OUTPUT_DIR;/winds/pcp_combine_winds_NETCDF_WRF.nc \ + -v 3 + + + &OUTPUT_DIR;/winds/pcp_combine_winds_NETCDF_WRF.nc + + + + diff --git a/src/basic/vx_config/config_constants.h b/src/basic/vx_config/config_constants.h index 75e0629123..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 - bool operator==(const InterpInfo &) const; 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,47 @@ struct MaskLatLon { ~MaskLatLon() { clear(); } MaskLatLon(MaskLatLon const &i) { *this = i; } MaskLatLon &operator=(const MaskLatLon &a) noexcept; - bool operator==(const MaskLatLon &) const; 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); + } +}; + +//////////////////////////////////////////////////////////////////////// + +// +// Struct to store wind vector metadata +// + +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 + + WindMetadata() { clear(); } + ~WindMetadata() { clear(); } + WindMetadata(WindMetadata const &i) { *this = i; } + WindMetadata &operator=(const WindMetadata &a) noexcept; + void clear(); + + 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"; } + + 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); + } }; //////////////////////////////////////////////////////////////////////// @@ -751,6 +798,15 @@ 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"; + // // Entries to override file metadata // @@ -1329,8 +1385,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..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 MaskLatLon::operator==(const MaskLatLon &v) const { - bool match = true; - - if(!(name == v.name ) || - !(lat_thresh == v.lat_thresh) || - !(lon_thresh == v.lon_thresh)) { - match = false; - } - - return match; -} - -/////////////////////////////////////////////////////////////////////////////// - MaskLatLon &MaskLatLon::operator=(const MaskLatLon &a) noexcept { if(this != &a) { name = a.name; @@ -817,6 +803,61 @@ vector parse_conf_llpnt_mask(Dictionary *dict) { return v; } +/////////////////////////////////////////////////////////////////////////////// +// +// Code for WindMetadata struct +// +/////////////////////////////////////////////////////////////////////////////// + +void WindMetadata::clear() { + u_wind.clear(); + v_wind.clear(); + wind_speed.clear(); + wind_direction.clear(); +} + +/////////////////////////////////////////////////////////////////////////////// + +WindMetadata &WindMetadata::operator=(const WindMetadata &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; + } + return *this; +} + +/////////////////////////////////////////////////////////////////////////////// + +WindMetadata parse_conf_wind_metadata(Dictionary *dict) { + WindMetadata info; + + if(!dict) { + mlog << Error << "\nparse_conf_wind_metadata() -> " + << "empty dictionary!\n\n"; + exit(1); + } + + // Conf: 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.parse_css(dict->lookup_string(conf_key_v_wind_field_name)); + + // Conf: 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.parse_css(dict->lookup_string(conf_key_wind_direction_field_name)); + + return info; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Utility parsing functions +// /////////////////////////////////////////////////////////////////////////////// SingleThresh parse_conf_quality_mark_thresh(Dictionary *dict) { @@ -1732,23 +1773,6 @@ void InterpInfo::validate() { /////////////////////////////////////////////////////////////////////////////// -bool InterpInfo::operator==(const InterpInfo &v) const { - 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 )) { - match = false; - } - - return match; -} - -/////////////////////////////////////////////////////////////////////////////// - InterpInfo & InterpInfo::operator=(const InterpInfo &a) noexcept { if(this != &a) { field = a.field; 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/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 0) { @@ -58,8 +71,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,38 +86,59 @@ bool build_grid_by_grid_string(const ConcatString &grid_str, Grid &grid, //////////////////////////////////////////////////////////////////////// -bool derive_wdir(const DataPlane &u2d, const DataPlane &v2d, - DataPlane &wdir2d) { - const int nx = u2d.nx(); - const int ny = u2d.ny(); +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 &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_wdir() -> " + 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 " + if(uwnd.nx() != vwnd.nx() || uwnd.ny() != vwnd.ny()) { + mlog << Warning << "\nderive_kinetic_energy() -> " << "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 // - wind2d = u2d; - wind2d.set_constant(bad_data_double); + keng = uwnd; + keng.set_constant(bad_data_double); + + const int nx = uwnd.nx(); + const int ny = uwnd.ny(); #pragma omp parallel default(shared) \ - shared(u2d, v2d, wind2d) + shared(uwnd, vwnd, keng) { - // - // Compute the wind direction - // #pragma omp for schedule(static) \ collapse(2) for(int x=0; x " + << "the dimensions for wind speed and direction do not match: (" + << wspd.nx() << ", " << wspd.ny() << ") != (" + << wdir.nx() << ", " << wdir.ny() << ")\n\n"; + return false; + } + + // + // Initialize output + // + dp = wspd; + dp.set_constant(bad_data_double); + + const int nx = wspd.nx(); + const int ny = wspd.ny(); + +#pragma omp parallel default(shared) \ + shared(wspd, wdir, dp) + { + +#pragma omp for schedule(static) \ + collapse(2) + for(int x=0; xneed_uv_wind()) { + + // Create local copies + auto vinfo_uwnd = vinfo->clone(); + auto vinfo_vwnd = vinfo->clone(); + + DataPlane uwnd_dp; + DataPlane vwnd_dp; + 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.get(), + conf_key_v_wind_field_name, + vinfo->wind_info().v_wind, + vwnd_dp); + + if(status) { + + // Rotate U/V winds, if needed + 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); + 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); + } + + // 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(vinfo_uwnd->units()); + } + // 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"); + } + // 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 U and V from wind speed and direction + // + +else if(vinfo->is_u_wind() || vinfo->is_v_wind()) { + + // Create local copies + auto vinfo_wspd = vinfo->clone(); + auto vinfo_wdir = vinfo->clone(); + + DataPlane wspd_dp; + DataPlane wdir_dp; + 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.get(), + conf_key_wind_direction_field_name, + vinfo->wind_info().wind_direction, + wdir_dp); + + // Rotate wind direction, if needed + 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"; + rotate_wind_direction_grid_to_earth(wdir_dp_orig, + *Raw_Grid, wdir_dp); + vinfo->set_earth_relative(); + } + + if(status) { + 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(vinfo_wspd->units()); + } + else { + status = derive_v_wind(wspd_dp, wdir_dp, dp); + vinfo->set_long_name("V-Component of Wind"); + vinfo->set_units(vinfo_wspd->units()); + } + } +} + +return status; + +} + + +//////////////////////////////////////////////////////////////////////// + + +bool Met2dDataFile::derive_winds(VarInfo *vinfo, DataPlaneArray &dpa) + +{ + +static const char *method_name = "Met2dDataFile::derive_winds() -> "; + +if(!vinfo) return false; + +bool status = false; + + // + // Derive wind fields from U and V + // + +if(vinfo->need_uv_wind()) { + + // Create local copies + auto vinfo_uwnd = vinfo->clone(); + auto vinfo_vwnd = vinfo->clone(); + + DataPlaneArray uwnd_dpa; + DataPlaneArray vwnd_dpa; + 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.get(), + conf_key_v_wind_field_name, + vinfo->wind_info().v_wind, + vwnd_dpa); + + if(!status) return status; + + // Rotate U/V winds, if needed + 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 " + << "to earth-relative.\n"; + for(int i=0; iis_wind_speed()) { + vinfo->set_long_name("Wind Speed"); + 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"); + } + else if(vinfo->is_kinetic_energy()) { + vinfo->set_long_name("Kinetic Energy"); + vinfo->set_units("J/kg"); + } + + // 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 (" + << 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; iis_wind_speed()) { + status = derive_wind_speed(uwnd_dpa[i], vwnd_dpa[i], dp); + } + // 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); + } + + // 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()) { + + // Create local copies + auto vinfo_wspd = vinfo->clone(); + auto vinfo_wdir = vinfo->clone(); + + DataPlaneArray wspd_dpa; + DataPlaneArray wdir_dpa; + 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.get(), + conf_key_wind_direction_field_name, + vinfo->wind_info().wind_direction, + wdir_dpa); + + if(!status) return status; + + // 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 " + << "to earth-relative.\n"; + for(int i=0; iset_earth_relative(); + } + + // Store the long name and units + if(vinfo->is_u_wind()) { + vinfo->set_long_name("U-Component of Wind"); + vinfo->set_units(vinfo_wspd->units()); + } + else { + vinfo->set_long_name("V-Component of Wind"); + vinfo->set_units(vinfo_wspd->units()); + } + + if(wspd_dpa.n_planes() != wdir_dpa.n_planes()) { + 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 (" + << wdir_dpa.n_planes() + << ") for file '" << filename() << "'\n\n"; + return false; + } + + // + // Loop through each of the data planes + // + for(int i=0; iis_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::rotate_winds(const VarInfo *vinfo, DataPlane &dp) + +{ + +static const char *method_name = "Met2dDataFile::rotate_winds(DataPlane) -> "; + +if(!vinfo) return false; + +if(!vinfo->is_wind_rotation()) return true; + +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; +} + +bool status = false; + +// Create local copy +auto vinfo_wind = vinfo->clone(); + +DataPlane uwnd_dp; +DataPlane vwnd_dp; +DataPlane tmp_dp; + +// Rotate U-Wind +if(vinfo->is_u_wind()) { + uwnd_dp = dp; + status = read_wind_data(vinfo_wind.get(), + conf_key_v_wind_field_name, + vinfo->wind_info().v_wind, + vwnd_dp); + 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_wind.get(), + conf_key_u_wind_field_name, + vinfo->wind_info().u_wind, + uwnd_dp); + 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; + rotate_wind_direction_grid_to_earth(tmp_dp, *Raw_Grid, dp); + status = true; +} + +if(!status) { + mlog << Warning << "\n" << method_name + << "Trouble rotating wind field (" << vinfo->magic_str() + << ") from grid to earth relative.\n\n"; +} + +return status; + +} + + +//////////////////////////////////////////////////////////////////////// + + +bool Met2dDataFile::rotate_winds(const VarInfo *vinfo, DataPlaneArray &dpa) + +{ + +static const char *method_name = "Met2dDataFile::rotate_winds(DataPlaneArray) -> "; + +if(!vinfo) return false; + +if(!vinfo->is_wind_rotation() || dpa.n_planes() == 0) return true; + +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; +} + +bool status = false; + +// Create local copy +auto vinfo_wind = vinfo->clone(); + +DataPlaneArray uwnd_dpa; +DataPlaneArray vwnd_dpa; +DataPlaneArray tmp_dpa(dpa); +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_wind.get(), + conf_key_v_wind_field_name, + vinfo->wind_info().v_wind, + vwnd_dpa); + } + else { + vwnd_dpa = dpa; + uwnd_out = &tmp_dpa; + vwnd_out = &dpa; + status = read_wind_data(vinfo_wind.get(), + conf_key_u_wind_field_name, + vinfo->wind_info().u_wind, + uwnd_dpa); + } + + // 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"; +} + +return status; + +} + + +//////////////////////////////////////////////////////////////////////// + + +bool Met2dDataFile::read_wind_data(VarInfo *vinfo, + const char *conf_key, + const StringArray &names, + DataPlane &dp) + +{ + +static const char *method_name = "Met2dDataFile::read_wind_data(DataPlane) -> "; + +if(!vinfo) return false; + +bool status = false; + + // Update search names, if needed + +StringArray search_names(swap_uv_name(vinfo, conf_key, names)); + + // Try each of the possible names + +for(int i=0; ireset_dict_with_name(search_names[i].c_str()) && + data_plane(*vinfo, dp, false)) { + status = true; + mlog << Debug(3) << "Found matching wind field \"" + << vinfo->magic_str() << "\".\n"; + break; + } +} + +if(!status) { + mlog << Warning << "\n" << method_name + << "No matching wind field found for name(s) \"" + << write_css(search_names) << "\".\n" + << "Set \"" << conf_key + << "\" to specify the matching variable name.\n\n"; +} + +return status; + +} + + +//////////////////////////////////////////////////////////////////////// + + +bool Met2dDataFile::read_wind_data(VarInfo *vinfo, + const char *conf_key, + const StringArray &names, + DataPlaneArray &dpa) + +{ + +static const char *method_name = "Met2dDataFile::read_wind_data(DataPlaneArray) -> "; + +if(!vinfo) return false; + +bool status = false; + + // Update search names, if needed + +StringArray search_names(swap_uv_name(vinfo, conf_key, names)); + + // Try each of the possible names + +for(int i=0; ireset_dict_with_name(search_names[i].c_str()) && + data_plane_array(*vinfo, dpa, false)) { + status = true; + mlog << Debug(3) << "Found matching wind field(s) \"" + << vinfo->magic_str() << "\".\n"; + break; + } +} + +if(!status) { + mlog << Warning << "\n" << method_name + << "No matching wind field(s) found for name(s) \"" + << write_css(search_names) << "\".\n" + << "Set \"" << conf_key + << "\" to specify the matching variable name.\n\n"; +} + +return status; + +} + + //////////////////////////////////////////////////////////////////////// @@ -455,4 +1056,47 @@ return true; } +//////////////////////////////////////////////////////////////////////// + + +static StringArray swap_uv_name(const VarInfo *vinfo, + const ConcatString &conf_key, + const StringArray &names) +{ + + // 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; + 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 && + 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 && + names == default_names) { + cs.replace("V", "U", false); + cs.replace("v", "u", false); + if(cs != vinfo->name()) sa.insert(0, cs.c_str()); + } + + return sa; + +} + + //////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_data2d/data_class.h b/src/libcode/vx_data2d/data_class.h index 1b8cd6493d..de36548069 100644 --- a/src/libcode/vx_data2d/data_class.h +++ b/src/libcode/vx_data2d/data_class.h @@ -83,6 +83,13 @@ class Met2dDataFile : public Met2dData { void mtddf_init_from_scratch(); + bool read_wind_data(VarInfo *, + const char *, const StringArray &, + DataPlane &); + bool read_wind_data(VarInfo *, + const char *, const StringArray &, + DataPlaneArray &); + bool GridShifted; protected: @@ -141,11 +148,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_winds = true) = 0; // retrieve all matching data planes - virtual int data_plane_array(VarInfo &, DataPlaneArray &) = 0; + virtual int data_plane_array(VarInfo &, DataPlaneArray &, bool do_winds = true) = 0; // retrieve the indexes of the first matching data plane @@ -156,6 +163,13 @@ class Met2dDataFile : public Met2dData { int data_planes(std::vector&, std::vector&); + // derive and rotate wind fields + + bool derive_winds(VarInfo *, DataPlane &); + bool derive_winds(VarInfo *, DataPlaneArray &); + bool rotate_winds(const VarInfo *, DataPlane &); + bool rotate_winds(const VarInfo *, DataPlaneArray &); + // post-process data after reading it bool process_data_plane(VarInfo *, DataPlane &); diff --git a/src/libcode/vx_data2d/table_lookup.cc b/src/libcode/vx_data2d/table_lookup.cc index b51bb40610..1a87c4cd0a 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; @@ -1043,435 +1044,211 @@ return true; } - //////////////////////////////////////////////////////////////////////// +int TableFlatFile::lookup_grib1(int code, int table_number, + vector &matches) const { + matches.clear(); -bool TableFlatFile::lookup_grib1(int code, int table_number, Grib1TableEntry & e) - -{ - -e.clear(); - -for (int j=0; j &matches) const { + 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) const { -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) const { + 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; - } - - 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"; +int TableFlatFile::lookup_grib1(const char *parm_name, int table_number, + int code,int center, int subcenter, + vector &matches) const { + 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); } - - 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) const { -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) const { + matches.clear(); -bool TableFlatFile::lookup_grib2(int a, int b, int c, Grib2TableEntry & e) - -{ - -e.clear(); - -for (int j=0; j &matches) const { + vector exact_matches; + vector partial_matches; -bool TableFlatFile::lookup_grib2(int a, int b, int c, - 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) const { + matches.clear(); -bool TableFlatFile::lookup_grib2(const char * parm_name, int a, int b, int c, - 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 - << ", index_a = " << it->index_a - << ", index_b = " << it->index_b - << ", index_c = " << it->index_c << "\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"; - - } - - 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) const { + vector exact_matches; + vector partial_matches; -bool TableFlatFile::lookup_grib2(const char * parm_name, - int a, int b, int c, - 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 - << ", index_a = " << it->index_a - << ", grib2_mtab = " << it->mtab_set - << ", grib2_cntr = " << it->cntr - << ", grib2_ltab = " << it->ltab - << ", index_b = " << it->index_b - << ", index_c = " << it->index_c - << "\n"; - - mlog << Debug(3) << "Using the first match found: " - << " parm_name: " << e.parm_name - << ", index_a = " << e.index_a - << ", grib2_mtab = " << e.mtab_set - << ", grib2_cntr = " << e.cntr - << ", grib2_ltab = " << e.ltab - << ", index_b = " << e.index_b - << ", index_c = " << e.index_c - << "\n\n"; - - } - else if( 0 == n_matches ){ - mlog << Debug(3) << "No match, lookup criteria (" - << log_arguments(parm_name, a, b, c, 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) 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 ae330ee1eb..5d95002849 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; @@ -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 &) const; + int lookup_grib1(int code, int table_number, int center, int subcenter, + std::vector &) const; + + // Assumes table_number = 2 by default + int lookup_grib1(int code, + std::vector &) const; + int lookup_grib1(const char * parm_name, + std::vector &) const; + + int lookup_grib1(const char * parm_name, int table_number, int code, + std::vector &) const; + int lookup_grib1(const char * parm_name, int table_number, int code,int center, int subcenter, + std::vector &) const; + + int lookup_grib2(int disc, int pcat, int pnum, + std::vector &) const; + int lookup_grib2(int disc, int pcat, int pnum, int mtab, int cntr, int ltab, + std::vector &) const; + int lookup_grib2(const char * parm_name, + std::vector &) const; + int lookup_grib2(const char * parm_name, int disc, int pcat, int pnum, + std::vector &) const; + int lookup_grib2(const char * parm_name, int disc, int pcat, int pnum, int mtab, int cntr, int ltab, + std::vector &) const; void readUserGribTables(const char * table_type); diff --git a/src/libcode/vx_data2d/var_info.cc b/src/libcode/vx_data2d/var_info.cc index 5e6aa8dd6a..309f61ef4c 100644 --- a/src/libcode/vx_data2d/var_info.cc +++ b/src/libcode/vx_data2d/var_info.cc @@ -87,6 +87,7 @@ void VarInfo::init_from_scratch() { void VarInfo::assign(const VarInfo &v) { // Copy + Dict = v.Dict; MagicStr = v.MagicStr; ReqName = v.ReqName; Name = v.Name; @@ -119,6 +120,9 @@ void VarInfo::assign(const VarInfo &v) { DefaultRegrid = v.DefaultRegrid; Regrid = v.Regrid; + GridRelativeFlag = v.GridRelativeFlag; + WindInfo = v.WindInfo; + SetAttrName = v.SetAttrName; SetAttrUnits = v.SetAttrUnits; SetAttrLevel = v.SetAttrLevel; @@ -148,6 +152,7 @@ void VarInfo::assign(const VarInfo &v) { void VarInfo::clear() { // Initialize + Dict.clear(); MagicStr.clear(); ReqName.clear(); Name.clear(); @@ -180,6 +185,9 @@ void VarInfo::clear() { DefaultRegrid.clear(); Regrid.clear(); + GridRelativeFlag = false; + WindInfo.clear(); + SetAttrName.clear(); SetAttrUnits.clear(); SetAttrLevel.clear(); @@ -289,6 +297,13 @@ void VarInfo::set_req_name(const char *str) { /////////////////////////////////////////////////////////////////////////////// +void VarInfo::set_req_name(const string &str) { + set_req_name(str.c_str()); + return; +} + +/////////////////////////////////////////////////////////////////////////////// + void VarInfo::set_name(const char *str) { Name = str; return; @@ -296,8 +311,8 @@ void VarInfo::set_name(const char *str) { /////////////////////////////////////////////////////////////////////////////// -void VarInfo::set_name(const string str) { - Name = str; +void VarInfo::set_name(const string &str) { + set_name(str.c_str()); return; } @@ -324,6 +339,13 @@ void VarInfo::set_units(const char *str) { /////////////////////////////////////////////////////////////////////////////// +void VarInfo::set_units(const string &str) { + set_units(str.c_str()); + return; +} + +/////////////////////////////////////////////////////////////////////////////// + void VarInfo::set_level_info(const LevelInfo &l) { Level = l; return; @@ -457,6 +479,21 @@ void VarInfo::set_regrid(const RegridInfo &ri) { /////////////////////////////////////////////////////////////////////////////// +void VarInfo::set_grid_relative_flag(bool f) { + GridRelativeFlag = f; + return; +} + +/////////////////////////////////////////////////////////////////////////////// + +void VarInfo::set_earth_relative() { + GridRelativeFlag = false; + SetAttrIsGridRelative = 0; + return; +} + +/////////////////////////////////////////////////////////////////////////////// + void VarInfo::set_magic(const ConcatString &nstr, const ConcatString &lstr) { // Check for embedded whitespace @@ -502,6 +539,9 @@ bool VarInfo::set_dict(Dictionary &dict, bool do_exit) { int n; const char *method_name = "VarInfo::set_dict(Dictionary &dict) -> "; + // Store the dictionary + Dict = dict; + // Set init time, if present s = dict.lookup_string(conf_key_init_time, false); if(dict.last_lookup_status()) set_init(timestring_to_unix(s.c_str())); @@ -549,6 +589,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); @@ -599,8 +642,16 @@ bool VarInfo::set_dict(Dictionary &dict, bool do_exit) { /////////////////////////////////////////////////////////////////////////////// -void VarInfo::set_level_info_grib(Dictionary & dict){ +bool VarInfo::reset_dict_with_name(const char *str) { + DictionaryEntry e; + e.set_string(conf_key_name, str); + Dict.store(e); + return set_dict(Dict); +} + +/////////////////////////////////////////////////////////////////////////////// +void VarInfo::set_level_info_grib(Dictionary & dict){ ConcatString field_level = dict.lookup_string(conf_key_level, false); LevelType lt; string lvl_type, lvl_val1, lvl_val2; @@ -774,6 +825,21 @@ 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_int; + + // 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 + if(is_bad_data(flag) && field_names.has(Name)) flag = 1; + + return flag; +} + +/////////////////////////////////////////////////////////////////////////////// + bool VarInfo::is_precipitation() const { return is_flag_set(SetAttrIsPrecipitation); } @@ -787,25 +853,66 @@ bool VarInfo::is_specific_humidity() const { /////////////////////////////////////////////////////////////////////////////// bool VarInfo::is_u_wind() const { - return is_flag_set(SetAttrIsUWind); + return is_flag_set(get_wind_flag(SetAttrIsUWind, + WindInfo.u_wind)); } /////////////////////////////////////////////////////////////////////////////// bool VarInfo::is_v_wind() const { - return is_flag_set(SetAttrIsVWind); + return is_flag_set(get_wind_flag(SetAttrIsVWind, + WindInfo.v_wind)); } /////////////////////////////////////////////////////////////////////////////// bool VarInfo::is_wind_speed() const { - return is_flag_set(SetAttrIsWindSpeed); + return is_flag_set(get_wind_flag(SetAttrIsWindSpeed, + WindInfo.wind_speed)); } /////////////////////////////////////////////////////////////////////////////// bool VarInfo::is_wind_direction() const { - return is_flag_set(SetAttrIsWindDirection); + return is_flag_set(get_wind_flag(SetAttrIsWindDirection, + WindInfo.wind_direction)); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool VarInfo::is_kinetic_energy() const { + return WindInfo.is_kinetic_energy(Name); +} + +/////////////////////////////////////////////////////////////////////////////// + +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 : + GridRelativeFlag); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool VarInfo::need_uv_wind() const { + return(is_wind_speed() || + is_wind_direction() || + is_kinetic_energy()); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool VarInfo::need_rotation() const { + return is_wind_rotation() && + is_grid_relative(); } /////////////////////////////////////////////////////////////////////////////// @@ -882,7 +989,7 @@ bool VarInfo::validate_wind_attributes(bool do_exit, const char *caller_name) co /////////////////////////////////////////////////////////////////////////////// ConcatString parse_set_attr_string(Dictionary &dict, const char *key, - bool check_ws) { + bool check_ws) { ConcatString cs; cs = dict.lookup_string(key, false); diff --git a/src/libcode/vx_data2d/var_info.h b/src/libcode/vx_data2d/var_info.h index bc3b32ae13..d68e306058 100644 --- a/src/libcode/vx_data2d/var_info.h +++ b/src/libcode/vx_data2d/var_info.h @@ -28,8 +28,8 @@ class VarInfo { protected: - ConcatString MagicStr; // Requested magic string Dictionary Dict; // Requested fcst/obs dictionary of fields + ConcatString MagicStr; // Requested magic string ConcatString ReqName; // Requested parameter name ConcatString Name; // Name of parameter @@ -60,6 +60,9 @@ class VarInfo RegridInfo DefaultRegrid; // Default regridding logic RegridInfo Regrid; // Regridding logic + bool GridRelativeFlag; // Wind data is grid relative + WindMetadata WindInfo; // Wind variable metadata + // Options to override metadata ConcatString SetAttrName; ConcatString SetAttrUnits; @@ -85,7 +88,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 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; @@ -98,13 +102,12 @@ 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; void clear(); - void clone_base() const; virtual void dump(std::ostream &) const; @@ -145,6 +148,7 @@ class VarInfo NumArray range() const; RegridInfo regrid() const; + WindMetadata wind_info() const; ConcatString magic_str_attr() const; ConcatString name_attr() const; @@ -167,10 +171,14 @@ class VarInfo virtual bool set_dict(Dictionary &, bool do_exit=true); virtual void add_grib_code(Dictionary &); + bool reset_dict_with_name(const char *); + 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_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 *); @@ -199,6 +207,9 @@ class VarInfo void set_default_regrid(const RegridInfo &); 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, double thresh_lo, double thresh_hi); @@ -213,6 +224,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_wind_rotation() const; + bool is_grid_relative() const; + bool need_uv_wind() const; + bool need_rotation() const; bool is_prob() const; }; @@ -250,6 +266,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/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..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 &); - VarInfo *clone() const; + std::unique_ptr clone() const override; void dump(std::ostream &) const; void clear(); diff --git a/src/libcode/vx_data2d_grib/data2d_grib.cc b/src/libcode/vx_data2d_grib/data2d_grib.cc index a004f5fca0..13ded47942 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_winds) { 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_winds); // Process multiple matches if ( n_planes > 0 ) { @@ -464,22 +465,22 @@ bool MetGrib1DataFile::data_plane(VarInfo &vinfo, DataPlane &plane) { //////////////////////////////////////////////////////////////////////// int MetGrib1DataFile::data_plane_array(VarInfo &vinfo, - DataPlaneArray &plane_array) { + 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); @@ -488,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() @@ -496,35 +497,14 @@ 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 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) status = process_data_plane(&vinfo, cur_plane); - if(!status) { cur_plane.clear(); lower = upper = bad_data_int; @@ -534,81 +514,27 @@ 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); } } // 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); + // Handle wind rotation + if(do_winds) rotate_winds(&vinfo, 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_wdir(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); - } - - // Add the current data plane - plane_array.add(cur_plane, u_plane_array.lower(i), u_plane_array.upper(i)); - - } // end for + // If nothing was found, try to build derived records + if(plane_array.n_planes() == 0 && do_winds) { + derive_winds(&vinfo, plane_array); + } - } // end if wdir or wind - } // end if n_planes == 0 + // Post-process each data plane + for(int i=0; i " << "Found " << plane_array.n_planes() @@ -619,101 +545,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_wdir_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 @@ -721,7 +552,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 fedc99b8d7..5f5cafed0b 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,15 +82,15 @@ class MetGrib1DataFile : public Met2dDataFile { // retrieve the first matching data plane - bool data_plane(VarInfo &, DataPlane &); + bool data_plane(VarInfo &, DataPlane &, bool do_winds = true) override; // retrieve all matching data planes - int data_plane_array(VarInfo &, DataPlaneArray &); + 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; }; diff --git a/src/libcode/vx_data2d_grib/data2d_grib_utils.cc b/src/libcode/vx_data2d_grib/data2d_grib_utils.cc index 938d390282..2afccda455 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,22 +156,21 @@ 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 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 the lookup still fails, then it's not a match - return false; - } + // 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 && + GribTable.lookup_grib1(field_name.c_str(), default_grib1_ptv, code_for_lookup, + default_grib1_center, default_grib1_subcenter, matches) == 0) + { + // if both lookups fail, then it's not a match + return false; } } @@ -187,22 +187,23 @@ 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 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) ) - { - 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); - } + // 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 && + 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 ( 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 abb48a9321..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)); } /////////////////////////////////////////////////////////////////////////////// @@ -102,14 +99,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 +119,14 @@ 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; + TRI = bad_data_int; return; } @@ -139,12 +137,13 @@ 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" + << " TRI = " << TRI << "\n"; return; } @@ -210,7 +209,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,27 +219,30 @@ 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 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, tab, tab_match) ) - { - 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); } } @@ -257,22 +258,25 @@ 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 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) ) - { - 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); - } + // 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 && + 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 ( tab.code ); - set_long_name ( tab.full_name.c_str() ); - set_units ( tab.units.c_str() ); + set_code ( matches[0].code ); + set_long_name ( matches[0].full_name.c_str() ); + set_units ( matches[0].units.c_str() ); } /////////////////////////////////////////////////////////////////////////////// @@ -281,8 +285,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 +329,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 +342,9 @@ 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_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; @@ -353,9 +357,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 +382,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 +407,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 +421,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 +435,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 +449,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_grib/var_info_grib.h b/src/libcode/vx_data2d_grib/var_info_grib.h index f3f0f49f96..c333924b39 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 @@ -67,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/data2d_grib2.cc b/src/libcode/vx_data2d_grib2/data2d_grib2.cc index 4508f334f1..4895d7f13f 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; } //////////////////////////////////////////////////////////////////////// @@ -148,7 +142,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_winds) { // narrow the vinfo pointer auto vinfo_g2 = (VarInfoGrib2*)(&vinfo); @@ -159,26 +154,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_winds) { + DataPlaneArray plane_array; + derive_winds(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 @@ -189,12 +182,21 @@ bool MetGrib2DataFile::data_plane(VarInfo &vinfo, DataPlane &plane) { plane = plane_array[0]; - return process_data_plane(vinfo_g2, plane); + // handle wind rotation + bool status = true; + if(do_winds) status = rotate_winds(vinfo_g2, plane); + + if(status) status = process_data_plane(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 @@ -226,21 +228,25 @@ 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); - // check the data plane for wind rotation - plane = check_uv_rotation(vinfo_g2, listMatch[0], plane); + if(status) { - if(read_success) read_success = 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); - return read_success; + if(status) status = process_data_plane(vinfo_g2, plane); + } + + return status; } //////////////////////////////////////////////////////////////////////// int MetGrib2DataFile::data_plane_array(VarInfo &vinfo, - DataPlaneArray &plane_array) { + DataPlaneArray &plane_array, + bool do_winds) { // Initialize plane_array.clear(); @@ -307,12 +313,12 @@ int MetGrib2DataFile::data_plane_array(VarInfo &vinfo, } // if nothing was found, try to build derived records - else { + else if(do_winds) { - plane_array = check_derived(vinfo_g2); + derive_winds(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 +327,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(); @@ -337,9 +342,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; @@ -348,9 +350,19 @@ int MetGrib2DataFile::data_plane_array(VarInfo &vinfo, lvl_upper = ( (double)(*it)->LvlVal2 ) / 100.0; } - if(process_data_plane(vinfo_g2, plane)) { - plane_array.add(plane, lvl_lower, lvl_upper); - } + // store grid relative status + vinfo_g2->set_grid_relative_flag(is_grid_relative(*it)); + + // add current plane to the data plane array + 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; idiscipline() == (*it)->Discipline && - vinfo->parm_cat() == (*it)->ParmCat && - vinfo->parm() == (*it)->Parm ) || - vinfo->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()) && @@ -579,115 +589,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; -} - -//////////////////////////////////////////////////////////////////////// - -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(array_u[i], array_v[i], - plane_deriv); - else derive_wdir(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; @@ -947,25 +848,22 @@ 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, + (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] << ", 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 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 @@ -1682,7 +1580,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) ); @@ -1690,7 +1594,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 ddcc6ce8cc..20c4aae5bc 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,14 +106,6 @@ class MetGrib2DataFile : public Met2dDataFile { void read_grib2_record_list(); - DataPlane check_uv_rotation( const VarInfoGrib2 *vinfo, - Grib2Record *rec, - DataPlane plane - ); - - DataPlaneArray check_derived( const VarInfoGrib2 *vinfo ); - - public: MetGrib2DataFile(); @@ -136,15 +123,15 @@ class MetGrib2DataFile : public Met2dDataFile { // retrieve the first matching data plane - bool data_plane(VarInfo &, DataPlane &); + bool data_plane(VarInfo &, DataPlane &, bool do_winds = true) override; // retrieve all matching data planes - int data_plane_array(VarInfo &, DataPlaneArray &); + 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_grib2/var_info_grib2.cc b/src/libcode/vx_data2d_grib2/var_info_grib2.cc index 297694fb3e..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)); } /////////////////////////////////////////////////////////////////////////////// @@ -324,8 +321,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 +357,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 +366,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 +393,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,20 +406,20 @@ 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() ); + 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() ); + 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() ); } // call the parent to set the level information @@ -453,8 +451,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 +461,12 @@ 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_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); @@ -482,9 +480,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 +504,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 +523,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 +544,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 +565,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 +586,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_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/data2d_nc_cf.cc b/src/libcode/vx_data2d_nc_cf/data2d_nc_cf.cc index 1b42a8f5c2..c91443ab57 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++; } @@ -270,56 +270,61 @@ 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 +bool MetNcCFDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, + bool do_winds) { + auto vinfo_nc = (VarInfoNcCF *) &vinfo; + static const string method_name + = "MetNcCFDataFile::data_plane() -> "; - 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); - - for (int idx=0; idxdimension(); + 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; idxset_grid_relative_flag(false); + + // Attempt to derive the data + if(!status && do_winds) { + status = derive_winds(vinfo_nc, plane); + } + + return status; } //////////////////////////////////////////////////////////////////////// -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) { - // Not sure why we do this - 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); @@ -368,7 +373,10 @@ bool MetNcCFDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, const LongArr } } - 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 @@ -393,10 +401,10 @@ bool MetNcCFDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, const LongArr //////////////////////////////////////////////////////////////////////// int MetNcCFDataFile::data_plane_array(VarInfo &vinfo, - DataPlaneArray &plane_array) { + DataPlaneArray &plane_array, + bool do_winds) { int n_rec = 0; DataPlane plane; - bool status = false; static const string method_name = "MetNcCFDataFile::data_plane_array(VarInfo &, DataPlaneArray &) -> "; @@ -420,16 +428,24 @@ 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++; } + // 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) { + 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 c8a15658d0..eec2fa4585 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,15 +99,15 @@ class MetNcCFDataFile : public Met2dDataFile { // retrieve the first matching data plane - bool data_plane(VarInfo &, DataPlane &); + bool data_plane(VarInfo &, DataPlane &, bool do_winds = true) override; // retrieve all matching data planes - int data_plane_array(VarInfo &, DataPlaneArray &); + 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/var_info_nc_cf.cc b/src/libcode/vx_data2d_nc_cf/var_info_nc_cf.cc index 52e550f06e..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)); } /////////////////////////////////////////////////////////////////////////////// @@ -383,9 +380,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 +399,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 +418,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 +431,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 +444,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 +457,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_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/data2d_nc_met.cc b/src/libcode/vx_data2d_nc_met/data2d_nc_met.cc index 616abe0b26..6a1a72fc48 100644 --- a/src/libcode/vx_data2d_nc_met/data2d_nc_met.cc +++ b/src/libcode/vx_data2d_nc_met/data2d_nc_met.cc @@ -209,7 +209,8 @@ void MetNcMetDataFile::set_range_azimuth_times(int i_track_point, DataPlane &pla //////////////////////////////////////////////////////////////////////// -bool MetNcMetDataFile::data_plane(VarInfo &vinfo, DataPlane &plane) { +bool MetNcMetDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, + bool do_winds) { bool status = false; ConcatString req_time_str, data_time_str; VarInfoNcMet * vinfo_nc = (VarInfoNcMet *) &vinfo; @@ -237,6 +238,14 @@ 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); + } + // Check that the times match those requested if(status) { @@ -277,7 +286,10 @@ 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); @@ -293,7 +305,8 @@ bool MetNcMetDataFile::data_plane(VarInfo &vinfo, DataPlane &plane) { //////////////////////////////////////////////////////////////////////// int MetNcMetDataFile::data_plane_array(VarInfo &vinfo, - DataPlaneArray &plane_array) { + DataPlaneArray &plane_array, + bool do_winds) { bool status = false; int n_rec = 0; DataPlane plane; @@ -302,7 +315,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_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 4174f58e4e..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 data_plane(VarInfo &, DataPlane &, bool do_winds = true) override; // retrieve all matching data planes - int data_plane_array(VarInfo &, DataPlaneArray &); + 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/var_info_nc_met.cc b/src/libcode/vx_data2d_nc_met/var_info_nc_met.cc index ea10b2df40..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)); } /////////////////////////////////////////////////////////////////////////////// @@ -266,9 +263,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 +282,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 +301,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 +314,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 +327,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 +340,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_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/data2d_nc_wrf.cc b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc index 037d3dc489..20130822e3 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,7 +21,6 @@ using namespace std; - //////////////////////////////////////////////////////////////////////// // // Code for class MetNcWrfDataFile @@ -121,9 +118,10 @@ 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_winds) { bool status = false; - double pressure; + double pressure = bad_data_double; ConcatString level_str; VarInfoNcWrf * vinfo_nc = (VarInfoNcWrf *) &vinfo; NcVarInfo *info = (NcVarInfo *) nullptr; @@ -131,26 +129,36 @@ 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); - 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); } - status = WrfNc->data(vinfo_nc->req_name().c_str(), - dimension, plane, pressure, info); + // Attempt to derive the data + if(!status && do_winds) { + status = derive_winds(vinfo_nc, plane); + } // Check that the times match those requested if(status) { @@ -177,13 +185,19 @@ 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 - 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,11 +212,9 @@ bool MetNcWrfDataFile::data_plane(VarInfo &vinfo, DataPlane &plane) { //////////////////////////////////////////////////////////////////////// int MetNcWrfDataFile::data_plane_array(VarInfo &vinfo, - DataPlaneArray &plane_array) { - int i, i_dim, n_level, status, lower, upper; - ConcatString level_str; - double pressure, min_level, max_level; - bool found = false; + DataPlaneArray &plane_array, + bool do_winds) { + double pressure; VarInfoNcWrf *vinfo_nc = (VarInfoNcWrf *) &vinfo; LongArray dim = vinfo_nc->dimension(); NcVarInfo *info = (NcVarInfo *) nullptr; @@ -214,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); + 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); + + // Attempt to derive the data + if(!status && do_winds) { + status = derive_winds(vinfo_nc, cur_plane); + } // Check that the times match those requested if(status) { @@ -270,12 +292,18 @@ 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); } + // Handle wind rotation + if(do_winds) rotate_winds(&vinfo, plane_array); + + // post-process each data plane + for(int j=0; jname_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()); @@ -295,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); 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..4512d49a61 100644 --- a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.h +++ b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.h @@ -61,15 +61,15 @@ class MetNcWrfDataFile : public Met2dDataFile { // retrieve the first matching data plane - bool data_plane(VarInfo &, DataPlane &); + bool data_plane(VarInfo &, DataPlane &, bool do_winds = true) override; // retrieve all matching data planes - int data_plane_array(VarInfo &, DataPlaneArray &); + 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/var_info_nc_wrf.cc b/src/libcode/vx_data2d_nc_wrf/var_info_nc_wrf.cc index e05a4c0f32..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)); } /////////////////////////////////////////////////////////////////////////////// @@ -303,9 +300,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 +319,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 +338,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 +360,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 +382,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,25 +401,10 @@ 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; } - -/////////////////////////////////////////////////////////////////////////////// - -bool VarInfoNcWrf::is_grid_relative() const { - - // - // 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 6acae0afef..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 @@ -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 @@ -204,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(); @@ -242,7 +216,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; }; /////////////////////////////////////////////////////////////////////////////// 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; } diff --git a/src/libcode/vx_data2d_python/data2d_python.cc b/src/libcode/vx_data2d_python/data2d_python.cc index b585ee2c60..2996333487 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 MetPythonDataFile::data_plane(VarInfo &vinfo, DataPlane &plane, + bool do_winds) { @@ -332,7 +333,9 @@ if ( status ) { plane = Plane; - status = process_data_plane(&vinfo, plane); + if(status && do_winds) status = rotate_winds(&vinfo, plane); + + if(status) status = process_data_plane(&vinfo, plane); } @@ -360,7 +363,9 @@ return true; //////////////////////////////////////////////////////////////////////// -int MetPythonDataFile::data_plane_array(VarInfo &vinfo, DataPlaneArray &plane_array) +int MetPythonDataFile::data_plane_array(VarInfo &vinfo, + DataPlaneArray &plane_array, + bool do_winds) { @@ -398,7 +403,9 @@ if ( status ) { plane = Plane; - status = process_data_plane(&vinfo, plane); + if(status && do_winds) status = rotate_winds(&vinfo, plane); + + if(status) status = process_data_plane(&vinfo, plane); } diff --git a/src/libcode/vx_data2d_python/data2d_python.h b/src/libcode/vx_data2d_python/data2d_python.h index 623967fd49..440838c444 100644 --- a/src/libcode/vx_data2d_python/data2d_python.h +++ b/src/libcode/vx_data2d_python/data2d_python.h @@ -86,11 +86,11 @@ class MetPythonDataFile : public Met2dDataFile { void dump (std::ostream &, int depth = 0) const; - bool data_plane(VarInfo &, DataPlane &); + bool data_plane(VarInfo &, DataPlane &, bool do_winds = true) override; - int data_plane_array(VarInfo &, DataPlaneArray &); + int data_plane_array(VarInfo &, DataPlaneArray &, bool do_winds = true) override; - int index(VarInfo &); + int index(VarInfo &) override; bool data_plane(DataPlane &); 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..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 &); - VarInfo *clone() const; + std::unique_ptr clone() const override; void dump(std::ostream &) const; void clear(); diff --git a/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc b/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc index a8c75a83dc..303cd2cfeb 100644 --- a/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc +++ b/src/libcode/vx_data2d_ugrid/data2d_ugrid.cc @@ -163,12 +163,12 @@ 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_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 @@ -177,8 +177,17 @@ 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); + 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); + } } else { LevelInfo level = vinfo.level(); @@ -191,7 +200,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 @@ -213,7 +222,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; @@ -221,7 +231,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 @@ -300,7 +310,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; @@ -309,7 +319,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_winds) { int n_rec = 0; DataPlane plane; static const string method_name @@ -322,7 +333,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"; @@ -336,7 +347,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++; } @@ -369,13 +380,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)) { + else if (data_plane(vinfo, plane, do_winds)) { plane_array.add(plane, lvl_lower, lvl_upper); n_rec++; } @@ -741,7 +752,8 @@ int MetUGridDataFile::index(VarInfo &vinfo){ //////////////////////////////////////////////////////////////////////// bool MetUGridDataFile::read_data_plane(ConcatString var_name, VarInfo &vinfo, - DataPlane &plane, LongArray &dimension) { + DataPlane &plane, const LongArray &dimension, + bool do_winds) { static const string method_name = "MetUGridDataFile::read_data_plane() -> "; // Read the data @@ -787,10 +799,10 @@ bool MetUGridDataFile::read_data_plane(ConcatString var_name, VarInfo &vinfo, status = false; } + // Handle wind rotation + if(status && do_winds) status = rotate_winds(&vinfo, plane); + if (status) status = process_data_plane(&vinfo, plane); - else { - mlog << Debug(2) << "\n" << method_name << "not processed data_plane\n"; - } // Set the VarInfo object's name, long_name, level, and units strings diff --git a/src/libcode/vx_data2d_ugrid/data2d_ugrid.h b/src/libcode/vx_data2d_ugrid/data2d_ugrid.h index 6f9ab51ff3..cb759ea87e 100644 --- a/src/libcode/vx_data2d_ugrid/data2d_ugrid.h +++ b/src/libcode/vx_data2d_ugrid/data2d_ugrid.h @@ -86,21 +86,22 @@ class MetUGridDataFile : public Met2dDataFile { // retrieve the first matching data plane - bool data_plane(VarInfo &, DataPlane &); - bool data_plane(VarInfo &, DataPlane &, const NcVarInfo *); + bool data_plane(VarInfo &, DataPlane &, bool do_winds = true) override; + bool data_plane(VarInfo &, DataPlane &, const NcVarInfo *, bool do_winds); // retrieve all matching data planes - int data_plane_array(VarInfo &, DataPlaneArray &); + int data_plane_array(VarInfo &, DataPlaneArray &, bool do_winds = true) override; // retrieve the index of the first matching record int extract_vlevels(const ConcatString &var_name_base, const char *var_name); - int index(VarInfo &); + int index(VarInfo &) override; bool read_data_plane(ConcatString var_name, VarInfo &vinfo, - DataPlane &plane, LongArray &dimension); + DataPlane &plane, const LongArray &dimension, + bool do_winds); // // do stuff diff --git a/src/libcode/vx_data2d_ugrid/var_info_ugrid.cc b/src/libcode/vx_data2d_ugrid/var_info_ugrid.cc index ab71e4bdb7..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)); } /////////////////////////////////////////////////////////////////////////////// @@ -319,9 +316,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 +335,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 +354,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 +367,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 +380,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 +393,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); } 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_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: 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/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 diff --git a/src/tools/core/ensemble_stat/ensemble_stat.cc b/src/tools/core/ensemble_stat/ensemble_stat.cc index 550975473b..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; i " << "trouble reading file \"" << infile << "\"\n\n"; @@ -740,8 +745,8 @@ 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(mtddf) { delete mtddf; mtddf = nullptr; } return found; } 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. diff --git a/src/tools/dev_utils/gen_climo_bin.cc b/src/tools/dev_utils/gen_climo_bin.cc index 1b4fe5ed8d..4ef81ea262 100644 --- a/src/tools/dev_utils/gen_climo_bin.cc +++ b/src/tools/dev_utils/gen_climo_bin.cc @@ -187,7 +187,7 @@ void process_binary() { // Read Nx*Ny records nxy = grid.nx()*grid.ny(); - mlog << "Processing " << nxy << " grid points.\n"; + mlog << Debug(2) << "Processing " << nxy << " grid points.\n"; // Loop over grid points for(i=0; i " << "trouble reading file \"" << infile << "\"\n\n"; exit(1); @@ -700,8 +702,8 @@ 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(mtddf) { delete mtddf; mtddf = nullptr; } return found; } diff --git a/src/tools/other/point2grid/point2grid.cc b/src/tools/other/point2grid/point2grid.cc index ac8278c6a3..470c6cb0f2 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); @@ -1191,7 +1202,7 @@ void process_point_met_data(MetPointData *met_point_obs, MetConfig &config, VarI mlog << Debug(3) << "Using " << var_count << " " << vinfo->name() << " 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 @@ -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);