From 07cacb0160670b4623c338b74a4eb63263e81fe1 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 11 Jan 2024 09:04:26 -0700 Subject: [PATCH] Bugfix #2782 develop MASSDEN (#2783) * Per #2782, port over fixes from the bugfix_2782_main_v11.1_MASSDEN branch over to the bugfix branch for develop. Will also add new GRIB2 filtering options in this branch. * Per #2782, add support for 4 new GRIB2 filtering options for GRIB2_aerosol_type, GRIB2_aerosol_interval_type, GRIB2_aerosol_size_lower, and GRIB2_aerosol_size_upper. These are useful in filtering the MASSDEN records in the RRFS smoke output files. * Per #2782, fix aerosol_size_lower() and aersol_size_upper() inline definitions. * Per #2782, add a unit test for GRIB2 table 4.48. * Per #2782, switch from strict equality to using the is_eq() function when checking the GRIB2_aerosol_size_lower and upper values since they're doubles and not ints. --- docs/Users_Guide/config_options.rst | 14 +++- .../test_unit/xml/unit_plot_data_plane.xml | 17 +++++ src/basic/vx_config/config_constants.h | 7 ++ src/libcode/vx_data2d_grib2/data2d_grib2.cc | 44 ++++++++++-- src/libcode/vx_data2d_grib2/data2d_grib2.h | 4 ++ src/libcode/vx_data2d_grib2/var_info_grib2.cc | 71 +++++++++++++++---- src/libcode/vx_data2d_grib2/var_info_grib2.h | 20 ++++++ 7 files changed, 157 insertions(+), 20 deletions(-) diff --git a/docs/Users_Guide/config_options.rst b/docs/Users_Guide/config_options.rst index 521ff451a8..9ff10893df 100644 --- a/docs/Users_Guide/config_options.rst +++ b/docs/Users_Guide/config_options.rst @@ -1084,7 +1084,19 @@ File-format specific settings for the "field" entry: * The "GRIB2_perc_val" is an integer specifying the requested percentile value (0 to 100) to be used. This applies only to GRIB2 product definition templates 4.6 and 4.10. - + + * The "GRIB2_aerosol_type" is an integer specifying the aerosol type + (Table 4.233). This applies only to GRIB2 product defintion templates + 4.46 and 4.48. + + * The "GRIB2_aerosol_interval_type" is an integer specifying the aerosol + size interval (Table 4.91). This applies only to GRIB2 product defintion + templates 4.46 and 4.48. + + * The "GRIB2_aerosol_size_lower" and "GRIB2_aerosol_size_upper" are doubles + specifying the endpoints of the aerosol size interval. These applies only + to GRIB2 product defintion templates 4.46 and 4.48. + * The "GRIB2_ipdtmpl_index" and "GRIB2_ipdtmpl_val" entries are arrays of integers which specify the product description template values to be used. The indices are 0-based. For example, use the following to diff --git a/internal/test_unit/xml/unit_plot_data_plane.xml b/internal/test_unit/xml/unit_plot_data_plane.xml index e9e5ae965f..86709b0621 100644 --- a/internal/test_unit/xml/unit_plot_data_plane.xml +++ b/internal/test_unit/xml/unit_plot_data_plane.xml @@ -564,4 +564,21 @@ + + &MET_BIN;/plot_data_plane + \ + &DATA_DIR_MODEL;/grib2/rrfs/rrfs.t00z.prslev.f036.conus_3km.MASSDEN.grib2 \ + &OUTPUT_DIR;/plot_data_plane/RRFS_GRIB2_TABLE_4.48_MASSDEN.ps \ + 'name="MASSDEN"; level="Z8"; \ + GRIB2_aerosol_type=62001; \ + GRIB2_aerosol_interval_type=0; \ + GRIB2_aerosol_size_lower=2.5e-06;' \ + -title "Mass Density of Dry Dust up to 2.5e-06" \ + -v 1 + + + &OUTPUT_DIR;/plot_data_plane/RRFS_GRIB2_TABLE_4.48_MASSDEN.ps + + + diff --git a/src/basic/vx_config/config_constants.h b/src/basic/vx_config/config_constants.h index 7b1fc43ad3..5794a86336 100644 --- a/src/basic/vx_config/config_constants.h +++ b/src/basic/vx_config/config_constants.h @@ -555,6 +555,7 @@ static const char conf_key_GRIB1_subcenter[] = "GRIB1_subcenter"; static const char conf_key_GRIB1_rec[] = "GRIB1_rec"; static const char conf_key_GRIB1_code[] = "GRIB1_code"; static const char conf_key_GRIB1_tri[] = "GRIB1_tri"; + static const char conf_key_GRIB2_disc[] = "GRIB2_disc"; static const char conf_key_GRIB2_parm_cat[] = "GRIB2_parm_cat"; static const char conf_key_GRIB2_parm[] = "GRIB2_parm"; @@ -567,6 +568,12 @@ static const char conf_key_GRIB2_ens_type[] = "GRIB2_ens_type"; static const char conf_key_GRIB2_der_type[] = "GRIB2_der_type"; static const char conf_key_GRIB2_stat_type[] = "GRIB2_stat_type"; static const char conf_key_GRIB2_perc_val[] = "GRIB2_perc_val"; + +static const char conf_key_GRIB2_aerosol_type[] = "GRIB2_aerosol_type"; +static const char conf_key_GRIB2_aerosol_interval_type[] = "GRIB2_aerosol_interval_type"; +static const char conf_key_GRIB2_aerosol_size_lower[] = "GRIB2_aerosol_size_lower"; +static const char conf_key_GRIB2_aerosol_size_upper[] = "GRIB2_aerosol_size_upper"; + static const char conf_key_GRIB2_ipdtmpl_index[] = "GRIB2_ipdtmpl_index"; static const char conf_key_GRIB2_ipdtmpl_val[] = "GRIB2_ipdtmpl_val"; static const char conf_key_level[] = "level"; diff --git a/src/libcode/vx_data2d_grib2/data2d_grib2.cc b/src/libcode/vx_data2d_grib2/data2d_grib2.cc index f86516c2b7..e86ef7ca2c 100644 --- a/src/libcode/vx_data2d_grib2/data2d_grib2.cc +++ b/src/libcode/vx_data2d_grib2/data2d_grib2.cc @@ -198,8 +198,9 @@ bool MetGrib2DataFile::data_plane(VarInfo &vinfo, DataPlane &plane) { if( 1 < listMatch.size() ){ ConcatString msg; for(size_t i=0; i < listMatch.size(); i++) { - msg << "record " << listMatch[i]->RecNum + msg << " Record " << listMatch[i]->RecNum << " field " << listMatch[i]->FieldNum + << ", table 4." << listMatch[i]->PdsTmpl << ": ipdtmpl[" << listMatch[i]->IPDTmpl.n() << "] = "; for(int j=0; j < listMatch[i]->IPDTmpl.n(); j++) { @@ -259,8 +260,9 @@ int MetGrib2DataFile::data_plane_array(VarInfo &vinfo, if( 1 < listMatchExact.size() ){ ConcatString msg; for(size_t i=0; i < listMatchExact.size(); i++) { - msg << "record " << listMatchExact[i]->RecNum + msg << " Record " << listMatchExact[i]->RecNum << " field " << listMatchExact[i]->FieldNum + << ", table 4." << listMatchExact[i]->PdsTmpl << ": ipdtmpl[" << listMatchExact[i]->IPDTmpl.n() << "] = "; for(int j=0; j < listMatchExact[i]->IPDTmpl.n(); j++) { @@ -435,6 +437,14 @@ void MetGrib2DataFile::find_record_matches(VarInfoGrib2* vinfo, continue; } + // test aerosol config file options + if( (!is_bad_data(vinfo->aerosol_type()) && vinfo->aerosol_type() != (*it)->AerosolType ) || + (!is_bad_data(vinfo->aerosol_interval_type()) && vinfo->aerosol_interval_type() != (*it)->AerosolIntervalType ) || + (!is_bad_data(vinfo->aerosol_size_lower()) && !is_eq(vinfo->aerosol_size_lower(), (*it)->AerosolSizeLower )) || + (!is_bad_data(vinfo->aerosol_size_upper()) && !is_eq(vinfo->aerosol_size_upper(), (*it)->AerosolSizeUpper )) ){ + continue; + } + // test ipdtmpl array values if(vinfo->n_ipdtmpl() > 0) { int i, j; @@ -728,11 +738,17 @@ void MetGrib2DataFile::read_grib2_record_list() { rec->PdsTmpl = gfld->ipdtnum; rec->ParmCat = gfld->ipdtmpl[0]; rec->Parm = gfld->ipdtmpl[1]; - rec->Process = gfld->ipdtmpl[2]; + + // get the process id + if( gfld->ipdtnum != 46 && gfld->ipdtnum != 48 ) { + rec->Process = gfld->ipdtmpl[2]; + } // get the level type if( gfld->ipdtnum == 46 ) { rec->LvlTyp = gfld->ipdtmpl[15]; + } else if( gfld->ipdtnum == 48 ) { + rec->LvlTyp = gfld->ipdtmpl[20]; } else { rec->LvlTyp = gfld->ipdtmpl[9]; } @@ -745,10 +761,16 @@ void MetGrib2DataFile::read_grib2_record_list() { // check for template number 46 if( gfld->ipdtnum == 46 ) { rec->LvlVal1 = scaled2dbl(gfld->ipdtmpl[16], gfld->ipdtmpl[17]); - rec->LvlVal2 = rec->LvlVal1; - // check for special fixed level types (1 through 10 or 101) and set the level values to 0 - // Reference: https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table4-5.shtml - } else if( (rec->LvlTyp >= 1 && rec->LvlTyp <= 10) || rec->LvlTyp == 101 ) { + rec->LvlVal2 = rec->LvlVal1; + } + // check for template number 48 + else if( gfld->ipdtnum == 48 ) { + rec->LvlVal1 = scaled2dbl(gfld->ipdtmpl[21], gfld->ipdtmpl[22]); + rec->LvlVal2 = rec->LvlVal1; + } + // check for special fixed level types (1 through 10 or 101) and set the level values to 0 + // Reference: https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table4-5.shtml + else if( (rec->LvlTyp >= 1 && rec->LvlTyp <= 10) || rec->LvlTyp == 101 ) { rec->LvlVal1 = 0; rec->LvlVal2 = 0; } else { @@ -805,6 +827,14 @@ void MetGrib2DataFile::read_grib2_record_list() { rec->PercVal = gfld->ipdtmpl[15]; } + // aerosol type and size for templates 46 and 48 + if( 46 == gfld->ipdtnum || 48 == gfld->ipdtnum ){ + rec->AerosolType = gfld->ipdtmpl[2]; + rec->AerosolIntervalType = gfld->ipdtmpl[3]; + rec->AerosolSizeLower = scaled2dbl(gfld->ipdtmpl[4], gfld->ipdtmpl[5]); + rec->AerosolSizeUpper = scaled2dbl(gfld->ipdtmpl[6], gfld->ipdtmpl[7]); + } + // depending on the template number, determine the reference times if( 8 <= gfld->ipdtnum && 12 >= gfld->ipdtnum ){ diff --git a/src/libcode/vx_data2d_grib2/data2d_grib2.h b/src/libcode/vx_data2d_grib2/data2d_grib2.h index 4191e19728..abf334a837 100644 --- a/src/libcode/vx_data2d_grib2/data2d_grib2.h +++ b/src/libcode/vx_data2d_grib2/data2d_grib2.h @@ -62,6 +62,10 @@ typedef struct { int DerType; int StatType; int PercVal; + int AerosolType; + int AerosolIntervalType; + double AerosolSizeLower; + double AerosolSizeUpper; IntArray IPDTmpl; } Grib2Record; diff --git a/src/libcode/vx_data2d_grib2/var_info_grib2.cc b/src/libcode/vx_data2d_grib2/var_info_grib2.cc index 90f5275bbc..6ea70eecfa 100644 --- a/src/libcode/vx_data2d_grib2/var_info_grib2.cc +++ b/src/libcode/vx_data2d_grib2/var_info_grib2.cc @@ -110,6 +110,11 @@ void VarInfoGrib2::assign(const VarInfoGrib2 &v) { StatType = v.StatType; PercVal = v.PercVal; + AerosolType = v.AerosolType; + AerosolIntervalType = v.AerosolIntervalType; + AerosolSizeLower = v.AerosolSizeLower; + AerosolSizeUpper = v.AerosolSizeUpper; + IPDTmplIndex = v.IPDTmplIndex; IPDTmplVal = v.IPDTmplVal; @@ -137,6 +142,11 @@ void VarInfoGrib2::clear() { StatType = bad_data_int; PercVal = bad_data_int; + AerosolType = bad_data_int; + AerosolIntervalType = bad_data_int; + AerosolSizeLower = bad_data_double; + AerosolSizeUpper = bad_data_double; + IPDTmplIndex.clear(); IPDTmplVal.clear(); @@ -149,18 +159,22 @@ void VarInfoGrib2::dump(ostream &out) const { // Dump out the contents out << "VarInfoGrib2::dump():\n" - << " Record = " << Record << "\n" - << " Discipline = " << Discipline << "\n" - << " MTable = " << MTable << "\n" - << " LTable = " << LTable << "\n" - << " ParmCat = " << ParmCat << "\n" - << " Parm = " << Parm << "\n" - << " PDTmpl = " << PDTmpl << "\n" - << " Process = " << Process << "\n" - << " EnsType = " << EnsType << "\n" - << " DerType = " << DerType << "\n" - << " StatType = " << StatType << "\n" - << " PercVal = " << PercVal << "\n"; + << " Record = " << Record << "\n" + << " Discipline = " << Discipline << "\n" + << " MTable = " << MTable << "\n" + << " LTable = " << LTable << "\n" + << " ParmCat = " << ParmCat << "\n" + << " Parm = " << Parm << "\n" + << " PDTmpl = " << PDTmpl << "\n" + << " Process = " << Process << "\n" + << " EnsType = " << EnsType << "\n" + << " DerType = " << DerType << "\n" + << " StatType = " << StatType << "\n" + << " PercVal = " << PercVal << "\n" + << " AerosolType = " << AerosolType << "\n" + << " AerosolIntervalType = " << AerosolIntervalType << "\n" + << " AerosolSizeLower = " << AerosolSizeLower << "\n" + << " AerosolSizeUpper = " << AerosolSizeUpper << "\n"; out << " IPDTmplIndex:\n"; IPDTmplIndex.dump(out); out << " IPDTmplVal:\n"; @@ -255,6 +269,34 @@ void VarInfoGrib2::set_perc_val(int v) { /////////////////////////////////////////////////////////////////////////////// +void VarInfoGrib2::set_aerosol_type(int v) { + AerosolType = v; + return; +} + +/////////////////////////////////////////////////////////////////////////////// + +void VarInfoGrib2::set_aerosol_interval_type(int v) { + AerosolIntervalType = v; + return; +} + +/////////////////////////////////////////////////////////////////////////////// + +void VarInfoGrib2::set_aerosol_size_lower(double v) { + AerosolSizeLower = v; + return; +} + +/////////////////////////////////////////////////////////////////////////////// + +void VarInfoGrib2::set_aerosol_size_upper(double v) { + AerosolSizeUpper = v; + return; +} + +/////////////////////////////////////////////////////////////////////////////// + void VarInfoGrib2::set_ipdtmpl_index(const IntArray &v) { IPDTmplIndex = v; return; @@ -292,6 +334,11 @@ void VarInfoGrib2::set_dict(Dictionary & dict) { StatType = dict.lookup_int (conf_key_GRIB2_stat_type, false); PercVal = dict.lookup_int (conf_key_GRIB2_perc_val, false); + AerosolType = dict.lookup_int (conf_key_GRIB2_aerosol_type, false); + AerosolIntervalType = dict.lookup_int (conf_key_GRIB2_aerosol_interval_type, false); + AerosolSizeLower = dict.lookup_double(conf_key_GRIB2_aerosol_size_lower, false); + AerosolSizeUpper = dict.lookup_double(conf_key_GRIB2_aerosol_size_upper, false); + IPDTmplIndex = dict.lookup_int_array(conf_key_GRIB2_ipdtmpl_index, false); IPDTmplVal = dict.lookup_int_array(conf_key_GRIB2_ipdtmpl_val, false); diff --git a/src/libcode/vx_data2d_grib2/var_info_grib2.h b/src/libcode/vx_data2d_grib2/var_info_grib2.h index 7f47facf08..619508358b 100644 --- a/src/libcode/vx_data2d_grib2/var_info_grib2.h +++ b/src/libcode/vx_data2d_grib2/var_info_grib2.h @@ -56,6 +56,11 @@ class VarInfoGrib2 : public VarInfo int StatType; // Statistical Processing Type (Table 4.10) int PercVal; // Percentile Value (Octet 35 for Templates 4.6 and 4.10) + int AerosolType; // Aerosol Type (Table 4.46 and 4.48) + int AerosolIntervalType; // Aerosol Interval Type (Table 4.46 and 4.48) + double AerosolSizeLower; // Lower limit of Aerosol Size + double AerosolSizeUpper; // Upper limit of Aerosol Size + IntArray IPDTmplIndex; // Index into the GRIB2 ipdtmpl array IntArray IPDTmplVal; // Corresponding GRIB2 ipdtmpl value @@ -89,6 +94,11 @@ class VarInfoGrib2 : public VarInfo int stat_type() const; int perc_val() const; + int aerosol_type() const; + int aerosol_interval_type() const; + double aerosol_size_lower() const; + double aerosol_size_upper() const; + int n_ipdtmpl() const; int ipdtmpl_index(int) const; int ipdtmpl_val(int) const; @@ -111,6 +121,10 @@ class VarInfoGrib2 : public VarInfo void set_der_type(int); void set_stat_type(int); void set_perc_val(int); + void set_aerosol_type(int); + void set_aerosol_interval_type(int); + void set_aerosol_size_lower(double); + void set_aerosol_size_upper(double); void set_ipdtmpl_index(const IntArray &); void set_ipdtmpl_val(const IntArray &); @@ -145,6 +159,12 @@ inline int VarInfoGrib2::ens_type() const { return(EnsType); } inline int VarInfoGrib2::der_type() const { return(DerType); } inline int VarInfoGrib2::stat_type() const { return(StatType); } inline int VarInfoGrib2::perc_val() const { return(PercVal); } + +inline int VarInfoGrib2::aerosol_type() const { return(AerosolType); } +inline int VarInfoGrib2::aerosol_interval_type() const { return(AerosolIntervalType); } +inline double VarInfoGrib2::aerosol_size_lower() const { return(AerosolSizeLower); } +inline double VarInfoGrib2::aerosol_size_upper() const { return(AerosolSizeUpper); } + inline int VarInfoGrib2::n_ipdtmpl() const { return(IPDTmplIndex.n()); } inline int VarInfoGrib2::ipdtmpl_index(int i) const {