Forest-of-octrees data structure for adaptive h-refinement of 3-D hexahedral meshes, the direct analogue of SELF_QuadTreeMesh_2D. Each base-mesh element is the root of an octree; refinement replaces a leaf with eight children (one per reference octant, SELF child ordering = CGNS corner order), and coarsening merges a family of eight leaf siblings back into their parent. The forest tracks refinement levels and the active leaf set; the physical geometry of any leaf is produced by repeated exact isoparametric subdivision of its root (SELF_RefinementPrimitives_3D).
This module owns the adaptive mesh mutation only. Turning an adaptively refined (and hence generally nonconforming) forest into a solver-ready Mesh3D_t - face-neighbour queries, 2:1 balancing, hanging-face/mortar generation - is SELF_AdaptiveMesh_3D. The intended driver loop each adaptation step matches the 2-D one:
indicator%Estimate(solution,ivar) ! per-leaf refine/keep/coarsen flags forest%AdaptFromFlags(indicator%flag) ! mutate the forest (this module) forest%Balance2to1() ; EmitMesh(...) ! balance + emit Mesh3D_t + mortars
2:1 balance is enforced across faces only : hanging edges and corners carry no interface data in the DG discretization (face mortars carry all of it), exactly as the 2-D quadtree tolerates corner-level jumps.
Coarsening does not currently reclaim the storage of removed child nodes (the node arrays grow monotonically); the active leaf set is always recovered by traversal from the roots, so orphaned nodes are simply never revisited. Storage compaction is a future optimisation.
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer, | public, | parameter | :: | OCTREE_COARSEN | = | -1 | |
| integer, | public, | parameter | :: | OCTREE_KEEP | = | 0 | |
| integer, | public, | parameter | :: | OCTREE_REFINE | = | 1 |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer, | public | :: | capacity | = | 0 | ||
| integer, | public, | allocatable | :: | child(:,:) | |||
| integer, | public, | allocatable | :: | leaf(:) | |||
| integer, | public, | allocatable | :: | level(:) | |||
| integer, | public | :: | nGeo | = | 0 | ||
| integer, | public | :: | nLeaves | = | 0 | ||
| integer, | public | :: | nNodes | = | 0 | ||
| integer, | public | :: | nRoots | = | 0 | ||
| integer, | public, | allocatable | :: | octant(:) | |||
| integer, | public, | allocatable | :: | parent(:) | |||
| integer, | public | :: | quadrature | = | 0 | ||
| integer, | public, | allocatable | :: | rootBC(:,:) | |||
| real(kind=prec), | public, | allocatable | :: | rootCoords(:,:,:,:,:) | |||
| integer, | public, | allocatable | :: | rootElem(:) | |||
| integer, | public, | allocatable | :: | rootFlip(:,:) | |||
| integer, | public, | allocatable | :: | rootMaterial(:) | |||
| integer, | public, | allocatable | :: | rootNbr(:,:) | |||
| integer, | public, | allocatable | :: | rootNbrSide(:,:) |
| procedure, public :: AdaptFromFlags => AdaptFromFlags_OctreeMesh3D | |
| procedure, public :: Balance2to1 => Balance2to1_OctreeMesh3D | |
| procedure, private :: EnsureCapacity => EnsureCapacity_OctreeMesh3D | |
| procedure, public :: FaceNeighbor => FaceNeighbor_OctreeMesh3D | |
| procedure, public :: Free => Free_OctreeMesh3D | |
| procedure, public :: Init => Init_OctreeMesh3D | |
| procedure, public :: InitGlobal => InitGlobal_OctreeMesh3D | |
| procedure, public :: LeafCoords => LeafCoords_OctreeMesh3D | |
| procedure, public :: MaxLevel => MaxLevel_OctreeMesh3D | |
| procedure, public :: MaxLevelJump => MaxLevelJump_OctreeMesh3D | |
| procedure, public :: RebuildLeaves => RebuildLeaves_OctreeMesh3D | |
| procedure, public :: RefineNode => RefineNode_OctreeMesh3D |
Largest refinement-level difference across any leaf face (0 on a conforming or uniformly refined forest, 1 on a 2:1-balanced adaptive forest). Because FaceNeighbor returns the equal-or-larger neighbour, every level difference is observed from the finer leaf as a coarser leaf neighbour; internal (finer) neighbours contribute nothing from this side.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(OctreeMesh3D), | intent(in) | :: | this |
Highest refinement level among the active leaves.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(OctreeMesh3D), | intent(in) | :: | this |
.true. if child c's face s is interior to its parent (its neighbour across s is a sibling): the child sits in the half-cube away from parent face s.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | s | |||
| integer, | intent(in) | :: | c |
The local face directly across an element from face s.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | s |
Sibling child index obtained by reflecting c across face s (swap the half-index of the direction normal to s).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | s | |||
| integer, | intent(in) | :: | c |
Face quadrant (1..4, in face s's trace coordinates) of child c on face s; 0 if c does not touch face s.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | c | |||
| integer, | intent(in) | :: | s |
Mutate the forest from a per-leaf flag array (indexed over the current leaves in this%leaf order, e.g. the flag array produced by the refinement indicator):
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(OctreeMesh3D), | intent(inout) | :: | this | |||
| integer, | intent(in) | :: | flag(1:this%nLeaves) |
Enforce the 2:1 face balance condition: no leaf face may separate elements differing by more than one refinement level. Iterates to a fixed point - in each sweep, any leaf whose equal-or-larger neighbour is a leaf two or more levels coarser triggers refinement of that coarser neighbour; refinement can ripple, so sweeps repeat until nothing changes. The leaf set is rebuilt on return.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(OctreeMesh3D), | intent(inout) | :: | this |
Grow the node arrays (amortized doubling) so at least need nodes fit.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(OctreeMesh3D), | intent(inout) | :: | this | |||
| integer, | intent(in) | :: | need |
Find the equal-or-larger face neighbour of node across its local face s using the
classic octree ascend/descend search. Returns:
nbr - neighbour node id (0 = physical domain boundary). It is either a LEAF at
any level <= level(node), or an INTERNAL node at exactly level(node)
(meaning the shared face is subdivided on the neighbour side, i.e. finer
neighbours exist).
ns - the neighbour's local face that faces node.
nf - the flip between the two shared faces (0..7, sideInfo(4) convention),
inherited from the base-mesh face where the search crosses a root boundary.
With this, a 2:1 hanging face is exactly "nbr is a leaf with level(nbr) =
level(node)-1", and finer neighbours are exactly "nbr is internal".
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(OctreeMesh3D), | intent(in) | :: | this | |||
| integer, | intent(in) | :: | node | |||
| integer, | intent(in) | :: | s | |||
| integer, | intent(out) | :: | nbr | |||
| integer, | intent(out) | :: | ns | |||
| integer, | intent(out) | :: | nf |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(OctreeMesh3D), | intent(inout) | :: | this |
Initialize the forest directly from GLOBAL base-mesh tables (one root per global base element, all leaves at level 0). This is the initialization path for a rank-replicated forest over a decomposed base mesh: every rank passes the same gathered tables and holds an identical forest. rootNbr carries global element ids (0 = physical boundary), rootNbrSide/rootFlip decode the base sideInfo(4) pairing, rootBC the base boundary-condition id per face, and rootMaterial the base material id per element.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(OctreeMesh3D), | intent(out) | :: | this | |||
| integer, | intent(in) | :: | nRoots | |||
| integer, | intent(in) | :: | nGeo | |||
| integer, | intent(in) | :: | quadrature | |||
| real(kind=prec), | intent(in) | :: | rootCoords(1:3,1:nGeo+1,1:nGeo+1,1:nGeo+1,1:nRoots) | |||
| integer, | intent(in) | :: | rootNbr(1:6,1:nRoots) | |||
| integer, | intent(in) | :: | rootNbrSide(1:6,1:nRoots) | |||
| integer, | intent(in) | :: | rootFlip(1:6,1:nRoots) | |||
| integer, | intent(in) | :: | rootBC(1:6,1:nRoots) | |||
| integer, | intent(in) | :: | rootMaterial(1:nRoots) |
Initialize the forest with one root per base-mesh element (all leaves at level 0). The base geometry (node coordinates) is copied so leaf geometry can be regenerated after any amount of refinement without holding a reference to the mesh. Requires a single-rank mesh (a decomposed mesh only stores its local elements); a rank-replicated forest over a decomposed base is built by gathering the global tables and calling InitGlobal.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(OctreeMesh3D), | intent(out) | :: | this | |||
| type(Mesh3D), | intent(in) | :: | mesh |
Physical geometry-node coordinates of leaf leafIndex, produced by repeated exact
isoparametric subdivision of its root element along the octree path. geomInterp
must be a degree-nGeo Lagrange interpolant on the mesh's geometry (quadrature)
nodes - the same interpolant SELF_MeshRefinement_3D builds. Level 0 leaves return
the root geometry directly. Pure function of (root coords, level, octant path), so
regenerated leaf geometry is bit-identical across epochs.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(OctreeMesh3D), | intent(in) | :: | this | |||
| integer, | intent(in) | :: | leafIndex | |||
| type(Lagrange), | intent(in) | :: | geomInterp | |||
| real(kind=prec), | intent(out) | :: | coords(1:3,1:this%nGeo+1,1:this%nGeo+1,1:this%nGeo+1) |
Recompute the active leaf set by depth-first traversal from the roots. Traversal (rather than a scan of all nodes) is what makes orphaned nodes left behind by coarsening invisible. The root-major DFS order with children visited 1..8 is the Morton (Z-order) curve within each root, which is what makes the contiguous block decomposition of the emitted element list a locality-preserving SFC partition.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(OctreeMesh3D), | intent(inout) | :: | this |
Subdivide one leaf node into eight children. Does nothing (with a warning) if the node is already refined. The caller is responsible for rebuilding the leaf list afterwards (or calling AdaptFromFlags, which does so).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(OctreeMesh3D), | intent(inout) | :: | this | |||
| integer, | intent(in) | :: | node |