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

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
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
11 changes: 6 additions & 5 deletions examples/compressible_euler/skamarock_klemp_nonhydrostatic.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
Domain, IO, OutputParameters, SemiImplicitQuasiNewton, SSPRK3, DGUpwind,
TrapeziumRule, 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
26 changes: 21 additions & 5 deletions examples/shallow_water/moist_thermal_williamson_5.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
ShallowWaterParameters, ShallowWaterEquations, Sum,
lonlatr_from_xyz, InstantRain, SWSaturationAdjustment, WaterVapour,
CloudWater, Rain, GeneralIcosahedralSphereMesh, RelativeVorticity,
ZonalComponent, MeridionalComponent
ZonalComponent, MeridionalComponent, RungeKuttaFormulation, SSPRK3,
SemiImplicitQuasiNewton, ThermalSWSolver
)

moist_thermal_williamson_5_defaults = {
Expand Down Expand Up @@ -142,13 +143,28 @@ def gamma_v(x_in):
gamma_r=gamma_r
)

transported_fields = [
SSPRK3(domain, "u", subcycle_by_courant=0.25),
SSPRK3(domain, "D", subcycle_by_courant=0.25, rk_formulation=RungeKuttaFormulation.linear),
SSPRK3(domain, "b", subcycle_by_courant=0.25),
SSPRK3(domain, "water_vapour", subcycle_by_courant=0.25),
SSPRK3(domain, "cloud_water", subcycle_by_courant=0.25),
]
transport_methods = [
DGUpwind(eqns, field_name) for field_name in eqns.field_names
DGUpwind(eqns, "u"),
DGUpwind(eqns, "D", advective_then_flux=True),
DGUpwind(eqns, "b"),
DGUpwind(eqns, "water_vapour"),
DGUpwind(eqns, "cloud_water")
]

# Timestepper
stepper = Timestepper(
eqns, RK4(domain), io, spatial_methods=transport_methods
# Linear solver
linear_solver = ThermalSWSolver(eqns)

# Time stepper
stepper = SemiImplicitQuasiNewton(
eqns, io, transported_fields, transport_methods,
linear_solver=linear_solver
)

# ------------------------------------------------------------------------ #
Expand Down
12 changes: 9 additions & 3 deletions examples/shallow_water/williamson_5.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
Domain, IO, OutputParameters, SemiImplicitQuasiNewton, SSPRK3, DGUpwind,
TrapeziumRule, 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
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