Source code for pycif.plugins.domains.dalecbethy.read_domain

from pathlib import Path

import numpy as np
import xarray as xr

from ....utils.check.errclass import CifKeyError, CifValueError


[docs] def read_grid(domain, **kwargs): """Read D&B's sample-point domain from its static forcing NetCDF file. Grid-cells are collapsed into a 1D list of ``nsp`` "sample points", skipping grid-cells where ``condition_simulate == 0``. Sets on *domain*: ``unstructured_domain``, ``nlon`` (=``nsp``), ``nlat`` (=1), ``zlon``, ``zlat`` (shape ``(1, nsp)``), plus a single-level vertical coordinate. Also sets ``ng`` (the full, unfiltered size of the static forcing file's flat grid-cell dimension) and ``active``, the indices (into that ``ng`` dimension) of the retained sample points, in the same order as ``zlon``/``zlat``; other D&B NetCDF files indexed along the same ``ng`` dimension (e.g. D&B's own ``dynforcing.nc``, see ``pycif.plugins.datastreams.fluxes.dalecbethy``) must be subset/scattered with these to line up with this domain. Args: domain: dalecbethy domain plugin instance with ``dir``/``file`` set. **kwargs: unused. Raises: CifKeyError: if a mandatory dimension/variable is missing. CifValueError: if no active sample point is found. """ domain.unstructured_domain = True file_path = Path(domain.dir, domain.file) with xr.open_dataset(file_path) as ds: if "condition_simulate" not in ds: raise CifKeyError( f"mandatory variable 'condition_simulate' not found in " f"'{file_path}'." ) condition_simulate = ds["condition_simulate"].values if "lon" not in ds or "lat" not in ds: raise CifKeyError( f"mandatory 'lon'/'lat' coordinates not found in " f"'{file_path}'." ) lon = ds["lon"].values lat = ds["lat"].values active = np.where(condition_simulate != 0)[0] nsp = active.size if nsp == 0: raise CifValueError( f"no active sample point found in D&B static forcing file " f"'{file_path}'." ) # D&B is a point cloud, not a regular grid: expose it the same way # as pycif.plugins.domains.unstructured_NetCDF (1 x nsp). domain.nlon = nsp domain.nlat = 1 domain.ng = condition_simulate.size domain.active = active domain.zlon = lon[active][np.newaxis, :] domain.zlat = lat[active][np.newaxis, :] # Complete the corner coordinates dlon = np.min(np.diff(np.unique(domain.zlon))) / 2 dlat = np.min(np.diff(np.unique(domain.zlat))) / 2 domain.zlonc = np.concatenate( [lon[active][np.newaxis, :] - dlon, lon[active][np.newaxis, :] - dlon, lon[active][np.newaxis, :] + dlon, lon[active][np.newaxis, :] + dlon], axis=0 ) domain.zlatc = np.concatenate( [lat[active][np.newaxis, :] - dlat, lat[active][np.newaxis, :] + dlat, lat[active][np.newaxis, :] + dlat, lat[active][np.newaxis, :] - dlat], axis=0 ) domain.nlev = 1 domain.sigma_a_mid = [1] domain.sigma_b_mid = [0]