# Pymob in minutes - the basics This guide provides a streamlined introduction to the basic Pymob workflow and its key functionalities. We will explore a simple linear regression model that we want to fit to a noisy dataset. Pymob supports the modeling process by providing several tools for *data structuring*, *parameter estimation* and *visualization of results*. If you are looking for a more detailed introduction, [click here](user_guide/Introduction). If you want to learn how to work with ODE models, check out [this tutorial](user_guide/advanced_tutorial_ODE_system). ## Pymob components 🧩 Before starting the modeling process, let's take a look at the main steps and modules of pymob: 1. __Simulation:__ First, we need to initialize a Simulation object by creating an instance of the {class}`pymob.simulation.SimulationBase` class from the simulation module. Optionally, we can configure the simulation with `sim.config.case_study.name = "linear-regression"`, `sim.config.case_study.scenario = "test"` and many other options. 2. __Model:__ Our model will be defined as a standard python function. We will then assign it to the Simulation object by accessing the `.model` attribute. 3. __Observations:__ Our observation data must be structured as an [xarray.Dataset](https://docs.xarray.dev/en/stable/generated/xarray.Dataset.html). We assign it to the {attr}`~pymob.simulation.SimulationBase.observations` attribute of our Simulation object. Calling `sim.config.data_structure` will give us further information about the layout of our data. 4. __Solver:__ A solver ({mod}`~pymob.solvers`) is required to solve the model. In our simple case, we will use the `solve_analytic_1d` solver from the {mod}`~pymob.solvers.analytic` module. We assign it to our Simulation object using the {attr}`~pymob.simulation.SimulationBase.solver` attribute. Since our model already provides an analytical solution, this solver basically does nothing. It is still needed to fulfill Pymob's requirement for a solver component. For more complex models (e.g. ODEs), the `JaxSolver` from the {mod}`~pymob.solvers.diffrax` module is a more powerful option. Users can also implement custom solvers as a subclass of {class}`pymob.solvers.base.SolverBase`. 5. __Inferer:__ The inferer handels the parameter estimation. Pymob supports [various backends](https://pymob.readthedocs.io/en/stable/user_guide/framework_overview.html). In this example, we will work with *NumPyro*. We assign the inferer to our Simulation object via the {attr}`~pymob.simulation.SimulationBase.inferer` attribute and configure the desired kernel (e.g. *nuts*). But before inference, we need to parameterize our model using the {class}`~pymob.sim.parameters.Param` class. Each parameter can be marked either as free or fixed, depending on whether it should be variable during the optimization procedure. The parameters are stored in the {attr}`~pymob.simulation.SimulationBase.model_parameters` dictionary, which holds model input values. By default, it takes the keys: `parameters`, `y0` and `x_in`. 6. __Evaluator:__ The Evaluator is an instance to manage model evaluations. It sets up tasks, coordinates parallel runs of the simulation and keeps track of the results from each simulation or parameter inference process. Evaluators store the raw output from a simulation and can generate an xarray object from it that corresponds to the data-structure of the observations with the {attr}`~pymob.sim.evaluator.Evaluator.results` property. This automatically aligns the simulations results with the observations, for simple computation of loss functions. 7. __Config:__ The simulation settings will be saved in a `.cfg` configuration file. The config file contains information about our simulation in various sections. [Learn more here](case_studies.md#configuration). We can further use it to create new simulations by loading settings from a config file.  ## Getting started 🛫 ```python # First, import the necessary python packages import numpy as np import matplotlib.pyplot as plt import xarray as xr # Import the pymob modules from pymob.simulation import SimulationBase from pymob.sim.solvetools import solve_analytic_1d from pymob.sim.config import Param ``` /home/docs/checkouts/readthedocs.org/user_builds/pymob/envs/0.5.27/lib/python3.11/site-packages/pydantic/_internal/_fields.py:149: UserWarning: Field "model_class" has conflict with protected namespace "model_". You may be able to resolve this warning by setting `model_config['protected_namespaces'] = ()`. warnings.warn( Since no measured data is provided, we will generate an artificial dataset. $y_{obs}$ represents the **observed data** over the time $t$ [0, 10]. To use this data later in the simulation, we need to convert it into an **xarray dataset**. In your own application, you would replace this with your measured experimental data. ```python # Parameter for the artificial data generation rng = np.random.default_rng(seed=1) # for reproducibility slope = rng.uniform(2,4) intercept = 1.0 num_points = 101 noise_level = 1.7 # generating time values t = np.linspace(0, 10, num_points) # generating y-values with noise noise = rng.normal(0, noise_level, num_points) y_obs = slope * t + intercept + noise # visualizing our data fig, ax = plt.subplots(figsize=(5, 4)) ax.scatter(t, y_obs, label='Datapoints') ax.set(xlabel='t [-]', ylabel='y_obs [-]', title ='Artificial Data') plt.tight_layout() # convert the data to an xr-Dataset data_obs = xr.DataArray(y_obs, coords={"t": t}).to_dataset(name="y") data_obs ```
<xarray.Dataset>
Dimensions: (t: 101)
Coordinates:
* t (t) float64 0.0 0.1 0.2 0.3 0.4 0.5 ... 9.5 9.6 9.7 9.8 9.9 10.0
Data variables:
y (t) float64 2.397 1.864 -0.6106 3.446 ... 27.91 31.2 29.83 32.7<xarray.Dataset>
Dimensions: (t: 101)
Coordinates:
* t (t) float64 0.0 0.1 0.2 0.3 0.4 0.5 ... 9.5 9.6 9.7 9.8 9.9 10.0
Data variables:
y (t) float64 1.0 1.3 1.6 1.9 2.2 2.5 ... 29.8 30.1 30.4 30.7 31.0