Skip to content

Commit

Permalink
Add support for source terms (#65)
Browse files Browse the repository at this point in the history
* add support for source terms

* fix calculation of source terms

* add test for manufactured solution of variable BBM-BBM

* fix test of convergence order

* adjust tolerance

* source terms for BBMBBMEquations

* format

* WIP: add source terms for Svärd-Kalisch equations

* Apply suggestions from code review

Co-authored-by: Hendrik Ranocha <[email protected]>

* add references

* add support of source terms for Svärd-Kalisch equations with constant bathymetry

* lower tolerances

* fix tolerances

* fix tolerances

---------

Co-authored-by: Hendrik Ranocha <[email protected]>
  • Loading branch information
JoshuaLampert and ranocha authored Nov 20, 2023
1 parent 68e64f4 commit a7dcc23
Show file tree
Hide file tree
Showing 13 changed files with 395 additions and 65 deletions.
40 changes: 40 additions & 0 deletions examples/bbm_bbm_1d/bbm_bbm_1d_manufactured.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using OrdinaryDiffEq
using DispersiveShallowWater

###############################################################################
# Semidiscretization of the BBM-BBM equations

equations = BBMBBMEquations1D(gravity_constant = 9.81, D = 4.0)

initial_condition = initial_condition_manufactured
source_terms = source_terms_manufactured
boundary_conditions = boundary_condition_periodic

# create homogeneous mesh
coordinates_min = 0.0
coordinates_max = 1.0
N = 512
mesh = Mesh1D(coordinates_min, coordinates_max, N)

# create solver with periodic SBP operators of accuracy order 4
accuracy_order = 4
solver = Solver(mesh, accuracy_order)

# semidiscretization holds all the necessary data structures for the spatial discretization
semi = Semidiscretization(mesh, equations, initial_condition, solver,
boundary_conditions = boundary_conditions,
source_terms = source_terms)

###############################################################################
# Create `ODEProblem` and run the simulation
tspan = (0.0, 1.0)
ode = semidiscretize(semi, tspan)
analysis_callback = AnalysisCallback(semi; interval = 10,
extra_analysis_errors = (:conservation_error,),
extra_analysis_integrals = (waterheight_total,
velocity, entropy))
callbacks = CallbackSet(analysis_callback)

saveat = range(tspan..., length = 100)
sol = solve(ode, Tsit5(), abstol = 1e-7, reltol = 1e-7,
save_everystep = false, callback = callbacks, saveat = saveat)
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using OrdinaryDiffEq
using DispersiveShallowWater

###############################################################################
# Semidiscretization of the BBM-BBM equations

equations = BBMBBMVariableEquations1D(gravity_constant = 9.81)

initial_condition = initial_condition_manufactured
source_terms = source_terms_manufactured
boundary_conditions = boundary_condition_periodic

# create homogeneous mesh
coordinates_min = 0.0
coordinates_max = 1.0
N = 512
mesh = Mesh1D(coordinates_min, coordinates_max, N)

# create solver with periodic SBP operators of accuracy order 4
accuracy_order = 4
solver = Solver(mesh, accuracy_order)

# semidiscretization holds all the necessary data structures for the spatial discretization
semi = Semidiscretization(mesh, equations, initial_condition, solver,
boundary_conditions = boundary_conditions,
source_terms = source_terms)

###############################################################################
# Create `ODEProblem` and run the simulation
tspan = (0.0, 1.0)
ode = semidiscretize(semi, tspan)
analysis_callback = AnalysisCallback(semi; interval = 10,
extra_analysis_errors = (:conservation_error,),
extra_analysis_integrals = (waterheight_total,
velocity, entropy))
callbacks = CallbackSet(analysis_callback)

saveat = range(tspan..., length = 100)
sol = solve(ode, Tsit5(), abstol = 1e-7, reltol = 1e-7,
save_everystep = false, callback = callbacks, saveat = saveat)
43 changes: 43 additions & 0 deletions examples/svaerd_kalisch_1d/svaerd_kalisch_1d_manufactured.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using OrdinaryDiffEq
using DispersiveShallowWater

###############################################################################
# Semidiscretization of the Svärd-Kalisch equations

equations = SvaerdKalischEquations1D(gravity_constant = 1.0, eta0 = 0.0,
alpha = 0.0004040404040404049,
beta = 0.49292929292929294,
gamma = 0.15707070707070708)

initial_condition = initial_condition_manufactured
source_terms = source_terms_manufactured
boundary_conditions = boundary_condition_periodic

# create homogeneous mesh
coordinates_min = 0.0
coordinates_max = 1.0
N = 128
mesh = Mesh1D(coordinates_min, coordinates_max, N)

# create solver with periodic SBP operators of accuracy order 4
accuracy_order = 4
solver = Solver(mesh, accuracy_order)

# semidiscretization holds all the necessary data structures for the spatial discretization
semi = Semidiscretization(mesh, equations, initial_condition, solver,
boundary_conditions = boundary_conditions,
source_terms = source_terms)

###############################################################################
# Create `ODEProblem` and run the simulation
tspan = (0.0, 1.0)
ode = semidiscretize(semi, tspan)
analysis_callback = AnalysisCallback(semi; interval = 10,
extra_analysis_errors = (:conservation_error,),
extra_analysis_integrals = (waterheight_total,
velocity, entropy))
callbacks = CallbackSet(analysis_callback)

saveat = range(tspan..., length = 100)
sol = solve(ode, Tsit5(), abstol = 1e-7, reltol = 1e-7,
save_everystep = false, callback = callbacks, saveat = saveat)
6 changes: 4 additions & 2 deletions src/DispersiveShallowWater.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import SummationByPartsOperators: grid, xmin, xmax

include("boundary_conditions.jl")
include("mesh.jl")
include("solver.jl")
include("equations/equations.jl")
include("solver.jl")
include("semidiscretization.jl")
include("callbacks_step/callbacks_step.jl")
include("visualization.jl")
Expand All @@ -47,7 +47,9 @@ export Semidiscretization, semidiscretize, grid

export boundary_condition_periodic

export initial_condition_convergence_test, initial_condition_dingemans
export initial_condition_convergence_test,
initial_condition_manufactured, source_terms_manufactured,
initial_condition_dingemans

export AnalysisCallback, RelaxationCallback
export tstops, errors, integrals
Expand Down
66 changes: 55 additions & 11 deletions src/equations/bbm_bbm_1d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,41 @@ function initial_condition_convergence_test(x, t, equations::BBMBBMEquations1D,
return SVector(eta, v)
end

"""
initial_condition_manufactured(x, t, equations::BBMBBMEquations1D, mesh)
A smooth manufactured solution in combination with [`source_terms_manufactured`](@ref).
"""
function initial_condition_manufactured(x, t,
equations::BBMBBMEquations1D,
mesh)
eta = exp(t) * cospi(2 * (x - 2 * t))
v = exp(t / 2) * sinpi(2 * (x - t / 2))
return SVector(eta, v)
end

"""
source_terms_manufactured(q, x, t, equations::BBMBBMEquations1D, mesh)
A smooth manufactured solution in combination with [`initial_condition_manufactured`](@ref).
"""
function source_terms_manufactured(q, x, t, equations::BBMBBMEquations1D)
g = equations.gravity
D = equations.D
a3 = cospi(t - 2 * x)
a4 = sinpi(t - 2 * x)
a5 = sinpi(2 * t - 4 * x)
a6 = sinpi(4 * t - 2 * x)
a7 = cospi(4 * t - 2 * x)
dq1 = -2 * pi^2 * D^2 * (4 * pi * a6 - a7) * exp(t) / 3 + 2 * pi * D * exp(t / 2) * a3 -
2 * pi * exp(3 * t / 2) * a4 * a6 + 2 * pi * exp(3 * t / 2) * a3 * a7 -
4 * pi * exp(t) * a6 + exp(t) * a7
dq2 = -pi^2 * D^2 * (a4 + 2 * pi * a3) * exp(t / 2) / 3 + 2 * pi * g * exp(t) * a6 -
exp(t / 2) * a4 / 2 - pi * exp(t / 2) * a3 - pi * exp(t) * a5

return SVector(dq1, dq2)
end
#
function create_cache(mesh,
equations::BBMBBMEquations1D,
solver,
Expand All @@ -61,24 +96,23 @@ function create_cache(mesh,
uEltype)
if solver.D1 isa PeriodicDerivativeOperator ||
solver.D1 isa UniformPeriodicCoupledOperator
invImD2_D = (I - 1 / 6 * equations.D^2 * sparse(solver.D2)) \ Matrix(solver.D1)
invImD2 = inv(I - 1 / 6 * equations.D^2 * Matrix(solver.D2))
elseif solver.D1 isa PeriodicUpwindOperators
invImD2_D = (I - 1 / 6 * equations.D^2 * sparse(solver.D2)) \
Matrix(solver.D1.central)
invImD2 = inv(I - 1 / 6 * equations.D^2 * Matrix(solver.D2))
else
@error "unknown type of first-derivative operator"
end
tmp1 = Array{RealT}(undef, nnodes(mesh))
return (invImD2_D = invImD2_D, tmp1 = tmp1)
tmp1 = Array{RealT}(undef, nnodes(mesh)) # tmp1 is needed for the `RelaxationCallback`
return (invImD2 = invImD2, tmp1 = tmp1)
end

# Discretization that conserves the mass (for eta and v) and the energy for periodic boundary conditions, see
# - Hendrik Ranocha, Dimitrios Mitsotakis and David I. Ketcheson (2020)
# A Broad Class of Conservative Numerical Methods for Dispersive Wave Equations
# [DOI: 10.4208/cicp.OA-2020-0119](https://doi.org/10.4208/cicp.OA-2020-0119)
function rhs!(du_ode, u_ode, t, mesh, equations::BBMBBMEquations1D, initial_condition,
::BoundaryConditionPeriodic, solver, cache)
@unpack invImD2_D, tmp1 = cache
::BoundaryConditionPeriodic, source_terms, solver, cache)
@unpack invImD2 = cache

q = wrap_array(u_ode, mesh, equations, solver)
dq = wrap_array(du_ode, mesh, equations, solver)
Expand All @@ -89,11 +123,21 @@ function rhs!(du_ode, u_ode, t, mesh, equations::BBMBBMEquations1D, initial_cond
dv = view(dq, 2, :)

# energy and mass conservative semidiscretization
@. tmp1 = -(equations.D * v + eta * v)
mul!(deta, invImD2_D, tmp1)
if solver.D1 isa PeriodicDerivativeOperator ||
solver.D1 isa UniformPeriodicCoupledOperator
deta[:] = -solver.D1 * (equations.D * v + eta .* v)
dv[:] = -solver.D1 * (equations.gravity * eta + 0.5 * v .^ 2)
elseif solver.D1 isa PeriodicUpwindOperators
deta[:] = -solver.D1.central * (equations.D * v + eta .* v)
dv[:] = -solver.D1.central * (equations.gravity * eta + 0.5 * v .^ 2)
else
@error "unknown type of first-derivative operator"
end

calc_sources!(dq, q, t, source_terms, equations, solver)

@. tmp1 = -(equations.gravity * eta + 0.5 * v^2)
mul!(dv, invImD2_D, tmp1)
deta[:] = invImD2 * deta
dv[:] = invImD2 * dv

return nothing
end
Expand Down
86 changes: 68 additions & 18 deletions src/equations/bbm_bbm_variable_bathymetry_1d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ For details see Example 5 in Section 3 from (here adapted for dimensional equati
Exact Traveling-Wave Solutions to Bidirectional Wave Equations
[DOI: 10.1023/A:1026667903256](https://doi.org/10.1023/A:1026667903256)
"""
function initial_condition_convergence_test(x,
t,
function initial_condition_convergence_test(x, t,
equations::BBMBBMVariableEquations1D,
mesh)
g = equations.gravity
Expand All @@ -58,6 +57,49 @@ function initial_condition_convergence_test(x,
return SVector(eta, v, D)
end

"""
initial_condition_manufactured(x, t, equations::BBMBBMVariableEquations1D, mesh)
A smooth manufactured solution in combination with [`source_terms_manufactured`](@ref).
"""
function initial_condition_manufactured(x, t,
equations::BBMBBMVariableEquations1D,
mesh)
eta = exp(t) * cospi(2 * (x - 2 * t))
v = exp(t / 2) * sinpi(2 * (x - t / 2))
D = 5.0 + 2.0 * cospi(2 * x)
return SVector(eta, v, D)
end

"""
source_terms_manufactured(q, x, t, equations::BBMBBMVariableEquations1D, mesh)
A smooth manufactured solution in combination with [`initial_condition_manufactured`](@ref).
"""
function source_terms_manufactured(q, x, t, equations::BBMBBMVariableEquations1D)
g = equations.gravity
a1 = cospi(2 * x)
a2 = sinpi(2 * x)
a3 = cospi(t - 2 * x)
a4 = sinpi(t - 2 * x)
a5 = sinpi(2 * t - 4 * x)
a6 = sinpi(4 * t - 2 * x)
a7 = cospi(4 * t - 2 * x)
dq1 = -2 * pi^2 * (4 * pi * a6 - a7) * (2 * a1 + 5)^2 * exp(t) / 3 +
8 * pi^2 * (a6 + 4 * pi * a7) * (2 * a1 + 5) * exp(t) * a2 / 3 +
2 * pi * (2 * a1 + 5) * exp(t / 2) * a3 - 2 * pi * exp(3 * t / 2) * a4 * a6 +
2 * pi * exp(3 * t / 2) * a3 * a7 + 4 * pi * exp(t / 2) * a2 * a4 -
4 * pi * exp(t) * a6 + exp(t) * a7
dq2 = 2 * pi * g * exp(t) * a6 -
pi^2 *
(8 * (2 * pi * a4 - a3) * (2 * a1 + 5) * a2 +
(a4 + 2 * pi * a3) * (2 * a1 + 5)^2 +
4 * (a4 + 2 * pi * a3) * (16 * sinpi(x)^4 - 26 * sinpi(x)^2 + 7)) * exp(t / 2) /
3 - exp(t / 2) * a4 / 2 - pi * exp(t / 2) * a3 - pi * exp(t) * a5

return SVector(dq1, dq2, 0.0)
end

"""
initial_condition_dingemans(x, t, equations::BBMBBMVariableEquations1D, mesh)
Expand Down Expand Up @@ -100,7 +142,7 @@ end

function create_cache(mesh,
equations::BBMBBMVariableEquations1D,
solver::Solver,
solver,
initial_condition,
RealT,
uEltype)
Expand All @@ -113,18 +155,16 @@ function create_cache(mesh,
K = Diagonal(D .^ 2)
if solver.D1 isa PeriodicDerivativeOperator ||
solver.D1 isa UniformPeriodicCoupledOperator
invImDKD_D = (I - 1 / 6 * sparse(solver.D1) * K * sparse(solver.D1)) \
Matrix(solver.D1)
invImD2K_D = (I - 1 / 6 * sparse(solver.D2) * K) \ Matrix(solver.D1)
invImDKD = inv(I - 1 / 6 * Matrix(solver.D1) * K * Matrix(solver.D1))
invImD2K = inv(I - 1 / 6 * Matrix(solver.D2) * K)
elseif solver.D1 isa PeriodicUpwindOperators
invImDKD_D = (I - 1 / 6 * sparse(solver.D1.minus) * K * sparse(solver.D1.plus)) \
Matrix(solver.D1.minus)
invImD2K_D = (I - 1 / 6 * sparse(solver.D2) * K) \ Matrix(solver.D1.plus)
invImDKD = inv(I - 1 / 6 * Matrix(solver.D1.minus) * K * Matrix(solver.D1.plus))
invImD2K = inv(I - 1 / 6 * Matrix(solver.D2) * K)
else
@error "unknown type of first-derivative operator"
end
tmp1 = Array{RealT}(undef, nnodes(mesh))
return (invImDKD_D = invImDKD_D, invImD2K_D = invImD2K_D, tmp1 = tmp1)
tmp1 = Array{RealT}(undef, nnodes(mesh)) # tmp1 is needed for the `RelaxationCallback`
return (invImDKD = invImDKD, invImD2K = invImD2K, tmp1 = tmp1)
end

# Discretization that conserves the mass (for eta and v) and the energy for periodic boundary conditions, see
Expand All @@ -133,9 +173,9 @@ end
# [DOI: 10.4208/cicp.OA-2020-0119](https://doi.org/10.4208/cicp.OA-2020-0119)
# Here, adapted for spatially varying bathymetry.
function rhs!(du_ode, u_ode, t, mesh, equations::BBMBBMVariableEquations1D,
initial_condition,
::BoundaryConditionPeriodic, solver, cache)
@unpack invImDKD_D, invImD2K_D, tmp1 = cache
initial_condition, ::BoundaryConditionPeriodic, source_terms,
solver, cache)
@unpack invImDKD, invImD2K = cache

q = wrap_array(u_ode, mesh, equations, solver)
dq = wrap_array(du_ode, mesh, equations, solver)
Expand All @@ -148,11 +188,21 @@ function rhs!(du_ode, u_ode, t, mesh, equations::BBMBBMVariableEquations1D,
dD = view(dq, 3, :)
fill!(dD, zero(eltype(dD)))

@. tmp1 = -(D * v + eta * v)
mul!(deta, invImDKD_D, tmp1)
if solver.D1 isa PeriodicDerivativeOperator ||
solver.D1 isa UniformPeriodicCoupledOperator
deta[:] = -solver.D1 * (D .* v + eta .* v)
dv[:] = -solver.D1 * (equations.gravity * eta + 0.5 * v .^ 2)
elseif solver.D1 isa PeriodicUpwindOperators
deta[:] = -solver.D1.minus * (D .* v + eta .* v)
dv[:] = -solver.D1.plus * (equations.gravity * eta + 0.5 * v .^ 2)
else
@error "unknown type of first-derivative operator"
end

calc_sources!(dq, q, t, source_terms, equations, solver)

@. tmp1 = -(equations.gravity * eta + 0.5 * v^2)
mul!(dv, invImD2K_D, tmp1)
deta[:] = invImDKD * deta
dv[:] = invImD2K * dv

return nothing
end
Expand Down
Loading

0 comments on commit a7dcc23

Please sign in to comment.