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 408edf31f7..710e45555d 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 @@ -208,8 +208,23 @@ void VarInfoNcCF::set_magic(const ConcatString &nstr, const ConcatString &lstr) as_offset = (*ptr2 != '@'); if (!as_offset) ptr2++; + ptr3 = strchr(ptr2, '-'); + //skip negative sign of the negative value to check the range + if (ptr3 != nullptr && ptr3 == ptr2) ptr3 = strchr((ptr2+1), '-'); + // Check for a range of levels - if ((ptr3 = strchr(ptr2, '-')) != nullptr) { + if (ptr3 != nullptr && ptr3 != ptr2) { + *ptr3 = 0; + ptr3++; + if (*ptr3 == '@') { + if (as_offset) { + mlog << Error << "\n" << method_name + << "Can not mix an offset and a value for NetCDF variable \"" + << MagicStr << "\".\n\n"; + exit(1); + } + ptr3++; // to support @vlevel_lower-@vlevel_upper + } // Check if a range has already been supplied if (Dimension.has(range_flag)) { 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 58b586b186..7d53df269f 100644 --- a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc +++ b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.cc @@ -121,33 +121,75 @@ void MetNcWrfDataFile::dump(ostream & out, int depth) const { //////////////////////////////////////////////////////////////////////// +bool MetNcWrfDataFile::get_real_dimension(const VarInfoNcWrf *vinfo_nc, + const NcVarInfo *info, LongArray &dimension) const { + static const string method_name + = "MetNcWrfDataFile::get_real_dimension() ->"; + int dim_count = dimension.n_elements(); + for (int k=0; klevel().is_offset()) { + dimension[k] = nint(vinfo_nc->level().lower()); + continue; + } + + if (dimension[k] != vx_data2d_dim_by_value && dimension[k] != range_flag) continue; + + string dim_name = GET_NC_NAME(get_nc_dim(info->var, k)); + NcVarInfo *var_info = find_var_info_by_dim_name(WrfNc->Var, dim_name, + WrfNc->Nvars); + if (var_info == nullptr) continue; + + if (dimension[k] == vx_data2d_dim_by_value) { + 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; + else { + mlog << Warning << "\n" << method_name + << "for \"" << vinfo_nc->req_name() + << "\" variable, the dimension value " + << vinfo_nc->dim_value(k) << " for " << dim_name + << " does not exist\n\n"; + return false; + } + } + else if (dimension[k] == range_flag) { + double lower = vinfo_nc->level().lower(); + double upper = vinfo_nc->level().upper(); + long new_offset = get_index_at_nc_data(var_info->var, lower, upper, + dim_name, (k == info->t_slot)); + if (new_offset != bad_data_int) dimension[k] = new_offset; + else { + mlog << Warning << "\n" << method_name + << "for \"" << vinfo_nc->req_name() + << "\" variable, the dimension value between " + << lower << " and " << upper << " for " << dim_name + << " does not exist\n\n"; + return false; + } + } + } + return true; + } + +//////////////////////////////////////////////////////////////////////// + bool MetNcWrfDataFile::data_plane(VarInfo &vinfo, DataPlane &plane) { bool status = false; double pressure; ConcatString level_str; - VarInfoNcWrf * vinfo_nc = (VarInfoNcWrf *) &vinfo; - NcVarInfo *info = (NcVarInfo *) nullptr; + auto vinfo_nc = (VarInfoNcWrf *) &vinfo; + auto info = (NcVarInfo *) nullptr; // Initialize the data plane plane.clear(); // Read the data 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 (! get_real_dimension(vinfo_nc, info, dimension)) + return false; status = WrfNc->data(vinfo_nc->req_name().c_str(), dimension, plane, pressure, info); @@ -198,7 +240,7 @@ bool MetNcWrfDataFile::data_plane(VarInfo &vinfo, DataPlane &plane) { //////////////////////////////////////////////////////////////////////// int MetNcWrfDataFile::data_plane_array(VarInfo &vinfo, - DataPlaneArray &plane_array) { + DataPlaneArray &plane_array) { int i, i_dim, n_level, status, lower, upper; ConcatString level_str; double pressure, min_level, max_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 ac29854595..11fc9963b5 100644 --- a/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.h +++ b/src/libcode/vx_data2d_nc_wrf/data2d_nc_wrf.h @@ -34,6 +34,8 @@ class MetNcWrfDataFile : public Met2dDataFile { private: void nc_wrf_init_from_scratch(); + bool get_real_dimension(const VarInfoNcWrf *vinfo_nc, const NcVarInfo *info, + LongArray &dimension) const; MetNcWrfDataFile(const MetNcWrfDataFile &); MetNcWrfDataFile & operator=(const MetNcWrfDataFile &); 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 10c04ca65e..aa23560f55 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 @@ -209,8 +209,23 @@ void VarInfoNcWrf::set_magic(const ConcatString &nstr, const ConcatString &lstr) as_offset = (*ptr2 != '@'); if (!as_offset) ptr2++; + ptr3 = strchr(ptr2, '-'); + //skip negative sign of the negative value to check the range + if (ptr3 != nullptr && ptr3 == ptr2) ptr3 = strchr((ptr2+1), '-'); + // Check for a range of levels - if((ptr3 = strchr(ptr2, '-')) != nullptr) { + if (ptr3 != nullptr && ptr3 != ptr2) { + *ptr3 = 0; + ptr3++; + if (*ptr3 == '@') { + if (as_offset) { + mlog << Error << "\n" << method_name + << "Can not mix an offset and a value for NetCDF variable \"" + << MagicStr << "\".\n\n"; + exit(1); + } + ptr3++; // to support @vlevel_lower-@vlevel_upper + } // Check if a range has already been supplied if(Dimension.has(range_flag)) { @@ -223,10 +238,11 @@ void VarInfoNcWrf::set_magic(const ConcatString &nstr, const ConcatString &lstr) else { add_dimension(range_flag); Level.set_lower(atoi(ptr2)); - Level.set_upper(atoi(++ptr3)); + Level.set_upper(atoi(ptr3)); // Assume pressure level type for a range of levels Level.set_type(LevelType_Pres); + Level.set_is_offset(as_offset); } } // Single level diff --git a/src/libcode/vx_nc_util/nc_utils.cc b/src/libcode/vx_nc_util/nc_utils.cc index e6f77db56d..c95efc1129 100644 --- a/src/libcode/vx_nc_util/nc_utils.cc +++ b/src/libcode/vx_nc_util/nc_utils.cc @@ -1888,10 +1888,19 @@ bool get_nc_data(NcVar *var, ncbyte *data, const LongArray &dims, const LongArra return return_status; } +//////////////////////////////////////////////////////////////////////// + +ConcatString get_value_string(double value, bool is_time) { + ConcatString value_str; + if (is_time && (value > 10000000.)) value_str << unix_to_yyyymmdd_hhmmss(value); + else value_str << value; + return value_str; +} + //////////////////////////////////////////////////////////////////////// // returns matching offset or bad_data_int if not found -int get_index_at_nc_data(NcVar *var, double value, const string dim_name, bool is_time) { +int get_index_at_nc_data(NcVar *var, double value, const string &dim_name, bool is_time) { int offset = bad_data_int; static const char *method_name = "get_index_at_nc_data() -> "; if (IS_VALID_NC_P(var)) { @@ -1948,6 +1957,78 @@ int get_index_at_nc_data(NcVar *var, double value, const string dim_name, bool i return offset; } +//////////////////////////////////////////////////////////////////////// +// returns matching offset or bad_data_int if not found + +int get_index_at_nc_data(NcVar *var, double value_min, double value_max, + const string &dim_name, bool is_time) { + int offset = bad_data_int; + static const char *method_name = "get_index_at_nc_data(min,max) -> "; + if (IS_VALID_NC_P(var)) { + int data_size = get_data_size(var); + vector values(data_size); + + if (get_nc_data(var, values.data())) { + unixtime ut; + int sec_per_unit; + bool no_leap_year = get_att_no_leap_year(var); + ut = sec_per_unit = 0; + if (is_time) { + ConcatString units; + bool has_attr = get_var_units(var, units); + if (has_attr && (!units.empty())) + parse_cf_time_string(units.c_str(), ut, sec_per_unit); + else { + mlog << Warning << "\n" << method_name + << "the time variable \"" << GET_NC_NAME_P(var) + << "\" must contain a \"" + << units_att_name << "\" attribute.\n\n"; + } + } + bool found = false; + // Select the first offset between value_min and value_max + for (int idx=0; idx= value_min && values[idx] <= value_max)) { + found = true; + } + if (!found && is_time) { + unixtime time_value = add_to_unixtime(ut, sec_per_unit, + values[idx], no_leap_year); + if (is_eq(time_value, value_min) + || is_eq(time_value, value_max) + || (time_value >= value_min && time_value <= value_max)) { + found = true; + } + } + if (found) { + offset = idx; + break; + } + } + } + + ConcatString value_max_str = get_value_string(value_max, is_time); + ConcatString value_min_str = get_value_string(value_min, is_time); + if (offset == bad_data_int) + mlog << Debug(7) << method_name << "Not found value between " << value_min_str + << " and " << value_max_str << " at " << GET_NC_NAME_P(var) + << " by dimension name \"" << dim_name << "\"\n"; + else { + ConcatString value_str = get_value_string(values[offset], is_time); + mlog << Debug(7) << method_name << "Found value " << value_str + << " (index=" << offset << ") at " << GET_NC_NAME_P(var) + << " by dimension name \"" << dim_name << "\"\n"; + } + } + else { + mlog << Debug(7) << method_name << "Not found a dimension variable for \"" + << dim_name << "\"\n"; + } + return offset; +} + //////////////////////////////////////////////////////////////////////// bool get_nc_data_to_array(NcVar *var, StringArray *array_buf) { diff --git a/src/libcode/vx_nc_util/nc_utils.h b/src/libcode/vx_nc_util/nc_utils.h index ddf57055d6..0002c955fe 100644 --- a/src/libcode/vx_nc_util/nc_utils.h +++ b/src/libcode/vx_nc_util/nc_utils.h @@ -335,7 +335,8 @@ extern bool get_dim_names(const netCDF::NcFile *nc, StringArray *dimNames); extern netCDF::NcVar get_nc_var_lat(const netCDF::NcFile *nc); extern netCDF::NcVar get_nc_var_lon(const netCDF::NcFile *nc); 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 int get_index_at_nc_data(netCDF::NcVar *var, double value, const std::string &dim_name, bool is_time=false); +extern int get_index_at_nc_data(netCDF::NcVar *var, double value_min, double value_max, 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