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

Climatology Test: Handing masked depths without zspan #107

Merged
merged 7 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
15 changes: 8 additions & 7 deletions ioos_qc/qartod.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,9 +335,6 @@ def check(self, tinp, inp, zinp):
flag_arr = np.ma.empty(inp.size, dtype='uint8')
flag_arr.fill(QartodFlags.UNKNOWN)

# If the value is masked set the flag to MISSING
flag_arr[inp.mask] = QartodFlags.MISSING

# Iterate over each member and apply its spans on the input data.
# Member spans are applied in order and any data points that fall into
# more than one member are flagged by each one.
Expand Down Expand Up @@ -372,8 +369,9 @@ def check(self, tinp, inp, zinp):
with np.errstate(invalid='ignore'):
z_idx = (~zinp.mask) & (zinp >= m.zspan.minv) & (zinp <= m.zspan.maxv)
else:
# Only test the values with masked Z, ie values with no Z
z_idx = zinp.mask
# If there is no z data in the config, don't try to filter by depth!
# Set z_idx to all True to prevent filtering
z_idx = np.ones(inp.size, dtype=bool)

# Combine the T and Z indexes
values_idx = (t_idx & z_idx)
Expand All @@ -387,11 +385,14 @@ def check(self, tinp, inp, zinp):
fail_idx = np.zeros(inp.size, dtype=bool)

suspect_idx = (inp < m.vspan.minv) | (inp > m.vspan.maxv)

with np.errstate(invalid='ignore'):
flag_arr[(values_idx & fail_idx)] = QartodFlags.FAIL
flag_arr[(values_idx & ~fail_idx & suspect_idx)] = QartodFlags.SUSPECT
flag_arr[(values_idx & ~fail_idx & ~suspect_idx)] = QartodFlags.GOOD
iwensu0313 marked this conversation as resolved.
Show resolved Hide resolved

# If the value is masked set the flag to MISSING
flag_arr[inp.mask] = QartodFlags.MISSING

return flag_arr

Expand Down Expand Up @@ -422,11 +423,11 @@ def climatology_test(config : Union[ClimatologyConfig, Sequence[Dict[str, Tuple]
config: A ClimatologyConfig object or a list of dicts containing tuples
that can be used to create a ClimatologyConfig object. See ClimatologyConfig
docs for more info.
inp: Input data as a numeric numpy array or a list of numbers.
tinp: Time data as a sequence of datetime objects compatible with pandas DatetimeIndex.
This includes numpy datetime64, python datetime objects and pandas Timestamp object.
ie. pd.DatetimeIndex([datetime.utcnow(), np.datetime64(), pd.Timestamp.now()]
If anything else is passed in the format is assumed to be seconds since the unix epoch.
vinp: Input data as a numeric numpy array or a list of numbers.
zinp: Z (depth) data, in meters positive down, as a numeric numpy array or a list of numbers.

Returns:
Expand Down
59 changes: 58 additions & 1 deletion tests/test_qartod.py
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,62 @@ def test_climatology_test_all_unknown(self):
self._run_test(test_inputs, expected_result)



class QartodClimatologyMissingTest(unittest.TestCase):
def setUp(self):
self.cc = qartod.ClimatologyConfig()
# different time range, no depth
self.cc.add(
tspan=(np.datetime64('2021-07'), np.datetime64('2021-09')),
vspan=(3.4, 5)
)

def _run_test(self, test_inputs, expected_result):
times, values, depths = zip(*test_inputs)
inputs = [
values,
np.asarray(values, dtype=np.float64),
dask_arr(np.asarray(values, dtype=np.float64))
]

for i in inputs:
results = qartod.climatology_test(
config=self.cc,
tinp=times,
inp=i,
zinp=depths
)
npt.assert_array_equal(
results,
np.ma.array(expected_result)
)

def test_climatology_missing_values(self):
test_inputs = [
# Not missing value or depth, value out of bounds
(
np.datetime64('2021-07-16'),
0,
0
),
# Missing value and depth
(
np.datetime64('2021-07-16'),
np.nan,
np.nan
),
# Not missing value and depth, value within bounds
(
np.datetime64('2021-07-16'),
4.16743,
0.08931513
)
]
expected_result = [3, 9, 1]
self._run_test(test_inputs, expected_result)



class QartodClimatologyTest(unittest.TestCase):

def setUp(self):
Expand Down Expand Up @@ -857,8 +913,9 @@ def test_climatology_test_depths(self):
101
)
]
expected_result = [1, 1, 1, 3, 3, 2]
expected_result = [1, 1, 1, 3, 3, 3]
self._run_test(test_inputs, expected_result)



class QartodSpikeTest(unittest.TestCase):
Expand Down
Loading