Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flag fixes #924

Merged
merged 2 commits into from
May 2, 2022
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
28 changes: 20 additions & 8 deletions compliance_checker/cf/cf_1_6.py
Original file line number Diff line number Diff line change
Expand Up @@ -1078,14 +1078,21 @@ def check_flags(self, ds):
ret_val.append(valid_masks)

if flag_values is not None and flag_masks is not None:
allv = list(
map(lambda a, b: a & b == a, list(zip(flag_values, flag_masks)))
)
vals_arr = np.array(flag_values, ndmin=1)
masks_arr = np.array(flag_masks, ndmin=1)
# IMPLEMENTATION CONFORMANCE 3.5 RECOMMENDED 1/1
# If shapes aren't equal, we can't do proper elementwise
# comparison
if vals_arr.size != masks_arr.size:
allv = False
else:
allv = np.all(vals_arr & masks_arr == vals_arr)

allvr = Result(BaseCheck.MEDIUM, all(allv), self.section_titles["3.5"])
allvr = Result(BaseCheck.MEDIUM, allv,
self.section_titles["3.5"])
if not allvr.value:
allvr.msgs = [
"flag masks and flag values for '{}' combined don't equal flag value".format(
"flag masks and flag values for '{}' combined don't equal flag values".format(
name
)
]
Expand Down Expand Up @@ -1121,9 +1128,9 @@ def _check_flag_values(self, ds, name):


# the flag values must be independent, no repeating values
flag_set = set(flag_values)
flag_set = np.unique(flag_values)
valid_values.assert_true(
len(flag_set) == np.array(flag_values).size,
flag_set.size == np.array(flag_values).size,
"{}'s flag_values must be independent and can not be repeated".format(name),
)

Expand Down Expand Up @@ -1167,7 +1174,7 @@ def _check_flag_masks(self, ds, name):

valid_masks.assert_true(
variable.dtype.type == flag_masks.dtype.type,
"flag_masks ({}) mustbe the same data type as {} ({})"
"flag_masks ({}) must be the same data type as {} ({})"
"".format(flag_masks.dtype.type, name, variable.dtype.type),
)

Expand All @@ -1177,6 +1184,11 @@ def _check_flag_masks(self, ds, name):
or np.issubdtype(variable.dtype, "b")
)

valid_masks.assert_true(0 not in np.array(flag_masks),
f"flag_masks for variable {variable.name} must "
"not contain zero as an element")


valid_masks.assert_true(
type_ok,
"{}'s data type must be capable of bit-field expression".format(name),
Expand Down
22 changes: 21 additions & 1 deletion compliance_checker/tests/test_cf.py
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,8 @@ def test_check_standard_name(self):
temperature.standard_name = "sea_water_temperature"
temperature.ancillary_variables = "temperature_flag"

temperature_flag = dataset.createVariable("temperature_flag", "i2", ("time",))
temperature_flag = dataset.createVariable("temperature_flag", "i2",
("time",))
# bad modifier
temperature_flag.standard_name = "sea_water_temperature status flag"
_, _, messages = get_results(self.cf.check_standard_name(dataset))
Expand Down Expand Up @@ -677,6 +678,10 @@ def test_check_flags(self):
# only 4 variables in this dataset do not have perfect scores
imperfect = [r.value for r in results if r.value[0] < r.value[1]]
assert len(imperfect) == 4
dataset.variables["conductivity_qc"] = MockVariable(dataset.variables["conductivity_qc"])
# Test with single element. Will fail, but should not throw exception.
dataset.variables["conductivity_qc"].flag_values = np.array([1], dtype=np.int8)
results = self.cf.check_flags(dataset)

def test_check_flag_masks(self):
dataset = self.load_dataset(STATIC_FILES["ghrsst"])
Expand All @@ -690,9 +695,24 @@ def test_check_flag_masks(self):
flags_var = dataset.createVariable("flags", "f8", ("time",))
flags_var.standard_name = "quality_flag"
flags_var.flag_meanings = "LAND"
flags_var.flag_values = [1]
# test single element
flags_var.flag_masks = np.array([1], dtype="i2")
results = self.cf.check_flags(dataset)
assert scored > 0 and scored == out_of
# TEST CONFORMANCE 3.5 REQUIRED 7/8
flags_var.flag_masks = np.array([0, 1], dtype="i2")
results = self.cf.check_flags(dataset)
score, out_of, messages = get_results(results)
assert ("flag_masks for variable flags must not contain zero as an "
"element" in messages)
# IMPLEMENTATION 3.5 REQUIRED 1/1
flags_var.flag_masks = np.array([1], dtype="i2")
flags_var.flag_values = np.array([2], dtype="i2")
results = self.cf.check_flags(dataset)
score, out_of, messages = get_results(results)
assert ("flag masks and flag values for 'flags' combined don't equal "
"flag values" in messages)

def test_check_bad_units(self):
"""Load a dataset with units that are expected to fail (bad_units.nc).
Expand Down