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
7 changes: 6 additions & 1 deletion src/access_moppy/qc/cmip7.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,12 @@ def _is_outside_allowed_range(observed: float, minimum: float, maximum: float) -
``-6e-24`` are treated as zero for a lower bound of ``0``.
"""

tolerance = 1e-12
# Many CMIP outputs are derived from float32 fields where boundary values
# (for example 100%) can round to slightly above/below the nominal limit.
# Use a scale-aware absolute tolerance so closed-interval checks remain
# robust without masking meaningfully out-of-range values.
scale = max(abs(observed), abs(minimum), abs(maximum), 1.0)
tolerance = max(1e-12, 8.0 * np.finfo(np.float32).eps * scale)
lower_violation = observed < minimum and not np.isclose(
observed, minimum, rtol=0.0, atol=tolerance
)
Expand Down
15 changes: 15 additions & 0 deletions tests/unit/test_cmip7_qc.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,21 @@ def test_validate_cmip7_output_allows_tiny_negative_noise_at_zero_bound(tmp_path
validate_cmip7_output(path)


@pytest.mark.unit
def test_validate_cmip7_output_allows_float32_boundary_noise_for_percent_range(
tmp_path,
):
path = _write_cmip7_output(
tmp_path,
values=[0.0, 100.00003],
experiment_id="historical",
variable_id="snc",
units="%",
)

validate_cmip7_output(path)


@pytest.mark.unit
def test_validate_cmip7_output_tas_fails_for_picontrol_range(tmp_path):
path = _write_cmip7_output(
Expand Down