Skip to content

Commit 34604db

Browse files
authored
Merge pull request #73 from hetalang/opt_prob
adds OptimizationProblem interface
2 parents 66c47fd + 98e4536 commit 34604db

File tree

12 files changed

+355
-232
lines changed

12 files changed

+355
-232
lines changed

.github/workflows/ci.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ jobs:
1616
fail-fast: false
1717
matrix:
1818
include:
19-
- {version: '1.9', os: windows-latest, arch: x64}
20-
- {version: '1.9', os: ubuntu-latest, arch: x64}
21-
- {version: '1.9', os: macos-latest, arch: aarch64}
2219
- {version: 'lts', os: windows-latest, arch: x64}
2320
- {version: 'lts', os: ubuntu-latest, arch: x64}
2421
- {version: 'lts', os: macos-latest, arch: aarch64}

Project.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
1111
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
1212
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
1313
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
14+
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
1415
LabelledArrays = "2ee39098-c373-598a-b85f-a56591580800"
1516
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
16-
NLopt = "76087f3c-5699-56af-9a33-bf431cd00edd"
17-
NLopt_jll = "079eb43e-fd8e-5478-9966-2cf3e3edb778"
1817
NaNMath = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
18+
OptimizationNLopt = "4e6fcdb7-1186-4e1f-a706-475e75c168bb"
1919
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
2020
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
2121
ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca"
@@ -31,18 +31,18 @@ CSV = "0.10"
3131
DataFrames = "1"
3232
DataStructures = "0.18"
3333
Distributions = "0.25"
34+
ForwardDiff = "0.10.38, 1.0.1"
3435
LabelledArrays = "1.6.1"
35-
NLopt = "1.0.3"
36-
NLopt_jll = "=2.8.0"
3736
NaNMath = "1"
37+
OptimizationNLopt = "0.2.2, 0.3.2"
3838
OrdinaryDiffEq = "6"
3939
ProgressMeter = "1"
4040
RecipesBase = "1"
4141
Reexport = "1"
4242
SciMLBase = "2.15"
4343
Sundials = "4.24"
4444
XLSX = "0.7, 0.8"
45-
julia = "1.9"
45+
julia = "1.10"
4646

4747
[extras]
4848
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

docs/src/basics/overview.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -564,8 +564,8 @@ fit_res = fit(p, to_fit)
564564
```
565565

566566
```julia
567-
FitResult with status :XTOL_REACHED
568-
Status: XTOL_REACHED
567+
FitResult with status :Success
568+
Status: Success
569569
Optimal values: [:kabs => 18.868605026704916, :Q => 4.043662480774219, :kel => 0.17104243648378176, :sigma1 => 0.020347955494158528, :sigma2 => 0.31561050699802246, :sigma3 => 0.5716026958426483]
570570
OF value: 140.96503722972034
571571
OF count: 8612

docs/src/tutorial/fit-files/fit-run.jl

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,19 +67,17 @@ res_optim = fit(p, params_df)
6767
res_optim = fit(
6868
p,
6969
params_df,
70-
fit_alg = :LN_SBPLX,
70+
fit_alg = NLopt.LN_SBPLX(),
7171
ftol_abs = 1e-5,
7272
ftol_rel = 0,
73-
maxeval = 10^6
73+
maxiters = 10^6
7474
)
7575
optim(res_optim)
7676

7777
#= see API docs
7878
fit_alg : fitting algorithm. Default is :LN_NELDERMEAD
79-
ftol_abs : absolute tolerance on function value. Default is 0.0
80-
ftol_rel : relative tolerance on function value. Default is 1e-4
81-
xtol_rel : relative tolerance on optimization parameters. Default is 0.0
82-
xtol_rel : absolute tolerance on optimization parameters. Default is 0.0
83-
maxeval : maximum number of function evaluations. Default is 1e4
79+
ftol_abs : absolute tolerance on objective value. Default is 0.0
80+
ftol_rel : relative tolerance on objective value. Default is 1e-4
81+
maxiters : maximum number of objective evaluations. Default is 1e4
8482
maxtime : maximum optimization time (in seconds). Default is 0
8583
=#

docs/src/tutorial/fit.md

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,8 @@ res_optim = fit(p, to_fit) # default fitting
172172
```
173173
┌ Info: Scenario ":multiple_15" has no measurements. It will be excluded from fitting.
174174
└ @ HetaSimulator y:\HetaSimulator.jl\src\fit.jl:77
175-
FitResult with status :XTOL_REACHED
176-
Status: XTOL_REACHED
175+
FitResult with status :Success
176+
Status: Success
177177
Optimal values: [:kabs => 18.868605026704916, :Q => 4.043662480774219, :kel => 0.17104243648378176, :sigma1 => 0.020347955494158528, :sigma2 => 0.31561050699802246, :sigma3 => 0.5716026958426483]
178178
OF value: 140.96503722971997
179179
OF count: 8612
@@ -246,38 +246,36 @@ res_optim = fit(p, params_df)
246246
```
247247
┌ Info: Scenario ":multiple_15" has no measurements. It will be excluded from fitting.
248248
└ @ HetaSimulator
249-
FitResult with status :FTOL_REACHED
250-
Status: FTOL_REACHED
249+
FitResult with status :Success
250+
Status: Success
251251
Optimal values: [:kabs => 8.669590504032879, :kel => 0.2299120380231296, :Q => 3.386457652767808, :sigma1 => 0.010105725225267037, :sigma2 => 0.09951673713071268, :sigma3 => 0.6024808584834973]
252252
OF value: -101.7645013649068
253253
OF count: 417
254254
```
255255

256256
## Additional optimization-specific options
257257

258-
Internally `HetaSimulator` uses `NLopt` library. One can choose the optimization algorithm as well as additional options.
258+
Internally, `HetaSimulator` uses the `Optimization.jl` interface, which supports various optimization packages. By default, `HetaSimulator` includes the NLopt library, allowing you to choose an NLopt-based optimization algorithm without installing additional packages. To access more optimizers, you can add any optimization package supported by `Optimization.jl` and use the preferred optimizer algorithm in `fit()`.
259259

260260
Read more about NLopt algorithms choice: <https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/>
261261

262262
```julia
263263
res_optim = fit(
264264
p,
265265
params_df,
266-
fit_alg = :LN_SBPLX,
266+
fit_alg = NLopt.LN_SBPLX(),
267267
ftol_abs = 1e-5,
268268
ftol_rel = 0,
269-
maxeval = 10^6
269+
maxiters = 10^6
270270
)
271271
optim(res_optim)
272272
```
273273

274274
There are several optimization related arguments, which are available for a user.
275275
To learn more read about [`fit`](@ref) method in API documentation.
276276

277-
- `fit_alg` : fitting algorithm. Default is `:LN_NELDERMEAD`
278-
- `ftol_abs` : absolute tolerance on function value. Default is `0.0`
279-
- `ftol_rel` : relative tolerance on function value. Default is `1e-4`
280-
- `xtol_rel` : relative tolerance on optimization parameters. Default is `0.0`
281-
- `xtol_rel` : absolute tolerance on optimization parameters. Default is `0.0`
282-
- `maxeval` : maximum number of function evaluations. Default is `1e4`
277+
- `fit_alg` : fitting algorithm. Default is `NLopt.LN_NELDERMEAD()`
278+
- `ftol_abs` : absolute tolerance on objective value. Default is `0.0`
279+
- `ftol_rel` : relative tolerance on objective value. Default is `1e-4`
280+
- `maxiters` : maximum number of objective evaluations. Default is `1e4`
283281
- `maxtime` : maximum optimization time (in seconds). Default is `0`

src/HetaSimulator.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ module HetaSimulator
2828
@reexport using SciMLBase.EnsembleAnalysis
2929
@reexport using OrdinaryDiffEq
3030
using Sundials
31-
31+
using ForwardDiff
3232
# fitting
33-
using NLopt
33+
@reexport using OptimizationNLopt
3434

3535
# utils
3636
using LabelledArrays
@@ -66,6 +66,7 @@ module HetaSimulator
6666
include("solution_interface.jl")
6767
include("plots.jl")
6868
include("loss.jl")
69+
include("optprob.jl")
6970
include("fit.jl")
7071
include("estimator.jl")
7172
include("monte_carlo.jl")
@@ -86,7 +87,7 @@ module HetaSimulator
8687
export CVODE_BDF, CVODE_Adams
8788
export optim, obj
8889
export sim, mc, mc!
89-
export fit, loss, estimator
90+
export fit, loss, estimator, generate_optimization_problem
9091
export HetaSimulatorDir
9192
export update
9293
export times, vals, status, status_summary

src/estimator.jl

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# aux function to allow user write both `Pair{Symbol,Float64}` and `Pair{Symbol,Real}`
44
# convert to regular `Vector{Pair{Symbol,Float64}}` for further processing
55
normalize_params(v::AbstractVector{<:Pair{Symbol,<:Real}}) =
6-
[k => Float64(val) for (k,val) in v]
6+
[k => float(val) for (k,val) in v]
77

88
"""
99
function estimator(
@@ -35,7 +35,7 @@ normalize_params(v::AbstractVector{<:Pair{Symbol,<:Real}}) =
3535
3636
Returns:
3737
38-
function(x:Vector{Float64}=last.(parameters_fitted))
38+
function(x=last.(parameters_fitted))
3939
4040
The method returns anonimous function which depends on parameters vector in the same order as in `parameters_fitted`.
4141
This function is ready to be passed to optimizer routine or identifiability analysis.
@@ -90,13 +90,17 @@ function estimator(
9090
function(prob,i,repeat) # internal_prob_func
9191
#update_init_values(selected_prob[i], last(selected_scenario_pairs[i]).init_func, x)
9292
scn = last(selected_scenario_pairs[i])
93-
params_total = merge_strict(scn.parameters, x)
93+
T = eltype(x)
94+
params_total = (T <: ForwardDiff.Dual) ? merge_strict(NamedTuple{keys(scn.parameters)}(T.(collect(scn.parameters))), x) : merge_strict(scn.parameters, x)
9495
remake_prob(selected_prob[i], scn.init_func, params_total; safetycopy=true) #?safetycopy=false
9596
end
9697
end
9798

9899
function _output(sol, i)
99-
sol.retcode != :Success && error("Simulated scenario $i returned $(sol.retcode) status")
100+
if !SciMLBase.successful_retcode(sol.retcode)
101+
@warn "Simulated scenario $i returned $(sol.retcode) status"
102+
return (Inf, false)
103+
end
100104
sv = sol.prob.kwargs[:callback].discrete_callbacks[1].affect!.saved_values
101105
simulation = Simulation(sv, NamedTuple(parameters_fitted_norm), sol.retcode)
102106
result = SimResult(simulation, last(selected_scenario_pairs[i]))
@@ -118,7 +122,7 @@ function estimator(
118122

119123
### function ready for fitting
120124

121-
function out(x::Vector{Float64}=last.(parameters_fitted_norm))
125+
function out(x=last.(parameters_fitted_norm))
122126
x_nt = NamedTuple{Tuple(parameters_fitted_names)}(x)
123127
solution = solve(
124128
prob(x_nt),
@@ -234,3 +238,4 @@ function estimator(
234238

235239
return estimator(scenario_pairs, parameters_fitted; kwargs...)
236240
end
241+

0 commit comments

Comments
 (0)