Skip to content

Commit c2396f6

Browse files
authored
Merge pull request #400 from control-toolbox/ctdirect-0.13
Include CTDirect v0.13
2 parents e3bfa5e + f70edc9 commit c2396f6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+1342
-990
lines changed

.github/workflows/CI.yml

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ jobs:
1414
matrix:
1515
version:
1616
- '1.10'
17+
- '1.11'
1718
os:
1819
- ubuntu-latest
1920
arch:

Project.toml

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "OptimalControl"
22
uuid = "5f98b655-cc9a-415a-b60e-744165666948"
33
authors = ["Olivier Cots <[email protected]>"]
4-
version = "0.12.3"
4+
version = "0.13.0"
55

66
[deps]
77
CTBase = "54762871-cc72-4466-b8e8-f6c8b58076cd"
@@ -11,9 +11,9 @@ CommonSolve = "38540f10-b2f7-11e9-35d8-d573e4eb0ff2"
1111
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
1212

1313
[compat]
14-
CTBase = "0.13"
15-
CTDirect = "0.12"
16-
CTFlows = "0.6"
14+
CTBase = "0.14"
15+
CTDirect = "0.13"
16+
CTFlows = "0.7"
1717
CommonSolve = "0.2"
1818
DocStringExtensions = "0.9"
1919
julia = "1.10"

docs/Project.toml

+11-12
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ DifferentiationInterface = "a0c0ee7d-e4b9-4e03-894e-1c5f64a51d63"
88
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
99
DocumenterMermaid = "a078cd44-4d9c-4618-b545-3ab9d77f9177"
1010
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
11-
Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"
1211
JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819"
1312
JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
1413
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
@@ -19,27 +18,27 @@ NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec"
1918
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
2019
Percival = "01435c0c-c90d-11e9-3788-63660f8fbccc"
2120
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
22-
Roots = "f2b01f46-fcfa-551c-844a-d8ac1e96c665"
21+
Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb"
2322

2423
[compat]
25-
BenchmarkTools = "1.5"
26-
CTBase = "0.13"
27-
CTDirect = "0.12"
28-
CTFlows = "0.6"
24+
BenchmarkTools = "1.6"
25+
CTBase = "0.14"
26+
CTDirect = "0.13"
27+
CTFlows = "0.7"
2928
CommonSolve = "0.2"
30-
DifferentiationInterface = "0.5"
31-
Documenter = "1.6"
29+
DifferentiationInterface = "0.6"
30+
Documenter = "1.8"
3231
DocumenterMermaid = "0.1"
3332
ForwardDiff = "0.10"
34-
Interpolations = "0.15"
35-
JLD2 = "0.4"
33+
JLD2 = "0.5"
3634
JSON3 = "1.14"
35+
LinearAlgebra = "1.11"
3736
MINPACK = "1.3"
3837
MadNLP = "0.8"
3938
NLPModelsIpopt = "0.10"
40-
NonlinearSolve = "3"
39+
NonlinearSolve = "4.4"
4140
OrdinaryDiffEq = "6"
4241
Percival = "0.7"
4342
Plots = "1.40"
44-
Roots = "2.1"
43+
Suppressor = "0.2"
4544
julia = "1.10"

docs/make.jl

+1-2
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,14 @@ makedocs(;
3838
"Solve" => "tutorial-solve.md",
3939
"Plot a solution" => "tutorial-plot.md",
4040
"Flow" => "tutorial-flow.md",
41-
"Functional syntax" => "tutorial-functional.md",
4241
"Control-toolbox REPL" => "tutorial-repl.md",
4342
],
4443
"Tutorials" => [
4544
"tutorial-continuation.md",
45+
"tutorial-nlp.md",
4646
"Goddard: direct, indirect" => "tutorial-goddard.md",
4747
"tutorial-iss.md",
4848
"Linear–quadratic regulator" => "tutorial-lqr-basic.md",
49-
"tutorial-nlp.md",
5049
"Minimal action" => "oc_mam.md",
5150
],
5251
"API" => [

docs/src/index.md

+3-4
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,9 @@ sol = solve(ocp)
6868
plot(sol)
6969
```
7070

71-
For more details about this problem, please check the
72-
[basic example tutorial](@ref tutorial-basic).
73-
For a comprehensive introduction to the syntax used above to describe the optimal control problem, check the
74-
[abstract syntax tutorial](@ref tutorial-abstract).
71+
For more details about this problem, please check the [basic example tutorial](@ref tutorial-double-integrator-energy).
72+
For a comprehensive introduction to the syntax used above to describe the optimal control problem, check the [abstract syntax tutorial](@ref tutorial-abstract).
73+
The solve options are described in the [solve tutorial](@ref tutorial-solve).
7574

7675
## Citing us
7776

docs/src/oc_mam.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ Ts = range(1,100,100)
111111
sol = solve(ocp(Ts[1]); display=false, init=init, grid_size=50)
112112
println(" Time Objective Iterations")
113113
for T=Ts
114-
global sol = solve(ocp(T); display=false, init=sol, grid_size=1000)
114+
global sol = solve(ocp(T); display=false, init=sol, grid_size=1000, tol=1e-8)
115115
@printf("%6.2f %9.6e %d\n", T, sol.objective, sol.iterations)
116116
push!(objectives, sol.objective)
117117
end

docs/src/tutorial-continuation.md

+19-19
Original file line numberDiff line numberDiff line change
@@ -76,31 +76,31 @@ function F1(x)
7676
r, v, m = x
7777
return [ 0, Tmax/m, -b*Tmax ]
7878
end
79-
80-
ocp = Model(variable=true)
81-
8279
r0 = 1
8380
v0 = 0
8481
m0 = 1
8582
mf = 0.6
86-
x0=[r0,v0,m0]
87-
83+
x0 = [r0, v0, m0]
8884
vmax = 0.1
8985
90-
state!(ocp, 3)
91-
control!(ocp, 1)
92-
variable!(ocp, 1)
93-
time!(ocp; t0=0, indf=1)
94-
95-
constraint!(ocp, :initial; lb=x0, ub=x0)
96-
constraint!(ocp, :final; rg=3, lb=mf, ub=Inf)
97-
constraint!(ocp, :state; lb=[r0,v0,mf], ub=[r0+0.2,vmax,m0])
98-
constraint!(ocp, :control; lb=0, ub=1)
99-
constraint!(ocp, :variable; lb=0.01, ub=Inf)
100-
101-
objective!(ocp, :mayer, (x0, xf, v) -> xf[1], :max)
102-
103-
dynamics!(ocp, (x, u, v) -> F0(x) + u*F1(x) )
86+
@def ocp begin
87+
tf ∈ R, variable
88+
t ∈ [0, tf], time
89+
x ∈ R^3, state
90+
u ∈ R, control
91+
0.01 ≤ tf ≤ Inf
92+
r = x[1]
93+
v = x[2]
94+
m = x[3]
95+
x(0) == x0
96+
m(tf) == mf
97+
r0 ≤ r(t) ≤ r0 + 0.1
98+
v0 ≤ v(t) ≤ vmax
99+
mf ≤ m(t) ≤ m0
100+
0 ≤ u(t) ≤ 1
101+
ẋ(t) == F0(x(t)) + u(t) * F1(x(t))
102+
r(tf) → max
103+
end
104104
105105
sol0 = solve(ocp; display=false)
106106
@printf("Objective for reference solution %.6f\n", objective(sol0))

docs/src/tutorial-discretisation.md

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# Discretisation methods
2+
3+
## Discretisation formulas
4+
When calling `solve`, the option `disc_method=...` can be used to set the discretisation scheme.
5+
In addition to the default implicit `:trapeze` method (aka Crank-Nicolson), other choices are available, namely implicit `:midpoint` and the Gauss-Legendre collocations with 2 and stages, `:gauss_legendre_2` and `:gauss_legendre_3`, of order 4 and 6 respectively.
6+
Note that higher order methods will typically lead to larger NLP problems for the same number of time steps, and that accuracy will also depend on the smoothness of the problem.
7+
8+
As an example we will use the [Goddard problem](@ref tutorial-goddard)
9+
```@example main
10+
using OptimalControl # to define the optimal control problem and more
11+
using NLPModelsIpopt # to solve the problem via a direct method
12+
using Plots # to plot the solution
13+
14+
t0 = 0 # initial time
15+
r0 = 1 # initial altitude
16+
v0 = 0 # initial speed
17+
m0 = 1 # initial mass
18+
vmax = 0.1 # maximal authorized speed
19+
mf = 0.6 # final mass to target
20+
21+
ocp = @def begin # definition of the optimal control problem
22+
23+
tf ∈ R, variable
24+
t ∈ [t0, tf], time
25+
x = (r, v, m) ∈ R³, state
26+
u ∈ R, control
27+
28+
x(t0) == [ r0, v0, m0 ]
29+
m(tf) == mf, (1)
30+
0 ≤ u(t) ≤ 1
31+
r(t) ≥ r0
32+
0 ≤ v(t) ≤ vmax
33+
34+
ẋ(t) == F0(x(t)) + u(t) * F1(x(t))
35+
36+
r(tf) → max
37+
38+
end;
39+
40+
# Dynamics
41+
const Cd = 310
42+
const Tmax = 3.5
43+
const β = 500
44+
const b = 2
45+
46+
F0(x) = begin
47+
r, v, m = x
48+
D = Cd * v^2 * exp(-β*(r - 1)) # Drag force
49+
return [ v, -D/m - 1/r^2, 0 ]
50+
end
51+
52+
F1(x) = begin
53+
r, v, m = x
54+
return [ 0, Tmax/m, -b*Tmax ]
55+
end
56+
nothing # hide
57+
```
58+
Now let us compare different discretisations
59+
```@example main
60+
sol_trapeze = solve(ocp; tol=1e-8)
61+
plot(sol_trapeze)
62+
63+
sol_midpoint = solve(ocp, disc_method=:midpoint; tol=1e-8)
64+
plot!(sol_midpoint)
65+
66+
sol_gl2 = solve(ocp, disc_method=:gauss_legendre_2; tol=1e-8)
67+
plot!(sol_gl2)
68+
69+
sol_gl3 = solve(ocp, disc_method=:gauss_legendre_3; tol=1e-8)
70+
plot!(sol_gl3)
71+
```
72+
73+
## Large problems and AD backend
74+
For some large problems, you may notice that solving spends a long time before the iterations actually begin.
75+
This is due to the computing of the sparse derivatives, namely the Jacobian of the constraints and the Hessian of the Lagrangian, that can become quite costly.
76+
A possible alternative is to set the option `adnlp_backend=:manual`, which will use more basic sparsity patterns.
77+
The resulting matrices are faster to compute but are also less sparse, so this is a trade-off bewteen the AD preparation and the optimization itself.
78+
79+
```@example main
80+
solve(ocp, disc_method=:gauss_legendre_3, grid_size=1000, adnlp_backend=:manual)
81+
nothing # hide
82+
```
83+
84+
## Explicit time grid
85+
The option `time_grid=...` allows to pass the complete time grid vector `t0, t1, ..., tf`, which is typically useful if one wants a non uniform grid.
86+
In the case of a free initial and/or final time, provide a normalised grid between 0 and 1.
87+
Note that `time_grid` will override `grid_size` if both are present.
88+
89+
```@example main
90+
sol = solve(ocp, time_grid=[0, 0.1, 0.5, 0.9, 1], display=false)
91+
println(time_grid(sol))
92+
```

docs/src/tutorial-double-integrator-energy.md

+9-6
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ nothing # hide
5151

5252
!!! note "Nota bene"
5353

54-
For a comprehensive introduction to the syntax used above to describe the optimal control problem, check [this abstract syntax tutorial](@ref abstract). In particular, there are non-unicode alternatives for derivatives, integrals, *etc.* There is also a non-standard but more classical functional syntax, check [this functional syntax tutorial](@ref functional).
54+
For a comprehensive introduction to the syntax used above to describe the optimal control problem, check [this abstract syntax tutorial](@ref abstract). In particular, there are non-unicode alternatives for derivatives, integrals, *etc.*
5555

5656
## [Solve and plot](@id basic-solve-plot)
5757

@@ -100,20 +100,23 @@ plot(sol)
100100

101101
## Save and load
102102

103-
We can save the solution in a Julia `.jld2` data file and reload it later, and also export a discretised version of the solution in a more portable [JSON](https://en.wikipedia.org/wiki/JSON) format.
103+
We can save the solution in a Julia `.jld2` data file and reload it later, and also export a discretised version of the solution in a more portable [JSON](https://en.wikipedia.org/wiki/JSON) format. Note that the OCP is needed when loading a solution.
104104

105105
```@example main
106106
# load additional modules
107107
using JLD2, JSON3
108108
109109
# JLD save / load
110-
save(sol, filename_prefix="my_solution")
111-
sol_reloaded = load("my_solution")
110+
using Suppressor # hide
111+
@suppress_err begin # hide
112+
export_ocp_solution(sol; filename_prefix="my_solution")
113+
end # hide
114+
sol_reloaded = import_ocp_solution(ocp; filename_prefix="my_solution")
112115
println("Objective from loaded solution: ", sol_reloaded.objective)
113116
114117
# JSON export / read
115-
export_ocp_solution(sol, filename_prefix="my_solution")
116-
sol_json = import_ocp_solution(ocp, filename_prefix="my_solution")
118+
export_ocp_solution(sol; filename_prefix="my_solution", format=:JSON)
119+
sol_json = import_ocp_solution(ocp; filename_prefix="my_solution", format=:JSON)
117120
println("Objective from JSON discrete solution: ", sol_json.objective)
118121
```
119122

docs/src/tutorial-double-integrator-time.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ nothing # hide
7070

7171
!!! note "Nota bene"
7272

73-
For a comprehensive introduction to the syntax used above to describe the optimal control problem, check [this abstract syntax tutorial](@ref abstract). In particular, there are non-unicode alternatives for derivatives, integrals, *etc.* There is also a non-standard but more classical functional syntax, check [this functional syntax tutorial](@ref functional).
73+
For a comprehensive introduction to the syntax used above to describe the optimal control problem, check [this abstract syntax tutorial](@ref abstract). In particular, there are non-unicode alternatives for derivatives, integrals, *etc.*
7474

7575
## Solve and plot
7676

docs/src/tutorial-flow.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,9 @@ end
9191
u(x, p) = p[2]
9292
```
9393

94-
```@repl main_repl
95-
f = Flow(ocp, u)
94+
```julia
95+
julia> f = Flow(ocp, u)
96+
ERROR: ExtensionError. Please make: julia> using OrdinaryDiffEq
9697
```
9798

9899
As you can see, an error occured since we need the package [OrdinaryDiffEq.jl](https://docs.sciml.ai/DiffEqDocs).

0 commit comments

Comments
 (0)