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

Dynamical integrators #545

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/StochasticDiffEq.jl
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ end

export TauLeaping, CaoTauLeaping

export BAOAB
export BAOAB, ABOBA, OBABO

export StochasticDiffEqRODEAlgorithm, StochasticDiffEqRODEAdaptiveAlgorithm,
StochasticDiffEqRODECompositeAlgorithm
Expand Down
5 changes: 5 additions & 0 deletions src/alg_utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ alg_order(alg::TauLeaping) = 1 // 1
alg_order(alg::CaoTauLeaping) = 1 // 1

alg_order(alg::BAOAB) = 1 // 1
alg_order(alg::ABOBA) = 2 // 1
alg_order(alg::OBABO) = 2 // 1

alg_order(alg::SKenCarp) = 2 // 1
alg_order(alg::Union{StochasticDiffEqCompositeAlgorithm,StochasticDiffEqRODECompositeAlgorithm}) = maximum(alg_order.(alg.algs))
Expand Down Expand Up @@ -225,6 +227,8 @@ alg_compatible(prob::DiffEqBase.AbstractSDEProblem, alg::IIF1M) = true
alg_compatible(prob::DiffEqBase.AbstractSDEProblem, alg::IIF2M) = true
alg_compatible(prob::DiffEqBase.AbstractSDEProblem, alg::Union{StochasticDiffEqCompositeAlgorithm,StochasticDiffEqRODECompositeAlgorithm}) = max((alg_compatible(prob, a) for a in alg.algs)...)
alg_compatible(prob::DiffEqBase.AbstractSDEProblem, alg::BAOAB) = is_diagonal_noise(prob)
alg_compatible(prob::DiffEqBase.AbstractSDEProblem, alg::ABOBA) = is_diagonal_noise(prob)
alg_compatible(prob::DiffEqBase.AbstractSDEProblem, alg::OBABO) = is_diagonal_noise(prob)

function alg_compatible(prob::JumpProblem, alg::Union{StochasticDiffEqJumpAdaptiveAlgorithm,StochasticDiffEqJumpAlgorithm})
prob.prob isa DiscreteProblem
Expand Down Expand Up @@ -259,6 +263,7 @@ alg_needs_extra_process(alg::RS2) = true
alg_needs_extra_process(alg::PL1WM) = true
alg_needs_extra_process(alg::NON) = true
alg_needs_extra_process(alg::NON2) = true
alg_needs_extra_process(alg::OBABO) = true

OrdinaryDiffEq._alg_autodiff(alg::StochasticDiffEqNewtonAlgorithm{CS,AD,FDT,ST,CJ,Controller}) where {CS,AD,FDT,ST,CJ,Controller} = Val{AD}()
OrdinaryDiffEq._alg_autodiff(alg::StochasticDiffEqNewtonAdaptiveAlgorithm{CS,AD,FDT,ST,CJ,Controller}) where {CS,AD,FDT,ST,CJ,Controller} = Val{AD}()
Expand Down
34 changes: 33 additions & 1 deletion src/algorithms.jl
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ Defaults to solving the Ito problem, but RKMilCommute(interpretation=:Stratonovi
Uses a 1.5/2.0 error estimate for adaptive time stepping.
Default: ii_approx=IICommutative() does not approximate the Levy area.
"""
struct RKMilCommute{T} <: StochasticDiffEqAdaptiveAlgorithm
struct RKMilCommute{T} <: StochasticDiffEqAdaptiveAlgorithm
interpretation::Symbol
ii_approx::T
end
Expand Down Expand Up @@ -869,3 +869,35 @@ struct BAOAB{T} <: StochasticDiffEqAlgorithm
scale_noise::Bool
end
BAOAB(;gamma=1.0, scale_noise=true) = BAOAB(gamma, scale_noise)


@doc raw"""
Leimkuhler B., Matthews C., Robust and efficient configurational molecular sampling via
Langevin dynamics, J. Chem. Phys. 138, 174102 (2013)
DOI:10.1063/1.4802990

```math
du = vdt \\
dv = f(v,u) dt - \gamma v dt + g(u) \sqrt{2\gamma} dW
```
"""
struct ABOBA{T} <: StochasticDiffEqAlgorithm
Copy link
Member

Choose a reason for hiding this comment

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

maybe add a docstring that contains the SDE form:
Screen Shot 2023-09-19 at 11 44 02 AM

(or to the SDE solver docs https://docs.sciml.ai/DiffEqDocs/stable/solvers/sde_solve/ given that it doesn't match our common diagonal/non-diagonal noise classification exactly?)

Copy link
Member

Choose a reason for hiding this comment

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

Or maybe it needs a different problem type?

Copy link
Author

Choose a reason for hiding this comment

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

There is already the DynamicalSDEProblem (was introduced by the previous implementation of BAOAB) that is supposed to be solved by those integrators

Copy link
Author

Choose a reason for hiding this comment

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

Should I add some alg_compatible() functions to allow only DynamicalSDEProblem to be solved by Dynamical integrators?

Copy link
Member

Choose a reason for hiding this comment

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

yes that would be helpful in order to gate it to the right form.

Copy link
Author

Choose a reason for hiding this comment

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

I just realize that the DynamicalSDEProblem constructor actually return a SDEProblem so alg_comptable functions won't be useful here

Copy link
Member

Choose a reason for hiding this comment

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

But it can dispatch on prob.problem_type

Copy link
Member

Choose a reason for hiding this comment

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

yeah I think we should use DynamicalSDEProblem and it's a good idea to use alg_compatible to make sure that only BAOAB, ABOBA, etc. can be used to solve it.

Copy link
Author

Choose a reason for hiding this comment

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

But it can dispatch on prob.problem_type

Not sure to understand, SDEProblem does not have a field problem_type.

gamma::T
scale_noise::Bool
end
ABOBA(;gamma=1.0, scale_noise=true) = ABOBA(gamma, scale_noise)

@doc raw"""
Leimkuhler B., Matthews C., Molecular Dynamics With Deterministic and Stochastic Numerical Methods,Interdisciplinary Applied Mathematics; Springer International Publishing: Cham, 2015; Vol. 39
DOI:10.1007/978-3-319-16375-8

```math
du = vdt \\
dv = f(v,u) dt - \gamma v dt + g(u) \sqrt{2\gamma} dW
```
"""
struct OBABO{T} <: StochasticDiffEqAlgorithm
gamma::T
scale_noise::Bool
end
OBABO(;gamma=1.0, scale_noise=true) = OBABO(gamma, scale_noise)
176 changes: 161 additions & 15 deletions src/caches/dynamical_caches.jl
Original file line number Diff line number Diff line change
@@ -1,42 +1,188 @@
abstract type StochasticDynamicalEqConstantCache <: StochasticDiffEqConstantCache end # Pourquoi faire ça, Si c'est pour avoir une seul function de check dans initialize!
abstract type StochasticDynamicalEqMutableCache <: StochasticDiffEqMutableCache end

mutable struct BAOABConstantCache{uType,uEltypeNoUnits} <: StochasticDiffEqConstantCache

mutable struct BAOABConstantCache{uType,uEltypeNoUnits,uCoeffType, uCoeffMType} <: StochasticDynamicalEqConstantCache
k::uType
half::uEltypeNoUnits
c1::uEltypeNoUnits
c2::uEltypeNoUnits
c2::uCoeffType
σ::uCoeffMType
end
@cache struct BAOABCache{uType,uEltypeNoUnits,rateNoiseType,uTypeCombined} <: StochasticDiffEqMutableCache
@cache struct BAOABCache{uType,uEltypeNoUnits,rateNoiseType,uCoeffType, uCoeffMType,uTypeCombined} <: StochasticDynamicalEqMutableCache
utmp::uType
dumid::uType
dutmp::uType
dunoise::uType
k::uType
gtmp::uType
noise::rateNoiseType
gtmp::rateNoiseType
noise::uType
half::uEltypeNoUnits
c1::uEltypeNoUnits
c2::uEltypeNoUnits
c2::uCoeffType
σ::uCoeffMType
tmp::uTypeCombined
end

function alg_cache(alg::BAOAB,prob,u,ΔW,ΔZ,p,rate_prototype,noise_rate_prototype,jump_rate_prototype,::Type{uEltypeNoUnits},::Type{uBottomEltypeNoUnits},::Type{tTypeNoUnits},uprev,f,t,dt,::Type{Val{false}}) where {uEltypeNoUnits,uBottomEltypeNoUnits,tTypeNoUnits}
k = zero(rate_prototype.x[1])
c1 = exp(-alg.gamma*dt)
c2 = sqrt(1 - alg.scale_noise*c1^2) # if scale_noise == false, c2 = 1
BAOABConstantCache(k, uEltypeNoUnits(1//2), uEltypeNoUnits(c1), uEltypeNoUnits(c2))
if typeof(alg.gamma) <: AbstractMatrix
c2 = exp(-alg.gamma*dt)
σ = cholesky(I - alg.scale_noise*c2*transpose(c2)).U# if scale_noise == false, c2 = 1
else
c2 = exp.(-alg.gamma*dt)
σ = sqrt.(1 .- alg.scale_noise*c2.^2)# if scale_noise == false, c2 = 1
end
BAOABConstantCache(k, uEltypeNoUnits(1//2),c2, c2)
end

function alg_cache(alg::BAOAB,prob,u,ΔW,ΔZ,p,rate_prototype,noise_rate_prototype,jump_rate_prototype,::Type{uEltypeNoUnits},::Type{uBottomEltypeNoUnits},::Type{tTypeNoUnits},uprev,f,t,dt,::Type{Val{true}}) where {uEltypeNoUnits,uBottomEltypeNoUnits,tTypeNoUnits}
dumid = zero(u.x[1])
dutmp = zero(u.x[1])
dunoise = zero(u.x[1])
utmp = zero(u.x[2])
k = zero(rate_prototype.x[1])

gtmp = zero(noise_rate_prototype)
noise = zero(rate_prototype.x[1])

half = uEltypeNoUnits(1//2)

if typeof(alg.gamma) <: AbstractMatrix
c2 = exp(-alg.gamma*dt)
σ = cholesky(I - alg.scale_noise*c2*transpose(c2)).U# if scale_noise == false, c2 = 1
else
c2 = exp.(-alg.gamma*dt)
σ = sqrt.(1 .- alg.scale_noise*c2.^2)# if scale_noise == false, c2 = 1
end

tmp = zero(u)

BAOABCache(utmp, dumid, dutmp, dunoise, k, gtmp, noise, half, c2, σ, tmp)
end



mutable struct ABOBAConstantCache{uType,uEltypeNoUnits, uCoeffType, uCoeffMType} <: StochasticDynamicalEqConstantCache
k::uType
half::uEltypeNoUnits
c2::uCoeffType
σ::uCoeffMType
end
@cache struct ABOBACache{uType,uEltypeNoUnits,rateNoiseType,uCoeffType, uCoeffMType,uTypeCombined} <: StochasticDynamicalEqMutableCache
utmp::uType
dumid::uType
dutmp::uType
dunoise::uType
k::uType
gtmp::rateNoiseType
noise::uType
half::uEltypeNoUnits
c2::uCoeffType
σ::uCoeffMType
tmp::uTypeCombined
end

function alg_cache(alg::ABOBA,prob,u,ΔW,ΔZ,p,rate_prototype,noise_rate_prototype,jump_rate_prototype,::Type{uEltypeNoUnits},::Type{uBottomEltypeNoUnits},::Type{tTypeNoUnits},uprev,f,t,dt,::Type{Val{false}}) where {uEltypeNoUnits,uBottomEltypeNoUnits,tTypeNoUnits}
k = zero(rate_prototype.x[1])

if typeof(alg.gamma) <: AbstractMatrix
c2 = exp(-alg.gamma*dt)
σ = cholesky(I - alg.scale_noise*c2*transpose(c2)).U
else
c2 = exp.(-alg.gamma*dt)
σ = sqrt.(1 .- alg.scale_noise*c2.^2)
end
# if scale_noise == false, c2 = 1
ABOBAConstantCache(k, uEltypeNoUnits(1//2), c2, σ)
end

function alg_cache(alg::ABOBA,prob,u,ΔW,ΔZ,p,rate_prototype, noise_rate_prototype,jump_rate_prototype,::Type{uEltypeNoUnits},::Type{uBottomEltypeNoUnits},::Type{tTypeNoUnits},uprev,f,t,dt,::Type{Val{true}}) where {uEltypeNoUnits,uBottomEltypeNoUnits,tTypeNoUnits}
dutmp = zero(u.x[1])
dumid = zero(u.x[1])
dunoise = zero(u.x[1])
utmp = zero(u.x[2])
k = zero(rate_prototype.x[1])

gtmp = zero(rate_prototype.x[1])
gtmp = zero(noise_rate_prototype)
noise = zero(rate_prototype.x[1])

half = uEltypeNoUnits(1//2)
c1 = exp(-alg.gamma*dt)
c2 = sqrt(1 - alg.scale_noise*c1^2) # if scale_noise == false, c2 = 1

if typeof(alg.gamma) <: AbstractMatrix
c2 = exp(-alg.gamma*dt)
σ = cholesky(I - alg.scale_noise*c2*transpose(c2)).U
else
c2 = exp.(-alg.gamma*dt)
σ = sqrt.(1 .- alg.scale_noise*c2.^2)
end

tmp = zero(u)

ABOBACache(utmp, dumid, dutmp, dunoise, k, gtmp, noise, half, c2, σ, tmp)
end




mutable struct OBABOConstantCache{uType,rateNoiseType, uEltypeNoUnits, uCoeffType, uCoeffMType} <: StochasticDynamicalEqConstantCache
k::uType
gt::rateNoiseType
half::uEltypeNoUnits
c2::uCoeffType
σ::uCoeffMType
end

@cache struct OBABOCache{uType,uEltypeNoUnits,rateNoiseType,uCoeffType, uCoeffMType,uTypeCombined} <: StochasticDynamicalEqMutableCache
utmp::uType
dumid::uType
dutmp::uType
dunoise::uType
k::uType
gtmp::rateNoiseType
noise::uType
half::uEltypeNoUnits
c2::uCoeffType
σ::uCoeffMType
tmp::uTypeCombined
end

function alg_cache(alg::OBABO,prob,u,ΔW,ΔZ,p,rate_prototype,noise_rate_prototype,jump_rate_prototype,::Type{uEltypeNoUnits},::Type{uBottomEltypeNoUnits},::Type{tTypeNoUnits},uprev,f,t,dt,::Type{Val{false}}) where {uEltypeNoUnits,uBottomEltypeNoUnits,tTypeNoUnits}
k = zero(rate_prototype.x[1])
gt = zero(noise_rate_prototype)
half=uEltypeNoUnits(1//2)

if typeof(alg.gamma) <: AbstractMatrix
c2 = exp(-alg.gamma*half*dt)
σ = cholesky(I - alg.scale_noise*c2*transpose(c2)).U
else
c2 = exp.(-alg.gamma*half*dt)
σ = sqrt.(1 .- alg.scale_noise*c2.^2)
end
# if scale_noise == false, c2 = 1
OBABOConstantCache(k, gt, half, c2, σ)
end

function alg_cache(alg::OBABO,prob,u,ΔW,ΔZ,p,rate_prototype, noise_rate_prototype,jump_rate_prototype,::Type{uEltypeNoUnits},::Type{uBottomEltypeNoUnits},::Type{tTypeNoUnits},uprev,f,t,dt,::Type{Val{true}}) where {uEltypeNoUnits,uBottomEltypeNoUnits,tTypeNoUnits}
dutmp = zero(u.x[1])
dumid = zero(u.x[1])
dunoise = zero(u.x[1])
utmp = zero(u.x[2])
k = zero(rate_prototype.x[1])

gtmp = zero(noise_rate_prototype)
noise = zero(rate_prototype.x[1])


half = uEltypeNoUnits(1//2)

if typeof(alg.gamma) <: AbstractMatrix
c2 = exp(-alg.gamma*half*dt)
σ = cholesky(I - alg.scale_noise*c2*transpose(c2)).U
else
c2 = exp.(-alg.gamma*half*dt)
σ = sqrt.(1 .- alg.scale_noise*c2.^2)
end

tmp = zero(u)

BAOABCache(utmp, dutmp, k, gtmp, noise, half, uEltypeNoUnits(c1), uEltypeNoUnits(c2), tmp)
OBABOCache(utmp, dumid, dutmp, dunoise, k, gtmp, noise, half, c2, σ, tmp)
end
Loading