# Stress models#

In this notebook we give a quick start guide to StressModels in Pastas. Pastas uses smaller submodels to translate one or multiple hydrological stress(es) (e.g., precipitation, river stages) to a contribution to the head fluctuations. The submodels are named “stress models” in Pastas. All stress models are contained in the `stressmodels`

module. There are different stress models for a variety of use-cases. It is the task of the hydrologist to select a specific stress model to simulate the head
contribution from a particular stress.

The following stress models are available:

```
[1]:
```

```
import pastas as ps
```

## Stresses#

To start, let’s read some common stresses and visualize them:

```
[2]:
```

```
import pandas as pd
head = pd.read_csv(
"../examples/data/head_nb1.csv", index_col=0, parse_dates=True
).squeeze()
prec = pd.read_csv(
"../examples/data/rain_nb1.csv", index_col=0, parse_dates=True
).squeeze()
evap = pd.read_csv(
"../examples/data/evap_nb1.csv", index_col=0, parse_dates=True
).squeeze()
# quick visualization
ps.plots.series(head=head, stresses=[prec, evap], hist=False);
```

**Figure 1: Observed head and stresses, in this case precipitation and evaporation (both positive)**

## Creating a StressModel#

One of the most commonly used stress models is the `ps.StressModel`

. This model takes a single stress (e.g., precipitation), and convolutes that stress with an impulse response function to compute the contribution of the precipitation to the head fluctuations. Here is how to create a stress model instance.

```
[3]:
```

```
sm = ps.StressModel(
stress=prec,
rfunc=ps.Gamma(),
name="precipitation",
up=True, # default (head goes up if it rains)
)
```

This stress model takes in a few required arguments, the `stress`

time series, the response function `rfunc`

, and the `name`

of the stress model. This name has to be unique among the stress models added to the model. In the example above, the argument `up=True`

is provided as well, which means that the head response to precipitation is positive (it rains, heads increase). Depending on the stress model, more or less input arguments are required. For each stress model, these arguments are
described in the docstring.

As the stress models are actually mini models, each stress model has a `simulate`

method that simulates the head contributions. One does typically not use these methods, as these are called internally by the `Model`

. However, for illustrative purposes we simulate the contribution here, using the initial parameters:

```
[4]:
```

```
p = sm.parameters.initial.values
sm.simulate(p=p, tmin="2005", tmax="2010").plot(figsize=(6, 2));
```

### Add stress models to the main Model#

As stated before, stress models are typically not used on their own, but as part of a larger model, the pastas Model. Stress models are added to a Model using the `.add_stressmodel()`

method and can be parsed seperately or as a list of stress models. This means that you can add multiple stress models if you want. Below we add a single stress model to the main model.

```
[5]:
```

```
ml = ps.Model(head)
ml.add_stressmodel(sm) # Adding the stress model
ml.simulate(tmin="2005", tmax="2010").plot(figsize=(6, 2));
```

```
WARNING: Model is not optimized yet, initial parameters are used.
```

Note how the simulated head is similar to that simulated by the stress model created above, plus the constant.

### Creating and adding more stress models#

Often multiple stresses are causing the head fluctuations. For example, if evaporation is affecting the head fluctuations, we can create a second stress model that simulate that contribution. As evaporation has a lowering effect on the heads, we set `up=False`

.

```
[6]:
```

```
sm2 = ps.StressModel(
stress=evap,
rfunc=ps.Gamma(),
name="evaporation",
up=False,
)
p = sm2.parameters.initial.values
sm2.simulate(p=p, tmin="2005", tmax="2010").plot(figsize=(6, 2));
```

Now we add the second stress model to the main model. We do not have to create a new Model instance again, but can just add it to the one we created earlier.

```
[7]:
```

```
ml.add_stressmodel(sm2) # Adding the second stress model
ml.simulate(tmin="2005", tmax="2010").plot(figsize=(6, 2));
```

```
WARNING: Model is not optimized yet, initial parameters are used.
```

This start to look like a real model, let’s estimate the parameters by calling `ml.solve`

and plot the estimated contributions of the two stresses to the head fluctuations using the `ml.plots.decomposition`

method.

```
[8]:
```

```
ml.solve(tmin="2005", tmax="2010", report=False)
ml.plots.decomposition(tmin="2005", tmax="2010", figsize=(5, 4));
```

### Stress model settings#

We now understand what stress models are, how they work, and how to add them to the model. Before we discuss other stress models, let’s dive a bit deeper into one particular argument that each stress model has: the `settings`

argument.

The settings determine how the stress time series are internally updated if necessary for simulation, for example if a different simulation frequency is chosen or if the time series need to be extended in time (for example to create data for a warmup period). The creation of the stress model is where these settings are chosen.

Some stress models have default settings for this, and use one of the predefined settings dictionaries (defined in `ps.rcParams["timeseries"]`

). Others have no default settings. In all cases, the user can always provide user-defined settings. Here’s how to use and set the settings:

```
[9]:
```

```
settings = ps.rcParams["timeseries"]["prec"] # Select from predefined settings options
settings
```

```
[9]:
```

```
{'sample_up': 'bfill',
'sample_down': 'mean',
'fill_nan': 0.0,
'fill_before': 'mean',
'fill_after': 'mean'}
```

```
[10]:
```

```
sm = ps.StressModel(
stress=prec,
rfunc=ps.Gamma(),
name="prec",
settings="prec", # Is similar to settings=ps.rcParams["timeseries"]["prec"]
)
```

## Other stress models in Pastas#

Pastas contains a number of other stress models for different hydrological stresses. The following stress models are available:

```
[11]:
```

```
ps.stressmodels.__all__
```

```
[11]:
```

```
['StressModel',
'Constant',
'StepModel',
'LinearTrend',
'RechargeModel',
'WellModel',
'TarsoModel',
'ChangeModel']
```

From these, the `LinearTrend`

and `StepModel`

stress models add a specific kind of trend that do not require a stress. In these cases, the modeller should have a clear idea of what is causing the trend or step. The `ChangeModel`

simulates a changing response function over time, to translate a single stress. The `WellModel`

deals with one or multiple wells which are pumping groundwater and cause a lowering head. For all of these stress models examples can be found in the examples section
on readthedocs.

Two other models deal with precipitation and evaporation in a single stress model: `RechargeModel`

and `TarsoModel`

. The `TarsoModel`

simulates a threshold-nonlinearity where the head responds differrently to precipitation and evaporation depending on the head itself.

Perhaps the most used model is the `RechargeModel`

, which takes in precipitation and potential evaporation and simulates recharge from these two stresses and finally the head contribution. How the model simulates the recharge depends on the `recharge`

model which is chosen.

```
[12]:
```

```
sm3 = ps.RechargeModel(
prec=prec,
evap=evap,
rfunc=ps.Exponential(), # default
name="recharge", # default
recharge=ps.rch.FlexModel(), # other options are ps.rch.Linear(), ps.rch.Peterson(), ps.rch.Berendrecht()
settings=("prec", "evap"), # default
)
```

### Other use cases for stressmodels#

There are many other use cases for the different stress models in Pastas. For more example check out the examples section.