Skip to content

Commit b841f08

Browse files
authored
Merge pull request #8 from lorenz96
Lorenz96 updates: 'regressed', ArgParse, ConfParser, 'gather_pairs' and 'random_init'
2 parents 123db3e + 1170f14 commit b841f08

File tree

7 files changed

+395
-106
lines changed

7 files changed

+395
-106
lines changed

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ authors = ["Simon Byrne <[email protected]>"]
44
version = "0.1.0"
55

66
[deps]
7+
ArgParse = "c7e460c6-2fb9-53a9-8c5b-16f535851c63"
8+
ConfParser = "88353bc9-fd38-507d-a820-d3b43837d6b9"
79
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
810
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
911
EllipsisNotation = "da5c29d0-fa7d-589e-88eb-ea29b0a81949"

examples/L96m/L96m.jl

Lines changed: 148 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,44 @@
11
using Parameters # lets you have defaults for fields
22

3+
"""
4+
Lorenz '96 multiscale
5+
6+
Parameters:
7+
- `K` : number of slow variables
8+
- `J` : number of fast variables per slow variable
9+
- `hx` : coupling term (in equations for slow variables)
10+
- `hy` : coupling term (in equations for fast variables)
11+
- `F` : forcing term for slow variables
12+
- `eps` : scale separation constant
13+
14+
Other:
15+
- `G` : functional closure for slow variables (usually a GPR-closure)
16+
"""
317
@with_kw mutable struct L96m
4-
"""
5-
Lorenz '96 multiscale
6-
7-
Parameters:
8-
- `K` : number of slow variables
9-
- `J` : number of fast variables per slow variable
10-
- `hx` : coupling term (in equations for slow variables)
11-
- `hy` : coupling term (in equations for fast variables)
12-
- `F` : forcing term for slow variables
13-
- `eps` : scale separation term
14-
15-
Other:
16-
- `G` : functional closure for slow variables (usually a GPR-closure)
17-
"""
1818
K::Int = 9
1919
J::Int = 8
2020
hx::Float64 = -0.8
21-
hy::Float64 = 1
22-
F::Float64 = 10
21+
hy::Float64 = 1.0
22+
F::Float64 = 10.0
2323
eps::Float64 = 2^(-7)
2424
G = nothing
2525
end
2626

27-
function full(rhs::Array{<:Real,1}, z::Array{<:Real,1}, p::L96m, t)
28-
"""
29-
Compute full RHS of the Lorenz '96 multiscale system.
30-
The convention is that the first K variables are slow, while the rest K*J
31-
variables are fast.
32-
33-
Input:
34-
- `z` : vector of size (K + K*J)
35-
- `p` : parameters
36-
- `t` : time (not used here since L96m is autonomous)
27+
"""
28+
Compute full RHS of the Lorenz '96 multiscale system.
29+
The convention is that the first K variables are slow, while the rest K*J
30+
variables are fast.
3731
38-
Output:
39-
- `rhs` : RHS computed at `z`
32+
Input:
33+
- `z` : vector of size (K + K*J)
34+
- `p` : parameters (L96m struct)
35+
- `t` : time (not used here since L96m is autonomous)
4036
41-
"""
37+
Output:
38+
- `rhs` : RHS computed at `z`
4239
40+
"""
41+
function full(rhs::Array{<:Real,1}, z::Array{<:Real,1}, p::L96m, t)
4342
K = p.K
4443
J = p.J
4544
x = @view(z[1:K])
@@ -83,22 +82,21 @@ function full(rhs::Array{<:Real,1}, z::Array{<:Real,1}, p::L96m, t)
8382
return rhs
8483
end
8584

86-
function balanced(rhs::Array{<:Real,1}, x::Array{<:Real,1}, p::L96m, t)
87-
"""
88-
Compute balanced RHS of the Lorenz '96 multiscale system; i.e. only slow
89-
variables with the linear closure.
90-
Both `rhs` and `x` are vectors of size p.K.
91-
92-
Input:
93-
- `x` : vector of size K
94-
- `p` : parameters
95-
- `t` : time (not used here since L96m is autonomous)
85+
"""
86+
Compute balanced RHS of the Lorenz '96 multiscale system; i.e. only slow
87+
variables with the linear closure.
88+
Both `rhs` and `x` are vectors of size p.K.
9689
97-
Output:
98-
- `rhs` : balanced RHS computed at `x`
90+
Input:
91+
- `x` : vector of size K
92+
- `p` : parameters (L96m struct)
93+
- `t` : time (not used here since L96m is autonomous)
9994
100-
"""
95+
Output:
96+
- `rhs` : balanced RHS computed at `x`
10197
98+
"""
99+
function balanced(rhs::Array{<:Real,1}, x::Array{<:Real,1}, p::L96m, t)
102100
K = p.K
103101

104102
# three boundary cases
@@ -115,15 +113,119 @@ function balanced(rhs::Array{<:Real,1}, x::Array{<:Real,1}, p::L96m, t)
115113
return rhs
116114
end
117115

116+
"""
117+
Compute slow-variable closed RHS of the Lorenz '96 Multiscale system;
118+
i.e. only slow variables with some closure instead of Yk.
119+
Closure is taken from p.G.
120+
Both `rhs` and `x` are vectors of size p.K.
121+
122+
Input:
123+
- `x` : vector of size K
124+
- `p` : parameters (L96m struct)
125+
- `t` : time (not used here since L96m is autonomous)
126+
127+
Output:
128+
- `rhs` : regressed RHS computed at `x`
129+
130+
"""
131+
function regressed(rhs::Array{<:Real,1}, x::Array{<:Real,1}, p::L96m, t)
132+
K = p.K
133+
134+
# three boundary cases
135+
rhs[1] = -x[K] * (x[K-1] - x[2]) - x[1]
136+
rhs[2] = -x[1] * (x[K] - x[3]) - x[2]
137+
rhs[K] = -x[K-1] * (x[K-2] - x[1]) - x[K]
138+
139+
# general case
140+
rhs[3:K-1] = -x[2:K-2] .* (x[1:K-3] - x[4:K]) - x[3:K-1]
141+
142+
# add forcing
143+
rhs .+= p.F
144+
145+
# add closure
146+
rhs .+= p.hx * p.G(x)
147+
148+
return rhs
149+
end
150+
151+
"""
152+
Reshape a vector of y_{j,k} into a matrix, then sum along one dim and divide
153+
by J to get averages
154+
"""
118155
function compute_Yk(p::L96m, z::Array{<:Real,1})
119-
"""
120-
Reshape a vector of y_{j,k} into a matrix, then sum along one dim and divide
121-
by J to get averages
122-
"""
123156
return dropdims(
124157
sum( reshape(z[p.K+1:end], p.J, p.K), dims = 1 ),
125158
dims = 1
126159
) / p.J
127160
end
128161

162+
"""
163+
Set the closure `p.G` to a linear one with slope `slope`.
164+
If unspecified, slope is equal to `p.hy`.
165+
"""
166+
function set_G0(p::L96m; slope = nothing)
167+
if (slope == nothing) || (!isa(slope, Real))
168+
slope = p.hy
169+
end
170+
p.G = x -> slope * x
171+
end
172+
173+
"""
174+
Wrapper for set_G0(p::L96m; slope = nothing).
175+
"""
176+
function set_G0(p::L96m, slope::Real)
177+
set_G0(p, slope = slope)
178+
end
179+
180+
"""
181+
Gather (xk, Yk) pairs that are further used to train a GP regressor
182+
183+
Input:
184+
- `p` : parameters (L96m struct)
185+
- `sol` : time series of a solution; time steps are in the 2nd dimension
186+
(usually, just `sol` output from a time-stepper)
187+
188+
Output:
189+
- `pairs` : a 2-d array of size (N, 2) containing (xk, Yk) pairs, where N is
190+
the 2nd dimension in `sol` (number of time steps)
191+
192+
"""
193+
function gather_pairs(p::L96m, sol)
194+
N = size(sol, 2)
195+
pairs = Array{Float64, 2}(undef, p.K * N, 2)
196+
for n in 1:N
197+
pairs[p.K * (n-1) + 1 : p.K * n, 1] = sol[1:p.K, n]
198+
pairs[p.K * (n-1) + 1 : p.K * n, 2] = compute_Yk(p, sol[:,n])
199+
end
200+
return pairs
201+
end
202+
203+
"""
204+
Returns a randomly initialized array that can be used as an IC to ODE solver
205+
206+
The returned array is of size `p.K + p.K * p.J`.
207+
The first `p.K` variables are slow and are drawn randomly ~ U[-5; 10]; each of
208+
the fast variables corresponding to the same slow variable is set to the value
209+
of that slow variable.
210+
211+
For example, if K == 2 and J = 3, the returned array will be
212+
[ rand1, rand2, rand1, rand1, rand1, rand2, rand2, rand2 ]
213+
214+
Input:
215+
- `p` : parameters (L96m struct)
216+
217+
Output:
218+
- `z00` : array of size `p.K + p.K * p.J` with random values
219+
"""
220+
function random_init(p::L96m)
221+
z00 = Array{Float64}(undef, p.K + p.K * p.J)
222+
223+
z00[1:p.K] .= rand(p.K) * 15 .- 5
224+
for k_ in 1:p.K
225+
z00[p.K+1 + (k_-1)*p.J : p.K + k_*p.J] .= z00[k_]
226+
end
227+
228+
return z00
229+
end
230+
129231

examples/L96m/cfg.ini

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[Runs]
2+
run_conv = true
3+
run_dns = true
4+
run_bal = true
5+
run_reg = true
6+
7+
[Integration]
8+
SOLVER = Tsit5
9+
10+
T = 4.0
11+
T_conv = 100.0
12+
13+
dtmax = 1e-3
14+
reltol = 1e-3
15+
abstol = 1e-6
16+

0 commit comments

Comments
 (0)