Core (Base Classes) of DA (Inversion) Methods#
Abstract classes for data assimilation algorithms (inverse problems); including both filtering (time-independent) and smoothing (time-dependent).
In filtering, one observation is used to update model state/parameter or the underlying probability distribution. In smoothing, on the other hand, multiple observations (e.g., at different times) are used. The output is an estimate of the model state/parameter uncertainty measure, e.g., posterior covariance, provided if a Bayesian approach is followed.
Note
There is a crucial design decision that requires making at this point. The register_observation, register_observation_error_model, and register_observation_operator functionality are related to each others. The experimental design (if an observation design (e.g., sensor locations)), influences the dimensionality of the observation(s) which depends on PyOED’s projection approach as defined by the settings module, specifically by pyoed.configs.SETTINGS.project_onto_active_design_space.
The
is_observation_vector()available for each observation operator checks if an object is a valid observation vector by inspecting each of the following:It is of a proper type (typically a 1d array)
The size of the observation vector is equal to:
the full observation space if pyoed.configs.SETTINGS.project_onto_active_design_space is False.
the number of active entries (non-zero design values) if pyoed.configs.SETTINGS.project_onto_active_design_space is True.
Since observations are collected in reality based on the current experimental design, the observation vector must match the observation operator active space as well as the observation error model active space if pyoed.configs.SETTINGS.project_onto_active_design_space is True. Otherwise, the observation vector need to match the full observation space as well as the full observation noise space.
Thus, the three registration methods above check those rules when attempting to register the corresponding object.
Note
Here are the registration rules:
Any observation to be registerd must ignore the experimental design. This means, the observations stored must be applicable even when the experimental design changes. This allows solving the assimilation problems for any design, and also allows proper evaluation of the OED functionality.
The
observations()attributes in any DA object (inverse problem) properly extracts the observations according to the current experimental design (based on the global PyOED configurations in pyoed.configs.SETTINGS.project_onto_active_design_space.The observation operator is a function of the simulation model state. Thus, the operator domain size (full shape ignoring design) must match the model state size.
The observation(s) are generated by the observation operator. To avoid any confusion, the registered observations must be valid observations, and thus they must comply with the dimension of the observation space accounting for existing experimental design. The assimilation procedures, however, need to be agnostic to the experimental design as it is assumed constant during the assimilation step. Thus, an observation vector is valid if the registered observation operator agrees that the observation vector is valid. Thus, to register observation(s):
a valid observation operator must be registered first,
the observation operator’s method
is_valid_observation()returns True for an observation to be acceptable and properly registered.
the observation error model weights the simulation and the observational data for any experimental design. Thus, an observation error model must satisfy that:
the error model full space size (ignoring the design) must match the full co-domain of the observation operator (ignoring the design).
Finally, any assimilation procedure must make sure the experimental design is consistent and is not different in the observation operator and the observation error model.
- class InverseProblemConfigs(*, debug=False, verbose=False, output_dir='./_PYOED_RESULTS_', name=None, model=None, prior=None, observation_error_model=None, observation_operator=None, observations=None, optimizer=None, optimizer_configs=None)[source]#
Bases:
PyOEDConfigsConfigurations class for the
InverseProblemabstract base class. This class inherits functionality fromPyOEDConfigsand only adds new class-level variables which can be updated as needed.See
PyOEDConfigsfor more details on the functionality of this class along with a few additional fields. OtherwiseInverseProblemConfigsprovides the following fields:- Parameters:
verbose (bool) – a boolean flag to control verbosity of the object.
debug (bool) – a boolean flag that enables adding extra functionality in a debug mode
output_dir (str | Path) – the base directory where the output files will be saved.
name (str | None) – name of the DA (inverse problem solver) approach/method.
model (None | SimulationModel) – the simulation model.
prior (None | ErrorModel) – Background/Prior model (e.g.,
GaussianErrorModel)observation_operator (None | ObservationOperator) – operator to map model state to observation space
observation_error_model (None | ErrorModel) – Observation error model (e.g.,
GaussianErrorModel)observations (None | Any) – Observational data (the data type is very much dependent of the DA method)
optimizer (None | Optimizer) –
the optimization routine (optimizer) to be registered and later used for solving the OED problem. This can be one of the following:
None: In this case, no optimizer is registered, and the
solve()won’t be functional until an optimization routine is registered.An optimizer instance (object that inherits :py:class`Optimizer`). In this case, the optimizer is registered as is and is updated with the passed configurations if available.
The class (subclass of
Optimizer) to be used to instantiate the optimizer.
optimizer_configs (None | dict | OptimizerConfigs) –
the configurations of the optimization routine. This can be one of the following:
None, in this case configurations are discarded, and whatever default configurations of the selected/passed optimizer are employed.
A dict holding full/partial configurations of the selected optimizer. These are either used to instantiate or update the optimizer configurations based on the type of the passed optimizer.
A class providing implementations of the configurations (this must be a subclass of
OptimizerConfigs.An instance of a subclass of
OptimizerConfigswhich is to set/udpate optimizer configurations.
Note
Not all DA (inverse problem) objects are optimization-based. For example, particle-based (EnKF, PF, etc.) employ a sample to estimate the flow of the distribution through the model dynamics (prior -> posterior). Thus, the optimizer (and configs) in this case (the default) are set to None. For optimization-based methods such as 3DVar, 4DVar, etc., an optimizer must be registered for the inverse problem to be solved.
- model: None | SimulationModel#
- prior: None | ErrorModel#
- observation_error_model: None | ErrorModel#
- observation_operator: None | ObservationOperator#
- optimizer_configs: None | dict | OptimizerConfigs#
- __init__(*, debug=False, verbose=False, output_dir='./_PYOED_RESULTS_', name=None, model=None, prior=None, observation_error_model=None, observation_operator=None, observations=None, optimizer=None, optimizer_configs=None)#
- class InverseProblem(configs=None)[source]#
Bases:
PyOEDObjectBase class for implementations of Inversion/Inference/DA (Data Assimilation) methods/approaches.
Note
The optimizer configuration attribute can be assigned an optimization routine to be used for solving the inverse problem (for optimization-based DA methods). For optimization based DA methods, the method
solve()relies on this object for solving the OED optimization problem. Since not all DA methods are optimization-base, this is None by default and need to be created by derived classes. One can, however, discard this attribute and write full functionality in thesolve()method. However, employing this attribute is expected for consistency.- Parameters:
configs (dict | InverseProblemConfigs | None) – (optional) configurations for the optimization object
- Raises:
PyOEDConfigsValidationError – if passed invalid configs
- validate_configurations(configs, raise_for_invalid=True)[source]#
Each simulation optimizer SHOULD implement it’s own function that validates its own configurations. If the validation is self contained (validates all configuations), then that’s it. However, one can just validate the configurations of of the immediate class and call super to validate configurations associated with the parent class.
If one does not wish to do any validation (we strongly advise against that), simply add the signature of this function to the optimizer class.
Note
The purpose of this method is to make sure that the settings in the configurations object self._CONFIGURATIONS are of the right type/values and are conformable with each other. This function is called upon instantiation of the object, and each time a configuration value is updated. Thus, this function need to be inexpensive and should not do heavy computations.
- Parameters:
configs (dict | InverseProblemConfigs) – configurations to validate. If a
InverseProblemonfigsobject is passed, validation is performed on the entire set of configurations. However, if a dictionary is passed, validation is performed only on the configurations corresponding to the keys in the dictionary.- Raises:
PyOEDConfigsValidationError – if the configurations are invalid and raise_for_invalid is set to True.
AttributeError – if any (or a group) of the configurations does not exist in the optimizer configurations
InverseProblemConfigs.
- update_configurations(**kwargs)[source]#
Take any set of keyword arguments, and lookup each in the configurations, and update as nessesary/possible/valid
- Raises:
PyOEDConfigsValidationError – if invalid configurations passed
- register_model(model=None)[source]#
Register (and return) the simulation model.
- Parameters:
model (None | SimulationModel) – the simulation model to register, or
Noneto clear it.- Returns:
the registered model (or
None).- Return type:
SimulationModel | None
- Raises:
PyOEDConfigsValidationError – if the type of passed model is not supported
- register_prior(prior=None)[source]#
Register (and return) the prior (background) error model.
- Parameters:
prior (None | ErrorModel) – the prior error model to register, or
Noneto clear it.- Returns:
the registered prior (or
None).- Return type:
ErrorModel | None
- Raises:
PyOEDConfigsValidationError – if the type of passed prior is not supported
- register_observation_operator(observation_operator=None)[source]#
Register (and return) the observation operator.
Validates that the operator is consistent with the registered simulation model (domain), observation error model (co-domain), observations, and experimental design.
- Parameters:
observation_operator (None | ObservationOperator) – the observation operator to register, or
Noneto clear it.- Returns:
the registered observation operator (or
None).- Return type:
ObservationOperator | None
- Raises:
PyOEDConfigsValidationError – if the type of passed observation operator is not supported
- register_observation_error_model(observation_error_model=None)[source]#
Register (and return) the observation error model.
Validates that the error model size is consistent with the registered observation operator co-domain and that their experimental designs match.
- Parameters:
observation_error_model (None | ErrorModel) – the observation error model to register, or
Noneto clear it.- Returns:
the registered observation error model (or
None).- Return type:
ErrorModel | None
- Raises:
PyOEDConfigsValidationError – if the type of passed observation error model is not supported
- register_observations(observations)[source]#
Register (and return) the observational data.
Validates that observations are consistent with the registered observation operator. An observation operator must be registered before actual observations can be registered (except for empty dictionaries used by smoothers).
- Parameters:
observations – the observational data to register. Can be a numpy array (for filters) or a
dictkeyed by time (for smoothers), orNoneto clear.- Returns:
the registered observations.
- Raises:
PyOEDConfigsValidationError – if the type of passed observational data is not supported
- register_optimizer(optimizer, *args, **kwargs)[source]#
Register (and return) the passed optimizer.
Note
This method does not create a new optimizer instance. It just takes the created optimizer, makes sure it is an instance derived from the
pyoed.optimization.Optimizerand associates it with this assimilation (DA) object.Note
A derived class is expected to create this optimizer, and pass it up by calling super().register_optimizer(optimizer) so that it can be registered properly.
- Returns:
the registered optimizer.
- Raises:
PyOEDConfigsValidationError – if the type of passed optimizer is not supported
- Return type:
Optimizer | None
- design_is_consistent(first, second)[source]#
Check that the experimental design is consistent in both first and second. We define a consistent design here as a design that:
If either of first or second is None, the design is assumed consistent (until properly set of course). Thus, this method needs to be called upon registeration of objects those need to be matched.
the design in the two objects is either a dictionary dict, or a numpy array. To allow other types, one has to reimplement this method.
for 1d numpy arrays, the two designs has the same size ignoring active/inactive entries, and the two designs has the same active entries.
for dictionaries, both designs must be indexed with the same keys (e.g., observation times), and the value for each key is a 1d array that satisfies the conditions 2 and 3 above for all keys.
The two objects provide a method project_onto_active_design_space which returns the same value True/False.
If the design of one object is a numpy array, and the design of the other object is a dictionary, all values in the dictionary must be consistent with the numpy array design of the other.
If the two objects first and second have experimental designs accessible through design property, and the conditions above are met, this method returns True. If any of the conditions are violated, the method returns False. If any of the objects does not provide design or project_onto_active_design_space properties, a TypeError is raised.
- solve_inverse_problem(*args, **kwargs)[source]#
Start solving the inverse problem (DA) for the registered configuration with passed arguments.
Warning
This method is added for backward compatibility, and it will be deprecated soon. User need to call
solve()instead.
- apply_forward_operator(*args, **kwargs)[source]#
Apply F, the forward operator to the passed state. The forward operator here, refers to the simulation model followed by the observation operator. The result is a data point (an observation), or a dictionary of observations indexed by the time (for time-dependent models).
For time-dependent simulations with multiple observation points (e.g., in 4D-Var settings), the observations are evaluated at the simulation time instances (corresponding to registered observations) over the registered time window.
- apply_forward_operator_adjoint(*args, **kwargs)[source]#
Apply F^*, the adjoint of the forward operator to the passed observation.
- show_registered_elements(display=True)[source]#
Compose and (optionally) print out a message containing the elements of the inverse problem and show what’s registered and what’s not
- Parameters:
display – if True print out the composed message about registered/unregistered elements
- Returns:
the composed message
- Return type:
None
- check_registered_elements(*args, **kwargs)[source]#
Check if all elements of the inverse problem (simulation model, observation operator, prior, observation error model, and observational data) are registered or not.
Note
This method SHOULD be modified by derived classed to check other elements. For example, a smoother requires observation times, assimilation window, etc.
- solve(init_guess=None)[source]#
Start solving the inverse problem.
Note
This method needs to be replicated (rewritten) for any DA (inverse problem) object so that it can replace the returned results object with teh appropriate one.
- Parameters:
init_guess – The initial guess of the design to be used as starting point of the optimization routine
- Returns:
an instance of (derived from) InverseProblemResults holding results obtained by solving the inverse problem
- plot_results(results, overwrite=False, bruteforce_results=None, num_active=None, uncertain_parameter_sample=None, exhaustive_parameter_search_results=None, show_legend=True, output_dir=None, keep_plots=False, fontsize=20, line_width=2, usetex=True, show_axis_grids=True, axis_grids_alpha=(0.25, 0.4), plots_format='pdf')[source]#
Generic plotting function for inverse problems. Given the results returned by
solve(), visualize the results. Additional plotters can be added to this method or derived methods…- Raises:
TypeError – if no valid optimizer is registered
- property optimizer#
The registered optimizer.
- property model#
The registered simulation (forward) model.
An instance of
SimulationModel(or one of its subclasses) used to propagate the state and produce model predictions. Register or update the model viaregister_model()or by direct assignment:da.model = my_simulation_model
- Return type:
SimulationModel | None
- property prior#
The registered prior probability distribution.
An instance of
ErrorModel(or one of its subclasses) representing the prior knowledge about the state or parameters before any observations are assimilated. Register or update it viaregister_prior()or by direct assignment:da.prior = GaussianErrorModel(configs={"mean": mu_b, "variance": B})
- Return type:
ErrorModel | None
- property posterior#
The posterior distribution (result of the last assimilation solve).
Populated by
solve_inverse_problem()after a successful assimilation step. The exact type depends on the concrete DA implementation (e.g., aErrorModelfor filtering, or a sequence of error models for smoothing).Nonebefore the first solve.
- property observation_error_model#
The registered observation error / noise model.
An instance of
ErrorModelcharacterising the statistical properties of the observation noise. Its full-space size must match the co-domain of the registeredobservation_operator. Register or update it viaregister_observation_error_model()or by direct assignment:da.observation_error_model = GaussianErrorModel(configs={"variance": R})
- Return type:
ErrorModel | None
- property observation_operator#
The registered observation operator.
An instance of
ObservationOperatorthat maps model states to the observation space. Its domain size must match the model state size. Register or update it viaregister_observation_operator()or by direct assignment:da.observation_operator = IdentityObservationOperator(configs={...})
- Return type:
ObservationOperator | None
- property observations#
The registered observational data. This property needs to be overridden by inheriting class to pose effect of the experimental design on the retrieved data.
- property project_onto_active_design_space#
Project observations onto active design space or not. This is determined by the same property project_onto_active_design_space associated with both the registered observation observation operator and observation error model. If the projection strategies are inconsistent, a
PyOEDConfigsValidationErroris raised.- Raises:
PyOEDConfigsValidationError – if either the observation error model or the observation operator is not registered
PyOEDConfigsValidationError – if the projection strategy in the observation operator does not match that in the observation error model.
- class InverseProblemResults(*, inverse_problem=None, optimization_results=None)[source]#
Bases:
PyOEDDataBase class to hold DA (inverse problems) data/results.
- Parameters:
inverse_problem (InverseProblem | None) – instance of a class derived from
InverseProblem.optimization_results (OptimizerResults | None) – results returned by the optimizer after solving the inverse problem (for optimization-based DA methods).
Nonefor non-optimization-based methods (e.g., ensemble filters).
- inverse_problem: InverseProblem | None#
- optimization_results: OptimizerResults | None#
- classmethod load_results(readfrom)[source]#
Inspect pickled file, and load inverse problem results;
- Raises:
IOError – if loading failed
- __init__(*, inverse_problem=None, optimization_results=None)#
- class FilterConfigs(*, debug=False, verbose=False, output_dir='./_PYOED_RESULTS_', name=None, model=None, prior=None, observation_error_model=None, observation_operator=None, observations=None, optimizer=None, optimizer_configs=None)[source]#
Bases:
InverseProblemConfigsConfigurations class for the
Filterabstract base class.- Parameters:
verbose (bool) – a boolean flag to control verbosity of the object.
debug (bool) – a boolean flag that enables adding extra functionality in a debug mode
output_dir (str | Path) – the base directory where the output files will be saved.
name (str | None) – name of the DA (inverse problem solver) approach/method.
model (None | SimulationModel) – the simulation model.
prior (None | ErrorModel) – Background/Prior model (e.g.,
GaussianErrorModel)observation_operator (None | ObservationOperator) – operator to map model state to observation space
observation_error_model (None | ErrorModel) – Observation error model (e.g.,
GaussianErrorModel)observations (None | Any) – Observational data (the data type is very much dependent of the DA method)
optimizer (None | Optimizer) –
the optimization routine (optimizer) to be registered and later used for solving the OED problem. This can be one of the following:
None: In this case, no optimizer is registered, and the
solve()won’t be functional until an optimization routine is registered.An optimizer instance (object that inherits :py:class`Optimizer`). In this case, the optimizer is registered as is and is updated with the passed configurations if available.
The class (subclass of
Optimizer) to be used to instantiate the optimizer.
optimizer_configs (None | dict | OptimizerConfigs) –
the configurations of the optimization routine. This can be one of the following:
None, in this case configurations are discarded, and whatever default configurations of the selected/passed optimizer are employed.
A dict holding full/partial configurations of the selected optimizer. These are either used to instantiate or update the optimizer configurations based on the type of the passed optimizer.
A class providing implementations of the configurations (this must be a subclass of
OptimizerConfigs.An instance of a subclass of
OptimizerConfigswhich is to set/udpate optimizer configurations.
Note
Not all DA (inverse problem) objects are optimization-based. For example, particle-based (EnKF, PF, etc.) employ a sample to estimate the flow of the distribution through the model dynamics (prior -> posterior). Thus, the optimizer (and configs) in this case (the default) are set to None. For optimization-based methods such as 3DVar, 4DVar, etc., an optimizer must be registered for the inverse problem to be solved.
- __init__(*, debug=False, verbose=False, output_dir='./_PYOED_RESULTS_', name=None, model=None, prior=None, observation_error_model=None, observation_operator=None, observations=None, optimizer=None, optimizer_configs=None)#
- class Filter(configs=None)[source]#
Bases:
InverseProblemBase class for all filtering (time-independent) DA implementations.
Filters solve inverse problems where a single observation vector is used to update the model state or parameter estimate. This includes methods such as Kalman filters, 3D-Var, and ensemble-based filters (e.g., EnKF).
Compared to the parent
InverseProblem, aFilterenforces:The observation operator must not be time-dependent.
The observation error model must not be time-dependent.
Observations must be a single array (not a dictionary keyed by time).
- Parameters:
configs (dict | FilterConfigs | None) – configurations for the filter
- register_model(model=None)[source]#
Register (and return) the simulation model to be registered. This calls InverseProblem.register_model and adds extra assertions/functionality specific for filters.
- Raises:
PyOEDConfigsValidationError – if the type of passed model is not supported
- register_prior(prior=None)[source]#
Register (and return) the prior to be registered. This calls InverseProblem.register_prior and adds extra assertions/functionality specific for filters.
- Raises:
PyOEDConfigsValidationError – if the type of passed prior is not supported
- register_observation_operator(observation_operator=None)[source]#
Register (and return) the observation operator to be registered. This calls InverseProblem.register_observation_operator and adds extra assertions/functionality specific for filters.
- Raises:
PyOEDConfigsValidationError – if the type of passed observation operator is not supported
- register_observation_error_model(observation_error_model=None)[source]#
Register (and return) the observation error model to be registered. This calls InverseProblem.register_observation_error_model and adds extra assertions/functionality specific for filters.
- Raises:
TypeError – if the type of passed observation error model is not supported
- register_observations(observations)[source]#
Register (and return) the observational data. This calls InverseProblem.register_observations and adds extra assertions/functionality specific for filters.
- Raises:
TypeError – if the type of passed observational data is not supported
- property observations#
The registered observational data. This property needs to be overridden by inheriting class to pose effect of the experimental design on the retrieved data.
- class FilterResults(*, inverse_problem=None, optimization_results=None)[source]#
Bases:
InverseProblemResultsBase class for objects holding results of
Filter.Derived filter implementations (e.g., 3D-Var, EnKF) should subclass this and add fields specific to their output (e.g., posterior state, analysis increment, ensemble).
- Parameters:
inverse_problem (InverseProblem | None) – instance of a class derived from
InverseProblem.optimization_results (OptimizerResults | None) – results returned by the optimizer after solving the inverse problem (for optimization-based DA methods).
Nonefor non-optimization-based methods (e.g., ensemble filters).
- __init__(*, inverse_problem=None, optimization_results=None)#
- class SmootherConfigs(*, debug=False, verbose=False, output_dir='./_PYOED_RESULTS_', name=None, model=None, prior=None, observation_error_model=None, observation_operator=None, observations=None, optimizer=None, optimizer_configs=None, window=None)[source]#
Bases:
InverseProblemConfigsConfigurations class for the
Smootherabstract base class.- Parameters:
verbose (bool) – a boolean flag to control verbosity of the object.
debug (bool) – a boolean flag that enables adding extra functionality in a debug mode
output_dir (str | Path) – the base directory where the output files will be saved.
name (str | None) – name of the DA (inverse problem solver) approach/method.
model (None | SimulationModel) – the simulation model.
prior (None | ErrorModel) – Background/Prior model (e.g.,
GaussianErrorModel)observation_operator (None | ObservationOperator) – operator to map model state to observation space
observation_error_model (None | ErrorModel) – Observation error model (e.g.,
GaussianErrorModel)observations (None | Any) – Observational data (the data type is very much dependent of the DA method)
optimizer (None | Optimizer) –
the optimization routine (optimizer) to be registered and later used for solving the OED problem. This can be one of the following:
None: In this case, no optimizer is registered, and the
solve()won’t be functional until an optimization routine is registered.An optimizer instance (object that inherits :py:class`Optimizer`). In this case, the optimizer is registered as is and is updated with the passed configurations if available.
The class (subclass of
Optimizer) to be used to instantiate the optimizer.
optimizer_configs (None | dict | OptimizerConfigs) –
the configurations of the optimization routine. This can be one of the following:
None, in this case configurations are discarded, and whatever default configurations of the selected/passed optimizer are employed.
A dict holding full/partial configurations of the selected optimizer. These are either used to instantiate or update the optimizer configurations based on the type of the passed optimizer.
A class providing implementations of the configurations (this must be a subclass of
OptimizerConfigs.An instance of a subclass of
OptimizerConfigswhich is to set/udpate optimizer configurations.
Note
Not all DA (inverse problem) objects are optimization-based. For example, particle-based (EnKF, PF, etc.) employ a sample to estimate the flow of the distribution through the model dynamics (prior -> posterior). Thus, the optimizer (and configs) in this case (the default) are set to None. For optimization-based methods such as 3DVar, 4DVar, etc., an optimizer must be registered for the inverse problem to be solved.
window (None | Iterable) – the assimilation window (t0, tf)
- __init__(*, debug=False, verbose=False, output_dir='./_PYOED_RESULTS_', name=None, model=None, prior=None, observation_error_model=None, observation_operator=None, observations=None, optimizer=None, optimizer_configs=None, window=None)#
- class Smoother(configs=None)[source]#
Bases:
InverseProblemBase class for all smoothing (time-dependent) DA implementations.
Smoothers solve inverse problems where multiple observations collected at different times are used to update the model state or parameter trajectory. This includes methods such as 4D-Var, Kalman smoothers, and ensemble smoothers.
Compared to
Filter, aSmoother:Requires a
TimeDependentModelas the simulation model.Stores observations as a
dictkeyed by observation time.Requires an assimilation window
(t0, tf)to be registered.
- Parameters:
configs (dict | SmootherConfigs | None) – configurations for the smoother
- register_model(model=None)[source]#
Register (and return) the simulation model to be registered. This calls InverseProblem.register_model and adds extra assertions/functionality specific for filters.
- Raises:
TypeError – if the type of passed model is not supported
- register_prior(prior=None)[source]#
Register (and return) the prior to be registered. This calls InverseProblem.register_prior and adds extra assertions/functionality specific for filters.
- Raises:
TypeError – if the type of passed prior is not supported
- register_observation_operator(observation_operator=None)[source]#
Register (and return) the observation operator to be registered. This calls InverseProblem.register_observation_operator and adds extra assertions/functionality specific for filters.
- Raises:
TypeError – if the type of passed observation operator is not supported
- register_observation_error_model(observation_error_model=None)[source]#
Register (and return) the observation error model to be registered. This calls InverseProblem.register_observation_error_model and adds extra assertions/functionality specific for filters.
- Raises:
TypeError – if the type of passed observation error model is not supported
- register_observations(observations)[source]#
Register (and return) the observational data. This calls InverseProblem.register_observations and adds extra assertions/functionality specific for filters.
- Raises:
TypeError – if the type of passed observational data is not supported
- register_observation(t, observation, overwrite=False)[source]#
Given an observation instance/vector and the associated time t, update observation/data information
- Parameters:
- Raises:
ValueError – is raised if: + overwrite=False and another observation exists at time t + No valid observation operator has been registered yet + The assimilation window is not yet registered
PyOEDConfigsValidationError – if an observation operator is registerd first.
TypeError – is raised if the observation is not validated by the associated observation operator
- find_observation_time(t, time_keys=None)[source]#
Local function to find the key in self.observations reresenting time equal to or within _TIME_EPS of the passed time
- Parameters:
t – the time to lookup
time_keys – the timespan to look into. If None, the registered observation times will be used.
- Returns:
the matched time (if found) or None
- check_registered_elements(*args, **kwargs)[source]#
Check if all elements of the inverse problem (simulation model, observation operator, prior, observation error model, and observational data) are registered or not.
Note
This method SHOULD be modified by derived classed to check other elements. For example, a smoother requires observation times, assimilation window, etc.
- show_registered_elements(display=True)[source]#
Compose and (optionally) print out a message containing the elements of the inverse problem and show what’s registered and what’s not
- Parameters:
display – if True print out the composed message about registered/unregistered elements
- Returns:
the composed message
- Return type:
None
- property observations#
The registered observational data. This property needs to be overridden by inheriting class to pose effect of the experimental design on the retrieved data.
- property observation_times#
Return a numpy array holding registered observation times.
- property window#
The registered assimilation time window
(t0, tf).
- class SmootherResults(*, inverse_problem=None, optimization_results=None)[source]#
Bases:
InverseProblemResultsBase class for objects holding results of
Smoother.Derived smoother implementations (e.g., 4D-Var, Kalman smoother) should subclass this and add fields specific to their output (e.g., state trajectory, innovation sequence, cost function history).
- Parameters:
inverse_problem (InverseProblem | None) – instance of a class derived from
InverseProblem.optimization_results (OptimizerResults | None) – results returned by the optimizer after solving the inverse problem (for optimization-based DA methods).
Nonefor non-optimization-based methods (e.g., ensemble filters).
- __init__(*, inverse_problem=None, optimization_results=None)#
- class GaussianPosteriorConfigs(*, debug=False, verbose=False, output_dir='./_PYOED_RESULTS_', design=True, size=None, mean=0.0, variance=1.0, sparse=True, random_seed=None)[source]#
Bases:
GaussianErrorModelConfigsJust renaming (possibly add more features later) around Gaussian distribution/model configurations.
- Parameters:
verbose (bool) – a boolean flag to control verbosity of the object.
debug (bool) – a boolean flag that enables adding extra functionality in a debug mode
output_dir (str | Path) – the base directory where the output files will be saved.
design (None | bool | Sequence[bool] | ndarray) –
an experimental design to define active/inactive entries of the random variable (mean, variance/covariance matrix).
Note
If the design is None, it is set to all ones; that is everything is observed (default)
If the design is a binary vector ( or int dtype attributes with 0/1 entries) the mean, the covariance, and all random vectors are projected onto the space identified by the 1/True entries.
size (int | None) – dimension of the error model space. Detected from mean if None.
variance (float | ndarray | spmatrix) – variance/covariance of the error model
sparse (bool) – convert covariance to scipy.csc_matrix used if
size > 1random_seed (int | None) – random seed used when the Gaussian model is initiated. This is useful for reproductivity.
- __init__(*, debug=False, verbose=False, output_dir='./_PYOED_RESULTS_', design=True, size=None, mean=0.0, variance=1.0, sparse=True, random_seed=None)#
- class GaussianPosterior(configs=None)[source]#
Bases:
GaussianErrorModelA class approximating the posterior distribution of the 3D-Var problem around the MAP estimate. Everything is the same as in GaussianErrorModel, except for the attribute __STDEV which is involved in the methods covariance_matvec, and generate_noise. These two functions are replaced with matrix-free versions. Here, we do not construct the covariance (posterior covariance), instead, we use the fact that the posterior covariance is (or can be approximated by):
\[\mathbf{A}:= \left( \mathbf{B}^{-1} + \mathbf{M}^T \mathbf{H}^T \mathbf{R}_k^{-1} \mathbf{H} \mathbf{M} \right)^{-1} \,,\]where \(\mathbf{B}\) is the prior covariance matrix, \(\mathbf{H}\) is the linear observation operator (or the linearized, e.g., Jacobian, around the MAP estimate),
\(\mathbf{R}\) is the observation error covariance matrix, and \(\mathbf{M}\) is the tangent linear of the simulation model (TLM) evaluated at the MAP estimate
- class ComplexGaussianPosteriorConfigs(*, debug=False, verbose=False, output_dir='./_PYOED_RESULTS_', design=1.0, size=None, mean=0.0, variance=1 + 0j, relation=0j, sparse=True, map_to_real=False, random_seed=None)[source]#
Bases:
ComplexGaussianErrorModelConfigsJust renaming (possibly add more features later) around Complex-valued Gaussian distribution/model configurations.
- Parameters:
verbose (bool) – a boolean flag to control verbosity of the object.
debug (bool) – a boolean flag that enables adding extra functionality in a debug mode
output_dir (str | Path) – the base directory where the output files will be saved.
design (Sequence[int] | Sequence[bool] | ndarray) –
an experimental design to define active/inactive entries of the random variable (mean, variance/covariance matrix).
Note
If the design is None, it is set to all ones; that is everything is observed (default)
If the design is a binary vector ( or int dtype attributes with 0/1 entries) the mean, the covariance, and all random vectors are projected onto the space identified by the 1/True entries.
size (int | None) – dimension of the error model space. Detected from mean if None.
mean (complex | Sequence[complex] | ndarray) – mean of the error model
variance (complex | Sequence[complex] | Sequence[Sequence[complex]] | ndarray | spmatrix) – variance/covariance of the error model
sparse (bool) – convert covariance to scipy.csc_array used if
size > 1map_to_real (bool) – apply computations (e.g., pdf, etc.) by mapping to the real domain using the duality between with the composite real vector
random_seed (int | None) – random seed used when the Gaussian model is initiated. This is useful for reproductivity.
- __init__(*, debug=False, verbose=False, output_dir='./_PYOED_RESULTS_', design=1.0, size=None, mean=0.0, variance=1 + 0j, relation=0j, sparse=True, map_to_real=False, random_seed=None)#