@@ -9,16 +9,21 @@ function time_integration( Prog::PrognosticVars{Tprog},
9
9
@unpack du,dv,dη = Diag. Tendencies
10
10
@unpack um,vm = Diag. SemiLagrange
11
11
12
- @unpack dynamics,RKo,tracer_advection = S. parameters
12
+ @unpack dynamics,RKo,RKs,tracer_advection = S. parameters
13
+ @unpack time_scheme = S. parameters
13
14
@unpack RKaΔt,RKbΔt = S. constants
15
+ @unpack Δt_Δ,Δt_Δs = S. constants
14
16
15
17
@unpack nt,dtint = S. grid
16
18
@unpack nstep_advcor,nstep_diff,nadvstep,nadvstep_half = S. grid
17
19
18
- if dynamics == " linear"
19
- Ix! (Diag. VolumeFluxes. h_u,S. forcing. H)
20
- Iy! (Diag. VolumeFluxes. h_v,S. forcing. H)
21
- end
20
+ # some precalculations
21
+ thickness! (Diag. VolumeFluxes. h,η,S. forcing. H)
22
+ Ix! (Diag. VolumeFluxes. h_u,Diag. VolumeFluxes. h)
23
+ Iy! (Diag. VolumeFluxes. h_v,Diag. VolumeFluxes. h)
24
+ Ixy! (Diag. Vorticity. h_q,Diag. VolumeFluxes. h)
25
+ advection_coriolis! (u,v,η,Diag,S)
26
+ PVadvection! (Diag,S)
22
27
23
28
# propagate initial conditions
24
29
copyto! (u0,u)
@@ -40,29 +45,104 @@ function time_integration( Prog::PrognosticVars{Tprog},
40
45
copyto! (v1,v)
41
46
copyto! (η1,η)
42
47
43
- # Runge-Kutta 4th order / 3rd order
44
- for rki = 1 : RKo
45
- if rki > 1
46
- ghost_points! (u1,v1,η1,S)
48
+ if time_scheme == " RK" # classic RK4,3 or 2
49
+
50
+ for rki = 1 : RKo
51
+ if rki > 1
52
+ ghost_points! (u1,v1,η1,S)
53
+ end
54
+
55
+ # type conversion for mixed precision
56
+ u1rhs = convert (Diag. PrognosticVarsRHS. u,u1)
57
+ v1rhs = convert (Diag. PrognosticVarsRHS. v,v1)
58
+ η1rhs = convert (Diag. PrognosticVarsRHS. η,η1)
59
+
60
+ rhs! (u1rhs,v1rhs,η1rhs,Diag,S,t) # momentum only
61
+ continuity! (u1rhs,v1rhs,η1rhs,Diag,S,t) # continuity equation
62
+
63
+ if rki < RKo
64
+ caxb! (u1,u,RKbΔt[rki],du) # u1 .= u .+ RKb[rki]*Δt*du
65
+ caxb! (v1,v,RKbΔt[rki],dv) # v1 .= v .+ RKb[rki]*Δt*dv
66
+ caxb! (η1,η,RKbΔt[rki],dη) # η1 .= η .+ RKb[rki]*Δt*dη
67
+ end
68
+
69
+ # sum RK-substeps on the go
70
+ axb! (u0,RKaΔt[rki],du) # u0 .+= RKa[rki]*Δt*du
71
+ axb! (v0,RKaΔt[rki],dv) # v0 .+= RKa[rki]*Δt*dv
72
+ axb! (η0,RKaΔt[rki],dη) # η0 .+= RKa[rki]*Δt*dη
47
73
end
48
74
49
- # type conversion for mixed precision
50
- u1rhs = convert (Diag. PrognosticVarsRHS. u,u1)
51
- v1rhs = convert (Diag. PrognosticVarsRHS. v,v1)
52
- η1rhs = convert (Diag. PrognosticVarsRHS. η,η1)
75
+ elseif time_scheme == " SSPRK2" # s-stage 2nd order SSPRK
76
+
77
+ for rki = 1 : RKs
78
+ if rki > 1
79
+ # TODO technically the ghost point copy for u1,v1 is redundant as done further down
80
+ ghost_points! (u1,v1,η1,S)
81
+ end
82
+
83
+ # type conversion for mixed precision
84
+ u1rhs = convert (Diag. PrognosticVarsRHS. u,u1)
85
+ v1rhs = convert (Diag. PrognosticVarsRHS. v,v1)
86
+ η1rhs = convert (Diag. PrognosticVarsRHS. η,η1)
53
87
54
- rhs! (u1rhs,v1rhs,η1rhs,Diag,S,t)
88
+ rhs! (u1rhs,v1rhs,η1rhs,Diag,S,t)
55
89
56
- if rki < RKo
57
- caxb! (u1,u,RKbΔt[rki],du) # u1 .= u .+ RKb[rki]*Δt*du
58
- caxb! (v1,v,RKbΔt[rki],dv) # v1 .= v .+ RKb[rki]*Δt*dv
59
- caxb! (η1,η,RKbΔt[rki],dη) # η1 .= η .+ RKb[rki]*Δt*dη
90
+ # the update step
91
+ axb! (u1,Δt_Δs,du) # u1 = u1 + Δt/(s-1)*RHS(u1)
92
+ axb! (v1,Δt_Δs,dv)
93
+
94
+ # semi-implicit for continuity equation, use u1,v1 to calcualte dη
95
+ ghost_points! (u1,v1,S)
96
+ u1rhs = convert (Diag. PrognosticVarsRHS. u,u1)
97
+ v1rhs = convert (Diag. PrognosticVarsRHS. v,v1)
98
+ continuity! (u1rhs,v1rhs,η1rhs,Diag,S,t)
99
+ axb! (η1,Δt_Δs,dη) # η1 = η1 + Δt/(s-1)*RHS(u1)
60
100
end
61
101
62
- # sum RK-substeps on the go
63
- axb! (u0,RKaΔt[rki],du) # u0 .+= RKa[rki]*Δt*du
64
- axb! (v0,RKaΔt[rki],dv) # v0 .+= RKa[rki]*Δt*dv
65
- axb! (η0,RKaΔt[rki],dη) # η0 .+= RKa[rki]*Δt*dη
102
+ a = 1 / RKs
103
+ b = (RKs- 1 )/ RKs
104
+ cxayb! (u0,a,u,b,u1)
105
+ cxayb! (v0,a,v,b,v1)
106
+ cxayb! (η0,a,η,b,η1)
107
+
108
+ elseif time_scheme == " SSPRK3" # 4-stage SSPRK3
109
+
110
+ for rki = 1 : 4
111
+ if rki > 1
112
+ ghost_points! (u1,v1,η1,S)
113
+ end
114
+
115
+ # type conversion for mixed precision
116
+ u1rhs = convert (Diag. PrognosticVarsRHS. u,u1)
117
+ v1rhs = convert (Diag. PrognosticVarsRHS. v,v1)
118
+ η1rhs = convert (Diag. PrognosticVarsRHS. η,η1)
119
+
120
+ rhs! (u1rhs,v1rhs,η1rhs,Diag,S,t)
121
+
122
+ caxb! (u0,u1,Δt_Δ,du) # store Euler update into u0,v0
123
+ caxb! (v0,v1,Δt_Δ,dv)
124
+ cxab! (u1,1 / 2 ,u1,u0) # average u0,u1 and store in u1
125
+ cxab! (v1,1 / 2 ,v1,v0) # same
126
+
127
+ # semi-implicit for continuity equation, use u1,v1 to calcualte dη
128
+ ghost_points! (u1,v1,S)
129
+ u1rhs = convert (Diag. PrognosticVarsRHS. u,u1)
130
+ v1rhs = convert (Diag. PrognosticVarsRHS. v,v1)
131
+ continuity! (u1rhs,v1rhs,η1rhs,Diag,S,t)
132
+
133
+ caxb! (η0,η1,Δt_Δ,dη) # store Euler update into η0
134
+ cxab! (η1,1 / 2 ,η1,η0) # average η0,η1 and store in η1
135
+
136
+ if rki == 3
137
+ cxayb! (u1,2 / 3 ,u,1 / 3 ,u1)
138
+ cxayb! (v1,2 / 3 ,v,1 / 3 ,v1)
139
+ cxayb! (η1,2 / 3 ,η,1 / 3 ,η1)
140
+ elseif rki == 4
141
+ copyto! (u0,u1)
142
+ copyto! (v0,v1)
143
+ copyto! (η0,η1)
144
+ end
145
+ end
66
146
end
67
147
68
148
ghost_points! (u0,v0,η0,S)
@@ -76,7 +156,9 @@ function time_integration( Prog::PrognosticVars{Tprog},
76
156
# although included in the tendency of every RK substep,
77
157
# only update every nstep_advcor steps if nstep_advcor > 0
78
158
if dynamics == " nonlinear" && nstep_advcor > 0 && (i % nstep_advcor) == 0
159
+ UVfluxes! (u0rhs,v0rhs,η0rhs,Diag,S)
79
160
advection_coriolis! (u0rhs,v0rhs,η0rhs,Diag,S)
161
+ PVadvection! (Diag,S)
80
162
end
81
163
82
164
# DIFFUSIVE TERMS - SEMI-IMPLICIT EULER
@@ -86,23 +168,26 @@ function time_integration( Prog::PrognosticVars{Tprog},
86
168
bottom_drag! (u0rhs,v0rhs,η0rhs,Diag,S)
87
169
diffusion! (u0rhs,v0rhs,Diag,S)
88
170
add_drag_diff_tendencies! (u0,v0,Diag,S)
171
+ ghost_points! (u0,v0,S)
89
172
end
90
173
91
174
t += dtint
92
175
93
176
# TRACER ADVECTION
177
+ u0rhs = convert (Diag. PrognosticVarsRHS. u,u0) # copy back as add_drag_diff_tendencies changed u0,v0
178
+ v0rhs = convert (Diag. PrognosticVarsRHS. v,v0)
94
179
tracer! (i,u0rhs,v0rhs,Prog,Diag,S)
95
180
96
181
# feedback and output
97
182
feedback. i = i
98
183
feedback! (Prog,feedback,S)
99
- output_nc! (i,netCDFfiles,Prog,Diag,S)
184
+ output_nc! (i,netCDFfiles,Prog,Diag,S) # uses u0,v0,η0
100
185
101
186
if feedback. nans_detected
102
187
break
103
188
end
104
189
105
- # RK3/4 copy back from substeps
190
+ # Copy back from substeps
106
191
copyto! (u,u0)
107
192
copyto! (v,v0)
108
193
copyto! (η,η0)
@@ -134,14 +219,42 @@ function caxb!(c::Array{T,2},a::Array{T,2},x::T,b::Array{T,2}) where {T<:Abstrac
134
219
@boundscheck (m,n) == size (b) || throw (BoundsError ())
135
220
@boundscheck (m,n) == size (c) || throw (BoundsError ())
136
221
137
- # TODO @simd?
138
222
@inbounds for j ∈ 1 : n
139
223
for i ∈ 1 : m
140
224
c[i,j] = a[i,j] + x* b[i,j]
141
225
end
142
226
end
143
227
end
144
228
229
+ """ c equals add x multiplied to a plus b. c = x*(a+b) """
230
+ function cxab! (c:: Array{T,2} ,x:: Real ,a:: Array{T,2} ,b:: Array{T,2} ) where {T<: AbstractFloat }
231
+ m,n = size (a)
232
+ @boundscheck (m,n) == size (b) || throw (BoundsError ())
233
+ @boundscheck (m,n) == size (c) || throw (BoundsError ())
234
+
235
+ xT = T (x)
236
+ @inbounds for j ∈ 1 : n
237
+ for i ∈ 1 : m
238
+ c[i,j] = xT* (a[i,j] + b[i,j])
239
+ end
240
+ end
241
+ end
242
+
243
+ """ c equals add x multiplied to a plus b. c = x*(a+b) """
244
+ function cxayb! (c:: Array{T,2} ,x:: Real ,a:: Array{T,2} ,y:: Real ,b:: Array{T,2} ) where {T<: AbstractFloat }
245
+ m,n = size (a)
246
+ @boundscheck (m,n) == size (b) || throw (BoundsError ())
247
+ @boundscheck (m,n) == size (c) || throw (BoundsError ())
248
+
249
+ xT = T (x)
250
+ yT = T (y)
251
+ @inbounds for j ∈ 1 : n
252
+ for i ∈ 1 : m
253
+ c[i,j] = xT* a[i,j] + yT* b[i,j]
254
+ end
255
+ end
256
+ end
257
+
145
258
""" Convert function for two arrays, X1, X2, in case their eltypes differ.
146
259
Convert every element from X1 and store it in X2."""
147
260
function Base. convert (X2:: Array{T2,N} ,X1:: Array{T1,N} ) where {T1,T2,N}
0 commit comments