From a92fc04cad4e46e9d9c233ac688cf385300433d5 Mon Sep 17 00:00:00 2001 From: nh491 Date: Wed, 26 Jul 2023 14:07:40 +0100 Subject: [PATCH 1/4] evaluate physics at each stage of SSPRK3, RK4 and Heun's method --- gusto/time_discretisation.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/gusto/time_discretisation.py b/gusto/time_discretisation.py index a4db0a168..1dc1645b0 100644 --- a/gusto/time_discretisation.py +++ b/gusto/time_discretisation.py @@ -373,10 +373,14 @@ def solve_stage(self, x_in, stage): self.x1.assign(self.x_out) elif stage == 1: + for evaluate in self.evaluate_source: + evaluate(x_in, self.dt) self.solver.solve() self.x1.assign(0.75*x_in + 0.25*self.x_out) elif stage == 2: + for evaluate in self.evaluate_source: + evaluate(x_in, self.dt) self.solver.solve() self.x1.assign((1./3.)*x_in + (2./3.)*self.x_out) @@ -470,16 +474,22 @@ def solve_stage(self, x_in, stage): self.x1.assign(x_in + 0.5 * self.dt * self.k1) elif stage == 1: + for evaluate in self.evaluate_source: + evaluate(x_in, self.dt) self.solver.solve() self.k2.assign(self.x_out) self.x1.assign(x_in + 0.5 * self.dt * self.k2) elif stage == 2: + for evaluate in self.evaluate_source: + evaluate(x_in, self.dt) self.solver.solve() self.k3.assign(self.x_out) self.x1.assign(x_in + self.dt * self.k3) elif stage == 3: + for evaluate in self.evaluate_source: + evaluate(x_in, self.dt) self.solver.solve() self.k4.assign(self.x_out) self.x1.assign(x_in + 1/6 * self.dt * (self.k1 + 2*self.k2 + 2*self.k3 + self.k4)) @@ -538,6 +548,8 @@ def solve_stage(self, x_in, stage): self.x1.assign(self.x_out) elif stage == 1: + for evaluate in self.evaluate_source: + evaluate(x_in, self.dt) self.solver.solve() self.x1.assign(0.5 * x_in + 0.5 * (self.x_out)) From 47068db3d98d77921dfe78a9d02b6887dbf47142 Mon Sep 17 00:00:00 2001 From: nh491 Date: Thu, 27 Jul 2023 10:17:28 +0100 Subject: [PATCH 2/4] evaluate the source term at x1 instead of x_in at each stage --- gusto/time_discretisation.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gusto/time_discretisation.py b/gusto/time_discretisation.py index 1dc1645b0..ab81cbd20 100644 --- a/gusto/time_discretisation.py +++ b/gusto/time_discretisation.py @@ -374,13 +374,13 @@ def solve_stage(self, x_in, stage): elif stage == 1: for evaluate in self.evaluate_source: - evaluate(x_in, self.dt) + evaluate(self.x1, self.dt) self.solver.solve() self.x1.assign(0.75*x_in + 0.25*self.x_out) elif stage == 2: for evaluate in self.evaluate_source: - evaluate(x_in, self.dt) + evaluate(self.x1, self.dt) self.solver.solve() self.x1.assign((1./3.)*x_in + (2./3.)*self.x_out) @@ -475,21 +475,21 @@ def solve_stage(self, x_in, stage): elif stage == 1: for evaluate in self.evaluate_source: - evaluate(x_in, self.dt) + evaluate(self.x1, self.dt) self.solver.solve() self.k2.assign(self.x_out) self.x1.assign(x_in + 0.5 * self.dt * self.k2) elif stage == 2: for evaluate in self.evaluate_source: - evaluate(x_in, self.dt) + evaluate(self.x1, self.dt) self.solver.solve() self.k3.assign(self.x_out) self.x1.assign(x_in + self.dt * self.k3) elif stage == 3: for evaluate in self.evaluate_source: - evaluate(x_in, self.dt) + evaluate(self.x1, self.dt) self.solver.solve() self.k4.assign(self.x_out) self.x1.assign(x_in + 1/6 * self.dt * (self.k1 + 2*self.k2 + 2*self.k3 + self.k4)) @@ -549,7 +549,7 @@ def solve_stage(self, x_in, stage): elif stage == 1: for evaluate in self.evaluate_source: - evaluate(x_in, self.dt) + evaluate(self.x1, self.dt) self.solver.solve() self.x1.assign(0.5 * x_in + 0.5 * (self.x_out)) From 97f48a574098a95329bdf4911fdffdcdda9e0804 Mon Sep 17 00:00:00 2001 From: nh491 Date: Thu, 27 Jul 2023 10:21:08 +0100 Subject: [PATCH 3/4] use a SplitPhysicsTimestepper in the InstantRain test with RK4 for physics (and make the tolerance more slack) and note that we need to update this test when we have a CoupledAdvectionEquation --- .../physics/test_instant_rain.py | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/integration-tests/physics/test_instant_rain.py b/integration-tests/physics/test_instant_rain.py index 77b95c6d2..c963fc5e4 100644 --- a/integration-tests/physics/test_instant_rain.py +++ b/integration-tests/physics/test_instant_rain.py @@ -32,6 +32,8 @@ def run_instant_rain(dirname): fexpr = Constant(0) # Equation + # TODO: This should become a CoupledAdvectionEquation. Currently we set u + # and D to 0 in the ShallowWaterEquations so they do not evolve. vapour = WaterVapour(name="water_vapour", space='DG') rain = Rain(name="rain", space="DG", transport_eqn=TransportEquationType.no_transport) @@ -46,17 +48,17 @@ def run_instant_rain(dirname): dumplist=['vapour', "rain"]) diagnostic_fields = [CourantNumber()] io = IO(domain, output, diagnostic_fields=diagnostic_fields) - transport_method = DGUpwind(eqns, "water_vapour") + transport_method = [DGUpwind(eqns, "water_vapour")] # Physics schemes # define saturation function saturation = Constant(0.5) physics_schemes = [(InstantRain(eqns, saturation, rain_name="rain"), - ForwardEuler(domain))] + RK4(domain))] # Time stepper - stepper = PrescribedTransport(eqns, RK4(domain), io, transport_method, - physics_schemes=physics_schemes) + stepper = SplitPhysicsTimestepper(eqns, RK4(domain), io, transport_method, + physics_schemes=physics_schemes) # ------------------------------------------------------------------------ # # Initial conditions @@ -76,8 +78,8 @@ def run_instant_rain(dirname): VD = FunctionSpace(mesh, "DG", 1) initial_vapour = Function(VD).interpolate(vapour_expr) - # define expected solutions; vapour should be equal to saturation and rain - # should be (initial vapour - saturation) + # TODO: This test is based on the assumption that final vapour should be + # equal to saturation, which might not be true when timestepping physics. vapour_true = Function(VD).interpolate(saturation) rain_true = Function(VD).interpolate(vapour0 - saturation) @@ -96,16 +98,16 @@ def test_instant_rain_setup(tmpdir): r = stepper.fields("rain") # check that the maximum of the vapour field is equal to the saturation - assert v.dat.data.max() - saturation.values() < 0.001, "The maximum of the final vapour field should be equal to saturation" + assert v.dat.data.max() - saturation.values() < 0.1, "The maximum of the final vapour field should be equal to saturation" # check that the minimum of the vapour field hasn't changed - assert v.dat.data.min() - initial_vapour.dat.data.min() < 0.001, "The minimum of the vapour field should not change" + assert v.dat.data.min() - initial_vapour.dat.data.min() < 0.1, "The minimum of the vapour field should not change" # check that the maximum of the excess vapour agrees with the maximum of the # rain VD = Function(v.function_space()) excess_vapour = Function(VD).interpolate(initial_vapour - saturation) - assert excess_vapour.dat.data.max() - r.dat.data.max() < 0.001 + assert excess_vapour.dat.data.max() - r.dat.data.max() < 0.1 # check that the minimum of the rain is 0 assert r.dat.data.min() < 1e-8 From a6bc71a4adddb68795ba375829ca3f42d2131431 Mon Sep 17 00:00:00 2001 From: nh491 Date: Thu, 27 Jul 2023 10:24:22 +0100 Subject: [PATCH 4/4] make lint --- integration-tests/physics/test_instant_rain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/physics/test_instant_rain.py b/integration-tests/physics/test_instant_rain.py index c963fc5e4..075af40f2 100644 --- a/integration-tests/physics/test_instant_rain.py +++ b/integration-tests/physics/test_instant_rain.py @@ -58,7 +58,7 @@ def run_instant_rain(dirname): # Time stepper stepper = SplitPhysicsTimestepper(eqns, RK4(domain), io, transport_method, - physics_schemes=physics_schemes) + physics_schemes=physics_schemes) # ------------------------------------------------------------------------ # # Initial conditions