Skip to content

Commit 9e263b7

Browse files
authored
Merge pull request #458 from control-toolbox/457-dev-fix-goddard-tuto-in-doc-for-100
add SciMLSensitivity
2 parents 5900cb7 + 24c10c2 commit 9e263b7

File tree

4 files changed

+52
-168
lines changed

4 files changed

+52
-168
lines changed

docs/Project.toml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ MINPACK = "4854310b-de5a-5eb6-a2a5-c1dee2bd17f9"
1717
MadNLP = "2621e9c9-9eb4-46b1-8089-e8c72242dfb6"
1818
NLPModelsIpopt = "f4238b75-b362-5c4c-b852-0801c9a21d71"
1919
NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec"
20+
OptimalControl = "5f98b655-cc9a-415a-b60e-744165666948"
2021
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
2122
Percival = "01435c0c-c90d-11e9-3788-63660f8fbccc"
2223
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
@@ -27,18 +28,21 @@ BenchmarkTools = "1.6"
2728
CTBase = "0.15"
2829
CTDirect = "0.14"
2930
CTFlows = "0.8"
31+
CTModels = "0.2"
32+
CTParser = "0.2"
3033
CommonSolve = "0.2"
3134
DifferentiationInterface = "0.6"
3235
Documenter = "1.8"
3336
DocumenterMermaid = "0.2"
3437
ForwardDiff = "0.10"
3538
JLD2 = "0.5"
3639
JSON3 = "1.14"
40+
LinearAlgebra = "1"
3741
MINPACK = "1.3"
3842
MadNLP = "0.8"
3943
NLPModelsIpopt = "0.10"
40-
NonlinearSolve = "4.4"
41-
OrdinaryDiffEq = "6"
44+
NonlinearSolve = "4.6"
45+
OrdinaryDiffEq = "6.93"
4246
Percival = "0.7"
4347
Plots = "1.40"
4448
Suppressor = "0.2"

docs/src/tutorial-goddard.md

Lines changed: 27 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ using Plots # to plot the solution
5656
We define the problem
5757

5858
```@example main
59-
t0 = 0 # initial time
60-
r0 = 1 # initial altitude
61-
v0 = 0 # initial speed
62-
m0 = 1 # initial mass
63-
vmax = 0.1 # maximal authorized speed
64-
mf = 0.6 # final mass to target
59+
const t0 = 0 # initial time
60+
const r0 = 1 # initial altitude
61+
const v0 = 0 # initial speed
62+
const m0 = 1 # initial mass
63+
const vmax = 0.1 # maximal authorized speed
64+
const mf = 0.6 # final mass to target
6565
6666
ocp = @def begin # definition of the optimal control problem
6767
@@ -70,7 +70,7 @@ ocp = @def begin # definition of the optimal control problem
7070
x = (r, v, m) ∈ R³, state
7171
u ∈ R, control
7272
73-
x(t0) == [ r0, v0, m0 ]
73+
x(t0) == [r0, v0, m0]
7474
m(tf) == mf, (1)
7575
0 ≤ u(t) ≤ 1
7676
r(t) ≥ r0
@@ -80,7 +80,7 @@ ocp = @def begin # definition of the optimal control problem
8080
8181
r(tf) → max
8282
83-
end;
83+
end
8484
8585
# Dynamics
8686
const Cd = 310
@@ -91,12 +91,12 @@ const b = 2
9191
F0(x) = begin
9292
r, v, m = x
9393
D = Cd * v^2 * exp(-β*(r - 1)) # Drag force
94-
return [ v, -D/m - 1/r^2, 0 ]
94+
return [v, -D/m - 1/r^2, 0]
9595
end
9696
9797
F1(x) = begin
9898
r, v, m = x
99-
return [ 0, Tmax/m, -b*Tmax ]
99+
return [0, Tmax/m, -b*Tmax]
100100
end
101101
nothing # hide
102102
```
@@ -203,13 +203,13 @@ these expressions are straightforwardly translated into Julia code:
203203

204204
```@example main
205205
# Controls
206-
u0 = 0 # off control
207-
u1 = 1 # bang control
206+
const u0 = 0 # off control
207+
const u1 = 1 # bang control
208208
209209
H0 = Lift(F0) # H0(x, p) = p' * F0(x)
210-
H01 = @Lie { H0, H1 }
211-
H001 = @Lie { H0, H01 }
212-
H101 = @Lie { H1, H01 }
210+
H01 = @Lie {H0, H1}
211+
H001 = @Lie {H0, H01}
212+
H101 = @Lie {H1, H01}
213213
us(x, p) = -H001(x, p) / H101(x, p) # singular control
214214
215215
ub(x) = -(F0⋅g)(x) / (F1⋅g)(x) # boundary control
@@ -229,7 +229,7 @@ Then, we define the shooting function according to the optimal structure we have
229229
that is a concatenation of four arcs.
230230

231231
```@example main
232-
x0 = [ r0, v0, m0 ] # initial state
232+
x0 = [r0, v0, m0] # initial state
233233
234234
function shoot!(s, p0, t1, t2, t3, tf)
235235
@@ -239,7 +239,7 @@ function shoot!(s, p0, t1, t2, t3, tf)
239239
xf, pf = f0(t3, x3, p3, tf)
240240
241241
s[1] = xf[3] - mf # final mass constraint
242-
s[2:3] = pf[1:2] - [ 1, 0 ] # transversality conditions
242+
s[2:3] = pf[1:2] - [1, 0] # transversality conditions
243243
s[4] = H1(x1, p1) # H1 = H01 = 0
244244
s[5] = H01(x1, p1) # at the entrance of the singular arc
245245
s[6] = g(x2) # g = 0 when entering the boundary arc
@@ -283,85 +283,30 @@ println("\nNorm of the shooting function: ‖s‖ = ", norm(s), "\n")
283283
We aggregate the data to define the initial guess vector.
284284

285285
```@example main
286-
ξ = [ p0 ; t1 ; t2 ; t3 ; tf ] # initial guess
287-
```
288-
289-
### NonlinearSolve.jl
290-
291-
We first use the [NonlinearSolve.jl](https://github.com/SciML/NonlinearSolve.jl) package to solve the shooting
292-
equation. Let us define the problem.
293-
294-
```@example main
295-
# auxiliary function with aggregated inputs
296-
nle! = (s, ξ, λ) -> shoot!(s, ξ[1:3], ξ[4], ξ[5], ξ[6], ξ[7])
297-
298-
# NLE problem with initial guess
299-
prob = NonlinearProblem(nle!, ξ)
300-
nothing # hide
301-
```
302-
303-
Let us do some benchmarking.
304-
305-
```@example main
306-
using BenchmarkTools
307-
@benchmark solve(prob; abstol=1e-8, reltol=1e-8, show_trace=Val(false))
308-
```
309-
310-
For small nonlinear systems, it could be faster to use the
311-
[`SimpleNewtonRaphson()` descent algorithm](https://docs.sciml.ai/NonlinearSolve/stable/tutorials/code_optimization/).
312-
313-
```@example main
314-
@benchmark solve(prob, SimpleNewtonRaphson(); abstol=1e-8, reltol=1e-8, show_trace=Val(false))
315-
```
316-
317-
Now, let us solve the problem and retrieve the initial costate solution.
318-
319-
```@example main
320-
# resolution of S(ξ) = 0
321-
indirect_sol = solve(prob; abstol=1e-8, reltol=1e-8, show_trace=Val(true))
322-
323-
# we retrieve the costate solution together with the times
324-
p0 = indirect_sol.u[1:3]
325-
t1 = indirect_sol.u[4]
326-
t2 = indirect_sol.u[5]
327-
t3 = indirect_sol.u[6]
328-
tf = indirect_sol.u[7]
329-
330-
println("")
331-
println("p0 = ", p0)
332-
println("t1 = ", t1)
333-
println("t2 = ", t2)
334-
println("t3 = ", t3)
335-
println("tf = ", tf)
336-
337-
# Norm of the shooting function at solution
338-
s = similar(p0, 7)
339-
shoot!(s, p0, t1, t2, t3, tf)
340-
println("\nNorm of the shooting function: ‖s‖ = ", norm(s), "\n")
286+
ξ = [p0..., t1, t2, t3, tf] # initial guess
341287
```
342288

343289
### MINPACK.jl
344290

291+
We can use [NonlinearSolve.jl](https://github.com/SciML/NonlinearSolve.jl) package or, instead, the
292+
[MINPACK.jl](https://github.com/sglyon/MINPACK.jl) package to solve
293+
the shooting equation. To compute the Jacobian of the shooting function we use the
294+
[DifferentiationInterface.jl](https://gdalle.github.io/DifferentiationInterface.jl/DifferentiationInterface) package with
295+
[ForwardDiff.jl](https://github.com/JuliaDiff/ForwardDiff.jl) backend.
296+
345297
```@setup main
346-
using MINPACK
347298
function fsolve(f, j, x; kwargs...)
348299
try
349300
MINPACK.fsolve(f, j, x; kwargs...)
350301
catch e
351-
println("Erreur using MINPACK")
302+
println("Error using MINPACK")
352303
println(e)
353304
println("hybrj not supported. Replaced by hybrd even if it is not visible on the doc.")
354305
MINPACK.fsolve(f, x; kwargs...)
355306
end
356307
end
357308
```
358309

359-
Instead of the [NonlinearSolve.jl](https://github.com/SciML/NonlinearSolve.jl) package we can use the
360-
[MINPACK.jl](https://github.com/sglyon/MINPACK.jl) package to solve
361-
the shooting equation. To compute the Jacobian of the shooting function we use the
362-
[DifferentiationInterface.jl](https://gdalle.github.io/DifferentiationInterface.jl/DifferentiationInterface) package with
363-
[ForwardDiff.jl](https://github.com/JuliaDiff/ForwardDiff.jl) backend.
364-
365310
```@example main
366311
using DifferentiationInterface
367312
import ForwardDiff
@@ -381,21 +326,8 @@ nothing # hide
381326
```
382327

383328
We are now in position to solve the problem with the `hybrj` solver from MINPACK.jl through the `fsolve`
384-
function, providing the Jacobian. Let us do some benchmarking.
385-
386-
```@example main
387-
@benchmark fsolve(nle!, jnle!, ξ; show_trace=false) # initial guess given to the solver
388-
```
389-
390-
We can also use the [preparation step](https://gdalle.github.io/DifferentiationInterface.jl/DifferentiationInterface/stable/tutorial1/#Preparing-for-multiple-gradients) of DifferentiationInterface.jl.
391-
392-
```@example main
393-
extras = prepare_jacobian(nle!, similar(ξ), backend, ξ)
394-
jnle_prepared!(js, ξ) = jacobian!(nle!, similar(ξ), js, backend, ξ, extras)
395-
@benchmark fsolve(nle!, jnle_prepared!, ξ; show_trace=false)
396-
```
397-
398-
Now, let us solve the problem and retrieve the initial costate solution.
329+
function, providing the Jacobian.
330+
Let us solve the problem and retrieve the initial costate solution.
399331

400332
```@example main
401333
# resolution of S(ξ) = 0

docs/src/tutorial-iss.md

Lines changed: 12 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ Let us consider the following optimal control problem:
3030
with $t_0 = 0$, $t_f = 1$, $x_0 = -1$, $x_f = 0$, $\alpha=1.5$ and $\forall\, t \in [t_0, t_f]$, $x(t) \in \R$.
3131

3232
```@example main
33-
t0 = 0
34-
tf = 1
35-
x0 = -1
36-
xf = 0
37-
α = 1.5
33+
const t0 = 0
34+
const tf = 1
35+
const x0 = -1
36+
const xf = 0
37+
const α = 1.5
3838
ocp = @def begin
3939
4040
t ∈ [t0, tf], time
@@ -145,50 +145,17 @@ nothing # hide
145145

146146
## Resolution of the shooting equation
147147

148-
At the end, solving (BVP) is equivalent to solve $S(p_0) = 0$. This is what we call the
149-
**indirect simple shooting method**. We define an initial guess.
148+
At the end, solving (BVP) is equivalent to solve $S(p_0) = 0$. This is what we call the **indirect simple shooting method**. We define an initial guess.
150149

151150
```@example main
152-
ξ = [ 0.1 ] # initial guess
151+
ξ = [0.1] # initial guess
153152
nothing # hide
154153
```
155154

156-
### NonlinearSolve.jl
157-
158-
We first use the [NonlinearSolve.jl](https://github.com/SciML/NonlinearSolve.jl) package to solve the shooting
159-
equation. Let us define the problem.
160-
161-
```@example main
162-
nle! = (s, ξ, λ) -> s[1] = S(ξ[1]) # auxiliary function
163-
prob = NonlinearProblem(nle!, ξ) # NLE problem with initial guess
164-
nothing # hide
165-
```
166-
167-
Let us do some benchmarking.
168-
169-
```@example main
170-
using BenchmarkTools
171-
@benchmark solve(prob; show_trace=Val(false))
172-
```
173-
174-
For small nonlinear systems, it could be faster to use the
175-
[`SimpleNewtonRaphson()` descent algorithm](https://docs.sciml.ai/NonlinearSolve/stable/tutorials/code_optimization/).
176-
177-
```@example main
178-
@benchmark solve(prob, SimpleNewtonRaphson(); show_trace=Val(false))
179-
```
180-
181-
Now, let us solve the problem and retrieve the initial costate solution.
182-
183-
```@example main
184-
indirect_sol = solve(prob; show_trace=Val(true)) # resolution of S(p0) = 0
185-
p0_sol = indirect_sol.u[1] # costate solution
186-
println("\ncostate: p0 = ", p0_sol)
187-
println("shoot: |S(p0)| = ", abs(S(p0_sol)), "\n")
188-
```
189-
190155
### MINPACK.jl
191156

157+
We can use [NonlinearSolve.jl](https://github.com/SciML/NonlinearSolve.jl) package or, instead, [MINPACK.jl](https://github.com/sglyon/MINPACK.jl) to solve the shooting equation. To compute the Jacobian of the shooting function we use [DifferentiationInterface.jl](https://gdalle.github.io/DifferentiationInterface.jl/DifferentiationInterface) with [ForwardDiff.jl](https://github.com/JuliaDiff/ForwardDiff.jl) backend.
158+
192159
```@setup main
193160
using MINPACK
194161
function fsolve(f, j, x; kwargs...)
@@ -203,12 +170,6 @@ function fsolve(f, j, x; kwargs...)
203170
end
204171
```
205172

206-
Instead of the [NonlinearSolve.jl](https://github.com/SciML/NonlinearSolve.jl) package we can use the
207-
[MINPACK.jl](https://github.com/sglyon/MINPACK.jl) package to solve
208-
the shooting equation. To compute the Jacobian of the shooting function we use the
209-
[DifferentiationInterface.jl](https://gdalle.github.io/DifferentiationInterface.jl/DifferentiationInterface) package with
210-
[ForwardDiff.jl](https://github.com/JuliaDiff/ForwardDiff.jl) backend.
211-
212173
```@example main
213174
using DifferentiationInterface
214175
import ForwardDiff
@@ -224,22 +185,8 @@ jnle! = (js, ξ) -> jacobian!(nle!, similar(ξ), js, backend, ξ) # Jacobian
224185
nothing # hide
225186
```
226187

227-
We are now in position to solve the problem with the `hybrj` solver from MINPACK.jl through the `fsolve`
228-
function, providing the Jacobian. Let us do some benchmarking.
229-
230-
```@example main
231-
@benchmark fsolve(nle!, jnle!, ξ; show_trace=false) # initial guess given to the solver
232-
```
233-
234-
We can also use the [preparation step](https://gdalle.github.io/DifferentiationInterface.jl/DifferentiationInterface/stable/tutorial1/#Preparing-for-multiple-gradients) of DifferentiationInterface.jl.
235-
236-
```@example main
237-
extras = prepare_jacobian(nle!, similar(ξ), backend, ξ)
238-
jnle_prepared!(js, ξ) = jacobian!(nle!, similar(ξ), js, backend, ξ, extras)
239-
@benchmark fsolve(nle!, jnle_prepared!, ξ; show_trace=false)
240-
```
241-
242-
Now, let us solve the problem and retrieve the initial costate solution.
188+
We are now in position to solve the problem with the `hybrj` solver from MINPACK.jl through the `fsolve` function, providing the Jacobian.
189+
Let us solve the problem and retrieve the initial costate solution.
243190

244191
```@example main
245192
indirect_sol = fsolve(nle!, jnle!, ξ; show_trace=true) # resolution of S(p0) = 0
@@ -257,10 +204,7 @@ sol = φ((t0, tf), x0, p0_sol)
257204
plot(sol)
258205
```
259206

260-
In the indirect shooting method, the research of the optimal control is replaced by the computation
261-
of its associated extremal. This computation is equivalent to finding the initial covector solution
262-
to the shooting function. Let us plot the extremal in the phase space and the shooting function with
263-
the solution.
207+
In the indirect shooting method, the research of the optimal control is replaced by the computation of its associated extremal. This computation is equivalent to finding the initial covector solution to the shooting function. Let us plot the extremal in the phase space and the shooting function with the solution.
264208

265209
```@raw html
266210
<article class="docstring">
@@ -408,5 +352,3 @@ nothing # hide
408352
```@example main
409353
pretty_plot(S, p0_sol; size=(800, 450))
410354
```
411-
412-

test/Project.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,13 @@ SplitApplyCombine = "03a91e81-4c3e-53e1-a0a4-9c0c8f19dd66"
1010
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
1111

1212
[compat]
13+
CTModels = "0.2"
14+
DifferentiationInterface = "0.6"
15+
ForwardDiff = "0.10"
16+
LinearAlgebra = "1"
17+
MINPACK = "1.3"
1318
NLPModelsIpopt = "0.10"
14-
OrdinaryDiffEq = "6"
19+
OrdinaryDiffEq = "6.93"
1520
SplitApplyCombine = "1.2"
21+
Test = "1"
1622
julia = "1.10"

0 commit comments

Comments
 (0)