Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cdds/cdds/qc/plugins/base/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def execute(self, netcdf_file: Dataset, attr_dict: Dict[str, Any]) -> None:
"experiment": validator.experiment_validator(getattr(netcdf_file, "experiment_id")),
"institution": validator.institution_validator(getattr(netcdf_file, "institution_id")),
"Conventions": ValidatorFactory.value_in_validator(self.CF_CONVENTIONS),
"creation_date": ValidatorFactory.date_validator("%Y-%m-%dT%H:%M:%SZ"),
"creation_date": ValidatorFactory.date_validator("%Y-%m-%dT%H:%M:%SZ", "gregorian"),
"data_specs_version": ValidatorFactory.value_in_validator([self._cache.mip_tables.version]),
"license": ValidatorFactory.value_in_validator([self._cache.request.license.strip()]),
"mip_era": ValidatorFactory.value_in_validator([self._cache.request.mip_era]),
Expand Down
34 changes: 32 additions & 2 deletions cdds/cdds/tests/test_qc/plugins/base/test_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@
from unittest import TestCase
from unittest.mock import patch, MagicMock
from cdds.common.mip_tables import MipTables
from cdds.common.request import Request

from cdds.qc.plugins.base.checks import VariableAttributesCheckTask
from cdds.qc.plugins.base.checks import VariableAttributesCheckTask, StringAttributesCheckTask
from cdds.qc.plugins.base.validators import ControlledVocabularyValidator
from cdds.qc.plugins.cmip6.validators import Cmip6CVValidator
from cdds.qc.plugins.base.common import CheckCache
from cdds.tests.test_common.common import create_simple_netcdf_file
from cdds.tests.test_qc.plugins.constants import (MIP_TABLES_DIR, CV_REPO, TMP_DIR_FOR_NETCDF_TESTS, MINIMAL_CDL,
CORRECT_VARIABLE_METADATA_CDL, INCONSISTENT_VARIABLE_METADATA_CDL)
CORRECT_VARIABLE_METADATA_CDL, INCONSISTENT_VARIABLE_METADATA_CDL,
GLOBAL_ATTRIBUTES_CDL)


class TestVariableAttributesCheckTask(TestCase):
Expand Down Expand Up @@ -43,3 +46,30 @@ def test_variable_inconsistent_metadata(self):
self.assertListEqual(
self.class_under_test._messages,
["Variable attribute units has value of K instead of W m-2"])


class TestGlobalAttributesCheckTask(TestCase):

def setUp(self):
self.nc_path = os.path.join(TMP_DIR_FOR_NETCDF_TESTS, "test_file.nc")
mip_tables = MipTables(os.path.join(MIP_TABLES_DIR, "for_functional_tests"))
request = Request({
"mip_era": "CMIP6",
"license": ("CMIP6 model data produced by the Met Office Hadley Centre.")
}, [])
cache = CheckCache(request, mip_tables, Cmip6CVValidator(CV_REPO))
self.class_under_test = StringAttributesCheckTask(cache)

def tearDown(self):
os.remove(self.nc_path)

def test_creation_date(self):
create_simple_netcdf_file(GLOBAL_ATTRIBUTES_CDL, self.nc_path)
netcdf_file = Dataset(self.nc_path, 'a')
attr_dict = {"table_id": "Amon", "variable_id": "rsut"}
self.class_under_test.execute(netcdf_file, attr_dict)
self.maxDiff = None
self.assertListEqual(
self.class_under_test._messages,
["Mandatory attribute creation_date: "
"'2022-02-31T21:16:47Z' is not a valid date in a form of %Y-%m-%dT%H:%M:%SZ"])
10 changes: 9 additions & 1 deletion cdds/cdds/tests/test_qc/plugins/base/test_validators.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# (C) British Crown Copyright 2017-2021, Met Office.
# (C) British Crown Copyright 2017-2023, Met Office.
# Please see LICENSE.rst for license details.

import unittest
Expand Down Expand Up @@ -66,3 +66,11 @@ def test_int_validator(self):
self.assertRaises(ValidationError, validator, -4)
self.assertIsNone(zero_validator(0))
self.assertIsNone(negative_validator(-1))

def test_date_validator(self):
validator_360day = ValidatorFactory.date_validator("%Y-%m-%dT%H:%M:%SZ")
validator_gregorian = ValidatorFactory.date_validator("%Y-%m-%dT%H:%M:%SZ", "gregorian")
self.assertIsNone(validator_360day("2023-02-30T01:20:05Z"))
self.assertRaises(ValidationError, validator_gregorian, "2023-02-30T01:20:05Z")
self.assertRaises(ValidationError, validator_360day, "2023-07-31T01:20:05Z")
self.assertIsNone(validator_gregorian("2023-07-31T01:20:05Z"))
86 changes: 85 additions & 1 deletion cdds/cdds/tests/test_qc/plugins/constants.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# (C) British Crown Copyright 2017-2021, Met Office.
# (C) British Crown Copyright 2017-2023, Met Office.
# Please see LICENSE.rst for license details.
import os

Expand Down Expand Up @@ -107,3 +107,87 @@
time = 45 ;
}
"""

GLOBAL_ATTRIBUTES_CDL = """
netcdf filename {
dimensions:
lat = 1 ;
lon = 1 ;
time = UNLIMITED ; // (1 currently)
variables:
double lat(lat) ;
double lon(lon) ;
float rsut(time, lat, lon) ;
rsut:frequency = "mon" ;
rsut:modeling_realm = "atmos" ;
rsut:standard_name = "toa_outgoing_shortwave_flux" ;
rsut:units = "W m-2" ;
rsut:cell_methods = "area: time: mean" ;
rsut:cell_measures = "area: areacella" ;
rsut:long_name = "TOA Outgoing Shortwave Radiation" ;
rsut:comment = "at the top of the atmosphere" ;
rsut:dimensions = "longitude latitude time" ;
rsut:out_name = "rsut" ;
rsut:type = "real" ;
rsut:positive = "up" ;
rsut:missing_value = 1.e+20 ;
rsut:_FillValue = 1.e+20 ;
rsut:original_name = "foo" ;
double time(time) ;

// global attributes:
:Conventions = "CF-1.7 CMIP-6.2" ;
:activity_id = "CMIP" ;
:branch_method = "standard" ;
:branch_time_in_child = 0. ;
:branch_time_in_parent = 72000. ;
:creation_date = "2022-02-31T21:16:47Z" ;
:cv_version = "6.2.37.5" ;
:data_specs_version = "01.00.29" ;
:experiment = "all-forcing simulation of the recent past" ;
:experiment_id = "historical" ;
:external_variables = "areacella" ;
:forcing_index = 3 ;
:frequency = "day" ;
:further_info_url = "https://furtherinfo.es-doc.org/CMIP6.MOHC.UKESM1-0-LL.historical.none.r6i1p1f3" ;
:grid = "Native N96 grid; 192 x 144 longitude/latitude" ;
:grid_label = "gn" ;
:history = "" ;
:initialization_index = 1 ;
:institution = "Met Office Hadley Centre, Fitzroy Road, Exeter, Devon, EX1 3PB, UK" ;
:institution_id = "MOHC" ;
:mip_era = "CMIP6" ;
:mo_runid = "u-az515" ;
:nominal_resolution = "250 km" ;
:parent_activity_id = "CMIP" ;
:parent_experiment_id = "piControl" ;
:parent_mip_era = "CMIP6" ;
:parent_source_id = "UKESM1-0-LL" ;
:parent_time_units = "days since 1850-01-01" ;
:parent_variant_label = "r1i1p1f2" ;
:physics_index = 1 ;
:product = "model-output" ;
:realization_index = 6 ;
:realm = "atmos" ;
:source = "UKESM1.0-LL (2018)" ;
:source_id = "UKESM1-0-LL" ;
:source_type = "AOGCM AER BGC CHEM" ;
:sub_experiment = "none" ;
:sub_experiment_id = "none" ;
:table_id = "day" ;
:table_info = "Creation Date:(13 December 2018) MD5:f0588f7f55b5732b17302f8d9d0d7b8c" ;
:title = "UKESM1-0-LL output prepared for CMIP6" ;
:variable_id = "rsut" ;
:variable_name = "rsut" ;
:variant_label = "r6i1p1f3" ;
:license = "CMIP6 model data produced by the Met Office Hadley Centre." ;
:cmor_version = "3.4.0" ;
:tracking_id = "hdl:21.14100/60dc0e7f-c2d2-4d50-b578-5c93bca6ff51" ;

data:
lat = -89.375 ;
lon = 0.9375 ;
rsut = 213.0 ;
time = 45 ;
}
"""