-
-
Notifications
You must be signed in to change notification settings - Fork 70
Dynamical integrators #545
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
base: master
Are you sure you want to change the base?
Changes from 11 commits
a6347c4
d078c4c
18c09a2
e10ebfa
6423413
52beb4c
f43249b
9a80b47
508edf7
f836738
9783fbd
f03a017
84f2e9e
cb25c7c
3ac8f46
0b3baf1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 | ||
c1::uCoeffType | ||
c2::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 | ||
c1::uCoeffType | ||
c2::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 | ||
c1 = exp(-alg.gamma*dt) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are chosen as constant for efficiency in the constant dt case, as it is the most common case. Should I pass them as function anyway? Knowing that I have as plan for the future to implement the case of gamma being a function of the current state, in which case c1 and c2 would be function of both dt and gamma. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Writing "fixed time-stepping only" might not be sufficient because I think we typically only distinguish between adaptively chosen time steps and fixed time-stepping schemes. In particular, there could be situations where one has a concrete idea when It also seems relatively cheap to compute I think
is another very good reason to do it in this PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Generally symplectic integrators lose the symplectic property if you adapt the time steps. Even the ODE solver ones are only fixed time step. But indeed we might as well make it safe for future work. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the efficiency question: If you have a matricial gamma, if you have to do a matrix exponential and a chlolesky at each timestep you increase the computation time by a few percent. At least on my case, the typical use case of this type of dynamics is to infers it from larger system (molecular dynamics) that are too expensive to run for long trajectories and run the inferred dynamics for very long times, so even a few percent increase of runtime could lead to extra hours of computation. But ok, I will implement those coefficients as function, I could always add some caching behavior latter one if this becomes a performance issue. To be honest, I have never really thought to the possibility of time-stepping (losing the symplectic property is certainly an issue in my case), thanks for the reference, I will look at it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh, then it might also be enough to check this and throw an error (if nobody would ever want to/should change it)? I think
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I can see this point. But the cholesky/exponential also needs to be recomputed for fixed-time steps when gamma depends on the state, right? (so then it only hurts a few percent in the case of large matrix-valued gamma and fixed dt -- I have no intuition if that's a common use case.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That make sense, I will implement those as function, will do it this week. |
||
c2 = cholesky(I - alg.scale_noise*c1*transpose(c1)).U# if scale_noise == false, c2 = 1 | ||
else | ||
c1 = exp.(-alg.gamma*dt) | ||
c2 = sqrt.(1 .- alg.scale_noise*c1.^2)# if scale_noise == false, c2 = 1 | ||
end | ||
BAOABConstantCache(k, uEltypeNoUnits(1//2),c1, 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 | ||
c1 = exp(-alg.gamma*dt) | ||
c2 = cholesky(I - alg.scale_noise*c1*transpose(c1)).U# if scale_noise == false, c2 = 1 | ||
else | ||
c1 = exp.(-alg.gamma*dt) | ||
c2 = sqrt.(1 .- alg.scale_noise*c1.^2)# if scale_noise == false, c2 = 1 | ||
end | ||
|
||
tmp = zero(u) | ||
|
||
BAOABCache(utmp, dumid, dutmp, dunoise, k, gtmp, noise, half, c1, c2, tmp) | ||
end | ||
|
||
|
||
|
||
mutable struct ABOBAConstantCache{uType,uEltypeNoUnits, uCoeffType, uCoeffMType} <: StochasticDynamicalEqConstantCache | ||
k::uType | ||
half::uEltypeNoUnits | ||
c₂::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 | ||
c₂::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 | ||
c₂ = exp(-alg.gamma*dt) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not label them c1 and c2 as in the other methods? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good points, no particular reason, I will change this. The coefficients will be c2 for the friction term and σ for the diffusion term |
||
σ = cholesky(I - alg.scale_noise*c₂*transpose(c₂)).U | ||
else | ||
c₂ = exp.(-alg.gamma*dt) | ||
σ = sqrt.(1 .- alg.scale_noise*c₂.^2) | ||
end | ||
# if scale_noise == false, c2 = 1 | ||
ABOBAConstantCache(k, uEltypeNoUnits(1//2), c₂, σ) | ||
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 | ||
c₂ = exp(-alg.gamma*dt) | ||
σ = cholesky(I - alg.scale_noise*c₂*transpose(c₂)).U | ||
else | ||
c₂ = exp.(-alg.gamma*dt) | ||
σ = sqrt.(1 .- alg.scale_noise*c₂.^2) | ||
end | ||
|
||
tmp = zero(u) | ||
|
||
ABOBACache(utmp, dumid, dutmp, dunoise, k, gtmp, noise, half, c₂, σ, tmp) | ||
end | ||
|
||
|
||
|
||
|
||
mutable struct OBABOConstantCache{uType,rateNoiseType, uEltypeNoUnits, uCoeffType, uCoeffMType} <: StochasticDynamicalEqConstantCache | ||
k::uType | ||
gt::rateNoiseType | ||
half::uEltypeNoUnits | ||
c₂::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 | ||
c₂::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 | ||
c₂ = exp(-alg.gamma*half*dt) | ||
σ = cholesky(I - alg.scale_noise*c₂*transpose(c₂)).U | ||
frankschae marked this conversation as resolved.
Show resolved
Hide resolved
|
||
else | ||
c₂ = exp.(-alg.gamma*half*dt) | ||
σ = sqrt.(1 .- alg.scale_noise*c₂.^2) | ||
end | ||
# if scale_noise == false, c2 = 1 | ||
OBABOConstantCache(k, gt, half, c₂, σ) | ||
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 | ||
c₂ = exp(-alg.gamma*half*dt) | ||
σ = cholesky(I - alg.scale_noise*c₂*transpose(c₂)).U | ||
else | ||
c₂ = exp.(-alg.gamma*half*dt) | ||
σ = sqrt.(1 .- alg.scale_noise*c₂.^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, c₂, σ, tmp) | ||
end |
There was a problem hiding this comment.
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:

(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?)
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 usealg_compatible
to make sure that only BAOAB, ABOBA, etc. can be used to solve it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure to understand, SDEProblem does not have a field problem_type.