Skip to content

Commit 89ea90c

Browse files
authored
Merge pull request #740 from SciML/new_SciMLOptimization_paramfitting_tutorial
New SciML/Optimization for fitting parameters of ODEs tutorial tutorial
2 parents d8cfe78 + 0fb9c8a commit 89ea90c

File tree

6 files changed

+200
-26
lines changed

6 files changed

+200
-26
lines changed

docs/Project.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
BifurcationKit = "0f109fa4-8a5d-4b75-95aa-f515264e7665"
33
Catalyst = "479239e8-5488-4da2-87a7-35f2df7eef83"
44
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
5+
DiffEqParamEstim = "1130ab10-4a5a-5621-a13d-e4788d82bd4c"
56
DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa"
67
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
78
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
@@ -12,6 +13,8 @@ ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78"
1213
NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec"
1314
Optim = "429524aa-4258-5aef-a3af-852621145aeb"
1415
Optimization = "7f7a1694-90dd-40f0-9382-eb1efda571ba"
16+
OptimizationNLopt = "4e6fcdb7-1186-4e1f-a706-475e75c168bb"
17+
OptimizationOptimJL = "36348300-93cb-4f02-beb5-3c3902f8871e"
1518
OptimizationOptimisers = "42dfb2eb-d2b4-4451-abcd-913932933ac1"
1619
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
1720
PEtab = "48d54b35-e43e-4a66-a5a1-dde6b987cf69"
@@ -30,6 +33,7 @@ Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"
3033
BifurcationKit = "0.3"
3134
Catalyst = "13"
3235
DataFrames = "1"
36+
DiffEqParamEstim = "2.1"
3337
DifferentialEquations = "7.7"
3438
Distributions = "0.25"
3539
Documenter = "0.27"
@@ -39,6 +43,8 @@ ModelingToolkit = "8.47"
3943
NonlinearSolve = "3.4.0"
4044
Optim = "1"
4145
Optimization = "3.19"
46+
OptimizationNLopt = "0.1.8"
47+
OptimizationOptimJL = "0.1.14"
4248
OptimizationOptimisers = "0.1.1"
4349
OrdinaryDiffEq = "6"
4450
PEtab = "2"

docs/pages.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ pages = Any["Home" => "index.md",
1616
"catalyst_applications/homotopy_continuation.md",
1717
"catalyst_applications/nonlinear_solve.md",
1818
"catalyst_applications/bifurcation_diagrams.md"],
19-
"Inverse Problems" => Any["inverse_problems/parameter_estimation.md",
20-
"inverse_problems/petab_ode_param_fitting.md",
21-
"inverse_problems/structural_identifiability.md"],
19+
"Inverse Problems" => Any["inverse_problems/optimization_ode_param_fitting.md",
20+
"inverse_problems/petab_ode_param_fitting.md",
21+
"inverse_problems/structural_identifiability.md",
22+
"Inverse problem examples" => Any["inverse_problems/examples/ode_fitting_oscillation.md"]],
2223
"FAQs" => "faqs.md",
2324
"API" => "api/catalyst_api.md"]

docs/src/catalyst_applications/advanced_simulations.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ DifferentialEquations package](https://docs.sciml.ai/DiffEqDocs/stable/), which
99
Catalyst uses for all simulations.
1010

1111

12-
## Monte Carlo simulations using `EnsembleProblem`s
12+
## [Monte Carlo simulations using `EnsembleProblem`s](@id advanced_simulations_ensemble_problems)
1313
In many contexts one needs to run multiple simulations of a model, for example
1414
to collect statistics of SDE or jump process solutions, or to systematically
1515
vary parameter values within a model. While it is always possible to manually

docs/src/catalyst_applications/simulation_structure_interfacing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ oprob[:X1] = 10.0
3333
```
3434
with parameters using the same notation.
3535

36-
#### Remaking problems using the `remake` function
36+
#### [Remaking problems using the `remake` function](@id simulation_structure_interfacing_remake)
3737
Typically, when modifying problems, it is recommended to use the `remake` function. Unlike when we do `oprob[:X1] = 10.0` (which modifies the problem in question), `remake` creates a new problem object. The `remake` function takes a problem as input, and any fields you wish to modify (and their new values) as optional inputs. Thus, we can do:
3838
```@example ex1
3939
using DifferentialEquations

docs/src/inverse_problems/parameter_estimation.md renamed to docs/src/inverse_problems/examples/ode_fitting_oscillation.md

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,16 @@
1-
# [Parameter Estimation](@id parameter_estimation)
2-
The parameters of a model, generated by Catalyst, can be estimated using various
3-
packages available in the Julia ecosystem. Refer
4-
[here](https://docs.sciml.ai/Overview/stable/highlevels/inverse_problems/) for
5-
more extensive information. Below follows a quick tutorial of how
6-
[Optimization.jl](https://docs.sciml.ai/Optimization/stable/) can be used to fit
7-
a parameter set to data.
1+
# [Fitting Parameters for an Oscillatory System](@id parameter_estimation)
2+
In this example we will use [Optimization.jl](https://github.com/SciML/Optimization.jl) to fit the parameters of an oscillatory system (the Brusselator) to data. Here, special consideration is taken to avoid reaching a local minimum. Instead of fitting the entire time series directly, we will start with fitting parameter values for the first period, and then use those as an initial guess for fitting the next (and then these to find the next one, and so on). Using this procedure is advantageous for oscillatory systems, and enables us to reach the global optimum.
83

94
First, we fetch the required packages.
105
```@example pe1
116
using Catalyst
12-
using DifferentialEquations
13-
using SciMLSensitivity
7+
using OrdinaryDiffEq
148
using Optimization
15-
16-
# for the ADAM optimizer
17-
using OptimizationOptimisers
9+
using OptimizationOptimisers # Required for the ADAM optimizer.
10+
using SciMLSensitivity # Required for `Optimization.AutoZygote()` automatic differentiation option.
1811
```
1912

20-
Next, we declare our model. For our example, we will use the Brusselator, a
21-
simple oscillator.
13+
Next, we declare our model, the Brusselator oscillator.
2214
```@example pe1
2315
brusselator = @reaction_network begin
2416
A, ∅ --> X
@@ -27,10 +19,11 @@ brusselator = @reaction_network begin
2719
1, X --> ∅
2820
end
2921
p_real = [:A => 1., :B => 2.]
22+
nothing # hide
3023
```
3124

3225
We simulate our model, and from the simulation generate sampled data points
33-
(with added noise), to which we will attempt to fit a parameter et.
26+
(to which we add noise). We will use this data to fit the parameters of our model.
3427
```@example pe1
3528
u0 = [:X => 1.0, :Y => 1.0]
3629
tspan = (0.0, 30.0)
@@ -54,8 +47,8 @@ scatter!(sample_times, sample_vals'; color = [:blue :red], legend = nothing)
5447

5548
Next, we create a function to fit the parameters using the `ADAM` optimizer. For
5649
a given initial estimate of the parameter values, `pinit`, this function will
57-
fit parameter values, `p`, to our data samples. `tend` is used to indicate the
58-
time interval over which to fit to the ODE solution.
50+
fit parameter values, `p`, to our data samples. We use `tend` to indicate the
51+
time interval over which we fit the model.
5952
```@example pe1
6053
function optimise_p(pinit, tend)
6154
function loss(p, _)
@@ -124,14 +117,14 @@ The final parameter estimate is then
124117
```@example pe1
125118
p_estimate
126119
```
127-
which is close to the actual parameters of `[1.0, 2.0]`.
120+
which is close to the actual parameter set of `[1.0, 2.0]`.
128121

129-
## Why we fit the parameters in iterations.
130-
The reason we chose to fit the model on a smaller interval to begin with, and
122+
## Why we fit the parameters in iterations
123+
As previously mentioned, the reason we chose to fit the model on a smaller interval to begin with, and
131124
then extend the interval, is to avoid getting stuck in a local minimum. Here
132125
specifically, we chose our initial interval to be smaller than a full cycle of
133126
the oscillation. If we had chosen to fit a parameter set on the full interval
134-
immediately we would have received an inferior solution.
127+
immediately we would have obtained poor fit and an inaccurate estimate for the parameters.
135128
```@example pe1
136129
p_estimate = optimise_p([5.0,5.0], 30.0)
137130

0 commit comments

Comments
 (0)