Skip to content

Stratified Couette flow verification #381

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 43 commits into from
Oct 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
c7dd889
Stratified Couette flow verification script
ali-ramadhan Aug 28, 2019
5e6a924
More comments
ali-ramadhan Aug 28, 2019
ba1afef
Use new HorizontalAverage diagnostic
ali-ramadhan Aug 28, 2019
b573c1f
Update script
ali-ramadhan Aug 28, 2019
1e280be
Diagnose viscous and diffusive CFL numbers from LES
ali-ramadhan Aug 28, 2019
84cb1f7
Don't divide time by length of Earth day.
ali-ramadhan Aug 29, 2019
42848ef
Fix errors in simulation setup
ali-ramadhan Aug 30, 2019
eb729dd
Add a lot more noise
ali-ramadhan Sep 5, 2019
259db0a
Use correct h when calculating frictional Re and Nu
ali-ramadhan Sep 6, 2019
8317668
Update model setup a bit
ali-ramadhan Sep 6, 2019
bccfd7c
Larger initial sine wave to encourage instability
ali-ramadhan Sep 6, 2019
5537310
Better notation for stratified Couette flow parameters
ali-ramadhan Sep 9, 2019
e2396a8
Nuke unused parameters
ali-ramadhan Sep 9, 2019
d5665b3
simulate_stratified_couette_flow function for automation
ali-ramadhan Sep 11, 2019
cc8ffe4
Simulate the three Pr = 0.7 cases
ali-ramadhan Sep 11, 2019
cdd04ba
Merge branch 'master' into stratified-couette-flow
ali-ramadhan Sep 11, 2019
73e9886
Use parameters to store stuff for Re and Nu functions
ali-ramadhan Sep 11, 2019
19ff426
Stratified Couette flow Re and Nu timeseries plot.
ali-ramadhan Sep 11, 2019
bdaa79b
Re and Nu scatter plot
ali-ramadhan Sep 11, 2019
0f8b229
Temperature and velocity profile verification
ali-ramadhan Sep 12, 2019
f06cdc4
Need N=128^3 to match published results
ali-ramadhan Sep 12, 2019
0277c6d
Plot LES profiles and U,T slices
ali-ramadhan Sep 12, 2019
1f3e271
No max filesize for output so analysis script always works
ali-ramadhan Sep 12, 2019
a1350a5
Clean up plots
ali-ramadhan Sep 12, 2019
1df3ca1
Uses horizontal averages directly for output, adds horizontal average…
glwagner Sep 12, 2019
fd3b351
Restores correct resolutions architecture for verification
glwagner Sep 12, 2019
b1c4957
Cannot set parameters to a dict because it must be kernel-ready
glwagner Sep 12, 2019
8c62fed
Some notational improvements to avoid confusion associated with the f…
glwagner Sep 12, 2019
8975044
changes scalars to statistics in stratified couette verification
glwagner Sep 12, 2019
6bc878c
Move verification directory to top-level
ali-ramadhan Sep 18, 2019
c1f121f
Spawn off run script and add arch kwarg
ali-ramadhan Sep 18, 2019
0fd80a6
end_time kwarg
ali-ramadhan Sep 18, 2019
4bb6901
Test that verification scripts run
ali-ramadhan Sep 18, 2019
9dfabba
Not sure why but test fails unless I include in global scope
ali-ramadhan Sep 18, 2019
773aef1
Only run for a single time step and actually include test
ali-ramadhan Sep 18, 2019
b78b37e
Specifically use Float64
ali-ramadhan Sep 19, 2019
ce661b4
Merge branch 'master' into stratified-couette-flow
ali-ramadhan Sep 20, 2019
929872f
Fix typo in test_examples.jl
ali-ramadhan Sep 20, 2019
fe044a4
Refactor stratified_couette_flow.jl for v0.11.0
ali-ramadhan Sep 20, 2019
6dc21af
Fix deepening_mixed_layer.jl example
ali-ramadhan Sep 20, 2019
3e6b73f
Try T0 to avoid conflicting with another T₀
ali-ramadhan Sep 20, 2019
54948b6
Merge branch 'master' into stratified-couette-flow
ali-ramadhan Oct 14, 2019
55ae7b1
Delete deepening_mixed_layer.jl
ali-ramadhan Oct 14, 2019
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
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,5 @@ EquationsOfState = (LinearEquationOfState, RoquetIdealizedNonlinearEquationOfSta
include("test_output_writers.jl")
include("test_regression.jl")
include("test_examples.jl")
include("test_verification.jl")
end
28 changes: 28 additions & 0 deletions test/test_verification.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
VERIFICATION_DIR = "../verification/"
EXPERIMENTS = ["stratified_couette_flow"]

for exp in EXPERIMENTS
script_filepath = joinpath(VERIFICATION_DIR, exp, exp * ".jl")
try
include(script_filepath)
catch err
@error sprint(showerror, err)
end
end

function run_stratified_couette_flow_verification(arch)
simulate_stratified_couette_flow(Nxy=16, Nz=8, arch=arch, Ri=0.01, Ni=1, end_time=1e-15)
return true
end


@testset "Verification" begin
println("Testing verification scripts...")

for arch in archs
@testset "Stratified Couette flow verification [$(typeof(arch))]" begin
println(" Testing stratified Couette flow verification [$(typeof(arch))]")
@test run_stratified_couette_flow_verification(arch)
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
include("stratified_couette_flow.jl")

simulate_stratified_couette_flow(Nxy=128, Nz=128, Ri=0)
simulate_stratified_couette_flow(Nxy=128, Nz=128, Ri=0.01)
simulate_stratified_couette_flow(Nxy=128, Nz=128, Ri=0.04)

260 changes: 260 additions & 0 deletions verification/stratified_couette_flow/stratified_couette_flow.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
using Statistics, Printf

using Oceananigans
using Oceananigans.TurbulenceClosures

""" Friction velocity. See equation (16) of Vreugdenhil & Taylor (2018). """
function uτ(model, Uavg)
Nz, Hz, Δz = model.grid.Nz, model.grid.Hz, model.grid.Δz
U_wall = model.parameters.U_wall
ν = model.closure.ν

U = Uavg(model)[1+Hz:end-Hz] # Exclude average of halo region.

# Use a finite difference to calculate dU/dz at the top and bottomtom walls.
# The distance between the center of the cell adjacent to the wall and the
# wall itself is Δz/2.
uτ²_top = ν * abs(U[1] - U_wall) / (Δz/2) # Top wall where u = +U_wall
uτ²_bottom = ν * abs(-U_wall - U[Nz]) / (Δz/2) # Bottom wall where u = -U_wall

uτ_top, uτ_bottom = √uτ²_top, √uτ²_bottom

return uτ_top, uτ_bottom
end

""" Heat flux at the wall. See equation (16) of Vreugdenhil & Taylor (2018). """
function q_wall(model, Tavg)
Nz, Hz, Δz = model.grid.Nz, model.grid.Hz, model.grid.Δz
Θ_wall = model.parameters.Θ_wall
κ = model.closure.κ

Θ = Tavg(model)[1+Hz:end-Hz] # Exclude average of halo region.

# Use a finite difference to calculate dθ/dz at the top and bottomtom walls.
# The distance between the center of the cell adjacent to the wall and the
# wall itself is Δz/2.
q_wall_top = κ * abs(Θ[1] - Θ_wall) / (Δz/2) # Top wall where Θ = +Θ_wall
q_wall_bottom = κ * abs(-Θ_wall - Θ[Nz]) / (Δz/2) # Bottom wall where Θ = -Θ_wall

return q_wall_top, q_wall_bottom
end

struct FrictionReynoldsNumber{H}
Uavg :: H
end

struct NusseltNumber{H}
Tavg :: H
end

""" Friction Reynolds number. See equation (20) of Vreugdenhil & Taylor (2018). """
function (Reτ::FrictionReynoldsNumber)(model)
ν = model.closure.ν
h = model.grid.Lz / 2
uτ_top, uτ_bottom = uτ(model, Reτ.Uavg)

return h * uτ_top / ν, h * uτ_bottom / ν
end

""" Nusselt number. See equation (20) of Vreugdenhil & Taylor (2018). """
function (Nu::NusseltNumber)(model)
κ = model.closure.κ
h = model.grid.Lz / 2
Θ_wall = model.parameters.Θ_wall

q_wall_top, q_wall_bottom = q_wall(model, Nu.Tavg)

return (q_wall_top * h)/(κ * Θ_wall), (q_wall_bottom * h)/(κ * Θ_wall)
end

"""
simulate_stratified_couette_flow(; Nxy, Nz, h=1, U_wall=1, Re=4250, Pr=0.7, Ri, Ni=10, end_time=1000)

Simulate stratified plane Couette flow with `Nxy` grid cells in each horizontal
direction, `Nz` grid cells in the vertical, in a domain of size (4πh, 2πh, 2h),
with wall velocities of `U_wall` at the top and -`U_wall` at the bottom, at a Reynolds
number `Re, Prandtl number `Pr`, and Richardson number `Ri`.

`Ni` is the number of "intermediate" time steps taken at a time before printing a progress
statement and updating the time step.
"""
function simulate_stratified_couette_flow(; Nxy, Nz, arch=GPU(), h=1, U_wall=1, Re=4250, Pr=0.7, Ri, Ni=10, end_time=1000)
####
#### Computed parameters
####

ν = U_wall * h / Re # From Re = U_wall h / ν
Θ_wall = Ri * U_wall^2 / h # From Ri = L Θ_wall / U_wall²
κ = ν / Pr # From Pr = ν / κ

parameters = (U_wall=U_wall, Θ_wall=Θ_wall, Re=Re, Pr=Pr, Ri=Ri)

####
#### Impose boundary conditions
####

Tbcs = HorizontallyPeriodicBCs( top = BoundaryCondition(Value, Θ_wall),
bottom = BoundaryCondition(Value, -Θ_wall))

ubcs = HorizontallyPeriodicBCs( top = BoundaryCondition(Value, U_wall),
bottom = BoundaryCondition(Value, -U_wall))

vbcs = HorizontallyPeriodicBCs( top = BoundaryCondition(Value, 0),
bottom = BoundaryCondition(Value, 0))

####
#### Non-dimensional model setup
####

model = Model(
architecture = arch,
grid = RegularCartesianGrid(N = (Nxy, Nxy, Nz), L = (4π*h, 2π*h, 2h)),
buoyancy = SeawaterBuoyancy(equation_of_state=LinearEquationOfState(α=1.0, β=0.0)),
closure = AnisotropicMinimumDissipation(ν=ν, κ=κ),
boundary_conditions = HorizontallyPeriodicSolutionBCs(u=ubcs, v=vbcs, T=Tbcs),
parameters = parameters
)

####
#### Set initial conditions
####

# Add a bit of surface-concentrated noise to the initial condition
ε(σ, z) = σ * randn() * z/model.grid.Lz * (1 + z/model.grid.Lz)

# We add a sinusoidal initial condition to u to encourage instability.
T₀(x, y, z) = 2Θ_wall * (1/2 + z/model.grid.Lz) * (1 + ε(5e-1, z))
u₀(x, y, z) = 2U_wall * (1/2 + z/model.grid.Lz) * (1 + ε(5e-1, z)) * (1 + 0.5*sin(4π/model.grid.Lx * x))
v₀(x, y, z) = ε(5e-1, z)
w₀(x, y, z) = ε(5e-1, z)

set_ic!(model, u=u₀, v=v₀, w=w₀, T=T₀)

####
#### Print simulation banner
####

@printf(
"""
Simulating stratified plane Couette flow

N : %d, %d, %d
L : %.3g, %.3g, %.3g
Re : %.3f
Ri : %.3f
Pr : %.3f
ν : %.3g
κ : %.3g
U_wall : %.3f
Θ_wall : %.3f

""", model.grid.Nx, model.grid.Ny, model.grid.Nz,
model.grid.Lx, model.grid.Ly, model.grid.Lz,
Re, Ri, Pr, ν, κ, U_wall, Θ_wall)

####
#### Set up field output writer
####

base_dir = @sprintf("stratified_couette_flow_data_Nxy%d_Nz%d_Ri%.2f", Nxy, Nz, Ri)
prefix = @sprintf("stratified_couette_flow_Nxy%d_Nz%d_Ri%.2f", Nxy, Nz, Ri)

function init_save_parameters_and_bcs(file, model)
file["parameters/reynolds_number"] = Re
file["parameters/richardson_number"] = Ri
file["parameters/prandtl_number"] = Pr
file["parameters/viscosity"] = ν
file["parameters/diffusivity"] = κ
file["parameters/wall_velocity"] = U_wall
file["parameters/wall_temperature"] = Θ_wall
end

fields = Dict(
:u => model -> Array(model.velocities.u.data.parent),
:v => model -> Array(model.velocities.v.data.parent),
:w => model -> Array(model.velocities.w.data.parent),
:T => model -> Array(model.tracers.T.data.parent),
:kappaT => model -> Array(model.diffusivities.κₑ.T.data.parent),
:nu => model -> Array(model.diffusivities.νₑ.data.parent))

field_writer = JLD2OutputWriter(model, fields; dir=base_dir, prefix=prefix * "_fields",
init=init_save_parameters_and_bcs,
interval=10, force=true, verbose=true)

push!(model.output_writers, field_writer)

####
#### Set up profile output writer
####

Uavg = HorizontalAverage(model, model.velocities.u; return_type=Array)
Vavg = HorizontalAverage(model, model.velocities.v; return_type=Array)
Wavg = HorizontalAverage(model, model.velocities.w; return_type=Array)
Tavg = HorizontalAverage(model, model.tracers.T; return_type=Array)
νavg = HorizontalAverage(model, model.diffusivities.νₑ; return_type=Array)
κavg = HorizontalAverage(model, model.diffusivities.κₑ.T; return_type=Array)

profiles = Dict(
:u => model -> Uavg(model),
:v => model -> Vavg(model),
:w => model -> Wavg(model),
:T => model -> Tavg(model),
:nu => model -> νavg(model),
:kappaT => model -> κavg(model))

profile_writer = JLD2OutputWriter(model, profiles; dir=base_dir, prefix=prefix * "_profiles",
init=init_save_parameters_and_bcs, interval=1, force=true, verbose=true)

push!(model.output_writers, profile_writer)

####
#### Set up statistic output writer
####

Reτ = FrictionReynoldsNumber(Uavg)
Nu = NusseltNumber(Tavg)

statistics = Dict(
:Re_tau => model -> Reτ(model),
:Nu => model -> Nu(model))

statistics_writer = JLD2OutputWriter(model, statistics; dir=base_dir, prefix=prefix * "_statistics",
init=init_save_parameters_and_bcs, interval=1/2, force=true, verbose=true)

push!(model.output_writers, statistics_writer)

####
#### Time stepping
####

wizard = TimeStepWizard(cfl=0.02, Δt=0.0001, max_change=1.1, max_Δt=0.02)

cfl(t) = min(0.01*t, 0.1)

while model.clock.time < end_time
wizard.cfl = cfl(model.clock.time)

walltime = @elapsed time_step!(model; Nt=Ni, Δt=wizard.Δt)
progress = 100 * (model.clock.time / end_time)

umax = maximum(abs, model.velocities.u.data.parent)
vmax = maximum(abs, model.velocities.v.data.parent)
wmax = maximum(abs, model.velocities.w.data.parent)
CFL = wizard.Δt / Oceananigans.cell_advection_timescale(model)

νmax = maximum(model.diffusivities.νₑ.data.parent)
κmax = maximum(model.diffusivities.κₑ.T.data.parent)

Δ = min(model.grid.Δx, model.grid.Δy, model.grid.Δz)
νCFL = wizard.Δt / (Δ^2 / νmax)
κCFL = wizard.Δt / (Δ^2 / κmax)

update_Δt!(wizard, model)

@printf("[%06.2f%%] i: %d, t: %4.2f, umax: (%6.3g, %6.3g, %6.3g) m/s, CFL: %6.4g, νκmax: (%6.3g, %6.3g), νκCFL: (%6.4g, %6.4g), next Δt: %8.5g, ⟨wall time⟩: %s\n",
progress, model.clock.iteration, model.clock.time,
umax, vmax, wmax, CFL, νmax, κmax, νCFL, κCFL,
wizard.Δt, prettytime(walltime / Ni))
end
end

Loading