Skip to content
Merged
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
27 changes: 26 additions & 1 deletion plugins/cmip7/cmip7.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,22 @@ def _load_toml(path: str) -> dict:
return toml.load(f)


def _is_flag_variable(ds, var_name):
"""Return True iff ``var_name`` carries CF flag semantics
(``flag_values`` or ``flag_meanings``). CMIP7 region-selector
variables like ``basin`` and ``siline`` are integer flag variables
per CF §7.5 and CMIP7 data descriptor ``type: integer``. The default
geophysical_variable.toml rules assume continuous float fields
(float ``_FillValue = 1e20`` and float type check) and cannot
describe the flag case.
"""
try:
attrs = ds.variables[var_name].ncattrs()
except Exception:
return False
return "flag_values" in attrs or "flag_meanings" in attrs


class Cmip7ProjectCheck(WCRPBaseCheck):
_cc_spec = "wcrp_cmip7"
_cc_spec_version = "1.0"
Expand Down Expand Up @@ -524,14 +540,21 @@ def check_Geophysical_Variable(self, ds):
return res

vcfg = self.config.variable
# CF flag-valued variables (basin, siline, similar CMIP7 region
# selectors) are integer by construction. The default TOML rules
# (float type, _FillValue = 1e20, missing_value = 1e20) do not
# fit them. Gate the float type check and the two fill/missing
# attribute rules on ``is_flag``; everything else still applies.
# See #59.
is_flag = _is_flag_variable(ds, geo)

# existence
if vcfg.existence:
sev = self.get_severity(vcfg.existence.severity)
res.extend(check_variable_existence(ds, geo, sev))

# type
if vcfg.type:
if vcfg.type and not is_flag:
sev = self.get_severity(vcfg.type.severity)
dt = (vcfg.type.data_type or "").lower()
allowed = ["f"] if dt in {"float", "double", "real"} else None
Expand Down Expand Up @@ -564,6 +587,8 @@ def check_Geophysical_Variable(self, ds):
for attr_key, rule in vcfg.attributes.items():
sev = self.get_severity(rule.severity)
name_in_file = rule.attribute_name or attr_key
if is_flag and name_in_file in ("_FillValue", "missing_value"):
continue
res.extend(
check_attribute_suite(
ds=ds,
Expand Down