diff --git a/data/config/Makefile.am b/data/config/Makefile.am
index f6ed69c168..a7f77480d4 100644
--- a/data/config/Makefile.am
+++ b/data/config/Makefile.am
@@ -49,6 +49,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 6ff5c30139..8a6b4ef954 100644
--- a/data/config/Makefile.in
+++ b/data/config/Makefile.in
@@ -340,6 +340,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
+
+
+
+
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 be015948a0..3368964737 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 6289029ba7..7d65ffea8f 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 177febf1df..2415caf24e 100644
--- a/src/libcode/vx_nc_util/nc_utils.cc
+++ b/src/libcode/vx_nc_util/nc_utils.cc
@@ -3508,6 +3508,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 671b3bf609..b0f46b9bd3 100644
--- a/src/libcode/vx_nc_util/nc_utils.h
+++ b/src/libcode/vx_nc_util/nc_utils.h
@@ -333,6 +333,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);