Skip to content

Commit e8cbb5e

Browse files
committed
compensated summation for RK4, Diff and tracer
1 parent 113b93e commit e8cbb5e

File tree

6 files changed

+174
-73
lines changed

6 files changed

+174
-73
lines changed

src/constants.jl

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ function SSPRK3coeff{T}(P::Parameter,Δt_Δ::T) where T
1818
s = n^2
1919
kn = n*(n+1) ÷ 2 + 1
2020
mn = (n-1)*(n-2) ÷ 2 + 1
21-
Δt_Δn = T(Δt_Δ/(n^2-n))
22-
kna = T((n-1)/(2n-1))
23-
knb = T(n/(2n-1))
24-
Δt_Δnc = T(Δt_Δ/(n*(2n-1)))
21+
Δt_Δn = convert(T,Δt_Δ/(n^2-n))
22+
kna = convert(T,(n-1)/(2n-1))
23+
knb = convert(T,n/(2n-1))
24+
Δt_Δnc = convert(T,Δt_Δ/(n*(2n-1)))
2525

2626
return SSPRK3coeff{T}(n,s,kn,mn,Δt_Δn,kna,knb,Δt_Δnc)
2727
end
@@ -76,37 +76,41 @@ function Constants{T,Tprog}(P::Parameter,G::Grid) where {T<:AbstractFloat,Tprog<
7676
end
7777

7878
# Δt/(s-1) for SSPRK2
79-
Δt_Δs = Tprog(G.dtint/G.Δ/(P.RKs-1))
79+
Δt_Δs = convert(Tprog,G.dtint/G.Δ/(P.RKs-1))
8080

8181
# time step and half the time step including the grid spacing as this is not included in the RHS
82-
Δt_Δ = Tprog(G.dtint/G.Δ)
83-
Δt_Δ_half = Tprog(G.dtint/G.Δ/2)
82+
Δt_Δ = convert(Tprog,G.dtint/G.Δ)
83+
Δt_Δ_half = convert(Tprog,G.dtint/G.Δ/2)
8484

8585
# coefficients for SSPRK3
8686
SSPRK3c = SSPRK3coeff{Tprog}(P,Δt_Δ)
8787

8888
# BOUNDARY CONDITIONS AND PHYSICS
89-
one_minus_α = Tprog(1-P.α) # for the ghost point copy/tangential boundary conditions
90-
g = T(P.g) # gravity - for Bernoulli potential
89+
one_minus_α = convert(Tprog,1-P.α) # for the ghost point copy/tangential boundary conditions
90+
g = convert(T,P.g) # gravity - for Bernoulli potential
9191

92-
# BOTTOM FRICTION COEFFICENTS
92+
# BOTTOM FRICTION COEFFICIENTS
9393
# incl grid spacing Δ for non-dimensional gradients
9494
# include scale for quadratic cD only to unscale the scale^2 in u^2
95-
cD = T(-G.Δ*P.cD/P.scale) # quadratic drag [m]
96-
rD = T(-G.Δ/(P.τD*24*3600)) # linear drag [m/s]
95+
cD = convert(T,-G.Δ*P.cD/P.scale) # quadratic drag [m]
96+
rD = convert(T,-G.Δ/(P.τD*24*3600)) # linear drag [m/s]
9797

9898
# INTERFACE RELAXATION FREQUENCY
9999
# incl grid spacing Δ for non-dimensional gradients
100-
γ = T(G.Δ/(P.t_relax*3600*24)) # [m/s]
100+
γ = convert(T,G.Δ/(P.t_relax*3600*24)) # [m/s]
101101

102102
# BIHARMONIC DIFFUSION
103103
# undo scaling here as smagorinksy diffusion contains scale^2 due to ~u^2
104-
cSmag = T(-P.cSmag/P.scale) # Smagorinsky coefficient
105-
νB = T(-P.νB/30000) # linear scaling based on 540m^s/s at Δ=30km
104+
cSmag = convert(T,-P.cSmag/P.scale) # Smagorinsky coefficient
105+
νB = convert(T,-P.νB/30000) # linear scaling based on 540m^s/s at Δ=30km
106106

107107
# TRACER ADVECTION
108-
τSST = T(G.dtadvint/(P.τSST*3600*24)) # tracer restoring [1]
109-
jSST = T(G.dtadvint/(P.jSST*3600*24)) # tracer consumption [1]
108+
τSST = convert(T,G.dtadvint/(P.τSST*3600*24)) # tracer restoring [1]
109+
jSST = convert(T,G.dtadvint/(P.jSST*3600*24)) # tracer consumption [1]
110+
111+
@unpack tracer_relaxation, tracer_consumption = P
112+
τSST = tracer_relaxation ? τSST : zero(T) # set zero as τ,j will be added
113+
jSST = tracer_consumption ? jSST : zero(T) # and executed in one loop
110114

111115
# TIME DEPENDENT FORCING
112116
ωFη = -2π*P.ωFη/24/365.25/3600
@@ -123,4 +127,4 @@ function Constants{T,Tprog}(P::Parameter,G::Grid) where {T<:AbstractFloat,Tprog<
123127
g,cD,rD,γ,cSmag,νB,τSST,jSST,
124128
ωFη,ωFx,ωFy,
125129
scale,scale_inv,scale_sst)
126-
end
130+
end

src/default_parameters.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,17 @@
5353
wk::Real=10e3 # width [m] in y of Gaussian used for surface forcing
5454

5555
# TIME STEPPING OPTIONS
56-
time_scheme::String="SSPRK3" # Runge-Kutta ("RK") or strong-stability preserving RK
56+
time_scheme::String="RK" # Runge-Kutta ("RK") or strong-stability preserving RK
5757
# "SSPRK2","SSPRK3","4SSPRK3"
5858
RKo::Int=4 # Order of the RK time stepping scheme (2, 3 or 4)
5959
RKs::Int=3 # Number of stages for SSPRK2
6060
RKn::Int=5 # n^2 = s = Number of stages for SSPRK3
61-
cfl::Real=4.0 # CFL number (1.0 recommended for RK4, 0.6 for RK3)
61+
cfl::Real=0.9 # CFL number (1.0 recommended for RK4, 0.6 for RK3)
6262
Ndays::Real=200.0 # number of days to integrate for
6363
nstep_diff::Int=1 # diffusive part every nstep_diff time steps.
6464
nstep_advcor::Int=0 # advection and coriolis update every nstep_advcor time steps.
6565
# 0 means it is included in every RK4 substep
66+
compensated::Bool=false # Compensated summation in the time integration?
6667

6768
# BOUNDARY CONDITION OPTIONS
6869
bc::String="periodic" # "periodic" or anything else for nonperiodic

src/diffusion.jl

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -218,23 +218,36 @@ function viscous_tensor_constant!( Diag::DiagnosticVars,
218218
end
219219

220220
"""Update u with bottom friction tendency (Bu,Bv) and biharmonic viscosity."""
221-
function add_drag_diff_tendencies!( u::Array{Tprog,2},
222-
v::Array{Tprog,2},
221+
function add_drag_diff_tendencies!( u::Matrix{Tprog},
222+
v::Matrix{Tprog},
223223
Diag::DiagnosticVars{T,Tprog},
224224
S::ModelSetup{T,Tprog}) where {T,Tprog}
225225

226226
@unpack Bu,Bv = Diag.Bottomdrag
227227
@unpack LLu1,LLu2,LLv1,LLv2 = Diag.Smagorinsky
228228
@unpack halo,ep,Δt_diff = S.grid
229+
@unpack compensated = S.parameters
230+
@unpack du_comp,dv_comp = Diag.Tendencies
229231

230232
m,n = size(u) .- (2*halo,2*halo)
231233
@boundscheck (m+2-ep,n+2) == size(Bu) || throw(BoundsError())
232234
@boundscheck (m,n+2) == size(LLu1) || throw(BoundsError())
233235
@boundscheck (m+2-ep,n) == size(LLu2) || throw(BoundsError())
234236

235-
@inbounds for j 1:n
236-
for i 1:m
237-
u[i+2,j+2] += Δt_diff*(Tprog(Bu[i+1-ep,j+1]) + Tprog(LLu1[i,j+1]) + Tprog(LLu2[i+1-ep,j]))
237+
if compensated
238+
@inbounds for j 1:n
239+
for i 1:m
240+
du = Δt_diff*convert(Tprog,Bu[i+1-ep,j+1] + LLu1[i,j+1] + LLu2[i+1-ep,j]) - du_comp[i+2,j+2]
241+
u_new = u[i+2,j+2] + du
242+
du_comp[i+2,j+2] = (u_new - u[i+2,j+2]) - du
243+
u[i+2,j+2] = u_new
244+
end
245+
end
246+
else
247+
@inbounds for j 1:n
248+
for i 1:m
249+
u[i+2,j+2] += Δt_diff*(Tprog(Bu[i+1-ep,j+1]) + Tprog(LLu1[i,j+1]) + Tprog(LLu2[i+1-ep,j]))
250+
end
238251
end
239252
end
240253

@@ -243,9 +256,20 @@ function add_drag_diff_tendencies!( u::Array{Tprog,2},
243256
@boundscheck (m,n+2) == size(LLv1) || throw(BoundsError())
244257
@boundscheck (m+2,n) == size(LLv2) || throw(BoundsError())
245258

246-
@inbounds for j 1:n
247-
for i 1:m
248-
v[i+2,j+2] += Δt_diff*(Tprog(Bv[i+1,j+1]) + Tprog(LLv1[i,j+1]) + Tprog(LLv2[i+1,j]))
259+
if compensated
260+
@inbounds for j 1:n
261+
for i 1:m
262+
dv = Δt_diff*convert(Tprog,Bv[i+1,j+1] + LLv1[i,j+1] + LLv2[i+1,j]) - dv_comp[i+2,j+2]
263+
v_new = v[i+2,j+2] + dv
264+
dv_comp[i+2,j+2] = (v_new - v[i+2,j+2]) - dv
265+
v[i+2,j+2] = v_new
266+
end
267+
end
268+
else
269+
@inbounds for j 1:n
270+
for i 1:m
271+
v[i+2,j+2] += Δt_diff*(Tprog(Bv[i+1,j+1]) + Tprog(LLv1[i,j+1]) + Tprog(LLv2[i+1,j]))
272+
end
249273
end
250274
end
251275
end

src/preallocate.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,16 @@ end
6060
du::Array{T,2} = zeros(T,nux+2*halo,nuy+2*halo) # tendency of u without time step
6161
dv::Array{T,2} = zeros(T,nvx+2*halo,nvy+2*halo) # tendency of v without time step
6262
::Array{T,2} = zeros(T,nx+2*haloη,ny+2*haloη) # tendency of η without time step
63+
64+
# sum of tendencies (incl time step) over all sub-steps
65+
du_sum::Array{T,2} = zeros(T,nux+2*halo,nuy+2*halo)
66+
dv_sum::Array{T,2} = zeros(T,nvx+2*halo,nvy+2*halo)
67+
dη_sum::Array{T,2} = zeros(T,nx+2*haloη,ny+2*haloη)
68+
69+
# compensation for tendencies (variant of Kahan summation)
70+
du_comp::Array{T,2} = zeros(T,nux+2*halo,nuy+2*halo)
71+
dv_comp::Array{T,2} = zeros(T,nvx+2*halo,nvy+2*halo)
72+
dη_comp::Array{T,2} = zeros(T,nx+2*haloη,ny+2*haloη)
6373
end
6474

6575
"""Generator function for Tendencies VarCollection."""
@@ -422,6 +432,9 @@ end
422432

423433
ssti::Array{T,2} = zeros(T,nx+2*halosstx,ny+2*halossty) # sst interpolated on departure points
424434
sst_ref::Array{T,2} = zeros(T,nx+2*halosstx,ny+2*halossty) # sst initial conditions for relaxation
435+
436+
# compensated summation
437+
dsst_comp::Array{T,2} = zeros(T,nx+2*halosstx,ny+2*halossty)
425438
end
426439

427440
"""Generator function for SemiLagrange VarCollection."""

src/time_integration.jl

Lines changed: 74 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@ function time_integration( Prog::PrognosticVars{Tprog},
77
@unpack u0,v0,η0 = Diag.RungeKutta
88
@unpack u1,v1,η1 = Diag.RungeKutta
99
@unpack du,dv,dη = Diag.Tendencies
10+
@unpack du_sum,dv_sum,dη_sum = Diag.Tendencies
11+
@unpack du_comp,dv_comp,dη_comp = Diag.Tendencies
12+
1013
@unpack um,vm = Diag.SemiLagrange
1114

1215
@unpack dynamics,RKo,RKs,tracer_advection = S.parameters
13-
@unpack time_scheme = S.parameters
16+
@unpack time_scheme,compensated = S.parameters
1417
@unpack RKaΔt,RKbΔt = S.constants
1518
@unpack Δt_Δ,Δt_Δs = S.constants
1619

@@ -55,6 +58,12 @@ function time_integration( Prog::PrognosticVars{Tprog},
5558

5659
if time_scheme == "RK" # classic RK4,3 or 2
5760

61+
if compensated
62+
fill!(du_sum,zero(Tprog))
63+
fill!(dv_sum,zero(Tprog))
64+
fill!(dη_sum,zero(Tprog))
65+
end
66+
5867
for rki = 1:RKo
5968
if rki > 1
6069
ghost_points!(u1,v1,η1,S)
@@ -74,10 +83,30 @@ function time_integration( Prog::PrognosticVars{Tprog},
7483
caxb!(η1,η,RKbΔt[rki],dη) #η1 .= η .+ RKb[rki]*Δt*dη
7584
end
7685

77-
# sum RK-substeps on the go
78-
axb!(u0,RKaΔt[rki],du) #u0 .+= RKa[rki]*Δt*du
79-
axb!(v0,RKaΔt[rki],dv) #v0 .+= RKa[rki]*Δt*dv
80-
axb!(η0,RKaΔt[rki],dη) #η0 .+= RKa[rki]*Δt*dη
86+
if compensated # accumulate tendencies
87+
axb!(du_sum,RKaΔt[rki],du)
88+
axb!(dv_sum,RKaΔt[rki],dv)
89+
axb!(dη_sum,RKaΔt[rki],dη)
90+
else # sum RK-substeps on the go
91+
axb!(u0,RKaΔt[rki],du) #u0 .+= RKa[rki]*Δt*du
92+
axb!(v0,RKaΔt[rki],dv) #v0 .+= RKa[rki]*Δt*dv
93+
axb!(η0,RKaΔt[rki],dη) #η0 .+= RKa[rki]*Δt*dη
94+
end
95+
end
96+
97+
if compensated
98+
# add compensation term to total tendency
99+
axb!(du_sum,-1,du_comp)
100+
axb!(dv_sum,-1,dv_comp)
101+
axb!(dη_sum,-1,dη_comp)
102+
103+
axb!(u0,1,du_sum) # update prognostic variable with total tendency
104+
axb!(v0,1,dv_sum)
105+
axb!(η0,1,dη_sum)
106+
107+
dambmc!(du_comp,u0,u,du_sum) # compute new compensation
108+
dambmc!(dv_comp,v0,v,dv_sum)
109+
dambmc!(dη_comp,η0,η,dη_sum)
81110
end
82111

83112
elseif time_scheme == "SSPRK2" # s-stage 2nd order SSPRK
@@ -116,6 +145,12 @@ function time_integration( Prog::PrognosticVars{Tprog},
116145

117146
@unpack s,kn,mn,kna,knb,Δt_Δnc,Δt_Δn = S.constants.SSPRK3c
118147

148+
# if compensated
149+
# fill!(du_sum,zero(Tprog))
150+
# fill!(dv_sum,zero(Tprog))
151+
# fill!(dη_sum,zero(Tprog))
152+
# end
153+
119154
for rki = 2:s+1 # number of stages (from 2:s+1 to match Ketcheson et al 2014)
120155
if rki > 2
121156
ghost_points_η!(η1,S)
@@ -134,6 +169,11 @@ function time_integration( Prog::PrognosticVars{Tprog},
134169
else # normal update case
135170
axb!(u1,Δt_Δn,du)
136171
axb!(v1,Δt_Δn,dv)
172+
173+
# if compensated
174+
# axb!(du_sum,Δt_Δn,du)
175+
# axb!(dv_sum,Δt_Δn,dv)
176+
# end
137177
end
138178

139179
# semi-implicit for continuity equation, use new u1,v1 to calcualte dη
@@ -146,6 +186,9 @@ function time_integration( Prog::PrognosticVars{Tprog},
146186
dxaybzc!(η1,kna,η1,knb,η0,Δt_Δnc,dη)
147187
else
148188
axb!(η1,Δt_Δn,dη)
189+
# if compensated
190+
# axb!(dη_sum,Δt_Δn,dη)
191+
# end
149192
end
150193

151194
# special stage that is needed later for the kn-th stage, store in u0,v0,η0 therefore
@@ -253,14 +296,15 @@ function time_integration( Prog::PrognosticVars{Tprog},
253296
end
254297

255298
"""Add to a x multiplied with b. a += x*b """
256-
function axb!(a::Array{T,2},x::T,b::Array{T,2}) where {T<:AbstractFloat}
299+
function axb!(a::Matrix{T},x::Real,b::Matrix{T}) where {T<:AbstractFloat}
257300
m,n = size(a)
258301
@boundscheck (m,n) == size(b) || throw(BoundsError())
259302

260-
#TODO @simd?
303+
xT = convert(T,x)
304+
261305
@inbounds for j 1:n
262306
for i 1:m
263-
a[i,j] += x*b[i,j]
307+
a[i,j] += xT*b[i,j]
264308
end
265309
end
266310
end
@@ -278,13 +322,28 @@ function caxb!(c::Array{T,2},a::Array{T,2},x::T,b::Array{T,2}) where {T<:Abstrac
278322
end
279323
end
280324

325+
"""d equals add a minus b minus c. c = (a - b) - c."""
326+
function dambmc!(d::Matrix{T},a::Matrix{T},b::Matrix{T},c::Matrix{T}) where {T<:AbstractFloat}
327+
m,n = size(a)
328+
@boundscheck (m,n) == size(b) || throw(BoundsError())
329+
@boundscheck (m,n) == size(c) || throw(BoundsError())
330+
@boundscheck (m,n) == size(d) || throw(BoundsError())
331+
332+
@inbounds for j 1:n
333+
for i 1:m
334+
d[i,j] = (a[i,j] - b[i,j]) - c[i,j]
335+
end
336+
end
337+
end
338+
281339
"""c equals add x multiplied to a plus b. c = x*(a+b) """
282340
function cxab!(c::Array{T,2},x::Real,a::Array{T,2},b::Array{T,2}) where {T<:AbstractFloat}
283341
m,n = size(a)
284342
@boundscheck (m,n) == size(b) || throw(BoundsError())
285343
@boundscheck (m,n) == size(c) || throw(BoundsError())
286344

287-
xT = T(x)
345+
xT = convert(T,x)
346+
288347
@inbounds for j 1:n
289348
for i 1:m
290349
c[i,j] = xT*(a[i,j] + b[i,j])
@@ -298,8 +357,9 @@ function cxayb!(c::Array{T,2},x::Real,a::Array{T,2},y::Real,b::Array{T,2}) where
298357
@boundscheck (m,n) == size(b) || throw(BoundsError())
299358
@boundscheck (m,n) == size(c) || throw(BoundsError())
300359

301-
xT = T(x)
302-
yT = T(y)
360+
xT = convert(T,x)
361+
yT = convert(T,y)
362+
303363
@inbounds for j 1:n
304364
for i 1:m
305365
c[i,j] = xT*a[i,j] + yT*b[i,j]
@@ -317,9 +377,9 @@ function dxaybzc!( d::Array{T,2},
317377
@boundscheck (m,n) == size(c) || throw(BoundsError())
318378
@boundscheck (m,n) == size(d) || throw(BoundsError())
319379

320-
xT = T(x) # convert to type T
321-
yT = T(y)
322-
zT = T(z)
380+
xT = convert(T,x)
381+
yT = convert(T,y)
382+
zT = convert(T,z)
323383

324384
@inbounds for j 1:n
325385
for i 1:m

0 commit comments

Comments
 (0)