import datetime
import os
import numpy as np
import xarray as xr
from netCDF4 import Dataset
from logging import debug
from .....utils.netcdf import readnc
from .....utils.check.errclass import CifError
from .....utils.hdf5 import _hdf5_lock
[docs]
def read(
self,
name,
varnames,
dates,
files,
interpol_flx=False,
comp_type=None,
ddi=None,
**kwargs
):
"""Read CHIMERE INI_CONCS/BOUN_CONCS data and load it into a pyCIF DataArray.
For ``comp_type == "inicond"``, reads the variable from the single
``INI_CONCS``-style file in ``files``. For ``"latcond"``/``"topcond"``,
reads the ``lat_conc``/``top_conc`` variable from each ``BOUN_CONCS``
file in turn, looks up the matching species and date index (falling
back to an index derived from ``ddi`` if the exact date string is not
found), and fills the corresponding slice with zeros if the species is
absent from the file.
Args:
self: The field/tracer Plugin.
name: Name of the component (used as fallback variable name).
varnames: Name of the variable/species to read; if empty, ``name``
is used instead.
dates: List of dates to extract, matching ``files``.
files: List of files matching ``dates``.
interpol_flx: Unused.
comp_type: Type of boundary condition to read: ``"inicond"``,
``"latcond"`` or ``"topcond"``.
ddi: Reference date used to compute a fallback time index when the
exact date string cannot be found in a ``BOUN_CONCS`` file.
**kwargs: Unused.
Returns:
xarray.DataArray: A 4-dimensional ``(time, lev, lat, lon)`` array.
Raises:
CifError: If ``comp_type`` is ``None``, unrecognized, or if ``ddi``
is needed but not given while a date cannot be matched exactly.
"""
var2extract = varnames if varnames != "" else name
# Check the type of limit condition to check
if comp_type is None:
raise CifError(
"Trying to read limit conditions for CHIMERE, "
"but did not specify the type"
)
# Read INI_CONCS
if comp_type == "inicond":
ic_file = files[0]
with _hdf5_lock:
ds = xr.open_dataset(ic_file)
data = ds[var2extract][:]
# Differentiate case when inicond or end files
if "Time" not in data.dims:
data = data.values[np.newaxis, :]
else:
data = data.values
xmod = xr.DataArray(
data,
coords={"time": [np.min(dates)]},
dims=("time", "lev", "lat", "lon"),
)
# Read Lateral boundary conditions
elif comp_type in ["latcond", "topcond"]:
# Reading required field files
trcr_bc = []
out_dates = []
for dd, ff in zip(dates, files):
# Getting the data
spec = "lat_conc" if comp_type == "latcond" else "top_conc"
data, times, specs = readnc(ff, [spec, "Times", "species"])
# Get the correct date and species index
try:
ispec = [
"".join(c).strip() for c in specs.astype(str)
].index(var2extract)
except ValueError:
ispec = -1
try:
idate = [
datetime.datetime.strptime("".join(d), "%Y-%m-%d_%H:%M:%S")
for d in times.astype(str)
].index(dd[0])
except ValueError:
debug(f"Try to read date {dd[0]} in file {ff}, but not available. Using index from {ddi} to fetch correct date")
if ddi is None:
raise CifError(f"Could not find correct index in {ff} because ddi was not given")
idate = int((dd[0] - ddi).total_seconds() // 3600)
# Appending
if ispec == -1: #### ajouter and fill_with_zeros: + voir si on met vraiment des 0 ou juste rien du tout = selon ce que fait CHIMERE ensuite
trcr_bc.append(data[idate, ..., 0] * 0.0)
else:
trcr_bc.append(data[idate, ..., ispec])
out_dates.append(dd[0])
# Putting the data into an xarray
# Adding an empty latitude axis
if comp_type == "latcond":
xout = np.array(trcr_bc)[..., np.newaxis, :]
else:
xout = np.array(trcr_bc)[:, np.newaxis, ...]
xmod = xr.DataArray(
xout, coords={"time": out_dates}, dims=("time", "lev", "lat", "lon")
)
else:
raise CifError(
f"Could not recognize the type of boundary condition to read in CHIMERE: {comp_type}"
)
return xmod