Skip to content
Merged
Show file tree
Hide file tree
Changes from 65 commits
Commits
Show all changes
113 commits
Select commit Hold shift + click to select a range
5ff2783
Support -snes_adapt
pbrubeck Jul 2, 2026
1c7406a
Support -snes_adapt
pbrubeck Jul 2, 2026
b4153b7
Native/redistributed transfer for AdaptiveMeshHierarcy
pbrubeck Jul 3, 2026
fc1e25e
cleanup
pbrubeck Jul 3, 2026
c999b13
Merge branch 'pbrubeck/snes-adapt' into pbrubeck/mg-redist
pbrubeck Jul 3, 2026
d588985
Works in serial
pbrubeck Jul 3, 2026
46e2514
WIP: RedistMesh
pbrubeck Jul 3, 2026
885a7eb
Deprecate AdaptiveTransferManager
pbrubeck Jul 3, 2026
c8b3473
WIP struggled a lot with injection
pbrubeck Jul 3, 2026
2e0ef75
remove anti-patterns
pbrubeck Jul 3, 2026
a60293f
workaround
pbrubeck Jul 4, 2026
e24125e
fix parallel
pbrubeck Jul 4, 2026
6c37126
add failing redistribution test
pbrubeck Jul 4, 2026
c9fba85
cleanup
pbrubeck Jul 4, 2026
f978cf9
Redistributed MeshHierarchy
pbrubeck Jul 4, 2026
4e4bbeb
refactoring, and some FIXMEs
pbrubeck Jul 4, 2026
a810d2f
Fix RedistMesh + AdaptiveMeshHierarchy
pbrubeck Jul 4, 2026
3df8ca5
refactoring
pbrubeck Jul 5, 2026
1523df1
reconstruct coefficient in either direction
pbrubeck Jul 6, 2026
dbd64f3
Merge branch 'pbrubeck/snes-adapt' into pbrubeck/mg-redist
pbrubeck Jul 6, 2026
631889c
cleanup
pbrubeck Jul 6, 2026
2c01147
move code around
pbrubeck Jul 6, 2026
fc16d28
reuse MeshTopology._set_partitioner
pbrubeck Jul 6, 2026
0d3aaef
expose the distribution_parameters
pbrubeck Jul 6, 2026
6ad926e
test second level
pbrubeck Jul 6, 2026
ba9bfb4
Fix compositions of MeshHierarchy and AdaptiveMeshHierarchy
pbrubeck Jul 6, 2026
2986a7b
DMPlex.adaptLabel
pbrubeck Jul 7, 2026
d3eab9b
Use DMPlex.adaptLabel()
pbrubeck Jul 7, 2026
9bd0dfb
restore redistribution
pbrubeck Jul 7, 2026
08957f9
Refactoring
pbrubeck Jul 7, 2026
7a2fa1a
Enable 3D (tetrahedron) support for refine_sbr adaptive refinement
pbrubeck Jul 8, 2026
4b96edc
Drop adapt label
pbrubeck Jul 8, 2026
1aa43b5
cleanup
pbrubeck Jul 8, 2026
c6d1474
cleanup tests
pbrubeck Jul 8, 2026
f3236b5
Fix adaptive injection
pbrubeck Jul 8, 2026
b80cb8f
Apply suggestions from code review
pbrubeck Jul 8, 2026
b42e28d
cleanup
pbrubeck Jul 8, 2026
8f83483
cleanup
pbrubeck Jul 8, 2026
651804e
basic test
pbrubeck Jul 8, 2026
edc9b7b
Unify coarsen/refine dispatch under a shared reconstruct base, and fi…
pbrubeck Jul 9, 2026
b9c5a21
Merge remote-tracking branch 'origin/main' into pbrubeck/snes-adapt
pbrubeck Jul 9, 2026
aa43084
refactoring
pbrubeck Jul 9, 2026
4035788
Apply suggestion from @pbrubeck
pbrubeck Jul 9, 2026
8c612ac
Merge branch 'pbrubeck/snes-adapt' into pbrubeck/mg-redist
pbrubeck Jul 10, 2026
0b4a188
Apply review suggestions: defer coefficient prolongation to transfer …
pbrubeck Jul 10, 2026
de7a0d0
Merge branch 'pbrubeck/snes-adapt' into pbrubeck/mg-redist
pbrubeck Jul 10, 2026
7ace418
Apply review suggestions: split MeshHierarchy into three stages
pbrubeck Jul 10, 2026
6cc4489
Apply follow-up review suggestions to MeshHierarchy
pbrubeck Jul 10, 2026
4564981
Apply review suggestions to interface.py, adapt.py, and redist.py
pbrubeck Jul 10, 2026
3fbf003
Apply further review suggestions to mesh.py, adapt.py, netgen.py
pbrubeck Jul 10, 2026
098ca74
Apply suggestions from code review
pbrubeck Jul 10, 2026
3e21650
Apply suggestion from @pbrubeck
pbrubeck Jul 10, 2026
5a0306a
Apply suggestion from @pbrubeck
pbrubeck Jul 10, 2026
f3d5e67
Apply suggestion from @pbrubeck
pbrubeck Jul 10, 2026
27a5260
Apply suggestions from code review
pbrubeck Jul 10, 2026
8339a52
fixes
pbrubeck Jul 10, 2026
b25d720
Apply suggestions from code review
pbrubeck Jul 10, 2026
0c87d21
Apply suggestion from @pbrubeck
pbrubeck Jul 10, 2026
9be2fbe
Apply suggestions from code review
pbrubeck Jul 10, 2026
60aa61b
Apply suggestion from @pbrubeck
pbrubeck Jul 10, 2026
7b4f5d8
fix inject
pbrubeck Jul 10, 2026
5e9b4cb
Deterministic tests
pbrubeck Jul 10, 2026
2fe1c33
API improvements
pbrubeck Jul 10, 2026
96e24f9
cythonize, remove balancing-based redistribution
pbrubeck Jul 13, 2026
04bf785
Merge branch 'pbrubeck/snes-adapt' into pbrubeck/mg-redist
pbrubeck Jul 16, 2026
82af367
Apply suggestions from code review
pbrubeck Jul 20, 2026
5761136
Merge branch 'main' into pbrubeck/snes-adapt
pbrubeck Jul 21, 2026
55dd08b
review comments
pbrubeck Jul 21, 2026
633448f
Merge branch 'pbrubeck/snes-adapt' into pbrubeck/mg-redist
pbrubeck Jul 21, 2026
c1b2ef1
Apply suggestion from @pbrubeck
pbrubeck Jul 21, 2026
fc7f092
Apply suggestions from code review
pbrubeck Jul 21, 2026
676ef79
set adaptive criterion when we detect a marking_callback
pbrubeck Jul 21, 2026
231ed2c
Merge branch 'pbrubeck/snes-adapt' into pbrubeck/mg-redist
pbrubeck Jul 21, 2026
c8a7ed4
Split mesh redistribution into a separate branch
pbrubeck Jul 21, 2026
459a2a0
Apply suggestions from code review
pbrubeck Jul 21, 2026
9001da6
Apply suggestions from code review
pbrubeck Jul 22, 2026
0aac44f
review suggestions
pbrubeck Jul 22, 2026
466e756
tidy
pbrubeck Jul 22, 2026
1ce6051
get_relative ensures that hierarchy is the same
pbrubeck Jul 22, 2026
8a04d52
Merge branch 'pbrubeck/snes-adapt' into pbrubeck/mg-redist
pbrubeck Jul 22, 2026
f825d59
Merge branch 'main' into pbrubeck/snes-adapt
pbrubeck Jul 22, 2026
2709cea
Fix
pbrubeck Jul 22, 2026
b355866
Fix a workaround for Real space
pbrubeck Jul 23, 2026
8b1dcd3
Make code less pythonic
pbrubeck Jul 23, 2026
3324471
review suggestions
pbrubeck Jul 23, 2026
dd2303e
Apply suggestion from @pbrubeck
pbrubeck Jul 23, 2026
c571474
reverse kwarg
pbrubeck Jul 23, 2026
73a8567
Merge branch 'pbrubeck/snes-adapt' into pbrubeck/mg-redist
pbrubeck Jul 23, 2026
115ac32
purge AdaptiveTransferManager
pbrubeck Jul 23, 2026
1d99930
Merge branch 'main' into pbrubeck/snes-adapt
pbrubeck Jul 24, 2026
1cf9f3c
Merge branch 'pbrubeck/snes-adapt' into pbrubeck/mg-redist
pbrubeck Jul 26, 2026
9bbdb59
Merge branch 'pbrubeck/mg-redist' of github.com:firedrakeproject/fire…
pbrubeck Jul 27, 2026
a4cd3c7
merge conflict
pbrubeck Jul 27, 2026
3582bb0
drop redist
pbrubeck Jul 27, 2026
1e4ef15
petsctools.inserted_options
pbrubeck Jul 27, 2026
e35d3b7
docstrings
pbrubeck Jul 27, 2026
3821989
drop redist
pbrubeck Jul 27, 2026
6b68257
Cython memory view, fixes for petsctools.inserted_options
pbrubeck Jul 27, 2026
51ae39b
more comments
pbrubeck Jul 27, 2026
c5fc2f9
Apply suggestions from code review
pbrubeck Jul 27, 2026
ef5aed1
comments
pbrubeck Jul 27, 2026
b74153e
make code more readable
pbrubeck Jul 27, 2026
21f4ab7
petsctools main
pbrubeck Jul 27, 2026
abdc3a1
Fix test that broke after splitting redistribution
pbrubeck Jul 27, 2026
2813f24
remove netgen fix
pbrubeck Jul 28, 2026
1dae5ad
Merge branch 'main' into pbrubeck/mg-redist
pbrubeck Jul 29, 2026
2c55fb1
Fuse AdaptiveMeshHierarchy into MeshHierarchy
pbrubeck Jul 30, 2026
ca39efa
Merge remote-tracking branch 'origin/main' into pbrubeck/mg-redist
pbrubeck Jul 30, 2026
8090999
review suggestions
pbrubeck Jul 30, 2026
e0e8ea1
Merge branch 'main' into pbrubeck/mg-redist
pbrubeck Jul 30, 2026
5761390
Apply suggestion from @pbrubeck
pbrubeck Jul 30, 2026
f00303e
Clarify why _transfer_high_order_coordinates clones the plex
pbrubeck Jul 30, 2026
739a3be
remove clone
pbrubeck Jul 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions demos/adaptive_multigrid/adaptive_multigrid.py.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ Contributed by Anurag Rao.

The purpose of this demo is to show how to use Firedrake's multigrid solver on a hierarchy of adaptively refined Netgen meshes.
We will first have a look at how to use the :class:`~.AdaptiveMeshHierarchy` to construct the mesh hierarchy with Netgen meshes, then we will consider a solution to the Poisson problem on an L-shaped domain.
Finally, we will show how to use the :class:`~.AdaptiveMeshHierarchy` and :class:`~.AdaptiveTransferManager` to construct a scalable solver. The :class:`~.AdaptiveMeshHierarchy` contains information of the mesh hierarchy and the parent child relations between the meshes.
The :class:`~.AdaptiveTransferManager` deals with the transfer operator logic across any given levels in the hierarchy.
Finally, we will show how to use the :class:`~.AdaptiveMeshHierarchy` to construct a scalable solver. The :class:`~.AdaptiveMeshHierarchy` contains information of the mesh hierarchy and the parent child relations between the meshes.
We begin by importing the necessary libraries ::

from firedrake import *
Expand All @@ -34,10 +33,9 @@ It is important to convert the initial Netgen mesh into a Firedrake mesh before
:align: center
:alt: Initial mesh.

We will also initialize the :class:`~.AdaptiveTransferManager` here: ::
We initialize the :class:`~.AdaptiveMeshHierarchy` here: ::

amh = AdaptiveMeshHierarchy(mesh)
atm = AdaptiveTransferManager()

Poisson Problem
---------------
Expand All @@ -62,15 +60,12 @@ Our approach strongly follows the similar problem in this `lecture course <https

problem = LinearVariationalProblem(a, L, uh, bcs)
solver = LinearVariationalSolver(problem, solver_parameters=params)

solver.set_transfer_manager(atm)
solver.solve()

its = solver.snes.getLinearSolveIterations()
return uh, its

Note the code after the construction of the :class:`~.LinearVariationalProblem`. To use the :class:`~.AdaptiveMeshHierarchy` with the existing Firedrake solver, we have to set the :class:`~.AdaptiveTransferManager` as the transfer manager of the multigrid solver.
Since we are using linear Lagrange elements, we will employ Jacobi as the multigrid relaxation, which we define with ::
To use the :class:`~.AdaptiveMeshHierarchy` in a multigrid solver, we just set the usual multigrid solver parameters. Since we are using linear Lagrange elements, we will employ Jacobi as the multigrid relaxation, which we define with ::

solver_params = {
"mat_type": "matfree",
Expand Down
209 changes: 209 additions & 0 deletions firedrake/adapt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
"""Adaptive mesh refinement helpers."""
import numpy as np

from pyop2.mpi import MPI
from firedrake.cython import dmcommon
from firedrake.cython import mgimpl as impl
from firedrake.petsc import PETSc
from firedrake.utils import IntType
from firedrake.function import Function
from firedrake.functionspace import FunctionSpace
from firedrake.mesh import Mesh, DISTRIBUTION_PARAMETERS_NOOP
from firedrake.netgen import _recurve_netgen_mesh
from firedrake.redist import (RedistributedMeshTransfer, dm_has_empty_rank,
redistribute_dm)


DM_ADAPT_REFINE = 1
Comment thread
pbrubeck marked this conversation as resolved.


def _refine_marked_elements_once(mesh, cell_marker):
"""Refine marked cells once and return parent-child cell maps."""
dm = mesh.topology_dm
ncoarse = mesh.cell_set.size

parent_name = "_adaptive_dmplex_parent"
adapt_name = "_adaptive_dmplex_adapt"
dm.createLabel(parent_name)
dm.createLabel(adapt_name)
impl.set_adaptive_parent_label(dm, mesh._cell_numbering, ncoarse, parent_name)
adapt_label = dm.getLabel(adapt_name)
adapt_indicator = np.zeros(cell_marker.dat.data_ro_with_halos.shape, dtype=IntType)
adapt_indicator[:ncoarse] = cell_marker.dat.data_ro.real > 0
dmcommon.mark_points_with_function_array(
dm, cell_marker.function_space().dm.getSection(), 0,
adapt_indicator, adapt_label, DM_ADAPT_REFINE,
)

opts = PETSc.Options()
had_prev = opts.hasName("dm_plex_transform_type")
prev = opts.getString("dm_plex_transform_type", "") if had_prev else None
Comment thread
pbrubeck marked this conversation as resolved.
Outdated
opts["dm_plex_transform_type"] = "refine_sbr"
try:
new_dm = dm.adaptLabel(adapt_name)
finally:
Comment thread
connorjward marked this conversation as resolved.
if had_prev:
opts["dm_plex_transform_type"] = prev
else:
opts.delValue("dm_plex_transform_type")
dm.removeLabel(parent_name)
dm.removeLabel(adapt_name)

# The transform propagates every label, including the temporary adapt label.
for label in ("pyop2_core", "pyop2_owned", "pyop2_ghost", adapt_name):
Comment thread
pbrubeck marked this conversation as resolved.
Outdated
if new_dm.hasLabel(label):
new_dm.removeLabel(label)

new_mesh = Mesh(
new_dm,
dim=mesh.geometric_dimension,
reorder=False,
distribution_parameters=DISTRIBUTION_PARAMETERS_NOOP,
comm=mesh.comm,
tolerance=mesh.tolerance,
)

coarse_to_fine, fine_to_coarse = impl.adaptive_parent_child_cell_maps(
new_dm, new_mesh._cell_numbering, ncoarse, new_mesh.cell_set.size,
parent_name,
)
new_dm.removeLabel(parent_name)

return new_mesh, coarse_to_fine, fine_to_coarse


def _copy_adaptive_refinement_metadata(source_mesh, target_mesh):
"""Copy mesh-construction metadata from a mesh onto its adaptively-derived successor."""
target_mesh._distribution_parameters = dict(source_mesh._distribution_parameters)
target_mesh._did_reordering = source_mesh._did_reordering
target_mesh._tolerance = source_mesh.tolerance
if hasattr(source_mesh, "netgen_mesh") and not hasattr(target_mesh, "netgen_mesh"):
target_mesh.netgen_mesh = source_mesh.netgen_mesh
if hasattr(source_mesh, "netgen_flags") and not hasattr(target_mesh, "netgen_flags"):
target_mesh.netgen_flags = source_mesh.netgen_flags


def _needs_adaptive_redistribution(mesh):
"""Return whether ``mesh`` has an empty rank."""
return dm_has_empty_rank(mesh.topology_dm)


def _redistribute_adaptive_refined_mesh(coarse_mesh, transfer_mesh,
redistribute=True):
"""Redistribute an adaptively refined mesh if the coarse mesh has empty ranks."""
_copy_adaptive_refinement_metadata(coarse_mesh, transfer_mesh)

needs_redist = (redistribute and coarse_mesh.comm.size > 1
and _needs_adaptive_redistribution(transfer_mesh))
if not needs_redist:
return transfer_mesh

redist_parameters = dict(coarse_mesh._distribution_parameters)
redist_parameters["partition"] = True
redist_dm = transfer_mesh.topology_dm.clone()
_, point_sf = redistribute_dm(redist_dm, redist_parameters)

redist_topology_mesh = Mesh(
redist_dm,
dim=transfer_mesh.geometric_dimension,
reorder=False,
distribution_parameters=DISTRIBUTION_PARAMETERS_NOOP,
comm=transfer_mesh.comm,
tolerance=transfer_mesh.tolerance,
)
_copy_adaptive_refinement_metadata(transfer_mesh, redist_topology_mesh)

redist_transfer = RedistributedMeshTransfer(
transfer_mesh, redist_topology_mesh, point_sf
)
Vredist = transfer_mesh.coordinates.function_space().reconstruct(
mesh=redist_topology_mesh
)
redist_coordinates = Function(Vredist)
redist_transfer.orig2redist(transfer_mesh.coordinates, redist_coordinates)
redist_mesh = Mesh(redist_coordinates, name=transfer_mesh.name)
_copy_adaptive_refinement_metadata(redist_topology_mesh, redist_mesh)
redist_mesh.redist = RedistributedMeshTransfer(
transfer_mesh, redist_mesh, point_sf
)
return redist_mesh


def refine_marked_elements(mesh, cell_marker, redistribute=True):
"""Adaptively refine a mesh using a DG0 marking function.

Positive integer marker values request repeated refinement of the
corresponding cells. Curved Netgen meshes are re-curved to the
original coordinate degree after refinement.

Parameters
----------
mesh
The mesh to refine.
cell_marker
A DG0 `~firedrake.function.Function` on ``mesh``: cells with a
positive value ``n`` are refined ``n`` times.
redistribute
If ``True``, redistribute the refined mesh when the coarse mesh
has empty ranks.

Returns
-------
MeshGeometry
The adaptively refined mesh, with ``_adaptive_cell_maps`` set
to the ``(coarse_to_fine, fine_to_coarse)`` cell maps relative
to ``mesh``.
"""
with cell_marker.dat.vec_ro as v:
_, max_rounds = v.max()
# Always run at least one adaptation pass, even when no cell is marked,
# so that a fresh mesh (with its own cell maps) is produced uniformly.
max_rounds = max(int(np.rint(max_rounds)), 1)

current_mesh = mesh
current_mark = cell_marker
fine_to_coarse_total = None
for round_idx in range(max_rounds):
new_mesh, _, f2c = _refine_marked_elements_once(current_mesh, current_mark)
parent = f2c[:, 0]
if fine_to_coarse_total is None:
fine_to_coarse_total = f2c.copy()
else:
composed = np.full_like(f2c, -1)
valid = parent >= 0
composed[valid, 0] = fine_to_coarse_total[parent[valid], 0]
Comment thread
connorjward marked this conversation as resolved.
Outdated
fine_to_coarse_total = composed

if round_idx < max_rounds - 1:
next_mark = Function(FunctionSpace(new_mesh, "DG", 0))
valid = (parent >= 0)
next_mark.dat.data_wo[valid] = np.maximum(current_mark.dat.data_ro[parent[valid]] - 1, 0)
current_mark = next_mark
current_mesh = new_mesh

ncoarse = mesh.cell_set.size
children = [[] for _ in range(ncoarse)]
for fine_cell, parent in enumerate(fine_to_coarse_total[:, 0]):
if parent >= 0:
children[parent].append(fine_cell)
max_children = max((len(c) for c in children), default=0)
max_children = mesh.comm.allreduce(max_children, MPI.MAX)
coarse_to_fine_total = np.full((ncoarse, max_children), -1, dtype=IntType)
for coarse_cell, fine_cells in enumerate(children):
coarse_to_fine_total[coarse_cell, :len(fine_cells)] = fine_cells
Comment thread
connorjward marked this conversation as resolved.
Outdated

final_mesh = current_mesh
if hasattr(mesh, "netgen_mesh"):
order = mesh.coordinates.function_space().ufl_element().degree()
if order > 1:
final_mesh = _recurve_netgen_mesh(mesh, final_mesh, order)

final_mesh._adaptive_cell_maps = (coarse_to_fine_total, fine_to_coarse_total)
final_mesh = _redistribute_adaptive_refined_mesh(
mesh, final_mesh, redistribute=redistribute
)
final_mesh._adaptive_cell_maps = (coarse_to_fine_total, fine_to_coarse_total)
redist = getattr(final_mesh, "redist", None)
if redist is not None:
redist.orig._adaptive_cell_maps = (coarse_to_fine_total, fine_to_coarse_total)
return final_mesh
74 changes: 74 additions & 0 deletions firedrake/cython/mgimpl.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import numpy as np
from firedrake.cython import dmcommon
from firedrake.petsc import PETSc
from firedrake.utils import IntType
from pyop2.mpi import MPI

cimport numpy as np
cimport petsc4py.PETSc as PETSc
Expand Down Expand Up @@ -97,6 +98,9 @@ def coarse_to_fine_nodes(Vc, Vf, np.ndarray coarse_to_fine_cells):
k = 0
for l in range(fine_cell_per_coarse_cell):
fine = coarse_to_fine_cells[i, l]
if fine < 0:
k += fine_per_cell * ratio
continue
for layer in range(ratio):
fine_layer = coarse_layer * ratio + layer
for m in range(fine_per_cell):
Expand All @@ -107,6 +111,9 @@ def coarse_to_fine_nodes(Vc, Vf, np.ndarray coarse_to_fine_cells):
k = 0
for l in range(fine_cell_per_coarse_cell):
fine = coarse_to_fine_cells[i, l]
if fine < 0:
k += fine_per_cell
continue
for m in range(fine_per_cell):
coarse_to_fine_map[node, k] = fine_map[fine, m]
k += 1
Expand Down Expand Up @@ -149,6 +156,8 @@ def fine_to_coarse_nodes(Vf, Vc, np.ndarray fine_to_coarse_cells):

for i in range(fine_cells):
for l, coarse_cell in enumerate(fine_to_coarse_cells[i, :]):
if coarse_cell < 0:
continue
for j in range(fine_per_cell):
node = fine_map[i, j]
if extruded:
Expand Down Expand Up @@ -192,6 +201,71 @@ def create_lgmap(PETSc.DM dm):
return lgmap


@cython.boundscheck(False)
@cython.wraparound(False)
def set_adaptive_parent_label(PETSc.DM dm,
PETSc.Section cell_numbering,
PetscInt ncoarse,
label_name):
"""Label owned cells by Firedrake cell number."""
Comment thread
pbrubeck marked this conversation as resolved.
Outdated
cdef:
PetscInt cStart, cEnd, c, off
DMLabel parent_label = NULL

label_name = label_name.encode()
CHKERR(DMGetLabel(dm.dm, <const char*>label_name, &parent_label))
cStart, cEnd = dm.getHeightStratum(0)
for c in range(cStart, cEnd):
CHKERR(PetscSectionGetOffset(cell_numbering.sec, c, &off))
if 0 <= off < ncoarse:
CHKERR(DMLabelSetValue(parent_label, c, off))


@cython.boundscheck(False)
@cython.wraparound(False)
def adaptive_parent_child_cell_maps(PETSc.DM dm,
PETSc.Section cell_numbering,
PetscInt ncoarse,
PetscInt nfine,
Comment thread
connorjward marked this conversation as resolved.
Outdated
label_name):
"""Build Firedrake-numbered parent/child cell maps from a DMPlex label."""
Comment thread
pbrubeck marked this conversation as resolved.
Outdated
cdef:
PetscInt cStart, cEnd, c, off, parent, max_children
DMLabel parent_label = NULL
np.ndarray fine_to_coarse
np.ndarray child_counts
np.ndarray coarse_to_fine

label_name = label_name.encode()
CHKERR(DMGetLabel(dm.dm, <const char*>label_name, &parent_label))
fine_to_coarse = np.full((nfine, 1), -1, dtype=IntType)
child_counts = np.zeros(ncoarse, dtype=IntType)
cStart, cEnd = dm.getHeightStratum(0)
for c in range(cStart, cEnd):
CHKERR(PetscSectionGetOffset(cell_numbering.sec, c, &off))
if not (0 <= off < nfine):
continue
CHKERR(DMLabelGetValue(parent_label, c, &parent))
if 0 <= parent < ncoarse:
fine_to_coarse[off, 0] = parent
child_counts[parent] += 1
Comment thread
pbrubeck marked this conversation as resolved.

max_children = 0
for c in range(ncoarse):
if child_counts[c] > max_children:
max_children = child_counts[c]
max_children = dm.comm.tompi4py().allreduce(max_children, op=MPI.MAX)
coarse_to_fine = np.full((ncoarse, max_children), -1, dtype=IntType)
child_counts[:] = 0
for c in range(nfine):
parent = fine_to_coarse[c, 0]
if parent >= 0:
coarse_to_fine[parent, child_counts[parent]] = c
child_counts[parent] += 1

return coarse_to_fine, fine_to_coarse


# Exposition:
#
# These next functions compute maps from coarse mesh cells to fine
Expand Down
Loading
Loading