Source code for pyrtid.inverse.loss_function
from typing import Optional, Sequence
import numpy as np
from pyrtid.forward import ForwardModel
from pyrtid.inverse.obs import (
Observable,
Observables,
get_observables_uncertainties_as_1d_vector,
get_observables_values_as_1d_vector,
get_predictions_matching_observations,
)
from pyrtid.inverse.params import AdjustableParameters, eval_weighted_loss_reg
from pyrtid.utils import NDArrayFloat
[docs]def eval_loss_ls(
d_obs: NDArrayFloat, d_calc: NDArrayFloat, x_sigma: NDArrayFloat
) -> float:
r"""
Return the objective function with regard to `x`.
.. math::
\mathcal{J} = \dfrac{1}{2} \sum_{n=0}^{N}
\left(\dfrac{d_{\mathrm{obs}}^{n}
- d_{\mathrm{calc}}^{n}}{\sigma_{\mathrm{obs}}^{n}} \right)^{2}
with $n$, a time with an observation, and $\lvert \bm{d}_{\mathrm{obs}} \rvert$
the number of observation points.
Parameters
----------
d_obs: NDArrayFloat
1D vector of observed values.
d_calc: NDArrayFloat
1D vector of calculated values.
d_obs: NDArrayFloat
1D vector of uncertainties on observed values.
Returns
-------
objective : float
the value of the objective function
"""
return 0.5 * np.sum(np.square((d_calc - d_obs) / x_sigma))
[docs]def eval_model_loss_ls(
model: ForwardModel,
observables: Observables,
max_obs_time: Optional[float] = None,
) -> float:
"""
Return the least-square loss function of the model for the given observations.
Parameters
----------
model : ForwardModel
The forward model from which to read the simulated values.
observables : Observables
Sequence of observable instances.
max_obs_time : Optional[float], optional
Maximum time for which to consider an observation value, by default None
Returns
-------
float
The objective function.
"""
if max_obs_time is not None:
max_obs_time = min(model.time_params.time_elapsed, max_obs_time)
else:
max_obs_time = model.time_params.time_elapsed
return eval_loss_ls(
get_observables_values_as_1d_vector(observables, max_obs_time),
get_predictions_matching_observations(model, observables, max_obs_time),
get_observables_uncertainties_as_1d_vector(observables, max_obs_time),
)
[docs]def eval_model_loss_function(
model: ForwardModel,
observables: Observables,
parameters_to_adjust: AdjustableParameters,
max_obs_time: Optional[float] = None,
) -> float:
"""_summary_
Parameters
----------
model : ForwardModel
Forward model.
parameters_to_adjust : AdjustableParameters
Sequence of adjusted parameter instances.
observables : Observables
Sequence of observable instances.
max_obs_time : Optional[float], optional
Maximum time for which to consider an observation value, by default None
Returns
-------
float
Total objective function (least-squares) for the forward model.
"""
return eval_model_loss_ls(
model, observables, max_obs_time
) + eval_weighted_loss_reg(parameters_to_adjust, model)
[docs]def get_theoretical_noise_level(
observables: Sequence[Observable], n_std: float = 5
) -> float:
"""
Get the theoretical noise level in the solution.
If the obersations uncertaintes are well mastered, it can be used as a threshold for
the loss function ad defined by Gao et al. 2006.
It is propotionnal to the number of observations. And assume that the observation
noise is well known.
"""
n_obs = np.sum([obs.values.size for obs in observables])
return 0.5 * n_obs + n_std * np.sqrt(0.5 * n_obs)