import copy
import os
import numpy as np
import pandas as pd
from logging import warning
from .utils import init_param
from ....utils.datastores.compress import compress_datastore
[docs]
def init_y0(obsvect, **kwargs):
"""Initializes the observation vector. In most cases the observation
vector is similar to the measurement vector but there is no reason
for it to be the same, especially when super-observations are used
(e.g. daily or afternoon averages, gradients, etc.)
Args:
obsvect (Plugin): the observation vector with all its attributes
measurements (Plugin): the pre-loaded measurements
Returns:
obsvect, updated with horizontal and vertical coordinates,
as well as model time steps
"""
datei = getattr(obsvect, "datei")
datef = getattr(obsvect, "datef")
obsvect.dim = 0
obsvect.yobs = np.ones(0)
obsvect.yobs_err = np.ones(0)
obsvect.ysim = np.ones(0)
obsvect.dy = np.ones(0)
obsvect.obsvect_mask = np.ones(0, dtype=bool)
datavect = obsvect.datavect
# If no definition is specified for the control vector in the Yaml,
# return empty control vector
if not hasattr(datavect, "components"):
return obsvect
# Else, carry on initializing
components = datavect.components
for comp in components.attributes:
component = getattr(components, comp)
# Skip if component does not have parameters
if not hasattr(component, "parameters"):
continue
component.isobs = comp in obsvect.default_obstypes
for trcr in component.parameters.attributes:
tracer = getattr(component.parameters, trcr)
# Skip tracers that are not control variables
tracer.isobs = (
comp in obsvect.default_obstypes
or tracer.isobs
)
if not tracer.isobs:
continue
# Keeping a pointer to the correct location in the whole control
tracer.ypointer = obsvect.dim
# Initializing data for tracer if needed
if obsvect.dir_obsvect == "":
obsvect.dir_obsvect = os.path.join(obsvect.workdir, "obsvect")
file_ref = "{}/{}/{}/monitor.nc".format(
obsvect.dir_obsvect, comp, trcr
)
param = getattr(tracer, "varname", "")
param = trcr if param == "" else param
init_param(obsvect, tracer, param, comp, file_ref)
# Replacing tracer name
tracer.datastore[("metadata", "parameter")] = \
len(tracer.datastore) * [trcr]
tracer.datastore[("metadata", "parameter")] = \
tracer.datastore[("metadata", "parameter")].astype("category")
# Compute end date for interpolation
tracer.datastore[("metadata", "enddate")] = \
tracer.datastore["metadata"]["date"] \
+ pd.to_timedelta(
tracer.datastore["metadata"]["duration"].astype(
float) * 3600,
unit="s")
# Deal with obsvect flag
if tracer.datastore["metadata"]["is_obsvect"].dtype == "O":
tracer.datastore[("metadata", "is_obsvect")] = \
~copy.deepcopy(
tracer.datastore.loc[:, ("metadata", "is_obsvect")]
== "False").values
tracer.datastore[("metadata", "is_obsvect")] = \
tracer.datastore[("metadata", "is_obsvect")].astype(bool)
mask_obsvect = \
tracer.datastore["metadata"].loc[
:, "is_obsvect"
].values.astype(bool)
if not getattr(tracer, "is_obsvect", True):
mask_obsvect[:] = False
setattr(tracer, "dont_propagate_obsvect", True)
# Crop data if obsvect_only
if obsvect.obsvect_only:
tracer.datastore = tracer.datastore.loc[mask_obsvect]
mask_obsvect = mask_obsvect[mask_obsvect]
tracer.datastore = tracer.datastore.reset_index(drop=True)
# If datastore is empty, do not treat as observation
if len(tracer.datastore) == 0:
tracer.isobs = False
warning(
f"No valid observation will be used for {comp} / {trcr}.\n"
"Please check your Yaml and input data if this is not the expected "
"behaviour. \n"
"This can happen for instance if your observation data are "
"all outside the simulation window."
)
continue
# Fill attributes depending on values
obsvect.obsvect_mask = np.append(
obsvect.obsvect_mask, mask_obsvect)
tracer.dim = len(tracer.datastore)
obsvect.dim += tracer.dim
obsvect.yobs = np.append(
obsvect.yobs, tracer.datastore["maindata"].loc[:, "obs"])
# Load simulations and increments from previous run if any
ysim = np.zeros(len(tracer.datastore))
dy = np.zeros(len(tracer.datastore))
if "sim" in tracer.datastore["maindata"]:
ysim = tracer.datastore["maindata"].loc[:, "sim"]
if "sim_tl" in tracer.datastore["maindata"]:
dy = tracer.datastore["maindata"].loc[:, "sim_tl"]
obsvect.ysim = np.append(obsvect.ysim, ysim)
obsvect.dy = np.append(obsvect.dy, dy)
# Appending errors
to_append = tracer.datastore["maindata"].loc[:, "obserror"] \
if "obserror" in tracer.datastore["maindata"] \
else np.zeros(len(tracer.datastore))
to_append = np.sqrt(
(to_append * getattr(tracer, "obserror_scale", 1)) ** 2
+ getattr(tracer, "obserror_value", 0) ** 2
)
obsvect.yobs_err = np.append(obsvect.yobs_err, to_append)
# Compressing the data
tracer.datastore = compress_datastore(tracer.datastore)
if obsvect.dump_obs:
obsvect.dump("{}/obsvect/".format(obsvect.workdir))
return obsvect