SELF_RefinementIndicator_2D_t Module

Modal (Legendre spectral-decay) refinement indicator for 2-D spectral element solutions.

Purpose

Provides the trigger mechanism for adaptive mesh refinement (AMR): a per-element scalar that measures how much of a solution field's energy sits in its highest polynomial modes. A well-resolved (smooth) field has energy that decays rapidly with mode number, so almost all of its energy lives in the low modes; an under-resolved field (a steep front, a discontinuity, or simply too-coarse an element) leaves significant energy in the top modes. Comparing the top-mode energy fraction against thresholds flags each element for refinement, coarsening, or no change.

Method (Legendre modal-energy / spectral-decay indicator)

Following Persson & Peraire (2006), "Sub-cell shock capturing for discontinuous Galerkin methods", AIAA 2006-112, and the robustified variant of Hennemann, Rueda-Ramirez, Hindenlang & Gassner (2021), J. Comput. Phys. 426, 109935 (the shock indicator used in Trixi.jl), the nodal solution on an element is expanded in a tensor-product Legendre modal basis

u(xi,eta) = sum_{p=0}^{N} sum_{q=0}^{N} uhat(p,q) Ltilde_p(xi) Ltilde_q(eta),

where Ltilde_p are the L2-normalized Legendre polynomials on [-1,1] (int_{-1}^{1} Ltilde_p Ltilde_q dxi = delta_pq). With that normalization the total modal energy equals the exact L2 energy of the field on the reference element,

E_tot = sum_{p,q} uhat(p,q)^2 = ||u||_{L2([-1,1]^2)}^2 .

Two "clipped" energies are formed by dropping the highest one and two modes in each direction,

E_clip1 = sum_{p,q <= N-1} uhat(p,q)^2 , E_clip2 = sum_{p,q <= N-2} uhat(p,q)^2 ,

and the smoothness ratio is the larger of the top-shell and next-shell energy fractions,

S_e = max( (E_tot - E_clip1)/E_tot , (E_clip1 - E_clip2)/E_clip1 ) .

The second term (present only for N >= 2) guards against the odd/even parity dropouts that a single-mode measure can suffer for symmetric data - this is the Hennemann-Gassner refinement of the original single-mode Persson-Peraire estimate. The indicator returned per element is the base-10 logarithm sigma_e = log10(S_e); a near-machine-zero floor keeps it finite for a perfectly resolved (or identically zero) field.

Trigger semantics

With user-supplied thresholds sigma_refine > sigma_coarsen the per-element flag is

sigma_e > sigma_refine -> SELF_AMR_REFINE (+1) top modes carry too much energy sigma_e < sigma_coarsen -> SELF_AMR_COARSEN (-1) field is over-resolved on this element otherwise -> SELF_AMR_KEEP (0)

Larger (closer to zero) sigma_e means a less smooth / less resolved field. Recommended starting values for double precision are sigma_refine ~ -3.0 and sigma_coarsen ~ -8.0; they are problem dependent and are deliberately left as required arguments rather than hidden defaults.

Units and input ranges

  • The indicator is dimensionless (an energy fraction); the driving field may carry any units.
  • Requires N >= 1 (a degree-0 element has no modal spectrum to measure).
  • The nodal->modal transform is the exact inverse of the Legendre Vandermonde built from the interpolant control points, so the indicator is independent of the control-node type (Legendre-Gauss or Legendre-Gauss-Lobatto) and is exact for polynomial data.

This module contains the portable (CPU) implementation using do concurrent over elements. The backend extension modules (SELF_RefinementIndicator_2D) add device storage and a GPU kernel while preserving the mathematics bit-for-bit in structure.


Uses

  • module~~self_refinementindicator_2d_t~~UsesGraph module~self_refinementindicator_2d_t SELF_RefinementIndicator_2D_t iso_c_binding iso_c_binding module~self_refinementindicator_2d_t->iso_c_binding module~self_constants SELF_Constants module~self_refinementindicator_2d_t->module~self_constants module~self_lagrange SELF_Lagrange module~self_refinementindicator_2d_t->module~self_lagrange module~self_scalar_2d SELF_Scalar_2D module~self_refinementindicator_2d_t->module~self_scalar_2d module~self_constants->iso_c_binding iso_fortran_env iso_fortran_env module~self_constants->iso_fortran_env module~self_lagrange->iso_c_binding module~self_lagrange->module~self_constants module~self_lagrange->iso_fortran_env module~self_lagrange_t SELF_Lagrange_t module~self_lagrange->module~self_lagrange_t module~self_scalar_2d->iso_c_binding module~self_scalar_2d->module~self_constants module~self_scalar_2d_t SELF_Scalar_2D_t module~self_scalar_2d->module~self_scalar_2d_t module~self_scalar_2d_t->iso_c_binding module~self_scalar_2d_t->module~self_constants module~self_scalar_2d_t->module~self_lagrange FEQParse FEQParse module~self_scalar_2d_t->FEQParse HDF5 HDF5 module~self_scalar_2d_t->HDF5 module~self_data SELF_Data module~self_scalar_2d_t->module~self_data module~self_metadata SELF_Metadata module~self_scalar_2d_t->module~self_metadata module~self_datapool SELF_DataPool module~self_scalar_2d_t->module~self_datapool module~self_hdf5 SELF_HDF5 module~self_scalar_2d_t->module~self_hdf5 module~self_lagrange_t->iso_c_binding module~self_lagrange_t->module~self_constants module~self_lagrange_t->iso_fortran_env module~self_lagrange_t->HDF5 module~self_lagrange_t->module~self_hdf5 module~self_quadrature SELF_Quadrature module~self_lagrange_t->module~self_quadrature module~self_supportroutines SELF_SupportRoutines module~self_lagrange_t->module~self_supportroutines module~self_data->iso_c_binding module~self_data->module~self_constants module~self_data->module~self_lagrange module~self_data->FEQParse module~self_data->HDF5 module~self_data->module~self_metadata module~self_data->module~self_hdf5 module~self_metadata->HDF5 module~self_metadata->module~self_hdf5 module~self_datapool->module~self_constants module~self_hdf5->module~self_constants module~self_hdf5->iso_fortran_env module~self_hdf5->HDF5 mpi mpi module~self_hdf5->mpi module~self_quadrature->module~self_constants module~self_quadrature->iso_fortran_env module~self_supportroutines->module~self_constants module~self_supportroutines->iso_fortran_env

Used by

  • module~~self_refinementindicator_2d_t~~UsedByGraph module~self_refinementindicator_2d_t SELF_RefinementIndicator_2D_t module~self_refinementindicator_2d~2 SELF_RefinementIndicator_2D module~self_refinementindicator_2d~2->module~self_refinementindicator_2d_t module~self_refinementindicator_2d SELF_RefinementIndicator_2D module~self_refinementindicator_2d->module~self_refinementindicator_2d_t module~self_amrcontroller_2d SELF_AMRController_2D module~self_amrcontroller_2d->module~self_refinementindicator_2d~2

Contents


Variables

TypeVisibilityAttributesNameInitial
integer, public, parameter:: SELF_AMR_ALLVARS =0
integer, public, parameter:: SELF_AMR_COARSEN =-1
integer, public, parameter:: SELF_AMR_KEEP =0
integer, public, parameter:: SELF_AMR_REFINE =1

Derived Types

type, public :: RefinementIndicator2D_t

Components

TypeVisibilityAttributesNameInitial
integer, public :: N =0

Polynomial degree of the interpolant the indicator is built for.

real(kind=prec), public, pointer, contiguous, dimension(:,:):: Pmodal=> null()

Nodal-to-modal transform. Pmodal(ii,p) is the (p,ii) entry of the inverse Legendre Vandermonde in the L2-normalized basis, so the 1-D modal coefficients are uhat(p) = sum_ii Pmodal(ii,p) * u(ii) (first index summed, SELF matrix convention).

real(kind=prec), public :: coarsenThreshold =0.0_prec

Elements with sigma_e below this value are flagged SELF_AMR_COARSEN.

integer, public, pointer, contiguous, dimension(:):: flag=> null()

Per-element refinement flag: SELF_AMR_REFINE / SELF_AMR_KEEP / SELF_AMR_COARSEN.

real(kind=prec), public, pointer, contiguous, dimension(:):: indicator=> null()

Per-element indicator value sigma_e = log10(S_e).

integer, public :: nElem =0

Number of (rank-local) elements the indicator arrays are sized for.

real(kind=prec), public :: refineThreshold =0.0_prec

Elements with sigma_e above this value are flagged SELF_AMR_REFINE.

Type-Bound Procedures

procedure, public :: CountFlagged => CountFlagged_RefinementIndicator2D_t
procedure, public :: Estimate => Estimate_RefinementIndicator2D_t
procedure, public :: Free => Free_RefinementIndicator2D_t
procedure, public :: Init => Init_RefinementIndicator2D_t
procedure, public :: SetThresholds => SetThresholds_RefinementIndicator2D_t
procedure, public :: UpdateDevice => UpdateDevice_RefinementIndicator2D_t
procedure, public :: UpdateHost => UpdateHost_RefinementIndicator2D_t

Functions

public function CountFlagged_RefinementIndicator2D_t(this, flagValue) result(n)

Count the rank-local elements currently carrying the requested flag value (SELF_AMR_REFINE / SELF_AMR_KEEP / SELF_AMR_COARSEN). Provided as a convenience for drivers and tests; a global count across MPI ranks is the caller's responsibility.

Arguments

TypeIntentOptionalAttributesName
class(RefinementIndicator2D_t), intent(in) :: this
integer, intent(in) :: flagValue

Return Value integer

public pure function NormalizedLegendre(p, x) result(Lp)

L2-normalized Legendre polynomial Ltilde_p(x) = L_p(x)*sqrt((2p+1)/2) on [-1,1], evaluated with the standard three-term recurrence. The normalization gives int_{-1}^{1} Ltilde_p Ltilde_q dx = delta_pq.

Arguments

TypeIntentOptionalAttributesName
integer, intent(in) :: p
real(kind=real64), intent(in) :: x

Return Value real(kind=real64)


Subroutines

public subroutine BuildModalTransform(controlPoints, N, Pmodal)

Build the nodal->modal transform Pmodal for a 1-D degree-N interpolant whose nodes are controlPoints(1:N+1). The transform is the exact inverse of the L2-normalized Legendre Vandermonde V(i,p) = Ltilde_{p-1}(x_i); Pmodal(ii,p) stores V^{-1}(p,ii) so that uhat(p) = sum_ii Pmodal(ii,p) * u(ii). The Vandermonde inverse is formed in double precision for conditioning and cast back to the working precision.

Arguments

TypeIntentOptionalAttributesName
real(kind=prec), intent(in) :: controlPoints(1:N+1)
integer, intent(in) :: N
real(kind=prec), intent(out) :: Pmodal(1:N+1,1:N+1)

public subroutine Estimate_RefinementIndicator2D_t(this, solution, ivar)

Compute the per-element modal-energy indicator sigma_e and refine/keep/coarsen flag from the nodal solution field. ivar selects the driving variable in [1,solution%nVar]; passing SELF_AMR_ALLVARS (=0) reduces the indicator over all variables by taking, per element, the largest (least smooth) smoothness ratio S_e before the log10.

Arguments

TypeIntentOptionalAttributesName
class(RefinementIndicator2D_t), intent(inout) :: this
class(Scalar2D), intent(in) :: solution
integer, intent(in) :: ivar

public subroutine Free_RefinementIndicator2D_t(this)

Arguments

TypeIntentOptionalAttributesName
class(RefinementIndicator2D_t), intent(inout) :: this

public subroutine Init_RefinementIndicator2D_t(this, interp, nElem, refineThreshold, coarsenThreshold)

Allocate the indicator for an interpolant of degree interp%N and nElem elements and precompute the nodal->modal transform matrix from the interpolant control points.

Arguments

TypeIntentOptionalAttributesName
class(RefinementIndicator2D_t), intent(out) :: this
type(Lagrange), intent(in), target:: interp
integer, intent(in) :: nElem
real(kind=prec), intent(in) :: refineThreshold
real(kind=prec), intent(in) :: coarsenThreshold

public subroutine InvertMatrix(A, Ainv, n)

Invert the n-by-n matrix A by Gauss-Jordan elimination with partial pivoting, in double precision. Used once at initialization for the small (N+1) Legendre Vandermonde; A is a well-conditioned Vandermonde in an orthonormal basis, so a direct solve is appropriate.

Arguments

TypeIntentOptionalAttributesName
real(kind=real64), intent(in) :: A(1:n,1:n)
real(kind=real64), intent(out) :: Ainv(1:n,1:n)
integer, intent(in) :: n

public subroutine SetThresholds_RefinementIndicator2D_t(this, refineThreshold, coarsenThreshold)

Update the refine/coarsen thresholds without rebuilding the transform.

Arguments

TypeIntentOptionalAttributesName
class(RefinementIndicator2D_t), intent(inout) :: this
real(kind=prec), intent(in) :: refineThreshold
real(kind=prec), intent(in) :: coarsenThreshold

public subroutine UpdateDevice_RefinementIndicator2D_t(this)

Arguments

TypeIntentOptionalAttributesName
class(RefinementIndicator2D_t), intent(inout) :: this

public subroutine UpdateHost_RefinementIndicator2D_t(this)

Arguments

TypeIntentOptionalAttributesName
class(RefinementIndicator2D_t), intent(inout) :: this