Limiters
The limiters supertype is
ClimaCore.Limiters.AbstractLimiter — Type
AbstractLimiterSupertype for all limiters.
Subtypes:
QuasiMonotoneLimiter: horizontal quasi-monotone flux limiter for spectral element advection.VerticalMassBorrowingLimiter: vertical mass-borrowing limiter that removes negative tracer mass.
Subtypes implement apply_limiter!.
QuasiMonotoneLimiter acts on the horizontal spectral-element structure of a field; VerticalMassBorrowingLimiter acts along each column. Both are applied to the state after a step or stage (Limit tracers).
Interfaces
ClimaCore.Limiters.QuasiMonotoneLimiter — Type
QuasiMonotoneLimiterQuasi-monotone limiter for tracer densities on spectral element spaces, after the OP1 limiter of [14], eqs. (37)-(40). Quasi-monotone means monotone with respect to the spectral element nodal values.
For each element, the limiter finds the nodal field closest, in the mass-weighted l2 norm, to the input field that satisfies min/max bounds on the concentration q = ρq / ρ. As in HOMME, it clips the nodal values that violate the bounds to the nearest bound, which changes the tracer mass of the element, and then redistributes the mass change over the nodes that are not at a bound so that the l2 error is smallest. Redistribution can violate the bounds again, so the two steps are iterated until abs(Δtracer_mass) <= rtol * tracer_mass or Nq^2 iterations have been done. The optimization is local to each element; the neighbors enter only through the bounds.
Fields
q_bounds: min and max ofqin each element.q_bounds_nbr: min and max ofqover each element and its neighbors.ghost_buffer: buffer for exchangingq_boundswith neighboring processes.rtol: relative tolerance for the tracer mass change per element [-].convergence_stats:LimiterConvergenceStats(orNoConvergenceStats) accumulated byapply_limiter!.
Constructor
QuasiMonotoneLimiter(
ρq::Field;
rtol = eps(eltype(parent(ρq))),
convergence_stats = LimiterConvergenceStats{eltype(parent(ρq))}(),
)Create a limiter for the tracer density field ρq, where q is the tracer concentration per unit mass; ρq can be a scalar-valued or a struct-valued Field. convergence_stats records the number of apply_limiter! calls in which some element failed to converge, the largest relative mass error, and the smallest tracer mass; print_convergence_stats(limiter) prints them.
Examples
Call compute_bounds! on the fields at the start of the step, then apply_limiter! on the updated fields:
limiter = QuasiMonotoneLimiter(ρq)
compute_bounds!(limiter, ρq, ρ)
# ... advance ρq and ρ ...
apply_limiter!(ρq, ρ, limiter)ClimaCore.Limiters.VerticalMassBorrowingLimiter — Type
VerticalMassBorrowingLimiter(q_min)Vertical-only mass-borrowing limiter.
The limiter borrows tracer mass from adjacent lower layers to raise each layer's tracer value to at least its minimum. It conserves the total tracer mass in the column.
q_min is a tuple with one minimum tracer value per component of the limited field.
At level k, the limiter first borrows mass from layer k+1 (the lower level). If the mass in layer k+1 is not sufficient, it borrows from layer k+2, and so on down to the bottom layer. If the tracer mass in the bottom layer goes below the minimum, the limiter repeats the process from the bottom to the top. This makes the limiter work for any shape of mass profile.
Examples
ρ = fill(1.0, space)
q = fill((a = 0.1, b = 0.1), space)
limiter = VerticalMassBorrowingLimiter((0.0, 0.0))
Limiters.apply_limiter!(q, ρ, limiter)Adapted from the E3SM mass borrower; see [15].
ClimaCore.Limiters.compute_bounds! — Function
compute_bounds!(limiter::QuasiMonotoneLimiter, ρq::Field, ρ::Field)Compute the bounds on the tracer concentration q = ρq / ρ that apply_limiter! enforces, from the tracer density ρq and the density ρ, and store them in limiter.q_bounds_nbr.
The steps are:
compute_element_bounds!computes the min and max ofqin each element.- If distributed, start the ghost exchange of the element bounds.
compute_neighbor_bounds_local!widens the bounds with the local neighbors.- If distributed, complete the ghost exchange and widen the bounds with the ghost neighbors in
compute_neighbor_bounds_ghost!.
ClimaCore.Limiters.apply_limiter! — Function
apply_limiter!(ρq, ρ, limiter::QuasiMonotoneLimiter; warn = true)Limit the tracer density ρq in place so that the concentration q = ρq / ρ at each node lies within the bounds computed by compute_bounds!, while preserving the tracer mass of each element up to the relative tolerance limiter.rtol.
Each element is processed by apply_limit_slab!, with the density ρ times the quadrature weights as the weights of the least-squares redistribution. When some element fails to converge, limiter.convergence_stats is updated. On CPU devices with warn = true, the accumulated convergence statistics are printed with @warn after each call.
Return ρq on CPU devices and nothing on CUDA devices.
apply_limiter!(q::Fields.Field, ρ::Fields.Field, lim::VerticalMassBorrowingLimiter)Apply the vertical mass-borrowing limiter lim to the tracer field q in place, given the density field ρ.
Each component of q is limited column by column with the corresponding entry of lim.q_min, using the cell volume from the local geometry of ρ. Returns nothing.
ClimaCore.Limiters.print_convergence_stats — Function
print_convergence_stats(limiter::QuasiMonotoneLimiter)
print_convergence_stats(io::IO, stats)Print the convergence statistics accumulated by the Limiters.QuasiMonotoneLimiter limiter (to stdout), or the statistics object stats (to io): the number of elements in which the limiter iteration did not converge, the maximum relative error, and the minimum tracer mass. Nothing is printed if the limiter was constructed with convergence_stats = NoConvergenceStats().