Skip to content

Commit b2f6f58

Browse files
authored
Merge pull request #157 from milankl/scale
Scale sst, tracer relaxation & consumption, checkerboard initial conditions, ridges
2 parents 75c7b08 + ef25f76 commit b2f6f58

11 files changed

+126
-102
lines changed

src/constants.jl

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,17 @@ struct Constants{T<:AbstractFloat,Tprog<:AbstractFloat}
4646
γ::T # frequency of interface relaxation
4747
cSmag::T # Smagorinsky constant
4848
νB::T # biharmonic diffusion coefficient
49-
rSST::T # tracer restoring timescale
49+
τSST::T # tracer restoring timescale
5050
jSST::T # tracer consumption timescale
51-
SSTmin::T # tracer minimum
5251
ωFη::Float64 # frequency [1/s] of seasonal surface forcing incl 2π
5352
ωFx::Float64 # frequency [1/s] of seasonal wind x incl 2π
5453
ωFy::Float64 # frequency [1/2] of seasonal wind y incl 2π
5554

5655
# SCALING
5756
scale::T # multiplicative constant for low-precision arithmetics
58-
scale_inv::T # and it's inverse
57+
scale_inv::T # and its inverse
58+
scale_sst::T # scale for sst
59+
scale_sst_inv::T # and its inverse
5960
end
6061

6162
"""Generator function for the mutable struct Constants."""
@@ -105,22 +106,24 @@ function Constants{T,Tprog}(P::Parameter,G::Grid) where {T<:AbstractFloat,Tprog<
105106
νB = T(-P.νB/30000) # linear scaling based on 540m^s/s at Δ=30km
106107

107108
# TRACER ADVECTION
108-
rSST = T(G.dtadvint/(P.τSST*3600*24)) # tracer restoring [1]
109+
τSST = T(G.dtadvint/(P.τSST*3600*24)) # tracer restoring [1]
109110
jSST = T(G.dtadvint/(P.jSST*3600*24)) # tracer consumption [1]
110-
SSTmin = T(P.SSTmin)
111111

112112
# TIME DEPENDENT FORCING
113113
ωFη = -2π*P.ωFη/24/365.25/3600
114114
ωFx = 2π*P.ωFx/24/365.25/3600
115115
ωFy = 2π*P.ωFy/24/365.25/3600
116116

117117
# SCALING
118-
scale = T(P.scale)
119-
scale_inv = T(1/P.scale)
118+
scale = convert(T,P.scale)
119+
scale_inv = convert(T,1/P.scale)
120+
scale_sst = convert(T,P.scale_sst)
121+
scale_sst_inv = convert(T,1/P.scale_sst)
120122

121123
return Constants{T,Tprog}( RKaΔt,RKbΔt,Δt_Δs,Δt_Δ,Δt_Δ_half,
122124
SSPRK3c,one_minus_α,
123-
g,cD,rD,γ,cSmag,νB,rSST,
124-
jSST,SSTmin,ωFη,ωFx,ωFy,
125-
scale,scale_inv)
125+
g,cD,rD,γ,cSmag,νB,τSST,jSST,
126+
ωFη,ωFx,ωFy,
127+
scale,scale_inv,
128+
scale_sst,scale_sst_inv)
126129
end

src/default_parameters.jl

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,22 @@
2020
R::Real=6.371e6 # Earth's radius [m]
2121

2222
# SCALE
23-
scale::Real=1 # multiplicative scale for the momentum equations u,v
23+
scale::Real=2^6 # multiplicative scale for the momentum equations u,v
24+
scale_sst::Real=2^15 # multiplicative scale for sst
2425

2526
# WIND FORCING OPTIONS
26-
wind_forcing_x::String="channel" # "channel", "double_gyre", "shear","constant" or "none"
27+
wind_forcing_x::String="shear" # "channel", "double_gyre", "shear","constant" or "none"
2728
wind_forcing_y::String="constant" # "channel", "double_gyre", "shear","constant" or "none"
2829
Fx0::Real=0.12 # wind stress strength [Pa] in x-direction
2930
Fy0::Real=0.0 # wind stress strength [Pa] in y-direction
30-
seasonal_wind_x::Bool=false # Change the wind stress with a sine of frequency ωFx,ωFy
31+
seasonal_wind_x::Bool=true # Change the wind stress with a sine of frequency ωFx,ωFy
3132
seasonal_wind_y::Bool=false # same for y-component
32-
ωFx::Real=1.0 # frequency [1/year] for x component
33-
ωFy::Real=1.0 # frequency [1/year] for y component
33+
ωFx::Real=2 # frequency [1/year] for x component
34+
ωFy::Real=2 # frequency [1/year] for y component
3435

3536
# BOTTOM TOPOGRAPHY OPTIONS
3637
topography::String="ridges" # "ridge", "seamount", "flat", "ridges", "bathtub"
38+
topo_ridges_positions::Vector = [0.05,0.25,0.45,0.9]
3739
topo_height::Real=100. # height of seamount [m]
3840
topo_width::Real=300e3 # horizontal scale [m] of the seamount
3941

@@ -83,23 +85,21 @@
8385

8486
# TRACER ADVECTION
8587
tracer_advection::Bool=true # yes?
86-
tracer_relaxation::Bool=false # yes?
88+
tracer_relaxation::Bool=true # yes?
8789
tracer_consumption::Bool=false # yes?
88-
tracer_pumping::Bool=false # yes?
89-
injection_region::String="west" # "west", "south", "rect" or "flat"
90-
sst_initial::String="south" # "west", "south", "rect", "flat" or "restart"
90+
sst_initial::String="waves" # "west", "south", "linear", "waves","rect", "flat" or "restart"
9191
sst_rect_coords::Array{Float64,1}=[0.,0.15,0.,1.0]
9292
# (x0,x1,y0,y1) are the size of the rectangle in [0,1]
9393
Uadv::Real=0.2 # Velocity scale [m/s] for tracer advection
94-
SSTmax::Real=1. # tracer (sea surface temperature) max for restoring
95-
SSTmin::Real=-1. # tracer (sea surface temperature) min for restoring
96-
τSST::Real=500. # tracer restoring time scale [days]
97-
jSST::Real=365. # tracer consumption [days]
98-
SST_λ0::Real=222e3 # [m] transition position of relaxation timescale
99-
SST_λs::Real=111e3 # [m] transition width of relaxation timescale
100-
SST_γ0::Real=8.35 # [days] injection time scale
94+
SSTmax::Real=1. # tracer (sea surface temperature) max for initial conditions
95+
SSTmin::Real=-1. # tracer (sea surface temperature) min for initial conditions
96+
τSST::Real=100 # tracer restoring time scale [days]
97+
jSST::Real=365 # tracer consumption [days]
10198
SSTw::Real=5e5 # width [m] of the tangent used for the IC and interface relaxation
10299
SSTϕ::Real=0.5 # latitude/longitude fraction ∈ [0,1] of sst edge
100+
SSTwaves_ny::Real=4 # wave crests/troughs in y
101+
SSTwaves_nx::Real=SSTwaves_ny*L_ratio # wave crests/troughs in x
102+
SSTwaves_p::Real=1/2 # power for rectangles (p<1)/smootheness(p>=1) of waves
103103

104104
# OUTPUT OPTIONS
105105
output::Bool=false # netcdf output?
@@ -143,7 +143,6 @@
143143
@assert diffusion in ["Smagorinsky", "constant"] "Diffusion '$diffusion' unsupported."
144144
@assert νB > 0.0 "Diffusion scaling constant νB has to be >0, $νB given."
145145
@assert cSmag > 0.0 "Smagorinsky coefficient cSmag has to be >0, $cSmag given."
146-
@assert injection_region in ["west","south"] "Injection region '$injection_region' unsupported."
147146
@assert Uadv > 0.0 "Advection velocity scale Uadv has to be >0, $Uadv given."
148147
@assert output_dt > 0 "Output time step has to be >0, $output_dt given."
149148
@assert initial_cond in ["rest", "ncfile"] "Initial conditions '$initial_cond' unsupported."
@@ -175,20 +174,22 @@ Creates a Parameter struct with following options and default values
175174
R::Real=6.371e6 # Earth's radius [m]
176175
177176
# SCALE
178-
scale::Real=1 # multiplicative scale for the momentum equations u,v
177+
scale::Real=2^6 # multiplicative scale for the momentum equations u,v
178+
scale_sst::Real=2^15 # multiplicative scale for sst
179179
180180
# WIND FORCING OPTIONS
181-
wind_forcing_x::String="channel" # "channel", "double_gyre", "shear","constant" or "none"
181+
wind_forcing_x::String="shear" # "channel", "double_gyre", "shear","constant" or "none"
182182
wind_forcing_y::String="constant" # "channel", "double_gyre", "shear","constant" or "none"
183183
Fx0::Real=0.12 # wind stress strength [Pa] in x-direction
184184
Fy0::Real=0.0 # wind stress strength [Pa] in y-direction
185-
seasonal_wind_x::Bool=false # Change the wind stress with a sine of frequency ωFx,ωFy
185+
seasonal_wind_x::Bool=true # Change the wind stress with a sine of frequency ωFx,ωFy
186186
seasonal_wind_y::Bool=false # same for y-component
187-
ωFx::Real=1.0 # frequency [1/year] for x component
188-
ωFy::Real=1.0 # frequency [1/year] for y component
187+
ωFx::Real=2 # frequency [1/year] for x component
188+
ωFy::Real=2 # frequency [1/year] for y component
189189
190190
# BOTTOM TOPOGRAPHY OPTIONS
191191
topography::String="ridges" # "ridge", "seamount", "flat", "ridges", "bathtub"
192+
topo_ridges_positions::Vector = [0.05,0.25,0.45,0.9]
192193
topo_height::Real=100. # height of seamount [m]
193194
topo_width::Real=300e3 # horizontal scale [m] of the seamount
194195
@@ -238,29 +239,28 @@ Creates a Parameter struct with following options and default values
238239
239240
# TRACER ADVECTION
240241
tracer_advection::Bool=true # yes?
241-
tracer_relaxation::Bool=false # yes?
242+
tracer_relaxation::Bool=true # yes?
242243
tracer_consumption::Bool=false # yes?
243-
tracer_pumping::Bool=false # yes?
244-
injection_region::String="west" # "west", "south", "rect" or "flat"
245-
sst_initial::String="south" # "west", "south", "rect", "flat" or "restart"
244+
sst_initial::String="waves" # "west", "south", "linear", "waves","rect", "flat" or "restart"
246245
sst_rect_coords::Array{Float64,1}=[0.,0.15,0.,1.0]
247246
# (x0,x1,y0,y1) are the size of the rectangle in [0,1]
248247
Uadv::Real=0.2 # Velocity scale [m/s] for tracer advection
249-
SSTmax::Real=1. # tracer (sea surface temperature) max for restoring
250-
SSTmin::Real=-1. # tracer (sea surface temperature) min for restoring
251-
τSST::Real=500. # tracer restoring time scale [days]
252-
jSST::Real=365. # tracer consumption [days]
253-
SST_λ0::Real=222e3 # [m] transition position of relaxation timescale
254-
SST_λs::Real=111e3 # [m] transition width of relaxation timescale
255-
SST_γ0::Real=8.35 # [days] injection time scale
248+
SSTmax::Real=1. # tracer (sea surface temperature) max for initial conditions
249+
SSTmin::Real=-1. # tracer (sea surface temperature) min for initial conditions
250+
τSST::Real=100 # tracer restoring time scale [days]
251+
jSST::Real=365 # tracer consumption [days]
256252
SSTw::Real=5e5 # width [m] of the tangent used for the IC and interface relaxation
257253
SSTϕ::Real=0.5 # latitude/longitude fraction ∈ [0,1] of sst edge
254+
SSTwaves_ny::Real=4 # wave crests/troughs in y
255+
SSTwaves_nx::Real=SSTwaves_ny*L_ratio # wave crests/troughs in x
256+
SSTwaves_p::Real=1/2 # power for rectangles (p<1)/smootheness(p>=1) of waves
258257
259258
# OUTPUT OPTIONS
260259
output::Bool=false # netcdf output?
261260
output_vars::Array{String,1}=["u","v","η","sst"] # which variables to output? "du","dv","dη" also allowed
262261
output_dt::Real=24 # output time step [hours]
263262
outpath::String=pwd() # path to output folder
263+
compression_level::Int=3 # compression level
264264
265265
# INITIAL CONDITIONS
266266
initial_cond::String="rest" # "rest" or "ncfile" for restart from file

src/feedback.jl

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,25 @@ function duration_estimate(feedback::Feedback,S::ModelSetup)
5656
end
5757
end
5858

59+
"""Returns the number of NaNs in an array."""
60+
function countnans(A::AbstractArray)
61+
n_nan = 0
62+
for a in A
63+
n_nan += isnan(a) ? 1 : 0
64+
end
65+
return n_nan
66+
end
67+
5968
"""Returns a boolean whether the prognostic variables contains a NaN."""
6069
function nan_detection!(Prog::PrognosticVars,feedback::Feedback)
6170

62-
#TODO include a check for Posits
63-
#TODO include check for sst
64-
6571
@unpack u,v,η,sst = Prog
6672

67-
n_nan = sum(isnan.(u)) + sum(isnan.(v)) + sum(isnan.(η)) + sum(isnan.(sst))
73+
n_nan = countnans(u)
74+
n_nan += countnans(v)
75+
n_nan += countnans(η)
76+
n_nan += countnans(sst)
77+
6878
if n_nan > 0
6979
feedback.nans_detected = true
7080
end

src/forcing.jl

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -167,24 +167,24 @@ function Ridge(::Type{T},P::Parameter,G::Grid) where {T<:AbstractFloat}
167167
return T.(Hx),T.(Hy)
168168
end
169169

170-
"""Same as Ridge() but for 3 ridges at 1/4,1/2,3/4 of the domain."""
170+
"""Same as Ridge() but for n ridges at various x positions."""
171171
function Ridges(::Type{T},P::Parameter,G::Grid) where {T<:AbstractFloat}
172172

173173
@unpack x_T_halo,y_T_halo,Lx,Ly = G
174174
@unpack topo_width,topo_height,H = P
175+
@unpack topo_ridges_positions = P
176+
n_ridges = length(topo_ridges_positions)
175177

176178
xx_T,yy_T = meshgrid(x_T_halo,y_T_halo)
177179

178-
# bumps in x direction
179-
# shift slightly left/right to avoid a symmetric solution
180-
b0x = exp.(-(xx_T.^2)/(2*topo_width^2))
181-
b1x = exp.(-((xx_T .- 0.99*Lx/4).^2)/(2*topo_width^2))
182-
b2x = exp.(-((xx_T .- 1.01*Lx/2).^2)/(2*topo_width^2))
183-
b3x = exp.(-((xx_T .- 0.99*3*Lx/4).^2)/(2*topo_width^2))
184-
b4x = exp.(-((xx_T .- Lx).^2)/(2*topo_width^2))
180+
# loop over bumps in x direction
181+
R = zero(xx_T) .+ H
185182

186-
th = topo_height # for convenience
187-
return T.(H .- th*b0x .- th*b1x .- th*b2x .- th*b3x .- th*b4x)
183+
for i in 1:n_ridges
184+
R .-= topo_height*exp.(-((xx_T .- topo_ridges_positions[i]*Lx).^2)/(2*topo_width^2))
185+
end
186+
187+
return T.(R)
188188
end
189189

190190
"""Returns a matrix of constant water depth H."""
@@ -213,5 +213,5 @@ end
213213

214214
"""Time evolution of forcing."""
215215
function Ftime(::Type{T},t::Int::Real) where {T<:AbstractFloat}
216-
return T(sin*t))
217-
end
216+
return convert(T,sin*t))
217+
end

src/ghost_points.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ function add_halo( u::Array{T,2},
2222
sst = cat(zeros(T,nx+2*halosstx,halossty),sst,zeros(T,nx+2*halosstx,halossty),dims=2)
2323

2424
# SCALING
25-
@unpack scale = S.constants
25+
@unpack scale,scale_sst = S.constants
2626
u *= scale
2727
v *= scale
28-
sst *= scale
28+
sst *= scale_sst
2929

3030
ghost_points!(u,v,η,S)
3131
ghost_points_sst!(sst,S)
@@ -40,13 +40,13 @@ function remove_halo( u::Array{T,2},
4040
S::ModelSetup) where {T<:AbstractFloat}
4141

4242
@unpack halo,haloη,halosstx,halossty = S.grid
43-
@unpack scale_inv = S.constants
43+
@unpack scale_inv,scale_sst_inv = S.constants
4444

4545
# undo scaling as well
4646
ucut = scale_inv*u[halo+1:end-halo,halo+1:end-halo]
4747
vcut = scale_inv*v[halo+1:end-halo,halo+1:end-halo]
4848
ηcut = η[haloη+1:end-haloη,haloη+1:end-haloη]
49-
sstcut = scale_inv*sst[halosstx+1:end-halosstx,halossty+1:end-halossty]
49+
sstcut = scale_sst_inv*sst[halosstx+1:end-halosstx,halossty+1:end-halossty]
5050

5151
return ucut,vcut,ηcut,sstcut
5252
end

src/grid.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,8 @@ function meshgrid(x::AbstractVector,y::AbstractVector)
148148
m,n = length(x),length(y)
149149

150150
# preallocate preserving the data type of x,y
151-
xx = zeros(typeof(x[1]),m,n)
152-
yy = zeros(typeof(y[1]),m,n)
151+
xx = zeros(eltype(x),m,n)
152+
yy = zeros(eltype(y),m,n)
153153

154154
for i in 1:m
155155
xx[i,:] .= x[i]

src/initial_conditions.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ function initial_conditions(::Type{T},S::ModelSetup) where {T<:AbstractFloat}
119119
## SST
120120

121121
@unpack SSTmin, SSTmax, SSTw, SSTϕ = S.parameters
122+
@unpack SSTwaves_nx,SSTwaves_ny,SSTwaves_p = S.parameters
122123
@unpack sst_initial,scale = S.parameters
123124
@unpack x_T,y_T,Lx,Ly = S.grid
124125

@@ -128,6 +129,10 @@ function initial_conditions(::Type{T},S::ModelSetup) where {T<:AbstractFloat}
128129
sst = (SSTmin+SSTmax)/2 .+ tanh.(2π*(Ly/(4*SSTw))*(yy_T/Ly .- SSTϕ))*(SSTmin-SSTmax)/2
129130
elseif sst_initial == "west"
130131
sst = (SSTmin+SSTmax)/2 .+ tanh.(2π*(Lx/(4*SSTw))*(xx_T/Lx .- SSTϕ))*(SSTmin-SSTmax)/2
132+
elseif sst_initial == "linear"
133+
sst = SSTmin .+ yy_T/Ly*(SSTmax-SSTmin)
134+
elseif sst_initial == "waves"
135+
sst = waves(xx_T/Lx,yy_T/Ly,SSTwaves_nx,SSTwaves_ny,SSTwaves_p)
131136
elseif sst_initial == "flat"
132137
sst = fill(SSTmin,size(xx_T))
133138
elseif sst_initial == "rect"
@@ -158,3 +163,13 @@ function initial_conditions(::Type{T},S::ModelSetup) where {T<:AbstractFloat}
158163

159164
return PrognosticVars{T}(u,v,η,sst)
160165
end
166+
167+
"""Create a wave-checkerboard pattern over xx,yy like a nx x ny checkerboard.
168+
p is the power to which the waves are raised. Choose p<1 for rectangles, and
169+
p > 1 for more smootheness."""
170+
function waves(xx::AbstractMatrix,yy::AbstractMatrix,nx::Real,ny::Real,p::Real)
171+
@boundscheck size(xx) == size(yy) || throw(BoundsError())
172+
w = sin.(nx*π*xx) .* sin.(ny*π*yy)
173+
s = sign.(w)
174+
return s.*abs.(w).^p
175+
end

src/output.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ function output_nc!(i::Int,
9090

9191
@unpack halo,haloη,halosstx,halossty = S.grid
9292
@unpack f_q,ep,dtint = S.grid
93-
@unpack scale,scale_inv = S.constants
93+
@unpack scale,scale_inv,scale_sst_inv = S.constants
9494

9595
# CUT OFF HALOS
9696
# As output is before copyto!(u,u0), take u0,v0,η0
@@ -109,7 +109,7 @@ function output_nc!(i::Int,
109109
NetCDF.putvar(ncs.η,"eta",η,start=[1,1,iout],count=[-1,-1,1])
110110
end
111111
if ncs.sst != nothing
112-
@views sst = Float32.(scale_inv*Prog.sst[halosstx+1:end-halosstx,halossty+1:end-halossty])
112+
@views sst = Float32.(scale_sst_inv*Prog.sst[halosstx+1:end-halosstx,halossty+1:end-halossty])
113113
NetCDF.putvar(ncs.sst,"sst",sst,start=[1,1,iout],count=[-1,-1,1])
114114
end
115115
if ncs.q != nothing

src/preallocate.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,7 @@ end
421421
vinterp::Array{T,2} = zeros(T,nx,ny) # v interpolated on mid-point xd,yd
422422

423423
ssti::Array{T,2} = zeros(T,nx+2*halosstx,ny+2*halossty) # sst interpolated on departure points
424+
sst_ref::Array{T,2} = zeros(T,nx+2*halosstx,ny+2*halossty) # sst initial conditions for relaxation
424425
end
425426

426427
"""Generator function for SemiLagrange VarCollection."""

src/time_integration.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ function time_integration( Prog::PrognosticVars{Tprog},
3535
copyto!(v0,v)
3636
copyto!(η0,η)
3737

38+
# store initial conditions of sst for relaxation
39+
copyto!(Diag.SemiLagrange.sst_ref,sst)
40+
3841
# feedback, output initialisation and storing initial conditions
3942
feedback = feedback_init(S)
4043
netCDFfiles = NcFiles(feedback,S)

0 commit comments

Comments
 (0)