Source code for pycif.plugins.models.lmdz_ico.io.outputs.read_sim
from __future__ import annotations
from datetime import datetime
from os import PathLike
from pathlib import Path
from typing import Literal
import pandas as pd
import xarray as xr
from pandas import DataFrame
from ......utils.check.errclass import CifFileNotFoundError, CifRuntimeError
from ......utils.hdf5 import _hdf5_lock
[docs]
def read_sim(
self,
data2dump: dict[tuple[str, str], dict[datetime, DataFrame]],
ddi: datetime,
runsubdir: str | PathLike,
mode: Literal["fwd", "tl", "adj"],
) -> dict[tuple[str, str], DataFrame]:
"""Extract simulated concentrations"""
runsubdir = Path(runsubdir)
obs_file = runsubdir / "obs.nc"
sim_file = runsubdir / "obs_out.nc"
cols = []
for input_type, _ in data2dump:
if input_type == "concs":
cols.append("spec")
if mode == "tl":
cols.append("incr")
else:
cols.append(input_type)
if sim_file.exists():
# Read observations, if simulation file is present, observation file should
# also exits
with _hdf5_lock:
with (
xr.open_dataset(obs_file) as ds_obs,
xr.open_dataset(sim_file) as ds_sim,
):
# Restore original order (previously sorted by time)
ds_sim = ds_sim[cols].sortby(ds_obs.index)
ds_obs = ds_obs.sortby("index")
tracer_index = ds_obs["itrac"].values # starts from 1
sim = ds_sim.to_dataframe()
elif not obs_file.exists():
# Empty dataframe
tracer_index = pd.Series([0], dtype=int)
sim = pd.DataFrame(columns=cols)
else:
# Simulation file, should be present if observation file is
raise CifFileNotFoundError(
f"LMDZ did not produce a obs_out.nc file in '{runsubdir}'."
)
active_species = [spec.lower() for spec in self.chemistry.active_species]
dataout = {}
for (input_type, tracer), datastore in data2dump.items():
tracer = tracer.replace("__sample#", "_")
itrac = active_species.index(tracer.lower()) + 1
df = sim.loc[tracer_index == itrac]
dataloc = datastore[ddi]
if len(dataloc) == 0:
continue
if self.skip_obs_chunking:
if len(df) != len(dataloc):
raise CifRuntimeError(
"Length mismatch between source and target dataframes. "
+ "Disable 'skip_obs_chunking' to properly compute alignements"
)
else:
# Redistributing extracting data into correct rows of the dataframe
chunk_indexes = self.chunk_indexes[ddi][input_type][tracer]
if chunk_indexes is None:
raise CifRuntimeError(
f"chunk indexes for {input_type}/{tracer} are uninitialized"
)
df = df.loc[chunk_indexes]
if input_type == "concs":
dataloc.loc[:, ("maindata", "spec")] = df.loc[:, "spec"].to_numpy()
if mode == "tl":
dataloc.loc[:, ("maindata", "incr")] = df.loc[:, "incr"].to_numpy()
else:
dataloc.loc[:, ("maindata", "incr")] = 0.0
else:
dataloc.loc[:, ("maindata", "spec")] = df.loc[:, input_type].to_numpy()
dataloc.loc[:, ("maindata", "incr")] = 0.0
dataout[(input_type, tracer)] = dataloc.copy()
return dataout