diff --git a/data/config/UGridConfig_mpas b/data/config/UGridConfig_mpas
index 189eb3a959..73d8046c1b 100644
--- a/data/config/UGridConfig_mpas
+++ b/data/config/UGridConfig_mpas
@@ -18,7 +18,8 @@ ugrid_metadata_map = [
{ key = "lat_face"; val = "latCell"; },
{ key = "lon_face"; val = "lonCell"; },
{ key = "vert_face"; val = "zCell"; }, // optional
- { key = "time"; val = "xtime"; }
+ { key = "time"; val = "xtime"; },
+ { key = "init_time"; val = "initial_time"; } // optional
];
//
diff --git a/docs/Users_Guide/appendixH.rst b/docs/Users_Guide/appendixH.rst
index 49669c5bad..52a33ea903 100644
--- a/docs/Users_Guide/appendixH.rst
+++ b/docs/Users_Guide/appendixH.rst
@@ -41,8 +41,11 @@ To correctly parse the UGRID topology, MET needs the following information that
- Dimension name for the time coordinate
- Required
* - time
- - Coordinate variable for time
+ - Coordinate variable for valid time
- Required
+ * - init_time
+ - Coordinate variable for initialization time (used to compute the lead time)
+ - Optional
* - dim_vert
- Dimension name for the vertical coordinate, if present
- Optional
diff --git a/internal/test_unit/python/unit.py b/internal/test_unit/python/unit.py
index 198d0d052d..54cabf3f2d 100755
--- a/internal/test_unit/python/unit.py
+++ b/internal/test_unit/python/unit.py
@@ -146,6 +146,7 @@ def unit(test_xml, file_log=None, cmd_only=False, noexit=False, memchk=False, ca
ret_ok = (cmd_return.returncode == test['retval'])
if ret_ok:
out_ok = True
+ result = None
for filepath in test['out_pnc']:
result = subprocess.run([mpnc, '-v', filepath],
@@ -173,7 +174,10 @@ def unit(test_xml, file_log=None, cmd_only=False, noexit=False, memchk=False, ca
break
except FileNotFoundError:
cmd_outs += (f"\nERROR: stat file missing {filepath}\n")
- logger.debug(result.stdout)
+ if result:
+ logger.debug(result.stdout)
+ else:
+ logger.debug(f"No result object, stat file missing {filepath}")
out_ok = False
break
# check stat file has non-header lines
diff --git a/internal/test_unit/xml/unit_ugrid.xml b/internal/test_unit/xml/unit_ugrid.xml
index 52c3d4b619..255ff94760 100644
--- a/internal/test_unit/xml/unit_ugrid.xml
+++ b/internal/test_unit/xml/unit_ugrid.xml
@@ -35,8 +35,8 @@
-outdir &OUTPUT_DIR;/grid_stat_ugrid -v 1
@@ -53,8 +53,8 @@
-outdir &OUTPUT_DIR;/grid_stat_ugrid -v 1
@@ -79,7 +79,7 @@
-outdir &OUTPUT_DIR;/point_stat_ugrid -v 1
@@ -98,7 +98,7 @@
-outdir &OUTPUT_DIR;/point_stat_ugrid -v 1
@@ -118,7 +118,7 @@
-outdir &OUTPUT_DIR;/point_stat_ugrid -v 1
diff --git a/src/libcode/vx_data2d_ugrid/ugrid_file.cc b/src/libcode/vx_data2d_ugrid/ugrid_file.cc
index e2597d3c58..c1fd8efcfd 100644
--- a/src/libcode/vx_data2d_ugrid/ugrid_file.cc
+++ b/src/libcode/vx_data2d_ugrid/ugrid_file.cc
@@ -23,7 +23,6 @@
#include
#include "vx_math.h"
-#include "vx_cal.h"
#include "vx_log.h"
#include "config_util.h"
@@ -40,13 +39,13 @@ constexpr char def_config_prefix[] = "UGridConfig_";
constexpr char def_config_prefix2[] = "MET_BASE/config/UGridConfig_";
constexpr double lat_epsilon = 0.00001;
-array DIM_KEYS = {
+const array DIM_KEYS = {
"dim_face", "dim_node", "dim_edge", "dim_time", "dim_vert"
};
-array COORD_VAR_KEYS = {
+const array COORD_VAR_KEYS = {
"time", "lat_face", "lon_face", "vert_face", "lat_edge",
- "lon_edge", "lat_node", "lon_node", "cell_id"
+ "lon_edge", "lat_node", "lon_node", "cell_id", "init_time"
};
static double get_nc_var_att_double(const NcVar *nc_var, const char *att_name,
@@ -88,7 +87,6 @@ void UGridFile::init_from_scratch()
_ncFile = (NcFile *) nullptr;
_ncMetaFile = (NcFile *) nullptr;
Var = (NcVarInfo *) nullptr;
- _time_var_info = (NcVarInfo *)nullptr;
_faceDim = (NcDim *)nullptr;
_edgeDim = (NcDim *)nullptr;
@@ -97,6 +95,9 @@ void UGridFile::init_from_scratch()
_tDim = (NcDim *)nullptr;
_latVar = (NcVar *)nullptr;
_lonVar = (NcVar *)nullptr;
+ _zVar = (NcVar *)nullptr;
+ _tVar = (NcVar *)nullptr;
+ _init_time_var = (NcVar *)nullptr;
// Close any existing file
@@ -219,18 +220,18 @@ bool UGridFile::open(const char * filepath)
bool UGridFile::open_metadata(const char * filepath)
{
- unixtime ut = 0;
const char *method_name = "UGridFile::open_metadata() -> ";
// Open the file
_ncMetaFile = open_ncfile(filepath);
+ mlog << Debug(7) << method_name << "open " << filepath << "\n";
+
if (IS_INVALID_NC_P(_ncMetaFile)) {
close();
exit(1);
}
- NcDim dim;
StringArray dim_names;
get_dim_names(_ncMetaFile, &dim_names);
@@ -256,152 +257,23 @@ bool UGridFile::open_metadata(const char * filepath)
assign_dim_from_metadata(_ncFile, _tDim, DIM_KEYS[3], dim_names); // Time dimension
assign_dim_from_metadata(_ncFile, _virtDim, DIM_KEYS[4], dim_names); // Vertical dimension
- int max_dim_count = 0;
- StringArray var_names;
- ConcatString att_value;
- auto z_var = (NcVar *)nullptr;
- auto valid_time_var = (NcVar *)nullptr;
- string time_dim_name = find_metadata_name(DIM_KEYS[3], dim_names);
- string vert_dim_name = find_metadata_name(DIM_KEYS[4], dim_names);
+ metadata_coord_variables();
- StringArray time_names = get_metadata_names(COORD_VAR_KEYS[0]);
- StringArray lat_names = get_metadata_names(COORD_VAR_KEYS[1]);
- StringArray lon_names = get_metadata_names(COORD_VAR_KEYS[2]);
- StringArray z_names = get_metadata_names(COORD_VAR_KEYS[3]);
- for (int j=0; j max_dim_count) max_dim_count = dim_count;
-
- // parse the variable attributes
- get_att_str( MetaVar[j], long_name_att_name, MetaVar[j].long_name_att );
- get_att_str( MetaVar[j], units_att_name, MetaVar[j].units_att );
-
- if (0 == j && nullptr == _time_var_info) {
- valid_time_var = MetaVar[j].var;
- _time_var_info = &MetaVar[j];
- }
- else if (1 == j && nullptr == _latVar) _latVar = MetaVar[j].var;
- else if (2 == j && nullptr == _lonVar) _lonVar = MetaVar[j].var;
- else if (3 == j && nullptr == z_var) z_var = MetaVar[j].var;
- }
- } // for j
-
-
- // Pull out the valid and init times
- if (IS_INVALID_NC_P(valid_time_var)) {
+ InitTime = 0;
+ if (!metadata_time()) {
mlog << Debug(4) << method_name
<< "could not extract valid time from the "
<< "time variable from " << filepath << "\n";
-
- ValidTime.add(ut);
}
- else {
- int sec_per_unit;
-
- // Store the dimension for the time variable as the time dimension
- ConcatString units;
- bool use_bounds_var = false;
- int time_dim_count = get_dim_count(valid_time_var);
- if (time_dim_count == 1 || time_dim_count == 2) {
- NcDim tDim = get_nc_dim(valid_time_var, 0);
- if (IS_VALID_NC(tDim)) {
- _tDim = new NcDim(tDim);
- }
- }
-
- // Parse the units for the time variable.
- ut = sec_per_unit = 0;
- if (get_var_units(valid_time_var, units) && (time_dim_count < 2)) {
- if (units.empty()) {
- mlog << Warning << "\n" << method_name
- << "the \"time\" variable must contain a \"units\" attribute. "
- << "Using valid time of 0\n\n";
- }
- else {
- mlog << Debug(4) << method_name
- << "parsing units for the time variable \"" << units << "\"\n";
- parse_cf_time_string(units.c_str(), ut, sec_per_unit);
- }
- }
- // Determine the number of times present.
- int n_times = IS_VALID_NC_P(_tDim) ? get_dim_size(_tDim)
- : get_data_size(valid_time_var);
- int tim_buf_size = n_times;
- vector time_values(tim_buf_size);
- if(2 == time_dim_count) {
- for(int i=0; i 1 ) {
- double latest_time = bad_data_double;
- for(int i=0; ivar;
+ if (info) _zVar = info->var;
}
// Pull out the vertical levels
- if (IS_VALID_NC_P(z_var)) {
-
- int z_count = get_data_size(z_var);
+ if (IS_VALID_NC_P(_zVar)) {
+ int z_count = get_data_size(_zVar);
vector z_values(z_count);
- if( get_nc_data(z_var, z_values.data()) ) {
+ if( get_nc_data(_zVar, z_values.data()) ) {
for(int i=0; it_slot && k != var->z_slot) length = plane_size - a[k];
+ if (k != var->t_slot && k != var->z_slot) length = (int)(plane_size - a[k]);
}
lengths.add(length);
dim_size = v->getDim(k).getSize();
@@ -752,7 +626,7 @@ bool UGridFile::getData(NcVar * v, const LongArray & a, DataPlane & plane) const
log_message << " " << (a[idx] == vx_data2d_star ? "*" : std::to_string(a[idx]));
}
mlog << Debug(6) << method_name << "took "
- << (clock()-start_clock)/double(CLOCKS_PER_SEC) << " seconds. "
+ << (clock()-start_clock)/CLOCKS_PER_SEC << " seconds. "
<< GET_NC_NAME_P(v) << ": levels: (" << log_message << " )"
<< " min=" << min_value << ", max_value=" << max_value<< "\n";
@@ -773,7 +647,7 @@ bool UGridFile::getData(const char *var_name,
// store the times
unixtime valid_ut;
- if(info->t_slot >= 0) valid_ut = ValidTime[a[info->t_slot]];
+ if(info->t_slot >= 0) valid_ut = ValidTime[(int)a[info->t_slot]];
else valid_ut = ValidTime[0];
// if unset, set the init time to the valid time
@@ -790,8 +664,8 @@ bool UGridFile::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
@@ -820,7 +694,6 @@ bool UGridFile::get_var_info() {
}
NcDim dim;
- int max_dim_count = 0;
ConcatString att_value;
StringArray var_names;
@@ -835,7 +708,6 @@ bool UGridFile::get_var_info() {
int dim_count = GET_NC_DIM_COUNT(v);
Var[j].Ndims = dim_count;
- if (dim_count > max_dim_count) max_dim_count = dim_count;
Var[j].Dims = new NcDim * [dim_count];
@@ -864,6 +736,148 @@ int UGridFile::lead_time() const
////////////////////////////////////////////////////////////////////////
+void UGridFile::metadata_coord_variables() {
+ static const string method_name
+ = "UGridFile::metadata_coord_variables() => ";
+
+ //Variables at the data file first
+ StringArray time_names = get_metadata_names(COORD_VAR_KEYS[0]);
+ StringArray lat_names = get_metadata_names(COORD_VAR_KEYS[1]);
+ StringArray lon_names = get_metadata_names(COORD_VAR_KEYS[2]);
+ StringArray z_names = get_metadata_names(COORD_VAR_KEYS[3]);
+ StringArray init_time_names = get_metadata_names(COORD_VAR_KEYS[9]);
+ for (int j=0; j ";
+
+ // Pull out the valid and init times
+ if (IS_INVALID_NC_P(_tVar)) {
+ ValidTime.add(0);
+ return false;
+ }
+
+ // Store the dimension for the time variable as the time dimension
+ bool use_bounds_var = false;
+ int time_dim_count = get_dim_count(_tVar);
+ if (nullptr == _tDim && (time_dim_count == 1 || time_dim_count == 2)) {
+ NcDim tDim = get_nc_dim(_tVar, 0);
+ if (IS_VALID_NC(tDim)) {
+ _tDim = new NcDim(tDim);
+ }
+ }
+
+ int data_type = GET_NC_TYPE_ID_P(_tVar);
+ bool is_string_time = (NC_CHAR == data_type || NC_STRING == data_type);
+
+ // Determine the number of times present.
+ int n_times = IS_VALID_NC_P(_tDim) ? get_dim_size(_tDim)
+ : get_data_size(_tVar);
+ vector time_values(n_times);
+ if(is_string_time) { // String type: YYYY-MM-DD HH:MM:SS
+ mlog << Debug(7) << method_name
+ << "from " << GET_NC_NAME_P(_tVar) << "\n";
+ for(int i=0; i _lat(face_count);
vector _lon(face_count);
-
+
if (IS_INVALID_NC_P(_latVar)) {
mlog << Error << "\n" << method_name << "latitude variable is missing\n\n";
exit(1);
diff --git a/src/libcode/vx_data2d_ugrid/ugrid_file.h b/src/libcode/vx_data2d_ugrid/ugrid_file.h
index a0d1828d60..cb58947244 100644
--- a/src/libcode/vx_data2d_ugrid/ugrid_file.h
+++ b/src/libcode/vx_data2d_ugrid/ugrid_file.h
@@ -30,7 +30,7 @@
static const int UG_DIM_COUNT = 5;
-static const int UG_META_VAR_COUNT = 9;
+static const int UG_META_VAR_COUNT = 10;
////////////////////////////////////////////////////////////////////////
@@ -65,8 +65,6 @@ class UGridFile {
return 1;
}
- NcVarInfo *get_time_var_info() const { return _time_var_info; }
-
//
// time
//
@@ -146,7 +144,9 @@ class UGridFile {
netCDF::NcVar *_latVar;
netCDF::NcVar *_lonVar;
- NcVarInfo *_time_var_info;
+ netCDF::NcVar *_zVar;
+ netCDF::NcVar *_tVar;
+ netCDF::NcVar *_init_time_var;
int face_count;
@@ -165,6 +165,8 @@ class UGridFile {
std::string find_metadata_name(const std::string &key, const StringArray &available_names);
StringArray get_metadata_names(const std::string &key);
+ void metadata_coord_variables();
+ bool metadata_time();
void radian_to_degree(std::vector &lat_values, const int lat_count) const;
void read_config(const ConcatString &config_filename);
void read_netcdf_grid();
diff --git a/src/libcode/vx_nc_util/nc_utils.cc b/src/libcode/vx_nc_util/nc_utils.cc
index 5a8b6e8ccb..cf16298f97 100644
--- a/src/libcode/vx_nc_util/nc_utils.cc
+++ b/src/libcode/vx_nc_util/nc_utils.cc
@@ -1157,12 +1157,11 @@ int get_int_var(NcVar * var, const int index) {
////////////////////////////////////////////////////////////////////////
double get_nc_time(NcVar * var, const int index) {
- double k;
vector start;
vector count;
const char *method_name = "get_nc_time() -> ";
- k = bad_data_double;
+ double k = bad_data_double;
if (IS_VALID_NC_P(var)) {
int dim_idx = 0;
int dim_size = get_dim_size(var, dim_idx);
@@ -1183,19 +1182,25 @@ double get_nc_time(NcVar * var, const int index) {
exit(1);
}
+ int buf_len = 512;
+ int dataType = GET_NC_TYPE_ID_P(var);
+ int dim_count = get_dim_count(var);
+ if (dataType == NC_CHAR) {
+ buf_len = get_dim_size(var, (dim_count-1));
+ }
+
int vi;
short vs;
float vf;
ncbyte vb;
long long vl;
unixtime ref_ut;
- int buf_len = 512;
- vector tmp_buf(buf_len);
- int dataType = GET_NC_TYPE_ID_P(var);
+ vector tmp_buf(buf_len+1);
start.emplace_back(index);
count.emplace_back(1);
tmp_buf[0] = 0;
+ tmp_buf[buf_len] = 0;
switch (dataType) {
case NC_DOUBLE:
@@ -1214,12 +1219,13 @@ double get_nc_time(NcVar * var, const int index) {
k = (double)vb;
break;
case NC_CHAR:
- if (2 == get_dim_count(var)) {
- buf_len = get_dim_size(var, 1);
+ if (2 == dim_count) {
start.emplace_back(0);
count.emplace_back(buf_len);
}
+ else count[0] = buf_len;
for (int i=0; igetVar(start, count, tmp_buf.data());
parse_time_string(tmp_buf.data(), ref_ut);
k = ref_ut;
@@ -3618,60 +3624,82 @@ int get_data_size(NcVar *var) {
}
////////////////////////////////////////////////////////////////////////
-// 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 get_init_time(NcVar *time_var) {
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 &) -> ";
+ const char *method_name = "get_init_time(NcVar *) -> ";
- if (IS_INVALID_NC(init_time_var)) {
+ if (IS_INVALID_NC_P(time_var)) {
mlog << Debug(4) << method_name
- << "could not extract init time from the "
- << "\"" << init_time_var_name << "\" variable.\n";
+ << "could not extract init time\n";
+ return init_time;
}
- else {
- unixtime ut = 0;
+
+ int data_type = GET_NC_TYPE_ID_P(time_var);
+ bool is_string_time = (NC_CHAR == data_type || NC_STRING == data_type);
+ double time_value = get_nc_time(time_var, 0);
+ init_time = (unixtime)time_value;
+ if (!is_string_time) {
int sec_per_unit = 0;
- ConcatString units;
+ bool no_leap_year = true;
+ unixtime ref_ut = get_reference_unixtime(time_var, sec_per_unit,
+ no_leap_year, method_name);
+ init_time = ref_ut + (unixtime)(sec_per_unit * time_value);
+ }
- // 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);
- }
- }
+ mlog << Debug(4) << method_name
+ << "get InitTime (" << unix_to_yyyymmdd_hhmmss(init_time)
+ << ") from \"" << GET_NC_NAME_P(time_var) << "\" variable (value="
+ << time_value << ").\n";
- double time_value = get_nc_time(&init_time_var,0);
- init_time = ut + (unixtime)(sec_per_unit * time_value);
+ return init_time;
+}
+////////////////////////////////////////////////////////////////////////
+// Moved from nc_cf_file.cc
+// init_time from NetCDF, default variable name is forecast_reference_time
+// Can get valid_time id byte or char type with variable name
+
+const string init_time_var_name = "forecast_reference_time";
+
+unixtime get_init_time(NcFile *nc_file, const char *time_var_name) {
+ unixtime init_time = 0;
+ const char *method_name = "get_init_time(NcFile *, string &) -> ";
+
+ if (time_var_name == nullptr) time_var_name = init_time_var_name.c_str();
+
+ NcVar time_var = get_var(nc_file, time_var_name);
+ if (IS_INVALID_NC(time_var)) {
mlog << Debug(4) << method_name
- << "get InitTime (" << unix_to_yyyymmdd_hhmmss(init_time)
- << ") from \"" << init_time_var_name << "\" variable (value=" << time_value<< ").\n";
+ << "could not extract init time from the "
+ << "\"" << time_var_name << "\" variable.\n";
+ }
+ else {
+ init_time = get_init_time(&time_var);
}
return init_time;
}
////////////////////////////////////////////////////////////////////////
+// retrurn 0 if units attribute is missing
unixtime get_reference_unixtime(NcVar *time_var, int &sec_per_unit,
- bool &no_leap_year) {
+ bool &no_leap_year, const char *caller) {
unixtime ref_ut = 0;
ConcatString time_unit_str;
static const char *method_name = "get_reference_unixtime() -> ";
+ sec_per_unit = 1;
if (get_var_units(time_var, time_unit_str)) {
- parse_cf_time_string(time_unit_str.c_str(), ref_ut, sec_per_unit);
- no_leap_year = (sec_per_day == sec_per_unit) ? get_att_no_leap_year(time_var) : false;
- }
- else {
- sec_per_unit = 1;
+ if (time_unit_str.empty()) {
+ mlog << Warning << "\n" << (caller != nullptr ? caller : method_name)
+ << "the \"" << GET_NC_NAME_P(time_var)
+ << "\" variable does not have a \"units\" attribute.\n\n";
+ }
+ else {
+ parse_cf_time_string(time_unit_str.c_str(), ref_ut, sec_per_unit);
+ }
}
+ no_leap_year = (sec_per_day == sec_per_unit) ? get_att_no_leap_year(time_var) : false;
return ref_ut;
}
@@ -3708,7 +3736,7 @@ bool is_nc_unit_time(const char *units) {
////////////////////////////////////////////////////////////////////////
-void parse_cf_time_string(const char *str, unixtime &ref_ut,
+bool parse_cf_time_string(const char *str, unixtime &ref_ut,
int &sec_per_unit) {
static const char *method_name = "parse_cf_time_string() -> ";
@@ -3721,7 +3749,7 @@ void parse_cf_time_string(const char *str, unixtime &ref_ut,
mlog << Warning << "\n" << method_name
<< "unexpected NetCDF CF convention time unit \""
<< str << "\"\n\n";
- return;
+ return false;
}
else {
// Tokenize the input string
@@ -3756,7 +3784,7 @@ void parse_cf_time_string(const char *str, unixtime &ref_ut,
mlog << Warning << "\n" << method_name
<< "Unsupported time step in the CF convention time unit \""
<< str << "\"\n\n";
- return;
+ return false;
}
// Parse the reference time
@@ -3775,7 +3803,7 @@ void parse_cf_time_string(const char *str, unixtime &ref_ut,
<< "\"\n\t\t as a reference time of " << unix_to_yyyymmdd_hhmmss(ref_ut)
<< " and " << sec_per_unit << " second(s) per time step.\n";
- return;
+ return true;
}
////////////////////////////////////////////////////////////////////////
@@ -3800,16 +3828,17 @@ void parse_time_string(const char *str, unixtime &ut) {
// 2016-01-28T12:00:00Z
// 1977-08-07 12:00:00Z
StringArray tok;
+ StringArray hms;
+ StringArray ymd;
tok.parse_delim(str, " _T");
// Parse the reference time
- StringArray ymd, hms;
ymd.parse_delim(tok[0], "-");
if(tok.n_elements() > 1) hms.parse_delim(tok[1], ":");
else hms.parse_delim("00:00:00", ":");
ut = mdyhms_to_unix(atoi(ymd[1].c_str()), atoi(ymd[2].c_str()),
- atoi(ymd[0].c_str()), atoi(hms[0].c_str()),
- hms.n_elements() > 1 ? atoi(hms[1].c_str()) : 0,
- hms.n_elements() > 2 ? atoi(hms[2].c_str()) : 0);
+ atoi(ymd[0].c_str()), atoi(hms[0].c_str()),
+ hms.n_elements() > 1 ? atoi(hms[1].c_str()) : 0,
+ hms.n_elements() > 2 ? atoi(hms[2].c_str()) : 0);
}
mlog << Debug(4) << method_name
diff --git a/src/libcode/vx_nc_util/nc_utils.h b/src/libcode/vx_nc_util/nc_utils.h
index 1817626e74..dae2a76494 100644
--- a/src/libcode/vx_nc_util/nc_utils.h
+++ b/src/libcode/vx_nc_util/nc_utils.h
@@ -340,16 +340,17 @@ extern int get_index_at_nc_data(netCDF::NcVar *var, double value_min, double
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_init_time(netCDF::NcVar *var);
+extern unixtime get_init_time(netCDF::NcFile *nc_file, const char *time_var_name=nullptr);
extern unixtime get_reference_unixtime(netCDF::NcVar *time_var, int &sec_per_unit,
- bool &no_leap_year);
+ bool &no_leap_year, const char *caller=nullptr);
extern bool is_nc_unit_time(const char *units);
extern bool is_nc_unit_longitude(const char *units);
extern bool is_nc_unit_latitude(const char *units);
-extern void parse_cf_time_string(const char *str, unixtime &ref_ut,
+extern bool parse_cf_time_string(const char *str, unixtime &ref_ut,
int &sec_per_unit);
extern void parse_time_string(const char *str, unixtime &ut);