Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stochsystem overhaul #76

Draft
wants to merge 28 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
a4f339c
do not export dev functions
oameye Apr 21, 2024
63ddb70
add ModelingToolkit SDE tests
oameye Apr 21, 2024
e5567fb
inspect integrator and parameter structure
oameye Apr 21, 2024
5c98773
make CoupledSDE struct
oameye Apr 21, 2024
a901219
add option for Multiplicative noise a la StochasticDiffEq
oameye Apr 22, 2024
36eac01
make CoupledSDEs a ContinuousTimeDynamicalSystem
oameye Apr 22, 2024
e5b9ba8
assume iterable object in predefined systems
oameye Apr 22, 2024
79a8ea7
enable trajactory(::CoupledSDEs)
oameye Apr 22, 2024
e46779c
comment unneeded stuff
oameye Apr 22, 2024
7c11459
rewrite stochprocess
oameye Apr 22, 2024
2b33ba8
reorganise folders structure
oameye Apr 22, 2024
1f6cc1c
update simulate and relax
oameye Apr 23, 2024
91ff50b
update transition
oameye Apr 23, 2024
84590b4
update transitions
oameye Apr 23, 2024
60c8167
update action.jl
oameye Apr 23, 2024
b374ced
Merge branch 'main' into stochsystem_overhaul
oameye Apr 23, 2024
fecbfda
update min_action_method to work with CoupledSDEs
reykboerner Apr 26, 2024
63f7cf9
adapted gMAM for CoupledSDEs and updated large deviations tests
reykboerner May 7, 2024
18dc342
updated test of simulate and trajectory functions
reykboerner May 7, 2024
649e893
streamline export
oameye May 8, 2024
0a91810
do not require SVector
oameye May 8, 2024
65e83a2
add skip kwargs to some tests
oameye May 8, 2024
46b0dc9
add TYPEDSIGNATURES docstrings
oameye May 8, 2024
7c91a83
delete auxilary action test file
oameye May 8, 2024
4a3bee1
put basin code in extention
oameye May 8, 2024
08b094c
exterminated Stochsystem in the docs
oameye May 8, 2024
bccbb18
fixed typo 'baisin' to 'basin'
reykboerner May 12, 2024
74b8358
created StochSystem alias, re-added custom types
reykboerner May 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

[![](https://img.shields.io/badge/docs-dev-blue.svg)](https://juliadynamics.github.io/CriticalTransitions.jl/dev/)
[![](https://img.shields.io/badge/docs-stable-blue.svg)](https://juliadynamics.github.io/CriticalTransitions.jl/stable/)

[![Tests](https://github.com/JuliaDynamics/CriticalTransitions.jl/actions/workflows/ci.yml/badge.svg)](github.com/JuliaDynamics/CriticalTransitions.jl/actions/workflows/ci.yml)

A Julia package for the numerical investigation of **noise- and rate-induced transitions in dynamical systems**.
Expand Down
3 changes: 2 additions & 1 deletion src/CriticalTransitions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ include("trajectories/transition.jl")
include("noiseprocesses/stochprocess.jl")
include("largedeviations/action.jl")
include("largedeviations/min_action_method.jl")
# include("largedeviations/geometric_min_action_method.jl")
include("largedeviations/geometric_min_action_method.jl")

include("../systems/fitzhughnagumo.jl")
include("../systems/truscottbrindley_mod.jl")
Expand All @@ -50,6 +50,7 @@ export equilib, fixedpoints, basins, basinboundary, basboundary
export simulate, relax
export transition, transitions
export fw_integrand, fw_action, om_action, action, geometric_action
export div_drift
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To keep the namespace minimal, we should limit the amount of functions we export. I don't think we need to export div_drift

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be convenient to export because it is quite central to the Onsager-Machlup action. Of course one can compute it pretty easily. We could also consider not exporting fw_integrand

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But a user would never call it in a usual workflow right? If they want to call they can just import the function in the namespace or calll it with Criticaltransition.div_drift

export min_action_method, geometric_min_action_method
export edgetracking, bisect_to_edge, attractor_mapper, bisect_to_edge2
export make_jld2, make_h5, sys_string, sys_info, intervals_to_box
Expand Down
19 changes: 10 additions & 9 deletions src/largedeviations/action.jl
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ function fw_action(sys::CoupledSDEs, path, time; cov_inv=nothing)
end;

"""
om_action(sys::CoupledSDEs, path, time; kwargs...)
om_action(sys::CoupledSDEs, path, time, noise_strength; kwargs...)
Calculates the Onsager-Machlup action of a given `path` with time points `time` for the
drift field `sys.f` at noise strength `sys.σ`.
drift field `sys.f` at given `noise_strength`.

The path must be a `(D x N)` matrix, where `D` is the dimensionality of the system `sys` and
`N` is the number of path points. The `time` array must have length `N`.
Expand All @@ -52,13 +52,13 @@ Returns a single number, which is the value of the action functional
where ``\\phi_t`` denotes the path in state space, ``b`` the drift field, ``T`` the total
time of the path, and ``\\sigma`` the noise strength. The subscript ``Q`` refers to the
generalized norm ``||a||_Q^2 := \\langle a, Q^{-1} b \\rangle`` (see [`anorm`](@ref)). Here
``Q`` is the noise covariance matrix `sys.Σ`.
``Q`` is the noise covariance matrix.

## Keyword arguments
* `cov_inv = nothing`: Inverse of the covariance matrix ``\\Sigma``.
If `nothing`, ``\\Sigma^{-1}`` is computed automatically.
"""
function om_action(sys::CoupledSDEs, path, time; cov_inv=nothing)
function om_action(sys::CoupledSDEs, path, time, noise_strength; cov_inv=nothing)
if ~all(diff(time) .≈ diff(time[1:2]))
error("Fw_action is only defined for equispaced time")
end
Expand All @@ -67,8 +67,8 @@ function om_action(sys::CoupledSDEs, path, time; cov_inv=nothing)
# Compute action integral
S = 0
for i in 1:(size(path, 2) - 1)
S += noise_strength(sys)^2/2 * ((div_b(sys, path[:,i+1]) + div_b(sys, path[:,i]))/2 *
(time[i+1]-time[i]))
S += noise_strength^2/2 * ((div_drift(sys, path[:,i+1])
+ div_drift(sys, path[:,i]))/2 * (time[i+1]-time[i]))
end
fw_action(sys, path, time, cov_inv=A) + S/2
end;
Expand All @@ -85,7 +85,8 @@ function action(sys::CoupledSDEs, path::Matrix, time, functional; kwargs...)
if functional == "FW"
return fw_action(sys, path, time; kwargs...)
elseif functional == "OM"
return om_action(sys, path, time; kwargs...)
error("Not yet implemented since it depends on noise strength.")
#return om_action(sys, path, time; kwargs...)
end
end;

Expand Down Expand Up @@ -151,10 +152,10 @@ function fw_integrand(sys::CoupledSDEs, path, time, A)
end;

"""
div_b(sys::CoupledSDEs, x)
div_drift(sys::CoupledSDEs, x)
Computes the divergence of the drift field `sys.f` at the given point `x`.
"""
function div_b(sys::CoupledSDEs, x)
function div_drift(sys::CoupledSDEs, x)
b(x) = drift(sys, x)
tr(ForwardDiff.jacobian(b, x))
end;
Expand Down
29 changes: 15 additions & 14 deletions src/largedeviations/geometric_min_action_method.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
#include("action.jl")

"""
geometric_min_action_method(sys::StochSystem, x_i::State, x_f::State, arclength=1; kwargs...)
geometric_min_action_method(sys::CoupledSDEs, x_i::SVector, x_f::SVector, arclength=1; kwargs...)

Computes the minimizer of the Freidlin-Wentzell action using the geometric minimum
action method (gMAM). Beta version, to be further documented.

To set an initial path different from a straight line, see the multiple dispatch method

- `geometric_min_action_method(sys::StochSystem, init::Matrix, arclength::Float64; kwargs...)`.
- `geometric_min_action_method(sys::CoupledSDEs, init::Matrix, arclength::Float64; kwargs...)`.

## Keyword arguments

Expand All @@ -29,7 +29,7 @@ algorithm[^1].
[^1]: [Heymann and Vanden-Eijnden, PRL (2008)](https://link.aps.org/doi/10.1103/PhysRevLett.100.140601)
"""
function geometric_min_action_method(
sys::StochSystem, x_i::State, x_f::State, arclength = 1.0;
sys::CoupledSDEs, x_i::SVector, x_f::SVector, arclength = 1.0;
N = 100,
maxiter = 100,
converge = 1e-5,
Expand All @@ -38,25 +38,25 @@ function geometric_min_action_method(
verbose=true,
showprogress=false)
path = reduce(hcat, range(x_i, x_f, length = N))
geometric_min_action_method(sys::StochSystem, path, arclength;
geometric_min_action_method(sys::CoupledSDEs, path, arclength;
maxiter = maxiter, converge = converge,
method = method, tau = tau, verbose = verbose, showprogress = showprogress)
end

"""
geometric_min_action_method(sys::StochSystem, init::Matrix, arclength::Float64; kwargs...)
geometric_min_action_method(sys::CoupledSDEs, init::Matrix, arclength::Float64; kwargs...)

Runs the geometric Minimum Action Method (gMAM) to find the minimum action path (instanton) from an
initial condition `init`, given a system `sys` and total arc length `arclength`.

The initial path `init` must be a matrix of size `(D, N)`, where `D` is the dimension
`length(sys.u)` of the system and `N` is the number of path points.
The initial path `init` must be a matrix of size `(D, N)`, where `D` is the dimension of the
system and `N` is the number of path points.

For more information see the main method,
[`geometric_min_action_method(sys::StochSystem, x_i::State, x_f::State, arclength::Float64; kwargs...)`](@ref).
[`geometric_min_action_method(sys::CoupledSDEs, x_i::SVector, x_f::SVector, arclength::Float64; kwargs...)`](@ref).
"""

function geometric_min_action_method(sys::StochSystem, init::Matrix, arclength=1.0;
function geometric_min_action_method(sys::CoupledSDEs, init::Matrix, arclength=1.0;
maxiter = 100,
converge = 1e-5,
method = LBFGS(),
Expand All @@ -66,7 +66,7 @@ function geometric_min_action_method(sys::StochSystem, init::Matrix, arclength=1

verbose && println("=== Initializing gMAM action minimizer ===")

A = inv(sys)
A = inv(covariance_matrix(sys))
path = init
x_i = init[:, 1]
x_f = init[:, end]
Expand Down Expand Up @@ -106,15 +106,16 @@ end
function interpolate_path(path, sys, N, arclength)
s = zeros(N)
for j in 2:N
s[j] = s[j - 1] + anorm(path[:, j] - path[:, j - 1], sys.Σ) #! anorm or norm?
s[j] = s[j - 1] + anorm(path[:, j] - path[:, j - 1], covariance_matrix(sys))
#! anorm or norm?
end
s_length = s / s[end] * arclength
interp = ParametricSpline(s_length, path, k = 3)
return reduce(hcat, [interp(x) for x in range(0, arclength, length = N)])
end

"""
heymann_vandeneijnden_step(sys::StochSystem, path, N, L; kwargs...)
heymann_vandeneijnden_step(sys::CoupledSDEs, path, N, L; kwargs...)

Solves eq. (6) of Ref.[^1] for an initial `path` with `N` points and arclength `L`.

Expand All @@ -126,12 +127,12 @@ Solves eq. (6) of Ref.[^1] for an initial `path` with `N` points and arclength `

[^1]: [Heymann and Vanden-Eijnden, PRL (2008)](https://link.aps.org/doi/10.1103/PhysRevLett.100.140601)
"""
function heymann_vandeneijnden_step(sys::StochSystem, path, N, L;
function heymann_vandeneijnden_step(sys::CoupledSDEs, path, N, L;
tau = 0.1,
diff_order = 4,
cov_inv = nothing)

(cov_inv == nothing) ? A = inv(sys) : A = cov_inv
(cov_inv == nothing) ? A = inv(covariance_matrix(sys)) : A = cov_inv

dx = L / (N - 1)
update = zeros(size(path))
Expand Down
19 changes: 15 additions & 4 deletions test/largedeviations/MAM.jl
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
@testset "OuMAM" begin
ou = StochSystem((u, p, t) -> -u, [], [1.0], 1.0)
@testset "MAM FitzHugh-Nagumo" begin
p = [0.1,3,1,1,1,0]
fhn = CoupledSDEs(fitzhugh_nagumo, diag_noise_funtion(0.1), zeros(2), p)
x_i = SA[sqrt(2/3), sqrt(2/27)]
x_f = SA[0.001, 0.0]
N, T = 200, 2.0
inst = min_action_method(fhn, x_i, x_f, N, T; maxiter=100, save_info=false)
S = fw_action(fhn, inst, range(0., T, length=N))
@test isapprox(S, 0.18, atol=0.01)
end

@testset "MAM Ornstein-Uhlenbeck" begin
ou = CoupledSDEs((u, p, t) -> -u, diag_noise_funtion(0.18), SA[1.0])
x0 = -1
xT = 2.0
T = 10.0
N = 51
t = range(0, T, N)
inst_mam = min_action_method(ou, [x0], [xT], N, T, verbose = false, save_info = false)
inst_mam = min_action_method(ou, SA[x0], SA[xT], N, T, verbose = false, save_info = false)
inst_sol = ((xT - x0 * exp(-T)) * exp.(t) .+ (x0 * exp(T) - xT) * exp.(-t)) /
(exp(T) - exp(-T))
@test maximum(abs.(inst_mam' .- inst_sol)) < 0.1
end
end
48 changes: 48 additions & 0 deletions test/largedeviations/action_fhn.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using Random
Random.seed!(SEED)

# System setup - FitzHugh-Nagumo model
p = [1.0, 3.0, 1.0, 1.0, 1.0, 0.0] # Parameters (ϵ, β, α, γ, κ, I)
σ = 0.215 # noise strength
sys = CoupledSDEs(fitzhugh_nagumo, diag_noise_funtion(σ), zeros(2), p, seed = SEED)
A = inv(CT.covariance_matrix(sys))
T, N = 2.0, 100
x_i = SA[sqrt(2/3), sqrt(2/27)]
x_f = SA[0.0, 0.0]
path = reduce(hcat, range(x_i, x_f, length=N))
time = range(0.0, T, length=N)

@testset "fw_action" begin
S = fw_action(sys, path, time)
@test isapprox(S, 0.32, atol=0.01)
end

# Test om_action function
@testset "om_action" begin
sigma = 0.2
S = om_action(sys, path, time, sigma)
@test isapprox(S, 0.26, atol=0.01)
end

# Test action function
@testset "action" begin
@test action(sys, path, time, "FW") == fw_action(sys, path, time)
end

# Test geometric_action function
@testset "geometric_action" begin
S = geometric_action(sys, path)
@test isapprox(S, 0.23, atol=0.01)
end

# Test fw_integrand function
@testset "fw_integrand" begin
integrand = fw_integrand(sys, path, time, A)
@test minimum(integrand) > 0.18
end

# Test div_drift function
@testset "div_drift" begin
@test div_drift(sys, zeros(2)) == -2.0
@test div_drift(sys, x_i) == -4.0
end
14 changes: 14 additions & 0 deletions test/largedeviations/gMAM.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
@testset "gMAM FitzHugh-Nagumo" begin
p = [0.1,3,1,1,1,0]
fhn = CoupledSDEs(fitzhugh_nagumo, diag_noise_funtion(0.1), zeros(2), p)
x_i = SA[sqrt(2/3), sqrt(2/27)]
x_f = SA[0.001, 0.0]
N = 100
res = geometric_min_action_method(fhn, x_i, x_f; N=75, maxiter=200)
S = geometric_action(fhn, res[1][end])
@test isapprox(S, 0.18, atol=0.01)
end


"""
@testset "gMAM Meier Stein" begin
function meier_stein(u, p, t) # out-of-place
x, y = u
Expand Down Expand Up @@ -36,3 +49,4 @@
# @test all(isapprox.(action_val, 0.3375, atol = 1e-3))
end # HeymannVandenEijnden
end # gMAM Meier Stein
"""
9 changes: 5 additions & 4 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ end
# include("stochsystem.jl")
# end

# @testset "Large Deviations" begin
# include("largedeviations/MAM.jl")
# include("largedeviations/gMAM.jl")
# end
@testset "Large Deviations" begin
include("largedeviations/action_fhn.jl")
include("largedeviations/MAM.jl")
include("largedeviations/gMAM.jl")
end

# @testset "utilities" begin
# include("utils.jl")
Expand Down