|
| 1 | +""" |
| 2 | +Land Cover Level3 classification |
| 3 | +""" |
| 4 | + |
| 5 | +from typing import Tuple |
| 6 | +import xarray as xr |
| 7 | +from odc.stats._algebra import expr_eval |
| 8 | +from ._registry import StatsPluginInterface, register |
| 9 | + |
| 10 | +NODATA = 255 |
| 11 | + |
| 12 | + |
| 13 | +class StatsLccsLevel3(StatsPluginInterface): |
| 14 | + NAME = "ga_ls_lccs_level3" |
| 15 | + SHORT_NAME = NAME |
| 16 | + VERSION = "0.0.1" |
| 17 | + PRODUCT_FAMILY = "lccs" |
| 18 | + |
| 19 | + @property |
| 20 | + def measurements(self) -> Tuple[str, ...]: |
| 21 | + _measurements = ["level3_class"] |
| 22 | + return _measurements |
| 23 | + |
| 24 | + def fuser(self, xx: xr.Dataset) -> xr.Dataset: |
| 25 | + return xx |
| 26 | + |
| 27 | + def reduce(self, xx: xr.Dataset) -> xr.Dataset: |
| 28 | + |
| 29 | + # Cultivated pipeline applies a mask which feeds only terrestrial veg (110) to the model |
| 30 | + # Just exclude no data (255 or nan) and apply the cultivated results |
| 31 | + # 255: load with product definition; nan: load without |
| 32 | + # hence accormmodate both |
| 33 | + |
| 34 | + res = expr_eval( |
| 35 | + "where((a!=a)|(a>=nodata), b, a)", |
| 36 | + {"a": xx.cultivated_class.data, "b": xx.classes_l3_l4.data}, |
| 37 | + name="mask_cultivated", |
| 38 | + dtype="float32", |
| 39 | + **{"nodata": xx.cultivated_class.attrs.get("nodata")}, |
| 40 | + ) |
| 41 | + |
| 42 | + # Mask urban results with bare sfc (210) |
| 43 | + |
| 44 | + res = expr_eval( |
| 45 | + "where(a==_u, b, a)", |
| 46 | + { |
| 47 | + "a": res, |
| 48 | + "b": xx.urban_classes.data, |
| 49 | + }, |
| 50 | + name="mark_urban", |
| 51 | + dtype="float32", |
| 52 | + **{"_u": 210}, |
| 53 | + ) |
| 54 | + |
| 55 | + # Mark nodata to 255 in case any nan |
| 56 | + |
| 57 | + res = expr_eval( |
| 58 | + "where(a==a, a, nodata)", |
| 59 | + { |
| 60 | + "a": res, |
| 61 | + }, |
| 62 | + name="mark_nodata", |
| 63 | + dtype="uint8", |
| 64 | + **{"nodata": NODATA}, |
| 65 | + ) |
| 66 | + |
| 67 | + attrs = xx.attrs.copy() |
| 68 | + attrs["nodata"] = NODATA |
| 69 | + dims = xx.classes_l3_l4.dims[1:] |
| 70 | + |
| 71 | + data_vars = { |
| 72 | + "level3_class": xr.DataArray(res.squeeze(), dims=dims, attrs=attrs) |
| 73 | + } |
| 74 | + |
| 75 | + coords = dict((dim, xx.coords[dim]) for dim in dims) |
| 76 | + level3 = xr.Dataset(data_vars=data_vars, coords=coords, attrs=attrs) |
| 77 | + |
| 78 | + return level3 |
| 79 | + |
| 80 | + |
| 81 | +register("lccs_level3", StatsLccsLevel3) |
0 commit comments