diff --git a/data/config/Makefile.am b/data/config/Makefile.am index 02678017c7..85aeeccfc9 100644 --- a/data/config/Makefile.am +++ b/data/config/Makefile.am @@ -51,6 +51,7 @@ config_DATA = \ PlotModeFieldConfig_default \ Point2GridConfig_default \ UGridConfig_lfric \ + UGridConfig_lfric_pressure_levels \ UGridConfig_mpas \ PlotPointObsConfig_default diff --git a/data/config/Makefile.in b/data/config/Makefile.in index 5268ac67b5..4628223cce 100644 --- a/data/config/Makefile.in +++ b/data/config/Makefile.in @@ -342,6 +342,7 @@ config_DATA = \ PlotModeFieldConfig_default \ Point2GridConfig_default \ UGridConfig_lfric \ + UGridConfig_lfric_pressure_levels \ UGridConfig_mpas \ PlotPointObsConfig_default diff --git a/data/config/UGridConfig_lfric b/data/config/UGridConfig_lfric index c6f198cd97..a8bef18b7c 100644 --- a/data/config/UGridConfig_lfric +++ b/data/config/UGridConfig_lfric @@ -2,13 +2,14 @@ // // Unstructured grid configuration file. // -// UGridConfig_lfric at the current working directory replaces the settings here. +// UGridConfig_lfric in the current working directory overrides the settings +// here for reading native model level data from the LFRic modeling system. // For additional or updated information, please see the MET User's Guide. // //////////////////////////////////////////////////////////////////////////////// // -// Dimensions and variables mapping for LFric dataset +// Dimensions and variables mapping for LFRic dataset // ugrid_metadata_map = [ { key = "dim_face"; val = "nMesh2d_face"; }, diff --git a/data/config/UGridConfig_lfric_pressure_levels b/data/config/UGridConfig_lfric_pressure_levels new file mode 100644 index 0000000000..5f62792106 --- /dev/null +++ b/data/config/UGridConfig_lfric_pressure_levels @@ -0,0 +1,37 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Unstructured grid configuration file. +// +// UGridConfig_lfric_pressure_levels in the current working directory overrides +// the settings here for reading pressure level data from LFRic modeling system. +// For additional or updated information, please see the MET User's Guide. +// +//////////////////////////////////////////////////////////////////////////////// + +// +// Dimensions and variables mapping for LFRic dataset +// +ugrid_metadata_map = [ + { key = "dim_face"; val = "dim1"; }, + { key = "dim_node"; val = "nMesh2d_node"; }, + { key = "dim_edge"; val = "nMesh2d_edge"; }, + { key = "dim_time"; val = "time_counter"; }, + { key = "dim_vert"; val = "pressure"; }, + { key = "cell_id"; val = "indexToCellID"; }, + { key = "lat_face"; val = "Mesh2d_face_y"; }, + { key = "lon_face"; val = "Mesh2d_face_x"; }, + { key = "vert_face"; val = "pressure"; }, + { key = "lat_edge"; val = "Mesh2d_edge_y"; }, + { key = "lon_edge"; val = "Mesh2d_edge_x"; }, + { key = "lat_node"; val = "Mesh2d_node_y"; }, + { key = "lon_node"; val = "Mesh2d_node_x"; }, + { key = "time"; val = "time_instant"; } +]; + +ugrid_max_distance_km = 30; + +//////////////////////////////////////////////////////////////////////////////// + +version = "V12.1.0"; + +//////////////////////////////////////////////////////////////////////////////// diff --git a/data/config/UGridConfig_mpas b/data/config/UGridConfig_mpas index af1be88620..927f6b8719 100644 --- a/data/config/UGridConfig_mpas +++ b/data/config/UGridConfig_mpas @@ -2,7 +2,8 @@ // // Unstructured grid configuration file. // -// UGridConfig_mpas at the current working directory replaces the settings here. +// UGridConfig_mpas in the current working directory overrides the settings +// here for reading data from the MPAS modeling system. // For additional or updated information, please see the MET User's Guide. // //////////////////////////////////////////////////////////////////////////////// diff --git a/internal/test_unit/config/PointStatConfig_ugrid_lfric_pressure_levels b/internal/test_unit/config/PointStatConfig_ugrid_lfric_pressure_levels new file mode 100644 index 0000000000..e5400c9efc --- /dev/null +++ b/internal/test_unit/config/PointStatConfig_ugrid_lfric_pressure_levels @@ -0,0 +1,188 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Point-Stat configuration file. +// +// For additional information, please see the MET User's Guide. +// +//////////////////////////////////////////////////////////////////////////////// + +// +// Output model name to be written +// +model = "FCST"; + +// +// Output description to be written +// May be set separately in each "obs.field" entry +// +desc = "NA"; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Verification grid +// May be set separately in each "field" entry +// +regrid = { + to_grid = NONE; + method = NEAREST; + width = 1; +} + +//////////////////////////////////////////////////////////////////////////////// + +obs_window = { + beg = ${BEG_DS}; + end = ${END_DS}; +} + +//////////////////////////////////////////////////////////////////////////////// + +mpr_column = []; +mpr_thresh = []; +cnt_thresh = [ NA ]; +cnt_logic = UNION; +wind_thresh = [ NA ]; +wind_logic = UNION; +eclv_points = 0.05; + +// +// Forecast and observation fields to be verified + +fcst = { + sid_inc = []; + sid_exc = []; + obs_quality_inc = []; + obs_quality_exc = []; + + file_type = NETCDF_UGRID; + + field = [ + { name = "u_in_w3"; level = "(21,*)"; set_attr_level = "P500"; }, + { name = "u_in_w3"; level = "(24,*)"; set_attr_level = "P850"; } + ]; +} +obs = { + sid_inc = []; + sid_exc = []; + obs_quality_inc = []; + obs_quality_exc = []; + + field = [ + { name = "UGRD"; level = "P500"; }, + { name = "UGRD"; level = "P850"; } + ]; +} + +//////////////////////////////////////////////////////////////////////////////// + +climo_mean = obs; +climo_mean = { + file_name = []; +} + +//////////////////////////////////////////////////////////////////////////////// + +mask = { + grid = []; + poly = []; + sid = []; + llpnt = [{ name = "ALLLATLON"; lat_thresh = NA; lon_thresh = NA; }]; +} + +//////////////////////////////////////////////////////////////////////////////// + +ci_alpha = [ 0.05 ]; + +boot = { + interval = PCTILE; + rep_prop = 1.0; + n_rep = 200; + rng = "mt19937"; + seed = "1"; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Interpolation methods +// May be set separately in each "obs.field" entry +// +interp = { + vld_thresh = 1.0; + shape = SQUARE; + + type = [ + { + method = NEAREST; + width = 1; + } + ]; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// HiRA verification method +// May be set separately in each "obs.field" entry +// +hira = { + flag = FALSE; + width = [ 2, 3, 4, 5 ]; + vld_thresh = 1.0; + cov_thresh = [ ==0.25 ]; + shape = SQUARE; + prob_cat_thresh = []; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Threshold for SEEPS p1 (Probability of being dry) +// +seeps_p1_thresh = >=0.1&&<=0.85; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Statistical output types +// May be set separately in each "obs.field" entry +// +output_flag = { + fho = NONE; + ctc = NONE; + cts = NONE; + mctc = NONE; + mcts = NONE; + cnt = NONE; + sl1l2 = NONE; + sal1l2 = NONE; + vl1l2 = NONE; + val1l2 = NONE; + vcnt = NONE; + pct = NONE; + pstd = NONE; + pjc = NONE; + prc = NONE; + ecnt = NONE; // Only for HiRA. + orank = NONE; // Only for HiRA. + rps = NONE; // Only for HiRA. + eclv = NONE; + mpr = STAT; + seeps = NONE; + seeps_mpr = NONE; +} + +//////////////////////////////////////////////////////////////////////////////// + +ugrid_dataset = "lfric_pressure_levels"; +ugrid_max_distance_km = 30; +//ugrid_coordinates_file = ""; + +//////////////////////////////////////////////////////////////////////////////// + +tmp_dir = "/tmp"; +output_prefix = "${OUTPUT_PREFIX}"; +version = "V12.1.0"; + +//////////////////////////////////////////////////////////////////////////////// diff --git a/internal/test_unit/xml/unit_ugrid.xml b/internal/test_unit/xml/unit_ugrid.xml index 5f6e517a7c..52c3d4b619 100644 --- a/internal/test_unit/xml/unit_ugrid.xml +++ b/internal/test_unit/xml/unit_ugrid.xml @@ -122,4 +122,24 @@ + + &MET_BIN;/point_stat + + BEG_DS -180000 + END_DS 180000 + OUTPUT_PREFIX UGRID_LFRIC_PRESSURE_LEVELS + CONFIG_DIR &CONFIG_DIR; + + \ + &DATA_DIR_UGRID;/lfric/lfric_2012-04-09_00.00.00.nc \ + &OUTPUT_DIR;/pb2nc/gdas1.20120409.t12z.prepbufr.nc \ + &CONFIG_DIR;/PointStatConfig_ugrid_lfric_pressure_levels \ + -ugrid_config ${MET_BASE}/config/UGridConfig_lfric_pressure_levels \ + -outdir &OUTPUT_DIR;/point_stat_ugrid -v 4 + + + &OUTPUT_DIR;/point_stat_ugrid/point_stat_UGRID_LFRIC_PRESSURE_LEVELS_180000L_20120409_180000V.stat + + + diff --git a/src/libcode/vx_data2d_nc_cf/nc_cf_file.cc b/src/libcode/vx_data2d_nc_cf/nc_cf_file.cc index 5ed138f93a..78c20bd550 100644 --- a/src/libcode/vx_data2d_nc_cf/nc_cf_file.cc +++ b/src/libcode/vx_data2d_nc_cf/nc_cf_file.cc @@ -173,7 +173,6 @@ void NcCfFile::close() bool NcCfFile::open(const char * filepath) { unixtime ut; - int sec_per_unit; const char *method_name = "NcCfFile::open() -> "; // Close any open files and clear out the associated members @@ -286,12 +285,11 @@ bool NcCfFile::open(const char * filepath) << "\"time\" variable.\n"; // Time not in file, get from file name - if ((ut = get_valid_time_from_file_path(filepath)) == 0) + ut = get_valid_time_from_file_path(filepath); + if (ut == 0) { mlog << Debug(4) << method_name << "could not extract valid time from file name.\n"; - } - if( ut == 0 ) { mlog << Warning << "\n" << method_name << "could not determine the valid time, using 0.\n\n"; } @@ -299,6 +297,8 @@ bool NcCfFile::open(const char * filepath) } else { + int sec_per_unit; + // Store the dimension for the time variable as the time dimension int time_dim_count = get_dim_count(valid_time_var); if (time_dim_count == 1) { @@ -383,43 +383,18 @@ bool NcCfFile::open(const char * filepath) else ValidTime.add(0); //Initialize } - NcVar init_time_var = get_var(_ncFile, "forecast_reference_time"); - if (IS_INVALID_NC(init_time_var)) - { - - mlog << Debug(4) << method_name - << "could not extract init time from the " - << "\"forecast_reference_time\" variable.\n"; - - // Time not in file, get from file name - if ((InitTime = get_init_time_from_file_path(filepath)) == 0) - { - mlog << Debug(4) << method_name - << "could not extract init time from file name.\n"; - } - } - else - { - - // Parse the units for the time variable. - if (get_var_units(&init_time_var, units)) { - if (units.empty()) { - mlog << Warning << "\n" << method_name - << "the \"forecast_reference_time\" variable must contain a \"units\" attribute.\n\n"; - ut = sec_per_unit = 0; - } - else { - mlog << Debug(4) << method_name - << "parsing units for the forecast_reference_time variable \"" << units << "\"\n"; - parse_cf_time_string(units.c_str(), ut, sec_per_unit); - } + InitTime = get_init_time(_ncFile); + if (InitTime == 0) { + // Time not in file, get from the file name + InitTime = get_init_time_from_file_path(filepath); + if (InitTime == 0) { + mlog << Debug(4) << method_name + << "could not extract init time from file name.\n"; } else { - ut = sec_per_unit = 0; + mlog << Debug(4) << method_name + << "get InitTime (" << unix_to_yyyymmdd_hhmmss(InitTime) << ") from the file name.\n"; } - - double time_value = get_nc_time(&init_time_var,0); - InitTime = ut + (unixtime)(sec_per_unit * time_value); } // Pull out the grid. This must be done after pulling out the dimension @@ -479,7 +454,7 @@ bool NcCfFile::open(const char * filepath) else { Var[j].z_slot = k; z_dims.add(dim_name); - if (0 == z_dim_name.length()) z_dim_name = dim_name; + if (z_dim_name.empty()) z_dim_name = dim_name; } } } @@ -487,7 +462,7 @@ bool NcCfFile::open(const char * filepath) } // for j // Find the vertical level variable from dimension name if not found - if (IS_INVALID_NC_P(z_var) && (0 < z_dim_name.length())) { + if (IS_INVALID_NC_P(z_var) && !z_dim_name.empty()) { NcVarInfo *info = find_var_by_dim_name(z_dim_name.c_str()); if (info) z_var = info->var; } @@ -739,6 +714,7 @@ unixtime NcCfFile::get_time_from_TRMM_3B42_daily_filename(const string &filename } +//////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// @@ -929,7 +905,6 @@ double NcCfFile::getData(NcVar * var, const LongArray & a) const double d = bad_data_double; double fill_value; - //double missing_value = get_var_missing_value(var); get_var_fill_value(var, fill_value); status = get_nc_data(var, &d, a); @@ -1201,8 +1176,8 @@ bool NcCfFile::getData(const char *var_name, plane.set_init(init_ut); plane.set_valid(valid_ut); - plane.set_lead(valid_ut - init_ut); - plane.set_accum(accum_time); + plane.set_lead((int)(valid_ut - init_ut)); + plane.set_accum((int)accum_time); // done @@ -1345,12 +1320,8 @@ NcVarInfo* NcCfFile::find_var_by_dim_name(const char *dim_name) const { NcVarInfo *var = find_var_name(dim_name); if (!var) { - //StringArray dimNames; for (int i=0; igetValues(att->as_string(0); ConcatString mapping_name; bool status = get_att_value_chars(grid_mapping_att, mapping_name); if (!status) @@ -1710,7 +1671,7 @@ void NcCfFile::get_grid_mapping_lambert_azimuthal_equal_area(const NcVar *grid_m << "assuming meters.\n\n"; } else { - if (0 == x_coord_units_name.length()) { + if (x_coord_units_name.empty()) { mlog << Warning << "\n" << method_name << " -> " << "Cannot extract X coordinate units from netCDF file -- " << "assuming meters.\n\n"; @@ -1735,7 +1696,7 @@ void NcCfFile::get_grid_mapping_lambert_azimuthal_equal_area(const NcVar *grid_m << "assuming meters.\n\n"; } else { - if (0 == y_coord_units_name.length()) { + if (y_coord_units_name.empty()) { mlog << Warning << "\n" << method_name << " -> " << "Cannot extract Y coordinate units from netCDF file -- " << "assuming meters.\n\n"; @@ -1964,7 +1925,7 @@ void NcCfFile::get_grid_mapping_lambert_conformal_conic(const NcVar *grid_mappin << "Units not given for X coordinate variable -- assuming meters.\n\n"; } else { - if (0 == x_coord_units_name.length()) { + if (x_coord_units_name.empty()) { mlog << Warning << "\n" << method_name << " -> " << "Cannot extract X coordinate units from netCDF file -- " << "assuming meters.\n\n"; @@ -1988,7 +1949,7 @@ void NcCfFile::get_grid_mapping_lambert_conformal_conic(const NcVar *grid_mappin << "Units not given for Y coordinate variable -- assuming meters.\n\n"; } else { - if (0 == y_coord_units_name.length()) { + if (y_coord_units_name.empty()) { mlog << Warning << "\n" << method_name << " -> " << "Cannot extract Y coordinate units from netCDF file -- " << "assuming meters.\n\n"; @@ -2362,7 +2323,7 @@ void NcCfFile::get_grid_mapping_polar_stereographic(const NcVar *grid_mapping_va << "Units not given for X coordinate variable -- assuming meters.\n\n"; } else { - if (0 == x_coord_units_name.length()) { + if (x_coord_units_name.empty()) { mlog << Warning << "\n" << method_name << "Cannot extract X coordinate units from netCDF file -- " << "assuming meters.\n\n"; @@ -2387,7 +2348,7 @@ void NcCfFile::get_grid_mapping_polar_stereographic(const NcVar *grid_mapping_va << "Units not given for Y coordinate variable -- assuming meters.\n\n"; } else { - if (0 == y_coord_units_name.length()) { + if (y_coord_units_name.empty()) { mlog << Warning << "\n" << method_name << "Cannot extract Y coordinate units from netCDF file -- " << "assuming meters.\n\n"; @@ -2469,8 +2430,12 @@ void NcCfFile::get_grid_mapping_polar_stereographic(const NcVar *grid_mapping_va scale_factor = proj_origin_scale_factor; eccentricity = false_east = false_north = 0.; if(!has_scale_factor && has_standard_parallel) { - double lat, lon; - double x, y, x2, y2; + double lat; + double lon; + double x; + double y; + double x2; + double y2; false_east = get_nc_var_att_double(grid_mapping_var, "false_east", false); false_north = get_nc_var_att_double(grid_mapping_var, "false_north", false); @@ -2526,8 +2491,12 @@ void NcCfFile::get_grid_mapping_polar_stereographic(const NcVar *grid_mapping_va //Note: do not set grid.set_swap_to_north() if(mlog.verbosity_level() >= 10) { - double lat1, lon1; - double x1, y1, x2, y2; + double lat1; + double lon1; + double x1; + double y1; + double x2; + double y2; mlog << Debug(15) << method_name << "dx_m=" << dx_m << ", dy_m=" << dy_m << "\n"; @@ -2696,7 +2665,7 @@ void NcCfFile::get_grid_mapping_rotated_latitude_longitude(const NcVar *grid_map continue; } - if (0 == dim_standard_name.length()) { + if (dim_standard_name.empty()) { continue; } diff --git a/src/libcode/vx_data2d_ugrid/ugrid_file.cc b/src/libcode/vx_data2d_ugrid/ugrid_file.cc index fb003a16a0..958575e34e 100644 --- a/src/libcode/vx_data2d_ugrid/ugrid_file.cc +++ b/src/libcode/vx_data2d_ugrid/ugrid_file.cc @@ -179,8 +179,7 @@ bool UGridFile::open(const char * filepath) // Open the file _ncFile = open_ncfile(filepath); - if (IS_INVALID_NC_P(_ncFile)) - { + if (IS_INVALID_NC_P(_ncFile)) { close(); return false; } @@ -398,6 +397,9 @@ bool UGridFile::open_metadata(const char * filepath) else ValidTime.add(0); //Initialize } + // Get InitTime from the forecast_reference_time + InitTime = get_init_time(_ncFile); + // Pull out the grid. This must be done after pulling out the dimension // and variable information since this information is used to pull out the // grid. This call sets the _faceDim and _edgeDim pointers. diff --git a/src/libcode/vx_nc_util/nc_utils.cc b/src/libcode/vx_nc_util/nc_utils.cc index 9712fcd9e7..8ab560f7f4 100644 --- a/src/libcode/vx_nc_util/nc_utils.cc +++ b/src/libcode/vx_nc_util/nc_utils.cc @@ -3516,6 +3516,46 @@ int get_data_size(NcVar *var) { return data_size; } +//////////////////////////////////////////////////////////////////////// +// Moved from nc_cf_file.cc +// init_time or valid_time from filename` + +string init_time_var_name = "forecast_reference_time"; +unixtime get_init_time(NcFile *nc_file) { + unixtime init_time = 0; + NcVar init_time_var = get_var(nc_file, init_time_var_name.c_str()); + const char *method_name = "get_init_time(NcFile *, string &) -> "; + + if (IS_INVALID_NC(init_time_var)) { + mlog << Debug(4) << method_name + << "could not extract init time from the " + << "\"" << init_time_var_name << "\" variable.\n"; + } + else { + unixtime ut = 0; + int sec_per_unit = 0; + ConcatString units; + + // Parse the units for the time variable. + if (get_var_units(&init_time_var, units)) { + if (units.empty()) { + mlog << Warning << "\n" << method_name + << "the \"" << init_time_var_name << "\" variable must contain a \"units\" attribute.\n\n"; + } + else { + parse_cf_time_string(units.c_str(), ut, sec_per_unit); + } + } + + double time_value = get_nc_time(&init_time_var,0); + init_time = ut + (unixtime)(sec_per_unit * time_value); + mlog << Debug(4) << method_name + << "get InitTime (" << unix_to_yyyymmdd_hhmmss(init_time) + << ") from \"" << init_time_var_name << "\" variable (value=" << time_value<< ").\n"; + } + return init_time; +} + //////////////////////////////////////////////////////////////////////// unixtime get_reference_unixtime(NcVar *time_var, int &sec_per_unit, diff --git a/src/libcode/vx_nc_util/nc_utils.h b/src/libcode/vx_nc_util/nc_utils.h index 5f238785ca..a8b5932656 100644 --- a/src/libcode/vx_nc_util/nc_utils.h +++ b/src/libcode/vx_nc_util/nc_utils.h @@ -334,6 +334,9 @@ extern netCDF::NcVar get_nc_var_time(const netCDF::NcFile *nc); extern int get_index_at_nc_data(netCDF::NcVar *var, double value, const std::string dim_name, bool is_time=false); extern netCDF::NcFile* open_ncfile(const char * nc_name, bool write = false); +// Moved from nc_cf_file.cc +extern unixtime get_init_time(netCDF::NcFile *nc_file); + extern unixtime get_reference_unixtime(netCDF::NcVar *time_var, int &sec_per_unit, bool &no_leap_year);