How to make a Balance law
Defining the set of solved PDEs in ClimateMachine revolve around defining a BalanceLaw
. A balance law solves equations of the form:
∂Y
-- = - ∇ • ( F_{first_order}(Y) + F_{second_order}(Y, Σ) ) + S_{non_conservative}(Y, Σ)
∂t
Here, Y
, Σ
, F_{first_order}
, F_{second_order}
, and S_{non_conservative}
can be thought of column vectors[1] expressing:
Y
the prognostic state variables, or unknowns of the PDEs to be solvedΣ
the gradients of functions of the prognostic state variablesF_{first-order}
contains all first-order fluxes (e.g. not functions
of gradients of any variables)
F_{second-order}
contains all second-order and higher-order fluxes
(e.g. functions of gradients of any variables)
S_{non_conservative}
non-conservative sources[2]
In order to alleviate users from being concerned with the burden of spatial discretization, users must provide their own implementations of the following methods, which are computed locally at each nodal point:
Variable name specification methods
The vars_state
method is used to specify the names of the variables for the following state variable types:
Type | Purpose |
---|---|
Prognostic | the variables in the prognostic state vector, typically mass, momentum, and various tracers. |
Auxiliary | any variables required for the balance law that aren't related to derivatives of the state variables (e.g. spatial coordinates or various integrals) or those needed to solve expensive auxiliary equations (e.g., temperature via a non-linear equation solve) |
Gradient | the gradients of functions of the prognostic state variables. used to represent values before and after differentiation |
GradientFlux | the gradient fluxes necessary to impose Neumann boundary conditions. typically the product of a diffusivity tensor with a gradient state variable, potentially equivalent to the second-order flux for a prognostic state variable |
UpwardIntegrals | any one-dimensional vertical integrals from bottom to top of the domain required for the balance law. used to represent both the integrand and the resulting indefinite integral |
DownwardIntegrals | any one-dimensional vertical integral from top to bottom of the domain required for the balance law. each variable here must also exist in vars_state since the reverse integral kernels use subtraction to reverse the integral instead of performing a new integral. use to represent the value before and after reversing direction |
Methods to compute gradients and integrals
Method | Purpose |
---|---|
compute_gradient_argument! | specify how to compute the arguments to the gradients. can be functions of prognostic state and auxiliary variables. |
compute_gradient_flux! | specify how to compute gradient fluxes. can be a functions of the gradient state, the prognostic state, and auxiliary variables. |
integral_load_auxiliary_state! | specify how to compute integrands. can be functions of the prognostic state and auxiliary variables. |
integral_set_auxiliary_state! | specify which auxiliary variables are used to store the output of the integrals. |
reverse_integral_load_auxiliary_state! | specify auxiliary variables need their integrals reversed. |
reverse_integral_set_auxiliary_state! | specify which auxiliary variables are used to store the output of the reversed integrals. |
update_auxiliary_state! | perform any updates to the auxiliary variables needed at the beginning of each time-step. Can be used to solve non-linear equations, calculate integrals, and apply filters. |
update_auxiliary_state_gradient! | same as above, but after computing gradients and gradient fluxes in case these variables are needed during the update. |
Methods to compute fluxes and sources
Method | Purpose |
---|---|
flux_first_order! | specify F_{first_order} for each prognostic state variable. can be functions of the prognostic state and auxiliary variables. |
flux_second_order! | specify F_{second_order} for each prognostic state variable. can be functions of the prognostic state, gradient flux state, and auxiliary variables. |
source! | specify S_{non_conservative} for each prognostic state variable. can be functions of the prognostic state, gradient flux state, and auxiliary variables. |
Methods to compute numerical fluxes
Method | Purpose |
---|---|
wavespeed | specify how to compute the local wavespeed if using the RusanovNumericalFlux . |
boundary_state! | define exterior nodal values of the prognostic state and gradient flux state used to compute the numerical boundary fluxes. |
Methods to set initial conditions
Method | Purpose |
---|---|
init_state_prognostic! | provide initial values for the prognostic state as a function of time and space. |
init_state_auxiliary! | provide initial values for the auxiliary variables as a function of the geometry. |
General Remarks
While Y
can be thought of a column vector (each row of which corresponds to each state variable and its prognostic equation), the second function argument inside these methods behave as dictionaries, for example:
struct MyModel <: BalanceLaw end
function vars_state(m::MyModel, ::Prognostic, FT)
@vars begin
ρ::FT
T::FT
end
end
function source!(m::MyModel, source::Vars, args...)
source.ρ = 1 # adds a source of 1 to RHS of ρ equation
source.T = 1 # adds a source of 1 to RHS of T equation
end
All equations are marched simultaneously in time.
Reference links
as this can leak conservation of the unknowns and lead to numerical instabilities. It is recommended to use either F_{diffusive}
or F_{non_diffusive}
, as these fluxes are communicated across elements[3]
where there may be many [Gauss-Lobatto][4] points
- 1Column Vectors
- 2Note that using non-conservative sources should be a final resort,
- 3MPI communication occurs only across elements, not within each element,
- 4Gauss-Lobatto