pymob.solvers package#
Submodules#
pymob.solvers.analytic module#
- pymob.solvers.analytic.solve_analytic_1d(model, parameters, dimensions, coordinates, data_variables, seed=None)#
Solves an anlytic function for all coordinates in the first data dimension of the model
parameters: define the model
y0: set the initial values of the ODE states
coordinates: are needed to know over which values to integrate
seed: In case stochastic processes take place inside the model this is necessary
In order to make things explicit, all information which is needed by the model needs to be specified in the function signature. This also makes the solvers functionally oriented, a feature that helps the usability of models accross inference frameworks. Where functions should not have side effects.
Additionally, passing arguments via the signature makes it easier to write up models in a casual way and only later embed them into more regulated structures such as pymob
pymob.solvers.base module#
- class pymob.solvers.base.SolverBase(model: Callable, dimensions: Tuple, dimension_sizes: frozendict[str, int], parameter_dims: frozendict[str, Tuple[str, ...]], n_ode_states: int, coordinates: frozendict[str, Tuple], coordinates_input_vars: frozendict[str, frozendict[str, frozendict[str, Tuple[float | int | str, ...]]]], dims_input_vars: frozendict[str, frozendict[str, Tuple[str, ...]]], coordinates_indices: frozendict[str, tuple], data_variables: Tuple, data_structure_and_dimensionality: frozendict[str, frozendict[str, int]], is_stochastic: bool, post_processing: Callable, solver_kwargs: frozendict = {}, indices: frozendict[str, Tuple] = {}, x_dim: str = 'time', batch_dimension: str = 'batch_id', exclude_kwargs_model: Tuple[str, ...] = ('t', 'x_in', 'y', 'X'), exclude_kwargs_postprocessing: Tuple[str, ...] = ('t', 'time', 'interpolation', 'results'))#
Bases:
objectThe idea of creating a solver as a class is that it is easier to pass on important arguments of the simulation relevant to the Solver. Therefore a solver can access all attributes of an Evaluator
- batch_dimension: str = 'batch_id'#
- coordinates: frozendict[str, Tuple]#
- coordinates_indices: frozendict[str, tuple]#
- coordinates_input_vars: frozendict[str, frozendict[str, frozendict[str, Tuple[float | int | str, ...]]]]#
- data_structure_and_dimensionality: frozendict[str, frozendict[str, int]]#
- data_variables: Tuple#
- dimension_sizes: frozendict[str, int]#
- dimensions: Tuple#
- dims_input_vars: frozendict[str, frozendict[str, Tuple[str, ...]]]#
- exclude_kwargs_model: Tuple[str, ...] = ('t', 'x_in', 'y', 'X')#
- exclude_kwargs_postprocessing: Tuple[str, ...] = ('t', 'time', 'interpolation', 'results')#
- indices: frozendict[str, Tuple] = {}#
- is_stochastic: bool#
- len_batch_coordinate: int#
- model: Callable#
- n_ode_states: int#
- parameter_dims: frozendict[str, Tuple[str, ...]]#
- post_processing: Callable#
- preprocess_parameters(parameters, num_backend: module = <module 'numpy' from '/home/docs/checkouts/readthedocs.org/user_builds/pymob/envs/latest/lib/python3.11/site-packages/numpy/__init__.py'>)#
- preprocess_x_in(x_in, num_backend: module = <module 'numpy' from '/home/docs/checkouts/readthedocs.org/user_builds/pymob/envs/latest/lib/python3.11/site-packages/numpy/__init__.py'>)#
- preprocess_y_0(y0, num_backend: module = <module 'numpy' from '/home/docs/checkouts/readthedocs.org/user_builds/pymob/envs/latest/lib/python3.11/site-packages/numpy/__init__.py'>)#
- shapes_coordinates: Dict[str, int]#
- shapes_input_vars_coordinates: frozendict[str, frozendict[str, Tuple[int, ...]]]#
- shapes_parameter_coordinates: Dict[str, Tuple[int, ...]]#
- solve()#
- solver_kwargs: frozendict = {}#
- test_batch_dim_consistency(X_in, Y_0, ode_args, pp_args, num_backend: module = <module 'numpy' from '/home/docs/checkouts/readthedocs.org/user_builds/pymob/envs/latest/lib/python3.11/site-packages/numpy/__init__.py'>)#
- test_matching_batch_dims()#
- test_x_coordinates()#
- x: Tuple[float]#
- x_dim: str = 'time'#
- x_shape_batched: Tuple[int, ...]#
- pymob.solvers.base.curve_jumps(x, y, i, r, n)#
- pymob.solvers.base.jump_interpolation(x_in: Dataset, x_dim: str = 'time', factor: float = 0.001, interpolation: Literal['fill-forward', 'linear'] = 'fill-forward') Dataset#
Make the interpolation safe by adding a coordinate just before each x-value (except the first vaue). The distance between the new and the next point are calculated as a fraction of the previous distance between neighboring points. The corresponding y-values are first set to NaN and then interpolated based on the interpolation method.
- Parameters:
x_in (xr.Dataset) – The input dataset which contains a coordinate (x) and a data variable (y)
x_dim (str, optional) – The name of the x coordinate, by default “time”
factor (float, optional) – The distance between the newly added points and the following existing points on the x-scale, by default 1e-4
interpolation (Literal["fill-forward", "linear"], optional) – The interpolation method. In addition to ‘fill-forward’ and ‘linear’, any method give in xr.interpolate_na can be chosen, by default “fill-forward”
- Returns:
The interpolated dataset
- Return type:
xr.Dataset
- pymob.solvers.base.mappar(func, parameters: Dict[str, float | int | List | Tuple], exclude=[], to: Literal['tuple', 'dict', 'names'] = 'tuple') Tuple | Dict#
- pymob.solvers.base.radius_interpolation(x_in: Dataset, x_dim: str = 'time', radius: float = 0.1, num_points: int = 10, rectify=True) Dataset#
Smooth the interpolation by first creating a dense x vector and forward filling all ys. Following this the values are smoothed by a gaussian filter.
WARNING! It is very pretty but does not work with diffrax
- Parameters:
x_in (xr.Dataset) – The input dataset which contains a coordinate (x) and a data variable (y)
x_dim (str, optional) – The name of the x coordinate, by default “time”
radius (float, optional) – The radius of the quarter-circle to curve the jump transition. By default 0.1
num_points (int, optional) – The number of points to interpolate each jump with. Default: 10
rectify (bool) – Whether the input should be converted to a stepwise pattern. Default is True. This is typically applied if an unprocessed signal is included. E.g. the signal was observed y_i
- Returns:
The interpolated dataset
- Return type:
xr.Dataset
- pymob.solvers.base.rect_interpolation(x_in: Dataset, x_dim: str = 'time')#
Use diffrax’ rectilinear_interpolation. To add values and interpolate one more step after the end of the timeseries
- pymob.solvers.base.smoothed_interpolation(x_in: Dataset, x_dim: str = 'time', factor: float = 0.001, sigma: int = 20) Dataset#
Smooth the interpolation by first creating a dense x vector and forward filling all ys. Following this the values are smoothed by a gaussian filter.
- Parameters:
x_in (xr.Dataset) – The input dataset which contains a coordinate (x) and a data variable (y)
x_dim (str, optional) – The name of the x coordinate, by default “time”
factor (float, optional) – The distance between the newly added points and the following existing points on the x-scale, by default 1e-4
- Returns:
The interpolated dataset
- Return type:
xr.Dataset
pymob.solvers.diffrax module#
- class pymob.solvers.diffrax.JaxSolver(model: ~typing.Callable, dimensions: ~typing.Tuple, dimension_sizes: ~frozendict.frozendict[str, int], parameter_dims: ~frozendict.frozendict[str, ~typing.Tuple[str, ...]], n_ode_states: int, coordinates: ~frozendict.frozendict[str, ~typing.Tuple], coordinates_input_vars: ~frozendict.frozendict[str, ~frozendict.frozendict[str, ~frozendict.frozendict[str, ~typing.Tuple[float | int | str, ...]]]], dims_input_vars: ~frozendict.frozendict[str, ~frozendict.frozendict[str, ~typing.Tuple[str, ...]]], coordinates_indices: ~frozendict.frozendict[str, tuple], data_variables: ~typing.Tuple, data_structure_and_dimensionality: ~frozendict.frozendict[str, ~frozendict.frozendict[str, int]], is_stochastic: bool, post_processing: ~typing.Callable, solver_kwargs: ~frozendict.frozendict = {}, indices: ~frozendict.frozendict[str, ~typing.Tuple] = {}, x_dim: str = 'time', batch_dimension: str = 'batch_id', exclude_kwargs_model: ~typing.Tuple[str, ...] = ('t', 'x_in', 'y', 'X'), exclude_kwargs_postprocessing: ~typing.Tuple[str, ...] = ('t', 'time', 'interpolation', 'results'), diffrax_solver: ~diffrax.solver.base._MetaAbstractSolver | str = <class 'diffrax.solver.dopri5.Dopri5'>, rtol: float = 1e-06, atol: float = 1e-07, pcoeff: float = 0.0, icoeff: float = 1.0, dcoeff: float = 0.0, max_steps: int = 100000, throw_exception: bool = True)#
Bases:
SolverBasesee https://jax.readthedocs.io/en/latest/faq.html#strategy-3-making-customclass-a-pytree to make thinks robust
- Parameters:
throw_exceptions (bool) – Default is True. The JaxSolver will throw an exception if it runs into a problem with the step size and return infinity. This is done, because likelihood based inference algorithms can deal with infinity values and consider the tested parameter combination impossible. If used without caution, this can lead to severely biased parameter estimates.
- atol: float = 1e-07#
- dcoeff: float = 0.0#
- diffrax_solver#
alias of
Dopri5
- icoeff: float = 1.0#
- max_steps: int = 100000#
- odesolve(y0, args, x_in)#
- odesolve_splitargs(*args, odestates, n_odeargs, n_ppargs, n_xin)#
- pcoeff: float = 0.0#
- preprocess_parameters(parameters, num_backend: module = <module 'jax.numpy' from '/home/docs/checkouts/readthedocs.org/user_builds/pymob/envs/latest/lib/python3.11/site-packages/jax/numpy/__init__.py'>)#
- preprocess_x_in(x_in, num_backend: module = <module 'jax.numpy' from '/home/docs/checkouts/readthedocs.org/user_builds/pymob/envs/latest/lib/python3.11/site-packages/jax/numpy/__init__.py'>)#
- preprocess_y_0(y0, num_backend: module = <module 'jax.numpy' from '/home/docs/checkouts/readthedocs.org/user_builds/pymob/envs/latest/lib/python3.11/site-packages/jax/numpy/__init__.py'>)#
- rtol: float = 1e-06#
- solve(parameters: Dict, y0: Dict = {}, x_in: Dict = {})#
- throw_exception: bool = True#
- x_in_jumps: Tuple[float, ...]#
pymob.solvers.scipy module#
- pymob.solvers.scipy.solve_ivp_1d(model, parameters, coordinates, data_variables)#
Initial value problems always need the same number of recurrent arguments
parameters: define the model
y0: set the initial values of the ODE states
coordinates: are needed to know over which values to integrate
seed: In case stochastic processes take place inside the model this is necessary
In order to make things explicit, all information which is needed by the model needs to be specified in the function signature. This also makes the solvers functionally oriented, a feature that helps the usability of models accross inference frameworks. Where functions should not have side effects.
Additionally, passing arguments via the signature makes it easier to write up models in a casual way and only later embed them into more regulated structures such as pymob