diff --git a/Src/cmor_axes.c b/Src/cmor_axes.c index 37b6834a..70f5303e 100644 --- a/Src/cmor_axes.c +++ b/Src/cmor_axes.c @@ -2210,31 +2210,34 @@ int cmor_axis(int *axis_id, char *name, char *units, int length, length, name ); + } + } + + if ((refaxis.axis == 'T') && (refaxis.climatology == 0)) { /* -------------------------------------------------------------------- */ /* here we check if interval is about right */ /* just keep the begining of units out */ /* no need to know the since par */ /* -------------------------------------------------------------------- */ - j = 0; - while (refaxis.units[j] == ' ') - j++; - i = 0; - while ((refaxis.units[i + j] != ' ') && - (refaxis.units[i + j] != '\0')) { - ctmp[i] = refaxis.units[i + j]; - i++; - } - ctmp[i] = '\0'; + j = 0; + while (refaxis.units[j] == ' ') + j++; + i = 0; + while ((refaxis.units[i + j] != ' ') && + (refaxis.units[i + j] != '\0')) { + ctmp[i] = refaxis.units[i + j]; + i++; + } + ctmp[i] = '\0'; - snprintf(msg, CMOR_MAX_STRING, "%lf %s", - cmor_axes[cmor_naxes].approx_interval, ctmp); + snprintf(msg, CMOR_MAX_STRING, "%lf %s", + cmor_axes[cmor_naxes].approx_interval, ctmp); /* -------------------------------------------------------------------- */ /* skip this for non standard cal */ /* -------------------------------------------------------------------- */ - i = cmor_check_interval(cmor_naxes, msg, - &cmor_axes[cmor_naxes].values[0], - length, 0); - } + i = cmor_check_interval(cmor_naxes, msg, + &cmor_axes[cmor_naxes].values[0], + length, 0); } } else { if ((refaxis.axis != 'T') && (refaxis.index_only == 'n')) { diff --git a/Src/cmor_variables.c b/Src/cmor_variables.c index e4e2f184..5b84bb84 100644 --- a/Src/cmor_variables.c +++ b/Src/cmor_variables.c @@ -3450,7 +3450,7 @@ int cmor_write_var_to_file(int ncid, cmor_var_t * avar, void *data, ); } - if (time_axis_count > 0) { + if (time_axis_count > 0 && refaxis->climatology == 0) { ierr = cmor_check_interval(avar->axes_ids[0], units, time_axis_vals, time_axis_count, 0); diff --git a/Test/test_cmor_time_interval_check.py b/Test/test_cmor_time_interval_check.py index 5678935a..a9b8849e 100644 --- a/Test/test_cmor_time_interval_check.py +++ b/Test/test_cmor_time_interval_check.py @@ -1,8 +1,23 @@ import cmor +import numpy import unittest from base_CMIP6_CV import BaseCVsTest +def build_e1hrclimmon_time3(): + """Build a monthly diurnal climatology time axis with month-to-month gaps.""" + points = [] + bounds = [] + for month_index in range(12): + month_start = month_index * 30.0 + for hour in range(24): + lower = month_start + hour / 24.0 + upper = month_start + 30.0 + (hour + 1) / 24.0 + points.append((lower + upper) / 2.0) + bounds.append([lower, upper]) + return numpy.array(points, dtype=numpy.float64), numpy.array(bounds, dtype=numpy.float64) + + def run(): unittest.main() @@ -87,6 +102,66 @@ def test_interval_warning(self): self.assertCV("Test/CMOR_input_example.json", "Input JSON:") self.assertCV("CMIP6_Amon.json", "Table JSON:") + def test_interval_too_big_in_axis_without_bounds(self): + cmor.setup(inpath='Tables', + netcdf_file_action=cmor.CMOR_REPLACE_4, + logfile=self.tmpfile) + + cmor.dataset_json("Test/CMOR_input_example.json") + cmor.load_table("CMIP6_E1hr.json") + + with self.assertRaises(cmor.CMORError): + _ = cmor.axis(table_entry='time1', + units='minutes since 2000-01-01 00:00:00', + coord_vals=[12.6, 90.0]) + + self.assertCV("0.041667 days", + "Expected interval between time axis values:") + self.assertCV("0.05375 days (29.0% difference)", + "Actual interval between time axis values 0 and 1:") + self.assertCV("CMIP6_E1hr.json", "Table JSON:") + + def test_interval_check_skipped_for_climatology_time_values(self): + cmor.setup(inpath='Tables', + netcdf_file_action=cmor.CMOR_REPLACE_4, + logfile=self.tmpfile) + + cmor.dataset_json("Test/CMOR_input_example.json") + cmor.load_table("CMIP6_E1hrClimMon.json") + + time_vals, time_bnds = build_e1hrclimmon_time3() + axis_ids = [ + cmor.axis(table_entry='time3', + units='days since 2000-01-01 00:00:00'), + cmor.axis(table_entry='latitude', + units='degrees_north', + coord_vals=[0.0], + cell_bounds=[-1.0, 1.0]), + cmor.axis(table_entry='longitude', + units='degrees_east', + coord_vals=[90.0], + cell_bounds=[89.0, 91.0]), + ] + varid = cmor.variable('rlut', 'W m-2', axis_ids, positive='up') + data = numpy.linspace(180.0, 220.0, num=time_vals.size, dtype=numpy.float64) + + filename = None + try: + self.assertEqual( + cmor.write(varid, data, time_vals=time_vals, time_bnds=time_bnds), + 0, + ) + filename = cmor.close(varid, file_name=True) + self.delete_files.append(filename) + self.assertTrue(filename.endswith("-clim.nc")) + finally: + cmor.close() + + with open(self.tmpfile) as handle: + log_text = handle.read() + self.assertNotIn("Time interval mismatch detected", log_text) + self.assertNotIn("No frequency attribute provided in dataset configuration.", log_text) + if __name__ == '__main__': run() diff --git a/Test/test_python_filename_time_range.py b/Test/test_python_filename_time_range.py index 024649d6..e427a369 100644 --- a/Test/test_python_filename_time_range.py +++ b/Test/test_python_filename_time_range.py @@ -390,7 +390,7 @@ def test_hour_rounds_minutes(self): axes = [ {'table_entry': 'time1', 'units': 'minutes since 2000-01-01 00:00:00', - 'coord_vals': np.array([12.6, 37.4])}, + 'coord_vals': np.array([12.6, 77.4])}, {'table_entry': 'latitude', 'units': 'degrees_north', 'coord_vals': [0], @@ -411,7 +411,7 @@ def test_hour_rounds_minutes(self): self.assertEqual(os.path.basename(self.path), 'psl_E1hr_PCMDI-test-1-0_piControl-withism_' - 'r3i1p1f1_gn_200001010013-200001010037.nc') + 'r3i1p1f1_gn_200001010013-200001010117.nc') def test_subhr_rounds_seconds(self): table = 'Tables/CMIP6_Esubhr.json'