SpECTRE Documentation Coverage Report
Current view: top level - __w/spectre/spectre/docs/DevGuide - Amr.md Hit Total Coverage
Commit: 923cd4a8ea30f5a5589baa60b0a93e358ca9f8e8 Lines: 0 1 0.0 %
Date: 2025-11-07 19:37:56
Legend: Lines: hit not hit

          Line data    Source code
       1           0 : \cond NEVER
       2             : Distributed under the MIT License.
       3             : See LICENSE.txt for details.
       4             : \endcond
       5             : 
       6             : # Adaptive mesh refinement (AMR) {#dev_guide_amr}
       7             : 
       8             : \tableofcontents
       9             : 
      10             : ### Introduction
      11             : 
      12             : SpECTRE implements a block-based anisotropic h-p adaptive mesh
      13             : refinement (AMR) algorithm.  Currently AMR can only occur at global
      14             : synchronization points, but it is planned to remove this restriction
      15             : in the future.
      16             : 
      17             : \warning AMR is still under active development. The elliptic
      18             : executables fully support AMR.  The evolution executables currently
      19             : only support p-adaptivity, and only when using a global time stepper,
      20             : and only when using a DG method.  The executable will abort with an
      21             : ERROR if local time stepping or h-refinement is done.
      22             : 
      23             : Here is an overview of what is described in detail in the sections below:
      24             : 
      25             : - \ref dev_guide_amr_algorithm "AMR Algorithm": An overview of the
      26             :   parallel phases, actions, and components that are used to do
      27             :   adaptive mesh refinement.
      28             : - \ref dev_guide_amr_criteria "AMR Criteria": Describes the
      29             :   expectations and restrictions on concrete classes implementing
      30             :   adaptive mesh refinement criteria.
      31             : - \ref dev_guide_amr_policies "AMR Policies": Describes restrictions
      32             :   and assumptions of the current algorithm, and what would be
      33             :   required to relax them.
      34             : - \ref dev_guide_amr_projectors "AMR Projectors": Describes the
      35             :   requirements on concrete classes which project data to the new or
      36             :   modified elements after mesh refinement.
      37             : - \ref dev_guide_amr_metavariables "AMR Metavariables": Describes the
      38             :   code that needs to be added to the metavariables of an executable in
      39             :   order to enable adaptive mesh refinement.
      40             : - \ref dev_guide_amr_input_options "Controlling AMR": Describes the
      41             :   options in the input file that control the behavior of adaptive mesh
      42             :   refinement.
      43             : 
      44             : ### AMR Algorithm {#dev_guide_amr_algorithm}
      45             : 
      46             : The AMR algorithm requires communication via simple actions between
      47             : the elements of the array component that are responsible for the
      48             : Element%s of the Domain and a singleton amr::Component.  See \ref
      49             : dev_guide_parallelization_foundations
      50             : "Parallelization and Core Concepts" for an overview of phases,
      51             : actions, metavariables, and other SpECTRE parallelization concepts.
      52             : 
      53             : Currently the AMR algorithm is run over several phases when a phase
      54             : change is triggered by an executable.  See \ref
      55             : dev_guide_amr_input_options "Controlling AMR" for how to control when
      56             : the AMR phases are triggered.
      57             : 
      58             : #### Evaluating refinement criteria
      59             : 
      60             : When AMR is triggered, the executable should enter
      61             : Parallel::Phase::EvaluateAmrCriteria.  In this phase, the
      62             : amr::Component triggers the simple action
      63             : amr::Actions::EvaluateRefinementCriteria on each element of the array
      64             : component (specified by `metavariables::amr::element_array`).  Each
      65             : element evaluates (in order) the user-specified refinement criteria,
      66             : each of which returns a refinement decision in each logical dimension
      67             : of the element represented as an amr::Flag.  The overall refinement
      68             : decision in each logical dimension is obtained by taking the highest
      69             : priority decision in the dimension over all criteria, where
      70             : amr::Flag::Split has the highest priority and amr::Flag::Join has the
      71             : lowest.  See \ref dev_guide_amr_criteria "AMR Criteria" for more
      72             : details on implementing criteria.  Once the overall refinement
      73             : decision based on the refinement criteria is made, the decision may be
      74             : modified to satisfy the \ref dev_guide_amr_policies "AMR Policies".
      75             : Finally, the element sends its decision (and other information in
      76             : amr::Info) to its neighbors by calling the simple action
      77             : amr::Actions::UpdateAmrDecision.
      78             : 
      79             : In amr::Actions::UpdateAmrDecision, an element decides whether or not it
      80             : needs to update its own refinement decision (or other information in
      81             : amr::Info) based on decisions (or other information in amr::Info) sent
      82             : by its neighbor.  Possible reasons to update the refinement decision
      83             : are, e.g., if a sibling neighbor does not want to join an element that
      84             : had initially decided to join, or if any of the amr::Policies would
      85             : be violated.  If the refinement decision (or other information in
      86             : amr::Info) of the element changes, the element will send its
      87             : updated amr::Info to its neighbors.
      88             : 
      89             : Note that simple actions are executed asynchronusly, so both
      90             : amr::Actions::EvaluateRefinementCriteria and
      91             : amr::Actions::UpdateAmrDecision have to handle the possibility that
      92             : they are executed out of order.  For example,
      93             : amr::Actions::UpdateAmrDecision could be executed before
      94             : amr::Actions::EvaluateRefinementCriteria.  Eventually all elements
      95             : will reach a state where they do not need to send new information to
      96             : their neighbors, thus reaching a state of quiescence.  When this
      97             : happens Parallel::Phase::EvaluateAmrCriteria ends. At this point all
      98             : elements have reached a consensus on how the domain should be adapted,
      99             : but no changes have been made to the domain.  In order to adjust the
     100             : domain, the executable should next start
     101             : Parallel::Phase::AdjustDomain.
     102             : 
     103             : #### Adjusting the domain
     104             : 
     105             : At the beginning of Parallel::Phase::AdjustDomain, the amr::Component
     106             : calls amr::Actions::AdjustDomain on each element of the array
     107             : component (specified by `metavariables::amr::element_array`).  If the
     108             : element wants to split in any dimension, it will call the simple
     109             : action amr::Actions::CreateChild on the amr::Component in order to
     110             : create new refined elements that will replace the existing element.
     111             : If the element wants to join in any dimension, it will either call
     112             : amr::Actions::CreateParent on the amr::Component (if it is the joining
     113             : sibling with the lowest SegmentId in each dimension being joined) or
     114             : do nothing in order to create a single new coarsened element that will
     115             : replace multiple existing elements.  If the element neither wants to
     116             : split nor join in any dimension, then the element mutates items in its
     117             : db::DataBox.  First the Element, Mesh and neighbor Mesh are updated.
     118             : Then the element calls the
     119             : \ref dev_guide_amr_projectors "AMR Projectors" that will update all
     120             : the mutable items in the db::DataBox.
     121             : Finally the amr::Info of the element and its neighbors are reset and
     122             : cleared so they are ready for a future invocation of AMR.
     123             : 
     124             : When amr::Actions::CreateChild is executed by the amr::Component, it
     125             : creates a new element in the `metavariables::amr::element_array`
     126             : passing a Parallel::SimpleActionCallback that will be executed after
     127             : the new element is created.  The callback will be either to call
     128             : amr::Actions::CreateChild again for the next child to be created, or
     129             : amr::Actions::SendDataToChildren which will be invoked on the element
     130             : that is being split.  amr::Actions::SendDataToChildren will then
     131             : invoke amr::Actions::InitializeChild on each new child element,
     132             : passing along all of the mutable items in its
     133             : db::DataBox. amr::Actions::SendDataToChildren will then deregister and
     134             : delete the element being split. amr::Actions::InitializeChild will
     135             : create its Element, Mesh, and neighbor Mesh, and then call the \ref
     136             : dev_guide_amr_projectors "AMR Projectors" that will update all the
     137             : mutable items in its db::DataBox.
     138             : 
     139             : When amr::Actions::CreateParent is executed by the amr::Component, it
     140             : creates a new element in the `metavariables::amr::element_array`
     141             : passing a Parallel::SimpleActionCallback that will be executed after
     142             : the new element is created.  The callback will be
     143             : amr::Actions::CollectDataFromChildren which will be invoked on one
     144             : of the elements that are joining.
     145             : amr::Actions::CollectDataFromChildren will then invoke either itself
     146             : on another element that is joining or amr::Actions::InitializeParent
     147             : on the new parent element, collecting all of the mutable items in each
     148             : joining element's db::DataBox. amr::Actions::CollectDataFromChildren
     149             : will then deregister and delete the element that is
     150             : joining. amr::Actions::InitializeParent will create its Element, Mesh,
     151             : and neighbor Mesh, and then call the \ref dev_guide_amr_projectors
     152             : "AMR Projectors" that will update all the mutable items in its
     153             : db::DataBox.
     154             : 
     155             : When all of the actions finish, a state of quiescence is reached.
     156             : When this happens Parallel::Phase::AdjustDomain ends.  The executable
     157             : should now either return to the phase which triggered AMR, or enter
     158             : Parallel::Phase::CheckDomain.
     159             : 
     160             : ### AMR Criteria {#dev_guide_amr_criteria}
     161             : 
     162             : When amr::Actions::EvaluateRefinementCriteria is executed, for each
     163             : element, it loops over a list of criteria that is specified in the
     164             : input file options
     165             : (See \ref dev_guide_amr_input_options "Controling AMR").
     166             : Each criterion must be an option-creatable class derived from
     167             : amr::Criterion (see its documentation for a list of requirements for
     168             : the derived classes).  In particular, each criterion should compute an
     169             : array of amr::Flag%s that represent the recommended refinemenent
     170             : choice in each logical dimension.  These choices can be computed from
     171             : any items in the db::DataBox of the element or additional compute
     172             : items specified by the criterion.  It is expected that a criterion
     173             : will compute something and then either choose to recommend refinement,
     174             : no change, or coarsening the element either in size (h-refinement) or
     175             : polynomial order (p-refinement).  A criterion does not need to handle
     176             : anything that is enforced by the amr::Policies such as worry about
     177             : bounds on the refinement level or number of grid points.
     178             : 
     179             : ### AMR Policies {#dev_guide_amr_policies}
     180             : 
     181             : The current AMR algorithm has a set of rules that are enforced after
     182             : the overall refinement choice is determined from the AMR criteria.
     183             : 
     184             : The following rules simplify the code:
     185             : 
     186             : - An Element cannot join if it is splitting in any dimension.  Instead
     187             :   any amr::Flag::Join is changed to amr::Flag::DoNothing. Relaxing
     188             :   this restriction would be a non-trivial change that would require
     189             :   more complicated logic in determining if neighboring elements can
     190             :   join, as well as an additional code path to handle the creation and
     191             :   initialization of the new elements. This should not be a significant
     192             :   restriction as in most cases when this would occur it is unlikely
     193             :   that the siblings of the Element would agree to a valid join.
     194             : 
     195             : - In two or three spatial dimensions, there must be a 2:1 balance
     196             :   (i.e. within one refinement level) between neighbors in the
     197             :   dimension(s) parallel to the face of the element.  Relaxing this
     198             :   restriction would be a significant change to the code as the
     199             :   code for communicating boundary corrections assumes 2:1 balance.  In
     200             :   order to maintain 2:1 balance with neighboring elements, a choice of
     201             :   amr::Flag::Join may be changed to amr::Flag::DoNothing, and
     202             :   amr::Flag::DoNothing may be changed to amr::Flag::Split.
     203             : 
     204             : The following policies are among those controlled by input file
     205             : options (see \ref dev_guide_amr_input_options "Controlling AMR" and
     206             : the documentation for amr::Policies):
     207             : 
     208             : - Whether to do isotropic or anisotropic refinement.  If isotropic
     209             :   refinement is done, the AMR decision in each dimension are changed
     210             :   to the decision of the dimension with the highest priority amr::Flag
     211             :   (i.e. amr::Flag::Split has the highest priority).
     212             : 
     213             : - Whether or not to enforce 2:1 balance for the refinement level in
     214             :   the direction perpendicular to the face.
     215             : 
     216             : - The minimum and maximum of the refinement level and the number of
     217             :   grid points.  The actual bounds on these will be the stricter of
     218             :   those specified by the input file and those set by the code.  For
     219             :   the number of grid points, the code bounds are set by
     220             :   Spectral::minimum_number_of_points and
     221             :   Spectral::maximum_number_of_points for the Spectral::Basis and
     222             :   Spectral::Quadrature of the Mesh.  For the refinement level, the
     223             :   minimum is zero, and the maximum is set by
     224             :   `ElementId::max_refinement_level`.
     225             : 
     226             : ### AMR Projectors {#dev_guide_amr_projectors}
     227             : 
     228             : After the grid adapts, the mutable items in the DataBox of new or
     229             : existing elements must be updated.  The Element, Mesh, neighbor Mesh,
     230             : amr::Info, and neighbor amr::Info along with the items in
     231             : `Parallel::Tags::distributed_object_tags` are automatically updated by
     232             : the AMR actions, but all other items must be explicitly updated via
     233             : projectors that conform to amr::protocols::Projector.  If any mutable
     234             : item has not been explicitly handled by any of the projectors, a
     235             : `static_assert` will be triggered listing the tags for the items that
     236             : have not been projected.
     237             : 
     238             : When a new element is created, the items in its DataBox are default
     239             : constructed.  Their Element, Mesh, and neighbor Mesh are mutated to
     240             : their desired state.  Then the AMR projectors are called, passing
     241             : along the items in the DataBox(es) from their splitting parent element
     242             : or joining children elements.  Existing elements first mutate their
     243             : Element, Mesh, and neighbor Mesh, and then call the AMR projectors,
     244             : passing along the old Element and Mesh.
     245             : 
     246             : The `return_tags` of each projector lists the tags for the items that
     247             : the projector mutates.  From the pre-AMR state, the projector must
     248             : compute the post-AMR state of these items.  Typically during
     249             : Parallel::Phase::Initialization, a group of items will be initialized
     250             : by a specific action or mutator in the action
     251             : `Initialization::Actions::InitializeItems`.  Therefore it makes sense
     252             : to create a projector that will handle the same group of items.
     253             : However some items are initialized from input file options, while
     254             : others are left default initialized and not mutated by any
     255             : initialization action.  These items will still need to be handled by
     256             : some projector.  Two convenience projectors are provided:
     257             : amr::projectors::DefaultInitialize which value initializes the items
     258             : corresponding to the listed tags; and
     259             : amr::projectors::CopyFromCreatorOrLeaveAsIs that will either copy the
     260             : item from the parent (or children, asserting that all children agree)
     261             : of a newly created element, or leave the item unmodified for an
     262             : existing element for the items corresponding to the listed tags.
     263             : 
     264             : The list of projectors is specified in
     265             : `metavariables::amr::projectors` in the executable, and the projectors
     266             : are evaluated in the order in which they are specified.
     267             : 
     268             : ### Enabling AMR for an executable {#dev_guide_amr_metavariables}
     269             : 
     270             : In order to enable AMR for an executable, the following changes need
     271             : to be made in the metavariables:
     272             : 
     273             : - The addition of a struct named `amr` such as the following example:
     274             : ```
     275             : struct amr : tt::ConformsTo<::amr::protocols::AmrMetavariables> {
     276             :     using element_array = dg_element_array;
     277             :     using projectors = tmpl::list<::amr::projectors::DefaultInitialize<
     278             :         domain::Tags::InitialExtents<Dim>,
     279             :         domain::Tags::InitialRefinementLevels<Dim>,
     280             :         evolution::dg::Tags::Quadrature>>;
     281             :     static constexpr bool keep_coarse_grids = false;
     282             :   };
     283             : ```
     284             : 
     285             :   where `element_array` specifies the array component on which AMR
     286             :   will operate and `projectors` is a type list of amr::projectors
     287             :   that govern how the items in the DataBox for the `element_array` are
     288             :   updated after refinement.
     289             : 
     290             : - The addition of amr::Component to the `component_list` of the metavariables
     291             : 
     292             : - The addition (or modification) of the following `tmpl::pair`s in
     293             :   `factory_creation::factory_classes`:
     294             : ```
     295             :         tmpl::pair<amr::Criterion,
     296             :                    tmpl::list<LIST_OF_CRITERIA>,
     297             :         tmpl::pair<
     298             :             PhaseChange,
     299             :             tmpl::list<
     300             :                 PhaseControl::VisitAndReturn<
     301             :                     Parallel::Phase::EvaluateAmrCriteria>,
     302             :                 PhaseControl::VisitAndReturn<Parallel::Phase::AdjustDomain>,
     303             :                 PhaseControl::VisitAndReturn<Parallel::Phase::CheckDomain>>,
     304             : ```
     305             : where `LIST_OF_CRITERIA` should be a list of amr::Criteria.
     306             : 
     307             : - The addition of the following item in the list of PhaseActions for
     308             :   the component specified in `amr::element_array`:
     309             : 
     310             : ```
     311             :           Parallel::PhaseActions<Parallel::Phase::CheckDomain,
     312             :                                  tmpl::list<::amr::Actions::SendAmrDiagnostics,
     313             :                                             Parallel::Actions::TerminatePhase>>,
     314             : ```
     315             : 
     316             : - The possible addition of `PhaseControl::Actions::ExecutePhaseChange`
     317             :   to the action list for the appropriate Phase in the PhaseAction of
     318             :   the `amr::element_array`
     319             : 
     320             : - The addition of the mutator `amr::Initialization::Initialize` to the
     321             :   list of mutators in `Initialization::Actions::InitializeItems` in
     322             :   the Parallel::PhaseActions list for Parallel::Phase::Initialization.
     323             : 
     324             : - The appropriate includes for all of the above.
     325             : 
     326             : ### Controlling AMR {#dev_guide_amr_input_options}
     327             : 
     328             : There are two places in the input file that control how and when AMR happens.
     329             : 
     330             : The "how" is controlled by the option group `Amr`.  Here you list the
     331             : amr::Criteria being used, the available options for the amr::Policies, and
     332             : the `Verbosity` of diagnostic messages that are printed.  Here is an
     333             : example:
     334             : ```
     335             : Amr:
     336             :   Criteria:
     337             :     - TruncationError:
     338             :         VariablesToMonitor: [Psi]
     339             :         AbsoluteTarget: 1.e-6
     340             :         RelativeTarget: 1.0
     341             :   Policies:
     342             :     EnforceTwoToOneBalanceInNormalDirection: true
     343             :     Isotropy: Anisotropic
     344             :     Limits:
     345             :       RefinementLevel: Auto
     346             :       NumGridPoints: Auto
     347             :       ErrorBeyondLimits: False
     348             :     AllowCoarsening: True
     349             :   Verbosity: Verbose
     350             : ```
     351             : 
     352             : Note that the values `Auto` for the Limits options choose the default
     353             : limits set by the code. Also note that if a criterion tries to refine beyond the
     354             : limits, whether or not the code should error is controlled by
     355             : `ErrorBeyondLimits`.
     356             : 
     357             : "When" AMR happens is controlled by specifying a Trigger and a list of
     358             : `PhaseChanges` in the top-level option `PhaseChangesAndTriggers`.  For
     359             : example:
     360             : ```
     361             : PhaseChangeAndTriggers:
     362             :   - Trigger:
     363             :       Slabs:
     364             :         EvenlySpaced:
     365             :           Interval: 10
     366             :           Offset: 0
     367             :     PhaseChanges:
     368             :       - VisitAndReturn(EvaluateAmrCriteria)
     369             :       - VisitAndReturn(AdjustDomain)
     370             :       - VisitAndReturn(CheckDomain)
     371             : ```
     372             : 
     373             : Both `EvaluateAmrCriteria` and `AdjustDomain` are required in order
     374             : for AMR to work.  `VisitAndReturn(CheckDomain)` performs diagnostics
     375             : and can be omitted.  To turn off AMR, omit the three phase changes above.

Generated by: LCOV version 1.14