Skip to content

Commit c342ae5

Browse files
authored
Merge pull request #94 from rubisco-sfa/soil-moisture-fixes
FIX: transform fixes due to xarray/pint oddities
2 parents a3e5df0 + 948430e commit c342ae5

File tree

1 file changed

+27
-17
lines changed

1 file changed

+27
-17
lines changed

ilamb3/transform/soilmoisture.py

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import xarray as xr
66

7+
import ilamb3
78
import ilamb3.dataset as dset
89
from ilamb3.transform.base import ILAMBTransform
910

@@ -35,34 +36,43 @@ def __call__(self, ds: xr.Dataset) -> xr.Dataset:
3536
def _to_vol_fraction(ds: xr.Dataset, varname: str) -> xr.DataArray:
3637
"""
3738
Convert the array from a mass area density to a volume fraction.
39+
40+
Note
41+
----
42+
As of xarray 2025.10.1, pint 0.25, pint-xarray 0.6.0, quantifying the
43+
dataarray here changes the depth dimension data yielding differences in the
44+
dimension on the order (1e-8). Here we avoid using quantify to circumvent
45+
this issue.
3846
"""
3947
da = ds[varname]
40-
da = da.pint.quantify()
41-
ureg = da.pint.registry
42-
quantity = 1.0 * da.pint.units
48+
ureg = ilamb3.units
49+
quantity = ureg(da.attrs["units"])
4350
if quantity.check(""):
44-
return da.pint.dequantify()
51+
# units are already compatible with volume fraction
52+
return da
4553
if not quantity.check("[mass] / [length]**2"):
46-
raise ValueError("Cannot convert array of this type.")
54+
raise ValueError(
55+
f"Cannot convert a variable with units of this type {da.pint.units}."
56+
)
4757
if dset.is_layered(da):
48-
depth_name = dset.get_dim_name(da, "depth")
49-
depth = da[depth_name]
50-
if "bounds" not in depth.attrs:
51-
raise ValueError(
52-
"Cannot convert soil mositure data when depth bounds are not coordinates."
53-
)
54-
depth_name = depth.attrs["bounds"]
55-
if depth_name not in ds:
58+
depth_dim = dset.get_dim_name(da, "depth")
59+
depth = ds[depth_dim]
60+
bnd_name = depth.attrs["bounds"] if "bounds" in depth.attrs else None
61+
if not dset.has_bounds(ds, depth_dim, bnd_name):
5662
raise ValueError(
5763
"Cannot convert soil mositure data when depth bounds are not coordinates."
5864
)
59-
depth = ds[depth_name] * da.pint.registry.meter
60-
da = da / depth.diff(dim=depth.dims[-1])
65+
depth = ds[bnd_name]
66+
interval_dim = set(depth.dims).difference([depth_dim]).pop()
67+
da = (
68+
da / depth.diff(dim=interval_dim).squeeze()
69+
) # <-- this was failing, see Note
70+
da = da.pint.quantify() / ureg.meter
6171
else:
6272
# If not layered, we are assuming this is mrsos which is the moisture in
6373
# the top 10cm
64-
depth = 0.1 * da.pint.registry.meter
65-
da = da / depth
74+
depth = 0.1 * ureg.meter
75+
da = da.pint.quantify() / depth
6676
water_density = 998.2071 * ureg.kilogram / ureg.meter**3
6777
da = (da / water_density).pint.to("dimensionless")
6878
da = da.pint.dequantify()

0 commit comments

Comments
 (0)