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

Tests for Terminator Toy and SplitPrescribedTransport #465

Merged
merged 11 commits into from
Dec 14, 2023
23 changes: 17 additions & 6 deletions integration-tests/model/test_prescribed_transport.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
"""
This tests the prescribed wind feature of the PrescribedTransport timestepper.
This tests the prescribed wind feature of the PrescribedTransport and
SplitPresribedTransport (with no physics schemes) timesteppers.
A tracer is transported with a time-varying wind and the computed solution is
compared with a true one to check that the transport is working correctly.
"""

from gusto import *
from firedrake import sin, cos, norm, pi, as_vector
import pytest


def run(timestepper, tmax, f_end):
timestepper.run(0, tmax)
return norm(timestepper.fields("f") - f_end) / norm(f_end)


def test_prescribed_transport_setup(tmpdir, tracer_setup):
@pytest.mark.parametrize('timestep_method', ['prescribed', 'split_prescribed'])
def test_prescribed_transport_setup(tmpdir, tracer_setup, timestep_method):

# Make domain using routine from conftest
geometry = "slice"
Expand All @@ -31,11 +34,19 @@ def u_evaluation(t):
sin(2*pi*t/setup.tmax)*sin(pi*z)])

transport_scheme = SSPRK3(domain)
transport_method = DGUpwind(eqn, 'f')

timestepper = PrescribedTransport(eqn, transport_scheme, setup.io,
transport_method,
prescribed_transporting_velocity=u_evaluation)
if timestep_method == 'prescribed':
transport_method = DGUpwind(eqn, 'f')
timestepper = PrescribedTransport(eqn, transport_scheme, setup.io,
transport_method,
prescribed_transporting_velocity=u_evaluation)
elif timestep_method == 'split_prescribed':
transport_method = [DGUpwind(eqn, 'f')]
timestepper = SplitPrescribedTransport(eqn, transport_scheme, setup.io,
transport_method,
prescribed_transporting_velocity=u_evaluation)
else:
raise NotImplementedError

# Initial conditions
timestepper.fields("f").interpolate(setup.f_init)
Expand Down
6 changes: 3 additions & 3 deletions integration-tests/physics/test_precipitation.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ def setup_fallout(dirname):

# Physics schemes
rainfall_method = DGUpwind(eqn, 'rain', outflow=True)
physics_parametrisations = [Fallout(eqn, 'rain', domain, rainfall_method)]
physics_parametrisations = [(Fallout(eqn, 'rain', domain, rainfall_method), SSPRK3(domain))]

# build time stepper
scheme = SSPRK3(domain)
stepper = PrescribedTransport(eqn, scheme, io, transport_method,
physics_parametrisations=physics_parametrisations)
stepper = SplitPrescribedTransport(eqn, scheme, io, transport_method,
physics_schemes=physics_parametrisations)

# ------------------------------------------------------------------------ #
# Initial conditions
Expand Down
112 changes: 112 additions & 0 deletions integration-tests/physics/test_terminator_toy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
"""
This tests the terminator toy physics scheme that models the interaction
of two chemical species through coupled ODEs.
"""

from gusto import *
from firedrake import IcosahedralSphereMesh, Constant, cos, \
sin, SpatialCoordinate, Function, max_value, as_vector, \
errornorm, norm
import numpy as np


def run_terminator_toy(dirname):

# ------------------------------------------------------------------------ #
# Set up model objects
# ------------------------------------------------------------------------ #

# A much larger timestep than in proper simulations, as this
# tests moving towards a steady state with no flow.
dt = 100000.

# Make the mesh and domain
R = 6371220.
mesh = IcosahedralSphereMesh(radius=R,
refinement_level=3, degree=2)
Copy link
Contributor

Choose a reason for hiding this comment

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

As this is just a test and the spatial discretisation is not important, could we use a coarser grid? e.g. refinement level 2?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That's a good point. Using a refinement level of 2 still successfully tests the ODEs moving the system towards the steady state, although I will need to halve the timestep size and slacken the tolerance on the test (error less than 0.4) to adjust.


domain = Domain(mesh, dt, 'BDM', 1)

# get lat lon coordinates
x = SpatialCoordinate(mesh)
lamda, theta, _ = lonlatr_from_xyz(x[0], x[1], x[2])

domain = Domain(mesh, dt, 'BDM', 1)

# Define the interacting species
X = ActiveTracer(name='X', space='DG',
variable_type=TracerVariableType.mixing_ratio,
transport_eqn=TransportEquationType.advective)

X2 = ActiveTracer(name='X2', space='DG',
variable_type=TracerVariableType.mixing_ratio,
transport_eqn=TransportEquationType.advective)

tracers = [X, X2]

# Equation
V = domain.spaces("HDiv")
eqn = CoupledTransportEquation(domain, active_tracers=tracers, Vu=V)

output = OutputParameters(dirname=dirname+"/terminator_toy",
dumpfreq=10)
io = IO(domain, output)

# Define the reaction rates:
theta_c = np.pi/9.
lamda_c = -np.pi/3.

k1 = max_value(0, sin(theta)*sin(theta_c) + cos(theta)*cos(theta_c)*cos(lamda-lamda_c))
k2 = 1

physics_schemes = [(TerminatorToy(eqn, k1=k1, k2=k2, species1_name='X',
species2_name='X2'), BackwardEuler(domain))]

# Set up a non-divergent, time-varying, velocity field
def u_t(t):
Copy link
Contributor

Choose a reason for hiding this comment

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

Since the wind is zero, do we need a function prescribing the velocity? Or could we just set the initial velocity to zero?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I can't find a way to get the prescribed_transporting_velocity to work without giving it a function.

return as_vector((Constant(0)*lamda, Constant(0)*lamda, Constant(0)*lamda))

transport_scheme = SSPRK3(domain)
transport_method = [DGUpwind(eqn, 'X'), DGUpwind(eqn, 'X2')]

X_0 = 4e-6 + 0*lamda
X2_0 = 0*lamda

transport_scheme = SSPRK3(domain)
transport_method = [DGUpwind(eqn, 'X'), DGUpwind(eqn, 'X2')]

stepper = SplitPrescribedTransport(eqn, transport_scheme, io,
spatial_methods=transport_method,
physics_schemes=physics_schemes,
prescribed_transporting_velocity=u_t)

stepper.fields("X").interpolate(X_0)
stepper.fields("X2").interpolate(X2_0)

stepper.run(t=0, tmax=10*dt)

# Compute the steady state solution to compare to
steady_space = domain.spaces('DG')
X_steady = Function(steady_space)
X2_steady = Function(steady_space)

X_T_0 = 4e-6
r = k1/(4*k2)
D_val = sqrt(r**2 + 2*X_T_0*r)

X_steady.interpolate(D_val - r)
X2_steady.interpolate(0.5*(X_T_0 - D_val + r))

return stepper, X_steady, X2_steady


def test_terminator_toy_setup(tmpdir):
dirname = str(tmpdir)
stepper, X_steady, X2_steady = run_terminator_toy(dirname)
X_field = stepper.fields("X")
X2_field = stepper.fields("X2")

# Assert that the physics scheme has sufficiently moved
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems like a sensible test to me!

# the species fields near their steady state solutions
assert errornorm(X_field, X_steady)/norm(X_steady) < 0.25, "The X field is not sufficiently close to the steady state profile"
assert errornorm(X2_field, X2_steady)/norm(X2_steady) < 0.25, "The X2 field is not sufficiently close to the steady state profile"
2 changes: 1 addition & 1 deletion integration-tests/physics/test_wind_drag.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def run_wind_drag(dirname, implicit_formulation):
eqn = CompressibleEulerEquations(domain, parameters)

# I/O
output = OutputParameters(dirname=dirname+"/surface_fluxes",
output = OutputParameters(dirname=dirname+"/wind_drag",
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for fixing this!

dumpfreq=1,
dumplist=['u'])
io = IO(domain, output)
Expand Down
Loading