Source code for pycif.plugins.models.lmdz_ico.io.inputs.chemfields

from __future__ import annotations

import datetime
from os import PathLike
from pathlib import Path
from typing import Any, Literal

import numpy as np
import xarray as xr
from numpy.random import f

from ......utils import path
from ......utils.check.errclass import CifValueError
from ......utils.hdf5 import _hdf5_lock


[docs] def get_species(self, input_type: str) -> list[str]: """Return the species list for a given chemistry input type""" if input_type == "prescrconcs": return self.chemistry.prescribed_species elif input_type == "prodloss3d": return self.chemistry.prodloss_species elif input_type == "deposition": return self.chemistry.deposition_species elif input_type == "photorates": return self.chemistry.jrates_varname else: raise CifValueError(f"Unknown chemistry input '{input_type}'")
[docs] def make_chemfields( self, datastore: dict[tuple[str, str], dict[str | datetime.datetime, Any]], input_type: Literal["prodloss3d", "prescrconcs", "deposition", "photorates"], ddi: datetime.datetime, runsubdir: str | PathLike, mode: Literal["fwd", "tl", "adj"], ) -> None: """Write chemistry concentration fields (prescribed, deposition, etc.) for LMDZ-ico""" for spec in get_species(self, input_type): trid = (input_type, spec) if trid not in datastore: continue tracer = datastore[trid]["tracer"] data = datastore[trid]["data"][ddi] if "spec" in data: target_path = Path(runsubdir, f"{input_type}.nc") self.chemfields.write(spec, target_path, data["spec"]) # If species is in the control vector, dump tangent-linear increments if tracer.iscontrol and mode == "tl": if input_type not in ("prodloss3d", "prescrconcs"): raise CifValueError( f"Chemistry input '{input_type}' is not supported for tangent-linear mode" ) if "incr" not in data: data["incr"] = data["spec"].copy(data=np.zeros(data["spec"].shape)) self.chemfields.write(f"{spec}_tl", target_path, data["incr"]) else: dirorig = datastore[trid]["dirorig"] fileorig = datastore[trid]["fileorig"] origin_path = Path(dirorig, ddi.strftime(fileorig)) target_path = Path(runsubdir, f"{input_type}_{spec}.nc") # Special legacy case for 'prodloss3d' and 'deposition' inputs if input_type == "prodloss3d": accepted_varnames = (spec, f"{spec}_prod") elif input_type == "deposition": accepted_varnames = (spec, f"Dep_{spec}") else: accepted_varnames = (spec,) if not tracer.varname or tracer.varname in accepted_varnames: # Tracer varname input argument is not specified or is identical # to the parameter name, can link safely path.link(origin_path, target_path) else: # Tracer varname input argument is different from the parameter # name, need to rename the variable so LMDZ can finfd it with _hdf5_lock: with xr.open_dataset(origin_path) as ds: if tracer.varname not in ds: raise CifValueError( f"Variable '{tracer.varname}' not found in file '{origin_path}'" ) ds = ds[[tracer.varname]].rename({tracer.varname: spec}) ds.to_netcdf(target_path)
[docs] def make_kinetic( self, datastore: dict[tuple[str, str], dict[str | datetime.datetime, Any]], ddi: datetime.datetime, runsubdir: str | PathLike, ) -> None: """Write the kinetic (pressure/temperature) field for one period""" target_path = Path(runsubdir, "kinetic.nc") for trid in datastore: data = datastore[trid]["data"][ddi] if "spec" in data: _, var_name = trid self.chemfields.write(var_name, target_path, data["spec"]) else: input_file_list = list(set(datastore[trid]["input_files"][ddi])) if len(input_file_list) == 0: raise CifValueError("There is no file to link to 'kinetic.nc'") if len(input_file_list) > 1: raise CifValueError("There is multiple files to link to 'kinetic.nc'") (input_file,) = input_file_list path.link(input_file, target_path)