Limiters
The limiters supertype is
ClimaCore.Limiters.AbstractLimiter
— TypeThis class of flux-limiters is applied only in the horizontal direction (on spectral advection operators).
Interfaces
ClimaCore.Limiters.QuasiMonotoneLimiter
— TypeQuasiMonotoneLimiter
This limiter is inspired by the one presented in Guba et al [15]. In the reference paper, it is denoted by OP1, and is outlined in eqs. (37)-(40). Quasimonotone here is meant to be monotone with respect to the spectral element nodal values. This limiter involves solving a constrained optimization problem (a weighted least square problem up to a fixed tolerance) that is completely local to each element.
As in HOMME, the implementation idea here is the following: we need to find a grid field which is closest to the initial field (in terms of weighted sum), but satisfies the min/max constraints. So, first we find values that do not satisfy constraints and bring these values to a closest constraint. This way we introduce some change in the tracer mass, which we then redistribute so that the l2 error is smallest. This redistribution might violate constraints; thus, we do a few iterations (until abs(Δtracer_mass) <= rtol * tracer_mass
).
ρq
: tracer density Field, whereq
denotes tracer concentration per unit mass. This can be a scalar field, or a struct-valued field.ρ
: fluid density Field (scalar).
Constructor
limiter = QuasiMonotoneLimiter(
ρq::Field;
rtol = eps(eltype(parent(ρq))),
convergence_stats = LimiterConvergenceStats()
)
Creates a limiter instance for the field ρq
with relative tolerance rtol
, and convergence_stats
, which collects statistics in apply_limiter!
(e.g., number of times that convergence is met or not). Users can call
Limiters.print_convergence_stats(::QuasiMonotoneLimiter)
to print the convergence stats.
Usage
Call compute_bounds!
on the input fields:
compute_bounds!(limiter, ρq, ρ)
Then call apply_limiter!
on the output fields:
apply_limiter!(ρq, ρ, limiter)
ClimaCore.Limiters.compute_bounds!
— Functioncompute_bounds!(limiter::QuasiMonotoneLimiter, ρq::Field, ρ::Field)
Compute the desired bounds for the tracer concentration per unit mass q
, based on the tracer density, ρq
, and density, ρ
, fields.
This is computed by
compute_element_bounds!
- starts the ghost exchange (if distributed)
compute_neighbor_bounds_local!
- completes the ghost exchange (if distributed)
compute_neighbor_bounds_ghost!
(if distributed)
ClimaCore.Limiters.apply_limiter!
— Functionapply_limiter!(ρq, ρ, limiter::QuasiMonotoneLimiter)
Apply the limiter on the tracer density ρq
, using the computed desired bounds on the concentration q
and density ρ
as an optimal weight. This iterates over each element, calling apply_limit_slab!
. If the limiter fails to converge for any element, a warning is issued.
Internals
ClimaCore.Limiters.compute_element_bounds!
— Functioncompute_element_bounds!(limiter::QuasiMonotoneLimiter, ρq, ρ)
Given two fields ρq
and ρ
, computes the min and max of q
in each element, storing it in limiter.q_bounds
.
Part of compute_bounds!
.
ClimaCore.Limiters.compute_neighbor_bounds_local!
— Functioncompute_neighbor_bounds_local!(limiter::QuasiMonotoneLimiter, topology)
Update the field limiter.q_bounds_nbr
based on limiter.q_bounds
in the local neighbors.
Part of compute_bounds!
.
ClimaCore.Limiters.compute_neighbor_bounds_ghost!
— Functioncompute_neighbor_bounds_ghost!(limiter::QuasiMonotoneLimiter, topology)
Update the field limiter.q_bounds_nbr
based on limiter.q_bounds
in the ghost neighbors. This should be called after the ghost exchange has completed.
Part of compute_bounds!
.
ClimaCore.Limiters.apply_limit_slab!
— Functionapply_limit_slab!(slab_ρq, slab_ρ, slab_WJ, slab_q_bounds, rtol)
Apply the computed bounds of the tracer concentration (slab_q_bounds
) in the limiter to slab_ρq
, given the total mass slab_ρ
, metric terms slab_WJ
, and relative tolerance rtol
. Return whether the tolerance condition could be satisfied.