Skip to content
This repository has been archived by the owner on Mar 1, 2023. It is now read-only.

Add SplitExplicitStepper with decoupled spin-down test #1257

Merged
merged 1 commit into from
Jun 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions docs/src/APIs/Numerics/ODESolvers/ODESolvers.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ ODESolvers.LSRKEulerMethod
ODESolvers.MultirateRungeKutta
```

## Split-explicit methods

```@docs
ODESolvers.SplitExplicitSolver
```

## GARK methods

```@docs
Expand Down
3 changes: 2 additions & 1 deletion slurmci-test.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ cpu_gpu = [
{ file = "test/Numerics/Mesh/interpolation.jl", slurmargs = ["--ntasks=3"], args = [] },
{ file = "test/Ocean/ShallowWater/GyreDriver.jl", slurmargs = ["--ntasks=1"], args = [] },
{ file = "test/Ocean/ShallowWater/2D_hydrostatic_spindown.jl", slurmargs = ["--ntasks=1"], args = [] },
{ file = "test/Ocean/HydrostaticBoussinesq/3D_hydrostatic_spindown.jl", slurmargs = ["--ntasks=3"], args = [] },
{ file = "test/Ocean/HydrostaticBoussinesq/3D_hydrostatic_spindown.jl", slurmargs = ["--ntasks=1"], args = [] },
{ file = "test/Ocean/SplitExplicit/hydrostatic_spindown.jl", slurmargs = ["--ntasks=1"], args = [] },
{ file = "tutorials/Numerics/DGMethods/nonnegative.jl", slurmargs = ["--ntasks=3"], args = [] },
{ file = "test/Atmos/Parameterizations/Microphysics/KM_saturation_adjustment.jl", slurmargs = ["--ntasks=3"], args = [] },
{ file = "test/Atmos/Parameterizations/Microphysics/KM_warm_rain.jl", slurmargs = ["--ntasks=3"], args = [] },
Expand Down
6 changes: 6 additions & 0 deletions src/BalanceLaws/interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -326,3 +326,9 @@ num_hyperdiffusive(m::BalanceLaw, FT) = varsize(vars_hyperdiffusive(m, FT))
num_integrals(m::BalanceLaw, FT) = varsize(vars_integrals(m, FT))
num_reverse_integrals(m::BalanceLaw, FT) =
varsize(vars_reverse_integrals(m, FT))

### split explicit functions
function initialize_states! end
function tendency_from_slow_to_fast! end
function cummulate_fast_solution! end
function reconcile_from_fast_to_slow! end
1 change: 1 addition & 0 deletions src/ClimateMachine.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ include(joinpath(
"HydrostaticBoussinesq",
"HydrostaticBoussinesqModel.jl",
))
include(joinpath("Ocean", "SplitExplicit", "SplitExplicitModel.jl"))
include(joinpath("Numerics", "SystemSolvers", "SystemSolvers.jl"))
include(joinpath("Numerics", "ODESolvers", "ODESolvers.jl"))
include(joinpath("Numerics", "ODESolvers", "GenericCallbacks.jl"))
Expand Down
1 change: 1 addition & 0 deletions src/Numerics/DGMethods/DGModel.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ struct DGModel{BL, G, NFND, NFD, GNF, AS, DS, HDS, D, DD, MD}
diffusion_direction::DD
modeldata::MD
end

function DGModel(
balance_law,
grid,
Expand Down
1 change: 1 addition & 0 deletions src/Numerics/ODESolvers/ODESolvers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -165,5 +165,6 @@ include("StrongStabilityPreservingRungeKuttaMethod.jl")
include("AdditiveRungeKuttaMethod.jl")
include("MultirateInfinitesimalStepMethod.jl")
include("MultirateRungeKuttaMethod.jl")
include("SplitExplicitMethod.jl")
blallen marked this conversation as resolved.
Show resolved Hide resolved

end # module
190 changes: 190 additions & 0 deletions src/Numerics/ODESolvers/SplitExplicitMethod.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
export SplitExplicitSolver

using ..BalanceLaws:
initialize_states!,
tendency_from_slow_to_fast!,
cummulate_fast_solution!,
reconcile_from_fast_to_slow!

LSRK2N = LowStorageRungeKutta2N

@doc """
SplitExplicitSolver(slow_solver, fast_solver; dt, t0 = 0, coupled = true)

This is a time stepping object for explicitly time stepping the differential
equation given by the right-hand-side function `f` with the state `Q`, i.e.,

```math
\\dot{Q_fast} = f_fast(Q_fast, Q_slow, t)
\\dot{Q_slow} = f_slow(Q_slow, Q_fast, t)
```

with the required time step size `dt` and optional initial time `t0`. This
time stepping object is intended to be passed to the `solve!` command.

This method performs an operator splitting to timestep the vertical average
of the model at a faster rate than the full model. This results in a first-
order time stepper.

""" SplitExplicitSolver
mutable struct SplitExplicitSolver{SS, FS, RT, MSA} <: AbstractODESolver
"slow solver"
slow_solver::SS
"fast solver"
fast_solver::FS
"time step"
dt::RT
"time"
t::RT
"flag to couple the models"
coupled
"storage for transfer tendency"
dQ2fast::MSA

function SplitExplicitSolver(
slow_solver::LSRK2N,
fast_solver,
Q = nothing;
dt = getdt(slow_solver),
t0 = slow_solver.t,
coupled = true,
) where {AT <: AbstractArray}
SS = typeof(slow_solver)
FS = typeof(fast_solver)
RT = real(eltype(slow_solver.dQ))

dQ2fast = similar(slow_solver.dQ)
MSA = typeof(dQ2fast)
return new{SS, FS, RT, MSA}(
slow_solver,
fast_solver,
RT(dt),
RT(t0),
coupled,
dQ2fast,
)
end
end

function dostep!(
Qvec,
split::SplitExplicitSolver{SS},
param,
time::Real,
) where {SS <: LSRK2N}
slow = split.slow_solver
fast = split.fast_solver

Qslow = Qvec.slow
Qfast = Qvec.fast

dQslow = slow.dQ
dQ2fast = split.dQ2fast

slow_bl = slow.rhs!.balance_law
fast_bl = fast.rhs!.balance_law

groupsize = 256

slow_dt = getdt(slow)
fast_dt_in = getdt(fast)

for slow_s in 1:length(slow.RKA)
# Current slow state time
slow_stage_time = time + slow.RKC[slow_s] * slow_dt

# Initialize fast model and tendency adjustment
# before evalution of slow mode
if split.coupled
initialize_states!(
slow_bl,
fast_bl,
slow.rhs!,
fast.rhs!,
Qslow,
Qfast,
)

# Evaluate the slow mode
# --> save tendency for the fast
slow.rhs!(dQ2fast, Qslow, param, slow_stage_time, increment = false)

# vertically integrate slow tendency to advance fast equation
# and use vertical mean for slow model (negative source)
# ---> work with dQ2fast as input
tendency_from_slow_to_fast!(
slow_bl,
fast_bl,
slow.rhs!,
fast.rhs!,
Qslow,
Qfast,
dQ2fast,
)
end

# Compute (and RK update) slow tendency
slow.rhs!(dQslow, Qslow, param, slow_stage_time, increment = true)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can replace this with something like

Suggested change
slow.rhs!(dQslow, Qslow, param, slow_stage_time, increment = true)
dQslow .+= dQ2fast

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(unless Qslow is modified in tendency_from_slow_to_fast)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jm-c can you test this change in your branch?


# Update (RK-stage) slow state
event = Event(array_device(Qslow))
event = update!(array_device(Qslow), groupsize)(
realview(dQslow),
realview(Qslow),
slow.RKA[slow_s % length(slow.RKA) + 1],
slow.RKB[slow_s],
slow_dt,
nothing,
nothing,
nothing;
ndrange = length(realview(Qslow)),
dependencies = (event,),
)
wait(array_device(Qslow), event)

# Fractional time for slow stage
if slow_s == length(slow.RKA)
γ = 1 - slow.RKC[slow_s]
else
γ = slow.RKC[slow_s + 1] - slow.RKC[slow_s]
end

# RKB for the slow with fractional time factor remove (since full
# integration of fast will result in scaling by γ)
nsubsteps = fast_dt_in > 0 ? ceil(Int, γ * slow_dt / fast_dt_in) : 1
fast_dt = γ * slow_dt / nsubsteps

updatedt!(fast, fast_dt)

for substep in 1:nsubsteps
fast_time = slow_stage_time + (substep - 1) * fast_dt
dostep!(Qfast, fast, param, fast_time)
if split.coupled
cummulate_fast_solution!(
slow_bl,
fast_bl,
fast.rhs!,
Qfast,
fast_time,
fast_dt,
substep,
)
end
end

# reconcile slow equation using fast equation
if split.coupled
reconcile_from_fast_to_slow!(
slow_bl,
fast_bl,
slow.rhs!,
fast.rhs!,
Qslow,
Qfast,
)
end
end
updatedt!(fast, fast_dt_in)

return nothing
end
7 changes: 5 additions & 2 deletions src/Ocean/HydrostaticBoussinesq/HydrostaticBoussinesqModel.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ using ..MPIStateArrays
using ..Mesh.Filters: apply!
using ..Mesh.Grids: VerticalDirection
using ..BalanceLaws: BalanceLaw
import ..BalanceLaws:
nodal_update_auxiliary_state!,
import ..BalanceLaws: nodal_update_auxiliary_state!
using ..DGMethods.NumericalFluxes: RusanovNumericalFlux

import ..DGMethods.NumericalFluxes: update_penalty!
import ..DGMethods:
vars_state_conservative,
vars_state_auxiliary,
vars_state_gradient,
Expand Down
36 changes: 36 additions & 0 deletions src/Ocean/SplitExplicit/SplitExplicitModel.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
module SplitExplicit

using ..HydrostaticBoussinesq
using ..ShallowWater

import ..BalanceLaws:
initialize_states!,
tendency_from_slow_to_fast!,
cummulate_fast_solution!,
reconcile_from_fast_to_slow!

@inline initialize_states!(
slow::HydrostaticBoussinesqModel,
fast::ShallowWaterModel,
_...,
) = nothing

@inline tendency_from_slow_to_fast!(
slow::HydrostaticBoussinesqModel,
fast::ShallowWaterModel,
_...,
) = nothing

@inline cummulate_fast_solution!(
slow::HydrostaticBoussinesqModel,
fast::ShallowWaterModel,
_...,
) = nothing

@inline reconcile_from_fast_to_slow!(
slow::HydrostaticBoussinesqModel,
fast::ShallowWaterModel,
_...,
) = nothing

end
Loading