Skip to content

Commit 1750ae9

Browse files
committed
Improve MAM tutorial: add problem statement, restructure continuation, use @init macro
1 parent e9c6fcb commit 1750ae9

1 file changed

Lines changed: 87 additions & 24 deletions

File tree

docs/src/tutorial-mam.md

Lines changed: 87 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
# Minimal Action Method using Optimal Control
22

3-
The Minimal Action Method is a numerical technique for finding the most probable transition pathway between stable states in stochastic dynamical systems. It achieves this by minimizing an action functional that represents the path's deviation from the deterministic dynamics, effectively identifying the path of least resistance through the system's landscape.
4-
This tutorial demonstrates how to implement MAM as an optimal control problem.
3+
```@meta
4+
Draft = false
5+
```
6+
7+
The Minimal Action Method (MAM) is a numerical technique for finding the most probable transition pathway between stable states in stochastic dynamical systems. It achieves this by minimizing an action functional that represents the path's deviation from the deterministic dynamics, effectively identifying the path of least resistance through the system's landscape.
8+
9+
This tutorial demonstrates how to implement MAM as an optimal control problem, using the classical Maier-Stein model as a benchmark example.
510

611
## Required Packages
712

@@ -11,9 +16,29 @@ using NLPModelsIpopt
1116
using Plots, Printf
1217
```
1318

19+
## Problem Statement
20+
21+
We aim to find the most probable transition path between two stable states of a stochastic dynamical system. For a system with deterministic dynamics $f(x)$ and small noise, the transition path minimizes the action functional:
22+
23+
```math
24+
S[x(\cdot), u(\cdot)] = \int_0^T \|u(t) - f(x(t))\|^2 \, dt
25+
```
26+
27+
subject to the path dynamics:
28+
29+
```math
30+
\dot{x}(t) = u(t), \quad x(0) = x_0, \quad x(T) = x_f
31+
```
32+
33+
where $x_0$ and $x_f$ are the initial and final states, and $T$ is the transition time.
34+
35+
!!! note "Physical interpretation"
36+
37+
The action $S$ measures the "cost" of deviating from the deterministic flow $f(x)$. Paths with smaller action are exponentially more likely in the small noise limit.
38+
1439
## Problem Setup
1540

16-
We'll consider a 2D system with a double-well flow, called the Maier-Stein model. It is a famous benchmark problem as it exhibits non-gradient dynamics with two stable equilibrium points at (-1,0) and (1,0), connected by a non-trivial transition path.
41+
We consider a 2D system with a double-well flow, called the Maier-Stein model. It is a famous benchmark problem as it exhibits non-gradient dynamics with two stable equilibrium points at $(-1,0)$ and $(1,0)$, connected by a non-trivial transition path.
1742
The system's deterministic dynamics are given by:
1843

1944
```@example main-mam
@@ -45,29 +70,39 @@ nothing # hide
4570

4671
## Initial Guess
4772

48-
We provide an initial guess for the path using a simple interpolation:
73+
We provide an initial guess for the path using a simple interpolation with the `@init` macro:
4974

5075
```@example main-mam
5176
# Time horizon
5277
T = 50
5378
54-
# Linear interpolation for x₁
55-
x1(t) = -(1 - t/T) + t/T
56-
57-
# Parabolic guess for x₂
58-
x2(t) = 0.3(-x1(t)^2 + 1)
59-
x(t) = [x1(t), x2(t)]
60-
u(t) = f(x(t))
61-
62-
# Initial guess
63-
init = (state=x, control=u)
79+
# Helper functions for initial state guess
80+
L(t) = -(1 - t/T) + t/T # Linear interpolation from -1 to 1
81+
P(t) = 0.3*(-L(t)^2 + 1) # Parabolic arc (approximates saddle crossing)
82+
83+
init = @init ocp(T) begin
84+
# Linear interpolation for x₁
85+
x₁(t) := L(t)
86+
# Parabolic guess for x₂
87+
x₂(t) := P(t)
88+
# Control from vector field
89+
u(t) := f(L(t), P(t))
90+
end
6491
nothing # hide
6592
```
6693

94+
!!! note "Initial guess strategy"
95+
96+
The initial guess uses a simple geometric path: linear interpolation in $x_1$ and a parabolic arc in $x_2$. This provides a reasonable starting point that avoids the unstable saddle point at the origin. The control is initialized to follow the deterministic flow along this path.
97+
6798
## Solving the Problem
6899

69100
We solve the problem in two steps for better accuracy:
70101

102+
!!! note "Two-step resolution"
103+
104+
Starting with a coarse grid (50 points) allows for faster initial convergence. Refining with a fine grid (1000 points) then improves accuracy of the solution.
105+
71106
```@example main-mam
72107
# First solve with coarse grid
73108
sol = solve(ocp(T); init=init, grid_size=50)
@@ -104,22 +139,50 @@ The resulting path shows the most likely transition between the two stable state
104139
To find the maximum likelihood path, we also need to minimize the transient time `T`. Hence, we perform a discrete continuation over the parameter `T` by solving the optimal control problem over a continuous range of final times `T`, using each solution to initialize the next problem.
105140

106141
```@example main-mam
107-
objectives = []
108-
Ts = range(1,100,100)
109-
sol = solve(ocp(Ts[1]); display=false, init=init, grid_size=200)
110-
println(" Time Objective Iterations")
111-
for T=Ts
112-
global sol = solve(ocp(T); display=false, init=sol, grid_size=1000, tol=1e-8)
113-
@printf("%6.2f %9.6e %d\n", T, objective(sol), iterations(sol))
114-
push!(objectives, objective(sol))
142+
# Continuation function to avoid global variables
143+
function continuation_mam(Ts; init_guess=init)
144+
objectives = Float64[]
145+
current_sol = init_guess
146+
147+
println(" Time Objective Iterations")
148+
for T in Ts
149+
current_sol = solve(ocp(T); display=false, init=current_sol, grid_size=1000, tol=1e-8)
150+
obj = objective(current_sol)
151+
@printf("%6.2f %9.6e %d\n", T, obj, iterations(current_sol))
152+
push!(objectives, obj)
153+
end
154+
155+
return objectives, current_sol
115156
end
157+
158+
# Perform continuation
159+
Ts = range(1, 100, 100)
160+
objectives, final_sol = continuation_mam(Ts)
161+
nothing # hide
116162
```
117163

164+
We can now analyze the results and identify the optimal transition time:
165+
166+
```@example main-mam
167+
# Find optimal time
168+
idx_min = argmin(objectives)
169+
T_min = Ts[idx_min]
170+
obj_min = objectives[idx_min]
171+
172+
@printf("Optimal transition time: T* = %.2f\n", T_min)
173+
@printf("Minimal action: S* = %.6e\n", obj_min)
174+
```
175+
176+
Let us visualize the evolution of the objective function with respect to the transition time:
177+
118178
```@example main-mam
119-
T_min = Ts[argmin(objectives)]
120179
plt1 = scatter(Ts, log10.(objectives), xlabel="Time", label="Objective (log10)")
121-
vline!(plt1, [T_min], label="Minimum", z_order=:back)
180+
vline!(plt1, [T_min], label="Minimum at T=$(round(T_min, digits=1))", z_order=:back)
122181
plt2 = scatter(Ts[40:100], log10.(objectives[40:100]), xlabel="Time", label="Objective (log10)")
123182
vline!(plt2, [T_min], label="Minimum", z_order=:back)
124183
plot(plt1, plt2, layout=(2,1), size=(800,800))
125184
```
185+
186+
!!! note "Interpretation"
187+
188+
The optimal transition time $T^*$ balances two competing effects: shorter times require larger deviations from the deterministic flow (higher action), while longer times allow the system to follow the flow more closely. The minimum represents the most probable transition time in the small noise limit.

0 commit comments

Comments
 (0)