Skip to content
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

Advective-then-Flux form for Runge-Kutta schemes #553

Merged
merged 7 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from 6 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
13 changes: 7 additions & 6 deletions examples/compressible_euler/skamarock_klemp_nonhydrostatic.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@
import numpy as np
from gusto import (
Domain, IO, OutputParameters, SemiImplicitQuasiNewton, SSPRK3, DGUpwind,
TrapeziumRule, SUPGOptions, CourantNumber, Perturbation, Gradient,
SUPGOptions, CourantNumber, Perturbation, Gradient,
CompressibleParameters, CompressibleEulerEquations, CompressibleSolver,
compressible_hydrostatic_balance, logger, RichardsonNumber
compressible_hydrostatic_balance, logger, RichardsonNumber,
RungeKuttaFormulation
)

skamarock_klemp_nonhydrostatic_defaults = {
Expand Down Expand Up @@ -106,13 +107,13 @@ def skamarock_klemp_nonhydrostatic(
# Transport schemes
theta_opts = SUPGOptions()
transported_fields = [
TrapeziumRule(domain, "u"),
SSPRK3(domain, "rho"),
SSPRK3(domain, "theta", options=theta_opts)
SSPRK3(domain, "u", subcycle_by_courant=0.25),
SSPRK3(domain, "rho", subcycle_by_courant=0.25, rk_formulation=RungeKuttaFormulation.linear),
SSPRK3(domain, "theta", subcycle_by_courant=0.25, options=theta_opts)
]
transport_methods = [
DGUpwind(eqns, "u"),
DGUpwind(eqns, "rho"),
DGUpwind(eqns, "rho", advective_then_flux=True),
DGUpwind(eqns, "theta", ibp=theta_opts.ibp)
]

Expand Down
14 changes: 10 additions & 4 deletions examples/shallow_water/williamson_5.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
)
from gusto import (
Domain, IO, OutputParameters, SemiImplicitQuasiNewton, SSPRK3, DGUpwind,
TrapeziumRule, ShallowWaterParameters, ShallowWaterEquations, Sum,
ShallowWaterParameters, ShallowWaterEquations, Sum,
lonlatr_from_xyz, GeneralIcosahedralSphereMesh, ZonalComponent,
MeridionalComponent, RelativeVorticity
MeridionalComponent, RelativeVorticity, RungeKuttaFormulation
)

williamson_5_defaults = {
Expand Down Expand Up @@ -83,8 +83,14 @@ def williamson_5(
io = IO(domain, output, diagnostic_fields=diagnostic_fields)

# Transport schemes
transported_fields = [TrapeziumRule(domain, "u"), SSPRK3(domain, "D")]
transport_methods = [DGUpwind(eqns, "u"), DGUpwind(eqns, "D")]
transported_fields = [
SSPRK3(domain, "u", subcycle_by_courant=0.25),
SSPRK3(domain, "D", subcycle_by_courant=0.25, rk_formulation=RungeKuttaFormulation.linear)
]
transport_methods = [
DGUpwind(eqns, "u"),
DGUpwind(eqns, "D", advective_then_flux=True)
]

# Time stepper
stepper = SemiImplicitQuasiNewton(
Expand Down
2 changes: 2 additions & 0 deletions gusto/core/labels.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ def __call__(self, target, value=None):
linearisation = Label("linearisation", validator=lambda value: type(value) in [LabelledForm, Term])
mass_weighted = Label("mass_weighted", validator=lambda value: type(value) in [LabelledForm, Term])
ibp_label = Label("ibp", validator=lambda value: type(value) == IntegrateByParts)
all_but_last = Label("all_but_last", validator=lambda value: type(value) in [LabelledForm, Term])


# labels for terms in the equations
time_derivative = Label("time_derivative")
Expand Down
85 changes: 62 additions & 23 deletions gusto/spatial_methods/transport_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
)
from firedrake.fml import Term, keep, drop
from gusto.core.configuration import IntegrateByParts, TransportEquationType
from gusto.core.labels import (prognostic, transport, transporting_velocity, ibp_label,
mass_weighted)
from gusto.core.labels import (
prognostic, transport, transporting_velocity, ibp_label, mass_weighted,
all_but_last
)
from gusto.core.logging import logger
from gusto.spatial_methods.spatial_methods import SpatialMethod

Expand Down Expand Up @@ -83,6 +85,10 @@ def replace_form(self, equation):
# Create new term
new_term = Term(self.form.form, original_term.labels)

# Add all_but_last form
if hasattr(self, "all_but_last_form"):
new_term = all_but_last(new_term, self.all_but_last_form)

# Check if this is a conservative transport
if original_term.has_label(mass_weighted):
# Extract the original and discretised mass_weighted terms
Expand Down Expand Up @@ -151,7 +157,8 @@ class DGUpwind(TransportMethod):
transported variable at facets.
"""
def __init__(self, equation, variable, ibp=IntegrateByParts.ONCE,
vector_manifold_correction=False, outflow=False):
vector_manifold_correction=False, outflow=False,
advective_then_flux=False):
"""
Args:
equation (:class:`PrognosticEquation`): the equation, which includes
Expand All @@ -163,50 +170,82 @@ def __init__(self, equation, variable, ibp=IntegrateByParts.ONCE,
vector manifold correction term. Defaults to False.
outflow (bool, optional): whether to include outflow at the domain
boundaries, through exterior facet terms. Defaults to False.
advective_then_flux (bool, optional): whether to use the advective-
then-flux formulation. This uses the advective form of the
transport equation for all but the last steps of some
(potentially subcycled) Runge-Kutta scheme, before using the
conservative form for the final step to deliver a mass-
conserving increment. This optiona only makes sense to use with
tommbendall marked this conversation as resolved.
Show resolved Hide resolved
Runge-Kutta, and should be used with the "linear" Runge-Kutta
formulation. Defaults to False, in which case the conservative
form is used for every step.
"""

super().__init__(equation, variable)
self.ibp = ibp
self.vector_manifold_correction = vector_manifold_correction
self.outflow = outflow

if (advective_then_flux
and self.transport_equation_type != TransportEquationType.conservative):
raise ValueError(
'DG Upwind: advective_then_flux form can only be used with '
+ 'the conservative form of the transport equation'
)

# -------------------------------------------------------------------- #
# Determine appropriate form to use
# -------------------------------------------------------------------- #
# first check for 1d mesh and scalar velocity space
if equation.domain.mesh.topological_dimension() == 1 and len(equation.domain.spaces("HDiv").shape) == 0:
assert not vector_manifold_correction
if self.transport_equation_type == TransportEquationType.advective:
form = upwind_advection_form_1d(self.domain, self.test,
self.field,
ibp=ibp, outflow=outflow)
form = upwind_advection_form_1d(
self.domain, self.test, self.field, ibp=ibp,
outflow=outflow
)
elif self.transport_equation_type == TransportEquationType.conservative:
form = upwind_continuity_form_1d(self.domain, self.test,
self.field,
ibp=ibp, outflow=outflow)
form = upwind_continuity_form_1d(
self.domain, self.test, self.field, ibp=ibp,
outflow=outflow
)

else:
if self.transport_equation_type == TransportEquationType.advective:
if vector_manifold_correction:
form = vector_manifold_advection_form(self.domain,
self.test,
self.field, ibp=ibp,
outflow=outflow)
form = vector_manifold_advection_form(
self.domain, self.test, self.field, ibp=ibp,
outflow=outflow
)
else:
form = upwind_advection_form(self.domain, self.test,
self.field,
ibp=ibp, outflow=outflow)
form = upwind_advection_form(
self.domain, self.test, self.field, ibp=ibp,
outflow=outflow
)

elif self.transport_equation_type == TransportEquationType.conservative:
if vector_manifold_correction:
form = vector_manifold_continuity_form(self.domain,
self.test,
self.field, ibp=ibp,
outflow=outflow)
form = vector_manifold_continuity_form(
self.domain, self.test, self.field, ibp=ibp,
outflow=outflow
)
else:
form = upwind_continuity_form(self.domain, self.test,
self.field,
ibp=ibp, outflow=outflow)
form = upwind_continuity_form(
self.domain, self.test, self.field, ibp=ibp,
outflow=outflow
)

if advective_then_flux and vector_manifold_correction:
self.all_but_last_form = vector_manifold_advection_form(
self.domain, self.test, self.field, ibp=ibp,
outflow=outflow
)

elif advective_then_flux:
self.all_but_last_form = upwind_advection_form(
self.domain, self.test, self.field, ibp=ibp,
outflow=outflow
)

elif self.transport_equation_type == TransportEquationType.circulation:
if outflow:
Expand Down
Loading
Loading