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

Tracer conservative transport #469

Merged
merged 25 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
bb11e7a
begun tracer_conservative transport
ta440 Dec 12, 2023
e6bb827
DGUpwind for tracer_conservative
ta440 Dec 12, 2023
8c4c7db
Merge remote-tracking branch 'origin/main' into tracer_conservative_t…
ta440 Dec 12, 2023
649d35e
more changes
ta440 Dec 13, 2023
f94df7c
DGUpwind scheme for tracer_conservative
ta440 Dec 13, 2023
9ca0395
tidy up descriptions
ta440 Dec 19, 2023
b14f4a0
add mass weighted label to time derivative and debugging statements. …
tommbendall Dec 21, 2023
f3064c3
implement new way of writing explicit RK schemes
tommbendall Jan 21, 2024
ef4582f
remove mass weighted label
tommbendall Jan 21, 2024
738b951
lint fixes
tommbendall Jan 21, 2024
54aa25d
Merge pull request #472 from firedrakeproject/TBendall/new_explicit_RK
ta440 Jan 22, 2024
852e876
Merge branch 'main' into tracer_conservative_transport
tommbendall Mar 1, 2024
9464323
added a ConservativeCoupledTransportEquation test
ta440 Mar 14, 2024
0525eb1
lint
ta440 Mar 14, 2024
2819c7a
integrate ConservativeCoupledTransportEquation into CoupledTransportE…
ta440 Mar 15, 2024
a08e4b8
Merge branch 'main' into tracer_conservative_transport
ta440 Mar 15, 2024
6b695b2
lint
ta440 Mar 15, 2024
f6c886a
lint
ta440 Mar 15, 2024
301c7ff
Update comments for the generate_tracer_mass_terms routine
ta440 Mar 15, 2024
a0f92a0
slacken suppress_vertical_wind test and update linear_sw_wave KGO
ta440 Mar 15, 2024
498034a
lint
ta440 Mar 15, 2024
4ffee21
Update gusto/equations.py to add back in non-periodic check in no nor…
ta440 Mar 18, 2024
ed99b80
better extraction of reference density for tracer_conservative transport
ta440 Mar 18, 2024
0f89ae8
lint
ta440 Mar 18, 2024
52f444d
made changes suggested by Alex
ta440 Mar 19, 2024
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
14 changes: 13 additions & 1 deletion gusto/active_tracers.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class ActiveTracer(object):
"""
def __init__(self, name, space, variable_type,
transport_eqn=TransportEquationType.advective,
density_name=None,
phase=Phases.gas, chemical=None):
"""
Args:
Expand All @@ -63,6 +64,10 @@ def __init__(self, name, space, variable_type,
transport_eqn (:class:`TransportEquationType`, optional): enumerator
indicating the type of transport equation to be solved (e.g.
advective). Defaults to `TransportEquationType.advective`.
density_name (str): the name of the associated density for a mixing
ratio when using the tracer_conservative transport. Defaults to None,
but raises an error if tracer_conservative transport is used without
a specified density.
phase (:class:`Phases`, optional): enumerator indicating the phase
of the tracer variable. Defaults to `Phases.gas`.
chemical (str, optional): string to describe the chemical that this
Expand All @@ -75,14 +80,21 @@ def __init__(self, name, space, variable_type,
self.name = name
self.space = space
self.transport_eqn = transport_eqn
self.density_name = density_name
self.variable_type = variable_type
self.phase = phase
self.chemical = chemical

if (variable_type == TracerVariableType.density and transport_eqn == TransportEquationType.advective):
if (variable_type == TracerVariableType.density
and transport_eqn == TransportEquationType.advective):
logger.warning('Active tracer initialised which describes a '
+ 'density but solving the advective transport eqn')

if (transport_eqn == TransportEquationType.tracer_conservative
and density_name is None):
raise ValueError(f'Active tracer {name} using tracer conservative '
+ 'transport needs an associated density.')


class WaterVapour(ActiveTracer):
"""An object encoding the details of water vapour as a tracer."""
Expand Down
27 changes: 26 additions & 1 deletion gusto/common_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
__all__ = ["advection_form", "continuity_form", "vector_invariant_form",
"kinetic_energy_form", "advection_equation_circulation_form",
"diffusion_form", "linear_advection_form", "linear_continuity_form",
"split_continuity_form"]
"split_continuity_form", "tracer_conservative_form"]


def advection_form(test, q, ubar):
Expand Down Expand Up @@ -262,3 +262,28 @@ def split_continuity_form(equation):
map_if_true=drop)

return equation


def tracer_conservative_form(test, q, rho, ubar):
u"""
The form corresponding to the continuity transport operator.

This describes ∇.(u*q*rho) for transporting velocity u and a
transported tracer (mixing ratio), q, with an associated density, rho.

Args:
test (:class:`TestFunction`): the test function.
q (:class:`ufl.Expr`): the tracer to be transported.
rho (:class:`ufl.Expr`): the reference density that will
mulitply with q before taking the divergence.
ubar (:class:`ufl.Expr`): the transporting velocity.

Returns:
class:`LabelledForm`: a labelled transport form.
"""

q_rho = q*rho
L = inner(test, div(outer(q_rho, ubar)))*dx
form = transporting_velocity(L, ubar)

return transport(form, TransportEquationType.tracer_conservative)
3 changes: 3 additions & 0 deletions gusto/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,16 @@ class TransportEquationType(Enum):
conservative: ∂q/∂t + ∇.(u*q) = 0 \n
vector_invariant: ∂q/∂t + (∇×q)×u + (1/2)∇(q.u) + (1/2)[(∇q).u -(∇u).q)] = 0
circulation: ∂q/∂t + (∇×q)×u + non-transport terms = 0
tracer_conservative: ∂(q*rho)/∂t + ∇.(u*q*rho) = 0, for a reference density of rho
for the tracer, q.
"""

no_transport = 702
advective = 19
conservative = 291
vector_invariant = 9081
circulation = 512
tracer_conservative = 296


class Configuration(object):
Expand Down
54 changes: 49 additions & 5 deletions gusto/equations.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
from gusto.common_forms import (
advection_form, continuity_form, vector_invariant_form,
kinetic_energy_form, advection_equation_circulation_form,
diffusion_form, linear_continuity_form, linear_advection_form
diffusion_form, linear_continuity_form, linear_advection_form,
tracer_conservative_form
)
from gusto.active_tracers import ActiveTracer, Phases, TracerVariableType
from gusto.configuration import TransportEquationType
Expand Down Expand Up @@ -430,6 +431,43 @@ def add_tracers_to_prognostics(self, domain, active_tracers):
else:
raise TypeError(f'Tracers must be ActiveTracer objects, not {type(tracer)}')

def generate_tracer_mass_terms(self, active_tracers):
"""
Adds the mass forms for the active tracers to the equation set.

Args:
active_tracers (list): A list of :class:`ActiveTracer` objects that
encode the metadata for the active tracers.

Returns:
:class:`LabelledForm`: a labelled form containing the mass
terms for the active tracers. This is the usual mass form
unless using tracer_conservative, where it is multiplied
by the reference density.
"""

for i, tracer in enumerate(active_tracers):
idx = self.field_names.index(tracer.name)
tracer_prog = split(self.X)[idx]
tracer_test = self.tests[idx]

if tracer.transport_eqn == TransportEquationType.tracer_conservative:
ref_density_idx = self.field_names.index(tracer.density_name)
ref_density = split(self.X)[ref_density_idx]
q = tracer_prog*ref_density
mass = subject(prognostic(inner(q, tracer_test)*dx,
self.field_names[idx]), self.X)
else:
mass = subject(prognostic(inner(tracer_prog, tracer_test)*dx,
self.field_names[idx]), self.X)

if i == 0:
mass_form = time_derivative(mass)
else:
mass_form += time_derivative(mass)

return mass_form

def generate_tracer_transport_terms(self, active_tracers):
"""
Adds the transport forms for the active tracers to the equation set.
Expand Down Expand Up @@ -473,6 +511,13 @@ def generate_tracer_transport_terms(self, active_tracers):
tracer_adv = prognostic(
continuity_form(tracer_test, tracer_prog, u),
tracer.name)
elif tracer.transport_eqn == TransportEquationType.tracer_conservative:
ref_density_idx = self.field_names.index(tracer.density_name)
ref_density = split(self.X)[ref_density_idx]
tracer_adv = prognostic(
tracer_conservative_form(tracer_test, tracer_prog,
ref_density, u), tracer.name)

else:
raise ValueError(f'Transport eqn {tracer.transport_eqn} not recognised')

Expand Down Expand Up @@ -562,9 +607,9 @@ def __init__(self, domain, active_tracers, Vu=None):
self.tests = TestFunctions(W)
self.X = Function(W)

mass_form = self.generate_mass_terms()

self.residual = subject(mass_form, self.X)
# Add mass forms for the tracers, which will use
# mass*density for any tracer_conservative terms
self.residual = self.generate_tracer_mass_terms(active_tracers)

# Add transport of tracers
self.residual += self.generate_tracer_transport_terms(active_tracers)
Expand All @@ -574,7 +619,6 @@ def __init__(self, domain, active_tracers, Vu=None):
# Specified Equation Sets
# ============================================================================ #


class ShallowWaterEquations(PrognosticEquationSet):
u"""
Class for the (rotating) shallow-water equations, which evolve the velocity
Expand Down
Loading
Loading