Skip to content
Draft
Show file tree
Hide file tree
Changes from 123 commits
Commits
Show all changes
183 commits
Select commit Hold shift + click to select a range
e58aeab
added first draft for RateSystem
raphael-roemer Oct 8, 2024
c7d44b1
Merge branch 'main' into RateSystem
oameye Oct 10, 2024
c71f1b4
Merge branch 'main' into RateSystem
reykboerner Oct 16, 2024
525c6a1
incorporated RateSystem file
reykboerner Oct 16, 2024
4e8366c
small typo fix
reykboerner Oct 16, 2024
727740f
undid wrong fix
reykboerner Oct 16, 2024
3acaddb
Removed RateSystem Lines
raphael-roemer Mar 19, 2025
cae20d6
Merge branch 'main' into RateSystem
raphael-roemer Mar 19, 2025
d32c1c5
Return RateSystem changes
raphael-roemer Mar 19, 2025
5ee2ed9
Again delete Rate stuff
raphael-roemer Mar 19, 2025
444eb72
Include Rate stuff again
raphael-roemer Mar 19, 2025
b8f145a
added new RateSystem Version
raphael-roemer Mar 19, 2025
f8230d7
Compressed RateSystemDraft2.jl script, created RateSystemTestsDraft.j…
ryandeeley Mar 19, 2025
320fa82
Corrected src/CriticalTransitions.jl file.
ryandeeley Mar 19, 2025
189f62b
Moved contents of dev/ file to test/ file and reset src/CriticalTrans…
ryandeeley Mar 19, 2025
bba545b
Collected all old and new RateSystem scripts into the test/ratesystem…
ryandeeley Mar 19, 2025
dcaf8aa
yep
ryandeeley Mar 20, 2025
650b6fa
Added PolynomialRoots to dependencies.
ryandeeley Mar 20, 2025
f6d97e3
See previous.
ryandeeley Mar 20, 2025
3febe82
See previous again.
ryandeeley Mar 20, 2025
8e0a7b3
Exported truscottbrindley-mod-gen-det function.
ryandeeley Mar 20, 2025
e2f006e
Removed CoupledODEs functionality from systems/ folder.
ryandeeley Mar 20, 2025
74ba1ae
Removed the system I added.
ryandeeley Mar 20, 2025
5786d48
Merge branch 'main' into RateSystem
reykboerner Jun 3, 2025
6e57725
Merge branch 'main' into RateSystem
oameye Jun 13, 2025
bdd468e
Starting a RateSystem Example
raphael-roemer Jun 28, 2025
020b80f
work on example of RateSystem
raphael-roemer Jun 29, 2025
894945b
work on example of RateSystem
raphael-roemer Jun 29, 2025
af0efc4
work on example of RateSystem
raphael-roemer Jun 29, 2025
9e1f68d
work on example of RateSystem
raphael-roemer Jun 29, 2025
d3c9ece
added documentation in RateSystem file
raphael-roemer Jun 29, 2025
12d4a01
Merge branch 'main' into RateSystem
raphael-roemer Jun 30, 2025
e3d2156
corrected mistake in RateSystem file
raphael-roemer Jun 30, 2025
90f4228
improved documentation of test2
raphael-roemer Jun 30, 2025
1703378
work on the example for RateSystem
raphael-roemer Jun 30, 2025
2a5619e
added codes for the RateSystem example
raphael-roemer Jun 30, 2025
260e18f
correction in MaierStein example
raphael-roemer Jun 30, 2025
64d775c
small corrections in Test and RateSystemDraft
raphael-roemer Jul 22, 2025
cdd41f4
addition to RateSystem example
raphael-roemer Jul 22, 2025
cbe4abe
additions to RateSystem example
raphael-roemer Jul 22, 2025
6ab08ec
additions to RateSystem example
raphael-roemer Jul 22, 2025
c47fdd4
correction in RateSystem example
raphael-roemer Jul 22, 2025
5266412
correction in RateSystem.jl
raphael-roemer Jul 22, 2025
12ab98f
added RateSystem.md to pages.jl
raphael-roemer Jul 23, 2025
f13cd91
Merge branch 'main' into RateSystem
reykboerner Jul 24, 2025
e9f90c8
moved RateSystem source code to src
reykboerner Jul 24, 2025
14a97d6
applied formatter, fixed typo, disabled spell check until PR review
reykboerner Jul 24, 2025
f8d73ef
remove CairoMakie dep
reykboerner Jul 25, 2025
cf5afb2
added RateSystem test
reykboerner Jul 25, 2025
e7f8580
small fix
reykboerner Jul 25, 2025
063b84b
applied Formatter
reykboerner Jul 25, 2025
1feff1a
small edits in docs and added docstring drafts
reykboerner Jul 25, 2025
4e0ab57
deleted test/ratesystem/RateSystem.jl
raphael-roemer Jul 28, 2025
41128cc
deleted test/ratesystem/RateSystemDraft1.jl and test/ratesystem/RateS…
raphael-roemer Jul 28, 2025
2dcffc8
deleted test/ratesystem
raphael-roemer Jul 28, 2025
00f0ef2
deleted examples/RateSystem.jl
raphael-roemer Jul 28, 2025
729ea5f
expanded documentaation of RateSystem
raphael-roemer Jul 28, 2025
648c863
expanded documentation
raphael-roemer Jul 28, 2025
b147beb
added plot of parameter shift in RateSystem documentation
raphael-roemer Jul 28, 2025
79715af
deleted NLPModelsIpopt from project.toml
raphael-roemer Jul 28, 2025
eb43377
fixed error in Project.toml
raphael-roemer Jul 28, 2025
4cdbd7d
fixed quotation marks in quickstart.md
raphael-roemer Jul 28, 2025
db71cb3
removed the ! from apply_ramping
raphael-roemer Jul 28, 2025
923849d
fixed error in documentation of RateSystem
raphael-roemer Jul 28, 2025
8634b8d
resolving documentation issue with RateProtocol-plot
raphael-roemer Jul 28, 2025
1c0999d
improved documentation of apply_ramping
raphael-roemer Jul 28, 2025
44f11fb
correction in tes of RaateSystem
raphael-roemer Jul 28, 2025
722cc74
corrected typo in RateProtocol docstring
raphael-roemer Jul 29, 2025
345865f
added plot of lambda to example of RateSystem
raphael-roemer Jul 29, 2025
a6e8029
removed unnecessary formatting information and improved beginning of …
raphael-roemer Jul 29, 2025
3c94279
correction in docstring
raphael-roemer Jul 29, 2025
5f1f6bc
recovered docs/Project.toml
reykboerner Jul 29, 2025
ef73286
updated .toml and applied Formatter
reykboerner Jul 29, 2025
5a1ec54
fixed typo in RateSystem.md
raphael-roemer Jul 29, 2025
7d15398
Merge branch 'main' into RateSystem
reykboerner Jul 29, 2025
fe0fc15
enable spell checking again
oameye Jul 30, 2025
c0d6f75
imporved docstring of apply_ramping
raphael-roemer Jul 30, 2025
2cf1029
improved docstring of RateProtocol
raphael-roemer Jul 30, 2025
dc1eda6
imporved docstring of apply_ramping
raphael-roemer Jul 30, 2025
b947592
imporved docstring of apply_ramping
raphael-roemer Jul 30, 2025
745f70c
imporved docstring of apply_ramping
raphael-roemer Jul 30, 2025
11986d4
fixed spelling mistake in RateSystem example
raphael-roemer Jul 30, 2025
ae01765
improved RateSytem Example
raphael-roemer Jul 30, 2025
c0758bf
changed name of R-Tipping documentation page
raphael-roemer Jul 30, 2025
25cdd07
improved RateSytem Example
raphael-roemer Jul 30, 2025
3bedbec
fix spelling
oameye Aug 1, 2025
38cedd7
Merge branch 'main' into RateSystem
oameye Aug 1, 2025
15c3a24
Merge branch 'main' into RateSystem
oameye Aug 2, 2025
4c5b185
Merge branch 'main' into RateSystem
reykboerner Aug 6, 2025
dce3efa
changed t_start,t_end to time_interval
raphael-roemer Aug 20, 2025
59f482b
corrected typo
raphael-roemer Aug 20, 2025
c0a0a3d
corrected typo
raphael-roemer Aug 20, 2025
efbab37
changed how to access the dynamic rule within modified_drift
raphael-roemer Aug 20, 2025
e8bcefb
changed how to access the dynamic rule within apply_ramping
raphael-roemer Aug 20, 2025
535be1e
included referrenced_sciml_prob in exported functions from DynamicalS…
raphael-roemer Aug 20, 2025
2b26698
Merge branch 'main' into RateSystem
raphael-roemer Aug 20, 2025
d5a2a1e
changed back to t_start and t_end to allow compatibility with the R-T…
raphael-roemer Aug 21, 2025
33f2121
adapted docs as well
raphael-roemer Aug 21, 2025
55066e3
adapted test as well
raphael-roemer Aug 21, 2025
3be44f6
correction in test
raphael-roemer Aug 21, 2025
90e2aa8
changed RateProtocol to RateConfig
raphael-roemer Aug 23, 2025
14c2558
changed RateProtocol to RateConfig in .md file
raphael-roemer Aug 23, 2025
22e8f1d
changed p_lambda to p_parameter
raphael-roemer Aug 23, 2025
295cc13
corrected typo
raphael-roemer Aug 23, 2025
82ae326
corrected typo
raphael-roemer Aug 23, 2025
165fa07
corrected typo
raphael-roemer Aug 23, 2025
c0708cf
changed lambda to p throughout
raphael-roemer Aug 23, 2025
176b480
corrected typo
raphael-roemer Aug 23, 2025
176a9a0
corrected typo
raphael-roemer Aug 23, 2025
a94a54e
1st try implementing dt dp setting
raphael-roemer Aug 23, 2025
518f530
changed error in test
raphael-roemer Aug 23, 2025
fb431b6
exported RateConfig
raphael-roemer Aug 23, 2025
0287780
added stretching/compression of ramping given by ramp_t_length
raphael-roemer Aug 23, 2025
684b8e7
change of reference window of ramping function
raphael-roemer Aug 23, 2025
a0e00c3
change of reference window of ramping function
raphael-roemer Aug 23, 2025
ab9df85
changed rp to rc
raphael-roemer Aug 23, 2025
9082622
adapted example in docs to explain dp dt structure
raphael-roemer Aug 23, 2025
02ec326
further adapted example in docs to explain dp dt structure
raphael-roemer Aug 23, 2025
bbd9e3b
corrected typo
raphael-roemer Aug 23, 2025
1126b78
improved example of r-tipping
raphael-roemer Aug 23, 2025
102743b
changed the start and end point conditions to recommendations
raphael-roemer Aug 24, 2025
e5732b2
updated docstrings
raphael-roemer Aug 24, 2025
fb49e96
Implemented changes to the RateSystem.jl source file (from discussion…
ryandeeley Aug 25, 2025
12cdc51
1st and 2ndIteration of RateSystem
raphael-roemer Sep 7, 2025
914a329
Added the third iteration of RateSystem.jl.
ryandeeley Sep 7, 2025
6be39fd
typo corrected
raphael-roemer Sep 7, 2025
8d4175e
typo corrected
raphael-roemer Sep 7, 2025
4970657
typo corrected
raphael-roemer Sep 7, 2025
765252b
typo corrected
raphael-roemer Sep 7, 2025
cf0012c
typo corrected
raphael-roemer Sep 7, 2025
54dc3ba
typo corrected
raphael-roemer Sep 7, 2025
a115f3c
typo corrected
raphael-roemer Sep 7, 2025
a975369
added example CriticalTransitions.jl/examples/RateSys3rdIterTest.jl
raphael-roemer Sep 7, 2025
acc61f6
Updated example test RateSys3rdIterTest.jl and made corrections to Ra…
ryandeeley Sep 7, 2025
39f8e7e
corrected typos
raphael-roemer Sep 8, 2025
22fd45f
corrected typos
raphael-roemer Sep 8, 2025
2aa37fe
added benchmarking in 'examples/RateSys3rdIterTest.jl' to test the sp…
raphael-roemer Sep 8, 2025
8e6a900
corrected error
raphael-roemer Sep 9, 2025
9a3f723
made a deepcop of auto_sys to avoid changing auto_sys
raphael-roemer Sep 9, 2025
ff71166
added docs
raphael-roemer Sep 9, 2025
00ae0c9
added documentation of the example
raphael-roemer Sep 9, 2025
c0e3773
adapted docstrings, updated tests
raphael-roemer Sep 9, 2025
2c48992
corrected docstrings
raphael-roemer Sep 9, 2025
1ce22d0
corrected docstrings
raphael-roemer Sep 9, 2025
b8bd829
corrected docstrings
raphael-roemer Sep 9, 2025
04fad43
improved docs
raphael-roemer Sep 9, 2025
566112a
started changes towards RateSystem interface
reykboerner Sep 24, 2025
3ef9dfe
small addition
reykboerner Sep 24, 2025
179a0a8
Merge branch 'main' into RateSystem
reykboerner Sep 25, 2025
8416059
corrected typo
raphael-roemer Sep 29, 2025
e69cd6c
corrected typo
raphael-roemer Sep 29, 2025
05b5798
corrected typo
raphael-roemer Sep 29, 2025
1efa93c
added example for new RateSystem version
raphael-roemer Sep 29, 2025
06055ec
corrected errors in RateSystem.jl
raphael-roemer Sep 29, 2025
f08cef5
corrected error in RateSystem.jl
raphael-roemer Sep 29, 2025
adccf47
corrected error in RateSystem.jl
raphael-roemer Sep 29, 2025
bcc0922
Added documentation in RateSys4thIter.jl
raphael-roemer Sep 29, 2025
6dfd5fd
Renamed RateSys4thIter.jl to RateSys4thIterTest.jl
raphael-roemer Sep 29, 2025
434a84a
added and expanded docstrings in RateSystem.jl
raphael-roemer Sep 29, 2025
e97ebe0
corrected docstrings in RateSystem.jl
raphael-roemer Sep 29, 2025
d349078
corrected docstrings in RateSystem.jl
raphael-roemer Sep 29, 2025
b6452b5
corrected docstrings in RateSystem.jl
raphael-roemer Sep 29, 2025
ab83fee
corrected docstrings in RateSystem.jl
raphael-roemer Sep 29, 2025
7412b93
corrected docstrings in RateSystem.jl
raphael-roemer Sep 29, 2025
494b130
Added test for new RateSystem setup
raphael-roemer Sep 29, 2025
2fc8e7b
added .md file for current version
raphael-roemer Sep 30, 2025
f987816
added linkcheck_ignore = [..] to make.jl to ignore this broken link f…
raphael-roemer Sep 30, 2025
02a0bcc
trying to fix docs error
raphael-roemer Sep 30, 2025
5500415
trying to fix docs error
raphael-roemer Sep 30, 2025
e2766ea
trying to fix docs error
raphael-roemer Sep 30, 2025
d06dc6d
trying to fix docs error
raphael-roemer Sep 30, 2025
538df9e
fixed docs
raphael-roemer Sep 30, 2025
20e5acc
Merge branch 'main' into RateSystem
reykboerner Sep 30, 2025
e2ea030
format and fix spell check
reykboerner Sep 30, 2025
986bc7c
fix spell check
reykboerner Sep 30, 2025
3da25c0
add :referrenced_sciml_prob to public import exception
oameye Sep 30, 2025
d3a5d98
update benchmarks to use benchamrtools
Datseris Oct 8, 2025
6156627
removed placeholder reference
reykboerner Oct 8, 2025
75d493b
replace 'section_start/end' fields with 'interval' tuple
reykboerner Oct 8, 2025
8527d7f
work on making RateSystem a proper ContinuousTimeDynamicalSystem subtype
reykboerner Oct 8, 2025
1e50aaa
removed outdated RateSystem files
reykboerner Oct 8, 2025
5031bb1
format
reykboerner Oct 8, 2025
9500149
remove copied CoupledODEs source code
reykboerner Oct 10, 2025
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 Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,4 @@ julia = "1.10"

[extras]
Attractors = "f3fd9213-ca85-4dba-9dfd-7fc91308fec7"
ChaosTools = "608a59af-f2a3-5ad4-90b4-758bdf3122a7"
ChaosTools = "608a59af-f2a3-5ad4-90b4-758bdf3122a7"
2 changes: 1 addition & 1 deletion docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
StochasticDiffEq = "789caeaf-c7a9-5a7d-9973-96adeb23e2a0"

[compat]
Documenter = "^1.4.1"
Documenter = "^1.4.1"
1 change: 1 addition & 0 deletions docs/pages.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pages = [
"Simple gMAM: Kerr Parametric Oscillator" => "examples/sgMAM_KPO.md",
"Transition Path Theory: Finite element method" => "examples/transition_path_theory_double_well.md",
"Minimal action method: Optimal Control problem" => "examples/OC_mam.md",
"Studying R-Tipping" => "examples/RateSystem.md",
],
"Manual" => Any[
"Define your system" => "man/CoupledSDEs.md",
Expand Down
101 changes: 101 additions & 0 deletions docs/src/examples/RateSystem.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Studying R-Tipping

Let us explore a simple prototypical example of how to use the R-tipping functionality of this package.
Copy link
Member

Choose a reason for hiding this comment

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

R-tipping isn't defined anywhere until here. Probably best to call this "rate dependent tipping".

On a side-note: there is no educational resources (to my knowledge) that properly teaches R-tipping to a non-PhD. The best attempt is a paper from Ritchie et al 2023, but it is still advanced (research article). I am currently working on one which will come in v2 of my textbook. I will try to upload some notes on GitHub in the meantime to cite here.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I also find Wieczorek et al. 2023 pretty good and understandable

Copy link
Collaborator

Choose a reason for hiding this comment

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

We will introduce R-tipping more high-level in the docs (see https://juliadynamics.github.io/CriticalTransitions.jl/dev/man/CoupledSDEs/)

We start with defining an autonomous deterministic dynamical system (i.e. a `CoupledODEs`). Then, we define a time-dependent forcing protocol called `RateConfig`, describing how the parameters of the previously defined autonomous `CoupledODEs` will be changed over time. For times `t` smaller than the time `t_start`, the system is autonomous, then non-autonomous for `t_start < t < t_start + ramp_t_length` with the paramter ramping given by the `RateConfig` and for `t > t_start + ramp_t_length` the system is autonomous again. This setting is a widely used and convenient for studying R-tipping.

We first consider the following simple one-dimensional autonomous system with one attractor, given by the ordinary differential equation:
```math
\begin{aligned}
\dot{x} &= (x+p)^2 - 1
\end{aligned}
```
The parameter ``p`` shifts the location of the extrema of the drift field.
We implement this system as follows:

```@example RateSystem
using CriticalTransitions
using CairoMakie
function f(u,p,t) # out-of-place
x = u[1]
dx = (x+p[1])^2 - 1
return SVector{1}(dx)
end
x0 = [-1.]
auto_sys = CoupledODEs(f,x0,[0.0]);
```

## Applying the parameter ramping

Now, we want to explore a non-autonomous version of the system by applying a parameter ramping.
As discussed, we consider a setting where in the past and in the future the system is autnonomous and in between there is a non-autonomous period `[t_start, t_start+ramp_t_length]` with a time-dependent parameter ramping given by the function ``p(t)``. Choosing different values of the parameter `ramp_t_length` allows us to vary the speed of the parameter ramping.

We start by defining the function `p(p_parameters, t)`:
```@example RateSystem
function p(p_parameters, t)
p_max = p_parameters[1]
p_ = (p_max/2)*(tanh(p_max*t/2)+1)
return SVector{1}(p_)
end
Copy link
Member

Choose a reason for hiding this comment

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

I don't agree with this design. I think the function p should not have parameters. It should just be p(t). Also, we should name it something else, as it missleadingly represents the universal symbol for parameters, even though it isn't a parameter at all. It is just a profile. We should name it profile(t).

Copy link
Member

Choose a reason for hiding this comment

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

What's the reason for the parameters? It defnitely isn't to control the rate/steepness of the profile, because this is controlled externally with the dp, dt arguments.

p_max = 1.0
p_parameters = [p_max] # parameter of the function p
```


We plot the function `p(p_parameters, t)`
```@example RateSystem
p_plotvals = [p(p_parameters, t)[1] for t in -10.0:0.1:10.0]
figp = Figure(); axsp = Axis(figp[1,1],xlabel="t",ylabel=L"p")
lines!(axsp,-10.0:0.1:10.0,p_plotvals,linewidth=2,label=L"p(p_{parameters}, t)")
axislegend(axsp,position=:rc,labelsize=10)
figp
```
Note that this function fulfills
```math
\begin{aligned}
p(t=-10)& =0 \ and \ p(t=10)=1.
\end{aligned}
```
We recommend this to be fulfilled for any ramping function to use the functionality of this package.
Copy link
Member

Choose a reason for hiding this comment

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

Why? It doens't matter at all as our transformation always casts the function to this form anyways.



Now, we define a `RateConfig`, which contains all the information to apply the parameter ramping given by
`p(p_parameters,t)` to the `auto_sys` during `[t_start, t_start+ramp_t_length]`:

```@example RateSystem
t_start = -10 # start time of non-autonomous part
ramp_t_length = 5 # duration of non-autonomous part
dp=3 # strength of the paramter ramping
rc = CriticalTransitions.RateConfig(p, p_parameters, t_start,ramp_t_length,dp)
```
Note that `dp` is defined as a prefactor of the function `p`. Thus, changing `dp` will change the amount of the parameter ramping. If the user provides a function fulfilling ``p(t=-10) =0 and p(t=10)=1``, setting `dp=10` would result in a parameter ramping from ``p(t=-10) = 0 and p(t=10) = 10``.


We set up the system with autonomous past and future and non-autonomous ramping in between:

```@example RateSystem
t0 = -10.0 # initial time of the system
nonauto_sys = apply_ramping(auto_sys, rc, t0);
```

We can compute trajectories of this new system in the familiar way:
```@example RateSystem
T = 50.0 # final simulation time
auto_traj = trajectory(auto_sys, T, x0)
nonauto_traj = trajectory(nonauto_sys, T, x0);
```

We plot the two trajectories
```@example RateSystem
fig = Figure(); axs = Axis(fig[1,1],xlabel="t",ylabel="x")
lines!(axs,t0.+auto_traj[2],auto_traj[1][:,1],linewidth=2,label=L"\text{Autonomous system}")
lines!(axs,nonauto_traj[2],nonauto_traj[1][:,1],linewidth=2,label=L"\text{Nonautonomous system}")
axislegend(axs,position=:rc,labelsize=10)
fig
```

-----
Author: Raphael Roemer; Date: 30 Jun 2025
7 changes: 6 additions & 1 deletion src/CriticalTransitions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ using DynamicalSystemsBase:
set_state!,
trajectory,
jacobian,
ContinuousTimeDynamicalSystem
ContinuousTimeDynamicalSystem,
referrenced_sciml_prob
using ConstructionBase: ConstructionBase
using StateSpaceSets: StateSpaceSets, dimension, StateSpaceSet
using StochasticDiffEq: StochasticDiffEq
Expand Down Expand Up @@ -57,6 +58,8 @@ include("largedeviations/geometric_min_action_method.jl")
include("largedeviations/sgMAM.jl")
include("largedeviations/string_method.jl")

include("r_tipping/RateSystem.jl")

# Experimental features
include("experimental/transition_path_theory/TransitionPathMesh.jl")
include("experimental/transition_path_theory/langevin.jl")
Expand All @@ -81,6 +84,8 @@ export MinimumActionPath
export deterministic_orbit
export transition, transitions

export RateConfig, apply_ramping

# Error hint for extensions stubs
function __init__()
Base.Experimental.register_error_hint(
Expand Down
122 changes: 122 additions & 0 deletions src/r_tipping/RateSystem.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# we consider the ODE dxₜ/dt = f(xₜ,p(rt))
# here p = p(t) ∈ Rᵐ is a function containing all the system parameters

# We ask the user to define:
# 1) a ContinuousTimeDynamicalSystem that should be investigated and
# 2) a protocol for the time-dependent forcing with the struct RateConfig

# Then we give back the ContinuousTimeDynamicalSystem with the parameter
# changing according to the rate protocol
"""
RateConfig
Time-dependent forcing protocol containing the information to apply a parameter shift to an autonomous system.
Fields
==============
- p: monotonic function which describes the time-dependent parametric forcing
Copy link
Member

Choose a reason for hiding this comment

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

this is a function but what are the inputs and what are the outputs?

- p_parameters: the vector of parameters which are associated with p
Copy link
Member

Choose a reason for hiding this comment

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

why does this have to be a vector? what is this in general? still not convinced why it should exist.

- t_pstart: the parameter values of the past limit system are given by p(p_parameteters,t_pstart)
- t_pend: the parameter values of the future limit system are given by p(p_parameters,t_pend)
- t_start: the explicit value of time at which the nonautonomous dynamics starts
Copy link
Collaborator

Choose a reason for hiding this comment

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

Hi, it seems redundant (and a bit confusing) to have all these different time inputs (t_pstart, t_start, ...). I am worried that we are making things too complicated.

To me, the most straight forward would be: you define a forcing function p(t) and a tuple (p_start, p_end). For all t, the parameters are then given by:

  • p(t_start) for $t \leq t_{start}$
  • p(t) for $t_{start} &lt; t &lt; t_{end}$
  • p(t_end) for $t \geq t_{end}$

This ensures the forcing is continuous. Its derivative might not be, but okay. If you have a tanh forcing on [t_start, t_end]and want the past and future limits to be closer to the 'true' limits of the tanh, just widen the interval [t_start, t_end].

Copy link
Collaborator

Choose a reason for hiding this comment

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

P.S. I am thinking that one applies the scaling (dp and rate) to the forcing first and then evaluates the start and end values of that rescaled forcing function using the specified t_start and t_end.

Copy link
Collaborator

@ryandeeley ryandeeley Aug 27, 2025

Choose a reason for hiding this comment

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

I would disagree that it's redundant and will try to dispel any possible confusion. One needs p, p_parameters, t_pstart and t_pend to define a function with piecewise constant tail ends that the R-tipping experiments are taken with respect to (see p_piecewise_scaled, here the dp simply scales the difference in parameter values across [t_pstart,t_pend]) . You need to fix a t_pstart and t_pend to fix the past and future limit systems. These have to be finite, because [t_pstart,t_pend] is rescaled into the finite interval [t_start,t_start+t_ramp_length]; this is the rescaling that was once associated with r (stretching / squeezing). If as you propose one simply transforms a rescaled forcing function into a function with piecewise constant tail ends from fixed t = t_start and t = t_end each time, then this is going to change the past and future limit systems depending on the rescaling (and could do so drastically if you consider a very shallow rate).

The parameter t_start in the current RateConfig struct is in my opinion unnecessary, since we could always fix t_start = -t_ramp_length/2 and have that the nonautonomous dynamics occurs in a symmetric window around t = 0.

Note also that for this formulation, it is less useful to think about r, and more useful to think about t_ramp_length (because these notions are only equivalent when the function has piecewise constant tail ends). Note that with the exception of dp, the code and system construction here is precisely the same as it was to before, except r has been replaced with t_ramp_length (thereby, restricting to cases where the time-dependent dynamics occurs over a finite time-interval, but since this is numerical, this restriction is not problematic).

- t_ramp_length: the duration of time of nonautonomous dynamics [i.e. within (t_start,t_start+t_ramp_length)]
- dp: the difference in parameter values attained across the ramping
Default values
==============
- t_pstart = -100
- t_pend = 100
- p_parameters = []
- t_start = -t_ramp_length/2
- dp = 1
Copy link
Member

Choose a reason for hiding this comment

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

I don't think these defaults make sense. Unless there is a singular unambiguous value, like 0 for starting time, you should not have defaults and request the user to provide them.
p_parameters should be nothing by default as with the rest of DynamicalSYstems.jl

"""
mutable struct RateConfig
p::Function
p_parameters::Vector
t_pstart::Float64
t_pend::Float64
t_start::Float64
t_ramp_length::Float64
dp::Float64
end

## convenience functions

RateConfig(p::Function, t_ramp_length::Float64) = RateConfig(p, [], -100.0, 100.0, -t_ramp_length/2, t_ramp_length, 1.0)
RateConfig(p::Function, t_ramp_length::Float64, dp::Float64) = RateConfig(p, [], -100.0, 100.0, -t_ramp_length/2, t_ramp_length, dp)

RateConfig(p::Function, p_parameters::Vector, t_ramp_length::Float64) = RateConfig(p, p_parameters, -100.0, 100.0, -t_ramp_length/2, t_ramp_length, 1.0)
RateConfig(p::Function, p_parameters::Vector, t_ramp_length::Float64, dp::Float64) = RateConfig(p, p_parameters, -100.0, 100.0, -t_ramp_length/2, t_ramp_length, dp)

## the following function creates a piecewise constant function with respect to t_pstart and t_pend...
## ...which is written such that p̃(t_pend)-p̃(t_pstart) = dp, for the time-dependent entries (otherwise p̃(t_pend)-p̃(t_pstart) = 0 as p̃(t)≡c)

function p_piecewise_scaled(p::Function,p_parameters::Vector,t_pstart::Float64,t_pend::Float64,dp::Float64,t::Float64)
if t t_pstart
return p(p_parameters,t_pstart)
else
np = length(p(p_parameters,t_pstart)) # the number of system parameters
differences = p(p_parameters,t_pend) .- p(p_parameters,t_pstart)
nonautonomous_inds = [ii for ii 1:np if differences[ii] != 0]
inds = [ii nonautonomous_inds ? 1/abs(differences[ii]) : 0 for ii 1:np] # takes value 1/|p(...,t_pend)-p(...,t_start)| when p(...,t_pend)=/=p(...,t_start); zero otherwise
if t < t_pend
return p(p_parameters,t_pstart) .+ dp .* inds .* (p(p_parameters,t) .- p(p_parameters,t_pstart))
else
return p(p_parameters,t_pstart) .+ dp .* inds .* (p(p_parameters,t_pend) .- p(p_parameters,t_pstart))
end
end
end

function modified_drift(
u,
p_parameters,
t,
ds::ContinuousTimeDynamicalSystem,
p::Function,
t_pstart::Float64,
t_pend::Float64,
t_start::Float64,
t_ramp_length::Float64,
dp::Float64;
kwargs...,
)

q(t) = p_piecewise_scaled(p,p_parameters,t_pstart,t_pend,dp,t)

time_shift = ((t_pend-t_pstart)/t_ramp_length)*(t-t_start)+t_pstart # such that [t_start,t_start+t_ramp_length] is shifted into [t_pstart,t_pend]

= q(time_shift)
Copy link
Member

Choose a reason for hiding this comment

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

not sure what this is. But importantly, something happens you that you don't discolse in the documentation. The function p the user provides must coincide with the parameter container of the original dynamical system. Is this really desirable?


return dynamic_rule(ds)(u, q̃, t)
Copy link
Member

Choose a reason for hiding this comment

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

what do you do for in-place systems here?

end;

"""
apply_ramping(sys::CoupledODEs, rc::RateConfig, t0=0.0; kwargs...)
Applies a time-dependent [`RateConfig`](@def) to a given autonomous deterministic dynamical system
`sys`, turning it into a non-autonomous dynamical system. The returned [`CoupledODEs`](@ref)
has the explicit parameter time-dependence incorporated.
The returned [`CoupledODEs`](@ref) is autonomous from `t_0` to `t_start`,
then non-autnonmous from `t_start` to `t_start+t_ramp_length` with the parameter shift given by the [`RateConfig`](@def),
and again autonomous from `t_start+t_ramp_length` to the end of the simulation:
`t_0` autonomous `t_start` non-autonomous `t_start+t_ramp_length` autonomous `∞`
Computing trajectories of the returned [`CoupledODEs`](@ref) can then be done in the same way as for any other [`CoupledODEs`](@ref).
"""
function apply_ramping(auto_sys::CoupledODEs, rc::RateConfig, t0=0.0; kwargs...)
# we wish to return a continuous time dynamical system with modified drift field

f(u, p_parameters, t) = modified_drift(
u, p_parameters, t, auto_sys, rc.p, rc.t_pstart, rc.t_pend, rc.t_start, rc.t_ramp_length, rc.dp; kwargs...
)
prob = remake(referrenced_sciml_prob(auto_sys); f, p=rc.p_parameters, tspan=(t0, Inf))
nonauto_sys = CoupledODEs(prob, auto_sys.diffeq)
Copy link
Collaborator

Choose a reason for hiding this comment

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

What if auto_sys is a CoupledSDEs? Then prob would be an SDEProblem and I'm not sure this would work. In this case the function should probably also return a CoupledSDEs and not a CoupledODEs.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

good point. For now, I fixed it by only allowing CoupledODEs as inputs, but I will have a look at whether and how this works for CoupledSDEs

Copy link
Collaborator

@ryandeeley ryandeeley Jul 29, 2025

Choose a reason for hiding this comment

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

I believe that if we use the use multiple dispatch functionality of Julia, we could essentially write two versions of the apply_ramping function, one where we require auto_sys::CoupledODEs and return nonauto_sys = CoupledODEs(prob, auto_sys.diffeq), and another where we require auto_sys::CoupledSDEs and return nonauto_sys = CoupledSDEs(prob, auto_sys.diffeq). The lines f(u, p, t) = modified_drift( u, p, t, auto_sys, rp.λ, rp.t_start, rp.t_end, rp.r; kwargs... ) and prob = remake(auto_sys.integ.sol.prob; f, p=rp.p_lambda, tspan=(t0, Inf)) should apply to both CoupledODEs and CoupledSDEs, since I believe the function remake can apply to both CoupledODEs and CoupledSDEs.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This would require making another function modified_diffusion which is analogous to modified_drift but we write return ds.integ.g(u, p̃, t) at the end instead.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Sounds good, I think! Could you add this?

return nonauto_sys
end



95 changes: 95 additions & 0 deletions src/r_tipping/RateSystemTimeInterval.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# we consider the ODE dxₜ/dt = f(xₜ,λ(rt))
# here λ = λ(t) ∈ Rᵐ is a function containing all the system parameters

# We ask the user to define:
# 1) a ContinuousTimeDynamicalSystem that should be investigated and
# 2) a protocol for the time-dependent forcing with the struct RateProtocol

# Then we give back the ContinuousTimeDynamicalSystem with the parameter
# changing according to the rate protocol
"""
RateProtocol

The RateProtocol contains all the fields (information) that allows to take an ODE of the form
`dxₜ/dt = f(xₜ, λ)`
with `λ ∈ Rᵐ` containing all system parameters, and make it an ODE of the form
`dxₜ/dt = f(xₜ, λ(rt))`
with `λ(t) ∈ Rᵐ` constant before time `time_interval[1]` and also after time `time_interval[2]`.

RateProtocol contains the following fields:
- `λ::Function`: forcing function of the form `λ(p, t_start; kwargs...)``
- `p_lambda::Vector`: parameters of the forcing function
- `r::Float64`: rate parameter
- `time_interval::Tuple`: start and end time of protocol

Default values
==============

time_interval = (-Inf, Inf)
p_lambda = []
"""
mutable struct RateProtocol
λ::Function
p_lambda::Vector
r::Float64
time_interval::Tuple
end

# convenience functions

function RateProtocol(λ::Function, p_lambda::Vector, r::Float64)
RateProtocol(λ, p_lambda, r, (-Inf, Inf))
end
RateProtocol(λ::Function, r::Float64)=RateProtocol(λ, [], r, (-Inf, Inf))
#RateProtocol(λ::Function,p_lambda::Vector,r::Float64,t_start::Float64)=RateProtocol(λ,p_lambda,r,t_start,Inf)
#RateProtocol(λ::Function,r::Float64,t_start::Float64)=RateProtocol(λ,[],r,t_start,Inf)

function modified_drift(
u,
p,
t,
ds::ContinuousTimeDynamicalSystem,
λ::Function,
time_interval::Tuple,
r::Float64;
kwargs...,
)
if time_interval[1] > time_interval[2]
error("Please ensure that time_interval[1] ≤ time_interval[2].")
end

p̃ = if r*t ≤ time_interval[1]
λ(p, time_interval[1]; kwargs...)
elseif time_interval[1] < r*t < time_interval[2]
λ(p, r*t; kwargs...) # the value(s) of λ(rt)
else
λ(p, time_interval[2]; kwargs...) # the value(s) of λ(rt)
end; # the value(s) of λ(rt)
return dynamic_rule(ds)(u, p̃, t)
end;

"""
apply_ramping(sys::CoupledODEs, rp::RateProtocol, t0=0.0; kwargs...)

Applies a time-dependent [`RateProtocol`](@def) to a given autonomous deterministic dynamical system `sys`,
returning a non-autonomous dynamical system of type [`CoupledODEs`](@ref).

The [`RateProtocol`](@def) replaces the parameters of `sys` by the function `λ(rt)` within the
time interval `time_interval`. Thus, the returned [`CoupledODEs`](@ref) has the explicit parameter time-dependence incorporated and is
autonomous from `t_0` to `time_interval[1]`, non-autnonmous from `time_interval[1]` to `time_interval[2]` with the parameter shift given by the [`RateProtocol`](@def),
and autonomous from `time_interval[2]` to the end of the simulation:

`t_0` autonomous `time_interval[1]` non-autonomous `time_interval[2]` autonomous `∞`

Computing trajectories of the returned [`CoupledODEs`](@ref) can then be done in the same way as for any other [`CoupledODEs`](@ref).
"""
function apply_ramping(auto_sys::CoupledODEs, rp::RateProtocol, t0=0.0; kwargs...)
# we wish to return a continuous time dynamical system with modified drift field

f(u, p, t) = modified_drift(
u, p, t, auto_sys, rp.λ, rp.time_interval, rp.r; kwargs...
)
prob = remake(referrenced_sciml_prob(auto_sys); f, p=rp.p_lambda, tspan=(t0, Inf))
nonauto_sys = CoupledODEs(prob, auto_sys.diffeq)
return nonauto_sys
end
6 changes: 3 additions & 3 deletions systems/CTLibrary.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ include("stommel.jl")
include("rivals.jl")

export fitzhugh_nagumo!, fitzhugh_nagumo, stommel, rivals!, rivals, cessi, rooth_smooth
modifiedtruscottbrindleywithdimensions!, modifiedtruscottbrindleywithdimensions
originaltruscottbrindley!, originaltruscottbrindley
rampedoriginaltruscottbrindley!, rampedoriginaltruscottbrindley
#modifiedtruscottbrindleywithdimensions!, modifiedtruscottbrindleywithdimensions
#originaltruscottbrindley!, originaltruscottbrindley
#rampedoriginaltruscottbrindley!, rampedoriginaltruscottbrindley

end
Loading
Loading