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

Relaxation physics #540

Open
wants to merge 66 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
a74b469
started relxation
Witt-D Oct 25, 2023
bee6f17
added relaxation class2
Witt-D Oct 26, 2023
31f2e65
added velocity friction
Witt-D Oct 26, 2023
16e710b
fixed labels
Witt-D Oct 30, 2023
3cf4634
adjusted rayleigh friction
Witt-D Oct 31, 2023
9fa989a
merge resolved
Witt-D Oct 31, 2023
c939235
added in functions
Witt-D Oct 31, 2023
7656b47
adjusted vector fields for relaxation
Witt-D Nov 13, 2023
d4e3acc
bug fix for the raylegh fricion
Witt-D Nov 13, 2023
e419640
sign issue
Witt-D Nov 13, 2023
37675dc
updating values
Witt-D Nov 13, 2023
d16e21e
updating values
Witt-D Nov 13, 2023
3b82e59
updating values
Witt-D Nov 13, 2023
0fa9d6e
updating values
Witt-D Nov 13, 2023
472194a
updating values
Witt-D Nov 13, 2023
769116b
updating values
Witt-D Nov 13, 2023
6aba406
adjusted theta to debug like the velocity friction
Witt-D Nov 14, 2023
48a23cc
fixed vel but theta still not workin
Witt-D Nov 16, 2023
c6a6a53
added manual evaluate
Witt-D Nov 16, 2023
8e72331
both working
Witt-D Nov 17, 2023
7ac6b9f
relaxation fix
Witt-D Nov 17, 2023
a799359
checks for sigma
Witt-D Nov 17, 2023
6bdc78f
removed unneccesary exners
Witt-D Nov 20, 2023
6975e72
adjusted sigma to have a exner / surface exner
Witt-D Nov 22, 2023
f6cedc3
new surface expression
Witt-D Nov 23, 2023
30fb167
resolved issue regarding the finite elements
Witt-D Nov 27, 2023
c7d230c
replaced vertical extension with a linear interpolation
Witt-D Nov 29, 2023
949b4ee
interpolated
Witt-D Nov 30, 2023
f7119c3
interpolator
Witt-D Nov 30, 2023
713323f
fixed typo
Witt-D Nov 30, 2023
75cb540
tidied up physics script to seperate interpolation and calculation
Witt-D Dec 11, 2023
4bb5624
re moved fluff
Witt-D Dec 11, 2023
c2e71e8
resolved conflict
Witt-D Dec 11, 2023
03ab5e3
resolved conflicT
Witt-D Dec 11, 2023
9e42f7c
conflict
Witt-D Dec 11, 2023
2604510
fixed import problems
Witt-D Dec 11, 2023
bbf75de
physics tidy up
Witt-D Dec 12, 2023
d0e37f4
Merge branch 'main' of https://github.com/firedrakeproject/gusto into…
Witt-D Jun 11, 2024
5e9d842
added column data for getting surface value
Witt-D Jun 11, 2024
51a65dd
Merge branch 'main' of https://github.com/firedrakeproject/gusto into…
Witt-D Jun 11, 2024
066767d
Merge branch 'Relaxation_Physics' of https://github.com/firedrakeproj…
Witt-D Jun 11, 2024
adbe5c1
edited some forcings
Witt-D Jun 12, 2024
79a90a3
tidied up
Witt-D Jun 14, 2024
e17b10e
Merge branch 'Relaxation_Physics' of https://github.com/firedrakeproj…
Witt-D Jun 14, 2024
024b48e
current state
Witt-D Jun 20, 2024
f29eddf
fixed sign error
Witt-D Jul 4, 2024
30148c0
temp
Witt-D Jul 4, 2024
bb012ee
merged
Witt-D Jul 4, 2024
9e599d7
recovered sigma to hdiv
Witt-D Jul 10, 2024
22c406b
Merge branch 'Relaxation_Physics' of https://github.com/firedrakeproj…
Witt-D Jul 10, 2024
b131aa5
storing changes
Witt-D Jul 22, 2024
0c781b6
Merge branch 'main' of https://github.com/firedrakeproject/gusto into…
Witt-D Jul 23, 2024
e3031bc
moved the forcing to their own file
Witt-D Jul 23, 2024
19d0e11
mergefix
Witt-D Aug 16, 2024
0faff2b
merge
Witt-D Aug 16, 2024
f776e38
started impleenting source terms
Witt-D Aug 16, 2024
32cd30e
added interpolators for the two terms
Witt-D Aug 16, 2024
f5d5a07
removed linear interpolator
Witt-D Aug 16, 2024
7c20c1f
updated interpolator for the fields
Witt-D Aug 19, 2024
a8bbde6
updated interpolator for the fields
Witt-D Aug 19, 2024
01bface
adjusts equilibrium
Witt-D Aug 19, 2024
dd5f6b0
latest commit
Witt-D Aug 19, 2024
8dd1a6f
minor change
Witt-D Aug 21, 2024
feeb64d
minor change
Witt-D Aug 21, 2024
be0be88
found a typo or two
Witt-D Aug 21, 2024
5d6eb0f
more typo fixes
Witt-D Aug 22, 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
180 changes: 180 additions & 0 deletions gusto/physics/Held_Suarez_forcing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import numpy as np
from firedrake import (Interpolator, Function, dx, pi, SpatialCoordinate,
split, conditional, ge, sin, dot, ln, cos, inner, Projector)
from firedrake.fml import subject
from gusto.core.coord_transforms import lonlatr_from_xyz
from gusto.recovery import Recoverer, BoundaryMethod
from gusto.physics.physics_parametrisation import PhysicsParametrisation
from gusto.core.labels import prognostic
from gusto.equations import thermodynamics


class Relaxation(PhysicsParametrisation):
"""
Relaxation term for Held Suarez
"""

def __init__(self, equation, variable_name, parameters=None):
"""
Args:
equation (:class:`PrognosticEquationSet`): the model's equation.
variable_name (str): the name of the variable

"""
label_name = f'relaxation_{variable_name}'
super().__init__(equation, label_name, parameters=None)

if equation.domain.on_sphere:
x, y, z = SpatialCoordinate(equation.domain.mesh)
_, lat, _ = lonlatr_from_xyz(x, y, z)
else:
# TODO: this could be determined some other way
# Take a mid-latitude
lat = pi / 4

self.X = Function(equation.X.function_space())
X = self.X
self.domain = equation.domain
theta_idx = equation.field_names.index('theta')
self.theta = X.subfunctions[theta_idx]
Vt = equation.domain.spaces('theta')
rho_idx = equation.field_names.index('rho')
rho = split(X)[rho_idx]

boundary_method = BoundaryMethod.extruded if equation.domain.vertical_degree == 0 else None
self.rho_averaged = Function(Vt)
self.rho_recoverer = Recoverer(rho, self.rho_averaged, boundary_method=boundary_method)
self.exner = Function(Vt)
self.exner_interpolator = Interpolator(
thermodynamics.exner_pressure(equation.parameters,
self.rho_averaged, self.theta), self.exner)
self.sigma = Function(Vt)

T0stra = 200 # Stratosphere temp
T0surf = 315 # Surface temperature at equator
T0horiz = 60 # Equator to pole temperature difference
T0vert = 10 # Stability parameter
self.kappa = equation.parameters.kappa
sigmab = 0.7
d = 24 * 60 * 60
taod = 40 * d
taou = 4 * d

theta_condition = (T0surf - T0horiz * sin(lat)**2 - (T0vert * ln(self.exner) * cos(lat)**2)/self.kappa)

Check failure on line 63 in gusto/physics/Held_Suarez_forcing.py

View workflow job for this annotation

GitHub Actions / Run linter

W291

gusto/physics/Held_Suarez_forcing.py:63:112: W291 trailing whitespace
Theta_eq = conditional(T0stra/self.exner >= theta_condition, T0stra/self.exner, theta_condition)

# timescale of temperature forcing
tao_cond = (self.sigma**(1/self.kappa) - sigmab) / (1 - sigmab)
newton_freq = 1 / taod + (1/taou - 1/taod) * conditional(0 >= tao_cond, 0, tao_cond) * cos(lat)**4
forcing_expr = newton_freq * (self.theta - Theta_eq)

Check failure on line 69 in gusto/physics/Held_Suarez_forcing.py

View workflow job for this annotation

GitHub Actions / Run linter

W291

gusto/physics/Held_Suarez_forcing.py:69:61: W291 trailing whitespace

# Create source for forcing
self.source_relaxation = Function(Vt)
self.source_interpolator = Interpolator(forcing_expr, self.source_relaxation)

# Add relaxation term to residual
test = equation.tests[theta_idx]
dx_reduced = dx(degree=4)
forcing_form = test * self.source_relaxation * dx_reduced
equation.residual += self.label(subject(prognostic(forcing_form, 'theta'), X), self.evaluate)

def evaluate(self, x_in, dt):
"""
Evalutes the source term generated by the physics.

Args:
x_in: (:class:`Function`): the (mixed) field to be evolved.
dt: (:class:`Constant`): the timestep, which can be the time
interval for the scheme.
"""
self.X.assign(x_in)
self.rho_recoverer.project()
self.exner_interpolator.interpolate()

# Determine sigma:= exner / exner_surf
exner_columnwise, index_data = self.domain.coords.get_column_data(self.exner, self.domain)
sigma_columnwise = np.zeros_like(exner_columnwise)
for col in range(len(exner_columnwise[:, 0])):
sigma_columnwise[col, :] = exner_columnwise[col, :] / exner_columnwise[col, 0]
self.domain.coords.set_field_from_column_data(self.sigma, sigma_columnwise, index_data)

self.source_interpolator.interpolate()


class RayleighFriction(PhysicsParametrisation):
"""
Forcing term on the velocity of the form
F_u = -u / a,
where a is some friction factor
"""
def __init__(self, equation, parameters=None):
"""
Args:
equation (:class:`PrognosticEquationSet`): the model's equation.
forcing_coeff (:class:`unsure what to put here`): the coefficient
determining rate of friction
"""
label_name = 'rayleigh_friction'
super().__init__(equation, label_name, parameters=parameters)
self.parameters = equation.parameters
self.domain = equation.domain
self.X = Function(equation.X.function_space())
X = self.X
k = equation.domain.k
u_idx = equation.field_names.index('u')
u = split(X)[u_idx]
theta_idx = equation.field_names.index('theta')
self.theta = X.subfunctions[theta_idx]
rho_idx = equation.field_names.index('rho')
rho = split(X)[rho_idx]
Vt = equation.domain.spaces('theta')
Vu = equation.domain.spaces('HDiv')
u_hori = u - k*dot(u, k)

boundary_method = BoundaryMethod.extruded if self.domain == 0 else None
self.rho_averaged = Function(Vt)
self.exner = Function(Vt)
self.rho_recoverer = Recoverer(rho, self.rho_averaged, boundary_method=boundary_method)
self.exner_interpolator = Interpolator(
thermodynamics.exner_pressure(equation.parameters,
self.rho_averaged, self.theta), self.exner)

self.sigma = Function(Vt)
sigmab = 0.7
self.kappa = self.parameters.kappa
taofric = 24 * 60 * 60

tao_cond = (self.sigma**(1/self.kappa) - sigmab) / (1 - sigmab)
wind_timescale = conditional(ge(0, tao_cond), 0, tao_cond) / taofric
forcing_expr = u_hori * wind_timescale

self.source_friction = Function(Vu)
self.source_projector = Projector(forcing_expr, self.source_friction)

tests = equation.tests
test = tests[u_idx]
dx_reduced = dx(degree=4)
source_form = inner(test, self.source_friction) * dx_reduced
equation.residual += self.label(subject(prognostic(source_form, 'u'), X), self.evaluate)

def evaluate(self, x_in, dt):
"""
Evaluates the source term generated by the physics. This does nothing if
the implicit formulation is not used.

Args:
x_in: (:class: 'Function'): the (mixed) field to be evolved.
dt: (:class: 'Constant'): the timestep, which can be the time
interval for the scheme.
"""
self.X.assign(x_in)
self.rho_recoverer.project()
self.exner_interpolator.interpolate
# Determine sigma:= exner / exner_surf
exner_columnwise, index_data = self.domain.coords.get_column_data(self.exner, self.domain)
sigma_columnwise = np.zeros_like(exner_columnwise)
for col in range(len(exner_columnwise[:, 0])):
sigma_columnwise[col, :] = exner_columnwise[col, :] / exner_columnwise[col, 0]
self.domain.coords.set_field_from_column_data(self.sigma, sigma_columnwise, index_data)

self.source_projector.project()
3 changes: 2 additions & 1 deletion gusto/physics/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
from gusto.physics.chemistry import * # noqa
from gusto.physics.boundary_and_turbulence import * # noqa
from gusto.physics.microphysics import * # noqa
from gusto.physics.shallow_water_microphysics import * # noqa
from gusto.physics.shallow_water_microphysics import * # noqa
from gusto.physics.Held_Suarez_forcing import * # noqa
Loading