|
| 1 | +""" |
| 2 | +Conductivity normalizer. |
| 3 | +
|
| 4 | +Converts conductivity variables to the canonical unit mS cm-1 before the |
| 5 | +derivation stage runs. Uses magnitude-based inference to detect and warn |
| 6 | +about declared-vs-actual mismatches. |
| 7 | +""" |
| 8 | + |
| 9 | +from __future__ import annotations |
| 10 | + |
| 11 | +import logging |
| 12 | +from typing import List, Tuple |
| 13 | + |
| 14 | +import xarray as xr |
| 15 | + |
| 16 | +from .utils import _base_name |
| 17 | +from seasenselib.readers.utils.conductivity_units import ( |
| 18 | + infer_conductivity_unit, |
| 19 | + to_mS_cm, |
| 20 | +) |
| 21 | + |
| 22 | +logger = logging.getLogger(__name__) |
| 23 | + |
| 24 | +_TARGET_UNIT = "mS cm-1" |
| 25 | + |
| 26 | + |
| 27 | +class ConductivityNormalizer: |
| 28 | + """Convert conductivity variables to mS cm-1.""" |
| 29 | + |
| 30 | + def normalize(self, ds: xr.Dataset) -> Tuple[xr.Dataset, List[str]]: |
| 31 | + """Normalise all conductivity variables to mS cm-1. |
| 32 | +
|
| 33 | + Parameters |
| 34 | + ---------- |
| 35 | + ds : xr.Dataset |
| 36 | +
|
| 37 | + Returns |
| 38 | + ------- |
| 39 | + tuple[xr.Dataset, list[str]] |
| 40 | + Updated dataset and list of normalisation records |
| 41 | + (``"var: old_unit -> mS cm-1"``). |
| 42 | + """ |
| 43 | + normalizations: List[str] = [] |
| 44 | + |
| 45 | + for var_name in list(ds.data_vars): |
| 46 | + if _base_name(var_name) != "conductivity": |
| 47 | + continue |
| 48 | + |
| 49 | + current_units = ds[var_name].attrs.get("units", "") |
| 50 | + if not current_units: |
| 51 | + continue |
| 52 | + if current_units == _TARGET_UNIT: |
| 53 | + continue |
| 54 | + |
| 55 | + values = ds[var_name].values |
| 56 | + try: |
| 57 | + inferred = infer_conductivity_unit(values, declared=current_units) |
| 58 | + converted, canonical = to_mS_cm(values, inferred) |
| 59 | + except ValueError as exc: |
| 60 | + logger.warning( |
| 61 | + "ConductivityNormalizer: cannot convert '%s' (units='%s'): %s", |
| 62 | + var_name, |
| 63 | + current_units, |
| 64 | + exc, |
| 65 | + ) |
| 66 | + continue |
| 67 | + |
| 68 | + saved_attrs = dict(ds[var_name].attrs) |
| 69 | + dims = ds[var_name].dims |
| 70 | + ds[var_name] = (dims, converted) |
| 71 | + ds[var_name].attrs.update(saved_attrs) |
| 72 | + ds[var_name].attrs["units"] = canonical |
| 73 | + ds[var_name].attrs["conductivity_normalised_from"] = current_units |
| 74 | + normalizations.append(f"{var_name}: {current_units} -> {canonical}") |
| 75 | + logger.info( |
| 76 | + "Normalised conductivity '%s': %s -> %s", |
| 77 | + var_name, |
| 78 | + current_units, |
| 79 | + canonical, |
| 80 | + ) |
| 81 | + |
| 82 | + return ds, normalizations |
0 commit comments