Skip to content

Commit e430d47

Browse files
committed
Merge branch 'main' into leo/refactor_interpolate
2 parents ff127b1 + 230b30b commit e430d47

File tree

13 files changed

+158
-51
lines changed

13 files changed

+158
-51
lines changed

.github/workflows/core.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ jobs:
335335
matrix.arch == 'default'
336336
run: |
337337
. venv/bin/activate
338-
git clone --depth 1 https://github.com/thetisproject/thetis.git thetis-repo
338+
git clone --depth 1 https://github.com/thetisproject/thetis.git thetis-repo --branch ${{ inputs.target_branch }}
339339
pip install --verbose ./thetis-repo
340340
python -m pytest -n 8 --verbose thetis-repo/test_adjoint/test_swe_adjoint.py
341341
timeout-minutes: 10
@@ -359,7 +359,7 @@ jobs:
359359
matrix.arch == 'default'
360360
run: |
361361
. venv/bin/activate
362-
git clone --depth 1 https://github.com/g-adopt/g-adopt.git g-adopt-repo
362+
git clone --depth 1 https://github.com/g-adopt/g-adopt.git g-adopt-repo --branch ${{ inputs.target_branch }}
363363
pip install --verbose ./g-adopt-repo
364364
make -C g-adopt-repo/demos/mantle_convection/base_case check
365365
timeout-minutes: 5

demos/patch/hcurl_riesz_star.py.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,17 @@ Contributed by `Robert Kirby <https://sites.baylor.edu/robert_kirby/>`_
55
and `Pablo Brubeck <https://www.maths.ox.ac.uk/people/pablo.brubeckmartinez/>`_.
66

77
Multigrid in H(div) and H(curl) also requires relaxation based on topological patches.
8-
Here, we demonstrate how to do this in the latter case. ::
8+
Here, we demonstrate how to do this in the latter case.
9+
10+
We start by importing firedrake and setting up a :func:`.MeshHierarchy` and the
11+
exact solution and forcing data. Crucially, the meshes must have an overlapping
12+
parallel domain decomposition that supports the vertex star patches. This is set
13+
via the `distribution_parameters` kwarg of the :func:`.Mesh` constructor. ::
914

1015
from firedrake import *
1116

12-
base = UnitCubeMesh(2, 2, 2)
17+
dparams = {"overlap_type": (DistributedMeshOverlapType.VERTEX, 1)}
18+
base = UnitCubeMesh(2, 2, 2, distribution_parameters=dparams)
1319
mh = MeshHierarchy(base, 3)
1420
mesh = mh[-1]
1521

demos/patch/hdiv_riesz_star.py.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,17 @@ Contributed by `Robert Kirby <https://sites.baylor.edu/robert_kirby/>`_
55
and `Pablo Brubeck <https://www.maths.ox.ac.uk/people/pablo.brubeckmartinez/>`_.
66

77
Multigrid in H(div) and H(curl) also requires relaxation based on topological patches.
8-
Here, we demonstrate how to do this in the former case. ::
8+
Here, we demonstrate how to do this in the former case.
9+
10+
We start by importing firedrake and setting up a :func:`.MeshHierarchy` and the
11+
exact solution and forcing data. Crucially, the meshes must have an overlapping
12+
parallel domain decomposition that supports the vertex star patches. This is set
13+
via the `distribution_parameters` kwarg of the :func:`.Mesh` constructor. ::
914

1015
from firedrake import *
1116

12-
base = UnitCubeMesh(2, 2, 2)
17+
dparams = {"overlap_type": (DistributedMeshOverlapType.VERTEX, 1)}
18+
base = UnitCubeMesh(2, 2, 2, distribution_parameters=dparams)
1319
mh = MeshHierarchy(base, 3)
1420
mesh = mh[-1]
1521

demos/patch/poisson_mg_patches.py.rst

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Using patch relaxation for multigrid
44
Contributed by `Robert Kirby <https://sites.baylor.edu/robert_kirby/>`_
55
and `Pablo Brubeck <https://www.maths.ox.ac.uk/people/pablo.brubeckmartinez/>`_.
66

7-
Simple relaxation like point Jacobi are not optimal or even suitable
7+
Simple multigrid relaxation methods like point Jacobi are not optimal or even suitable
88
smoothers for all applications. Firedrake supports additive Schwarz methods
99
based on local patch-based decompositions through two different paths.
1010

@@ -20,12 +20,15 @@ degree-independent iteration counts. Here, all the degrees of freedom in the ce
2020
For many problems, point Jacobi is even worse, and patches are required even to
2121
get a convergent method. We refer the reader to other demos.
2222

23-
We start by importing firedrake and setting up a mesh hierarchy and the
24-
exact solution and forcing data. ::
23+
We start by importing firedrake and setting up a :func:`.MeshHierarchy` and the
24+
exact solution and forcing data. Crucially, the meshes must have an overlapping
25+
parallel domain decomposition that supports the vertex star patches. This is set
26+
via the `distribution_parameters` kwarg of the :func:`.Mesh` constructor. ::
2527

2628
from firedrake import *
2729

28-
base = UnitSquareMesh(4, 4)
30+
dparams = {"overlap_type": (DistributedMeshOverlapType.VERTEX, 1)}
31+
base = UnitSquareMesh(4, 4, distribution_parameters=dparams)
2932
mh = MeshHierarchy(base, 1)
3033
mesh = mh[-1]
3134

demos/patch/stokes_vanka_patches.py.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,17 @@ of the patch but not pressures.
1616
In practice, we arrive at mesh-independent multigrid convergence using these relaxation.
1717
We can construct Vanka patches either through :class:`~.PatchPC`, in which the bilinear form
1818
is assembled on each vertex patch, or through :class:`~.ASMVankaPC`, in which the patch
19-
operators are extracted from the globally assembled stiffness matrix. ::
19+
operators are extracted from the globally assembled stiffness matrix.
20+
21+
We start by importing firedrake and setting up a :func:`.MeshHierarchy` and the
22+
exact solution and forcing data. Crucially, the meshes must have an overlapping
23+
parallel domain decomposition that supports the Vanka patches. This is set
24+
via the `distribution_parameters` kwarg of the :func:`.Mesh` constructor. ::
2025

2126
from firedrake import *
2227

23-
base = UnitSquareMesh(4, 4)
28+
dparams = {"overlap_type": (DistributedMeshOverlapType.VERTEX, 2)}
29+
base = UnitSquareMesh(4, 4, distribution_parameters=dparams)
2430
mh = MeshHierarchy(base, 3)
2531
mesh = mh[-1]
2632

docs/source/install.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,17 @@ For the default build, running ``firedrake-configure`` with
170170
.. literalinclude:: petsc_configure_options.txt
171171
:language: text
172172

173+
.. note::
174+
If you install MPI through PETSc by passing ``--download-openmpi`` or
175+
``--download-mpich`` it is helpful to run the command::
176+
177+
$ export PATH=$PETSC_DIR/$PETSC_ARCH:$PATH
178+
179+
180+
where ``PETSC_DIR=/path/to/petsc`` and ``PETSC_ARCH=arch-firedrake-default``.
181+
This will allow the MPI executables (``mpicc``, ``mpiexec``, etc) installed by
182+
PETSc to be found before any other versions installed on your machine.
183+
173184

174185
.. _install_firedrake:
175186

@@ -224,6 +235,11 @@ install Firedrake. To do this perform the following steps:
224235
you have exactly followed the instructions up to this point this should
225236
already be the case.
226237

238+
.. note::
239+
If you are using a non-system MPI it may be necessary to set ``LD_LIBRARY_PATH``
240+
so that it can be detected by mpi4py. See `here <https://mpi4py.readthedocs.io/en/stable/install.html#linux>`__
241+
for more information.
242+
227243
#. Install Firedrake::
228244

229245
$ pip install --no-binary h5py 'firedrake[check]'

docs/source/preconditioning.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,19 @@ multiplicatively within an MPI rank and additively between ranks.
6969
entities into lines or planes (useful for advection-dominated
7070
problems).
7171

72+
.. note::
73+
The additive Schwarz preconditioners listed here construct patches around
74+
mesh entities. Crucially, the mesh must have an overlapping parallel domain
75+
decomposition that supports the patches. This is set via the
76+
`distribution_parameters` kwarg of the :func:`.Mesh` constructor. For
77+
instance, vertex-star patches require ::
78+
79+
distribution_parameters["overlap_type"] = (DistributedMeshOverlapType.VERTEX, 1)
80+
81+
while Vanka patches require ::
82+
83+
distribution_parameters["overlap_type"] = (DistributedMeshOverlapType.VERTEX, 2)
84+
7285
Multigrid methods
7386
=================
7487

firedrake/adjoint_utils/blocks/function.py

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -202,15 +202,12 @@ def __init__(self, func, idx, ad_block_tag=None):
202202
def evaluate_adj_component(self, inputs, adj_inputs, block_variable, idx,
203203
prepared=None):
204204
eval_adj = firedrake.Cofunction(block_variable.output.function_space().dual())
205-
if type(adj_inputs[0]) is firedrake.Cofunction:
206-
eval_adj.sub(self.sub_idx).assign(adj_inputs[0])
207-
else:
208-
eval_adj.sub(self.sub_idx).assign(adj_inputs[0].function)
205+
eval_adj.sub(self.sub_idx).assign(adj_inputs[0])
209206
return eval_adj
210207

211208
def evaluate_tlm_component(self, inputs, tlm_inputs, block_variable, idx,
212209
prepared=None):
213-
return firedrake.Function.sub(tlm_inputs[0], self.sub_idx)
210+
return tlm_inputs[0].sub(self.sub_idx)
214211

215212
def evaluate_hessian_component(self, inputs, hessian_inputs, adj_inputs,
216213
block_variable, idx,
@@ -220,9 +217,7 @@ def evaluate_hessian_component(self, inputs, hessian_inputs, adj_inputs,
220217
return eval_hessian
221218

222219
def recompute_component(self, inputs, block_variable, idx, prepared):
223-
return maybe_disk_checkpoint(
224-
firedrake.Function.sub(inputs[0], self.sub_idx)
225-
)
220+
return maybe_disk_checkpoint(inputs[0].sub(self.sub_idx))
226221

227222
def __str__(self):
228223
return f"{self.get_dependencies()[0]}[{self.sub_idx}]"
@@ -264,23 +259,31 @@ def evaluate_adj_component(self, inputs, adj_inputs, block_variable, idx,
264259
adj_inputs[0].subfunctions[self.sub_idx].zero()
265260
return adj_inputs[0]
266261

267-
def evaluate_tlm(self, markings=False):
268-
tlm_input = self.get_dependencies()[0].tlm_value
269-
if tlm_input is None:
270-
return
271-
output = self.get_outputs()[0]
272-
if markings and not output.marked_in_path:
273-
return
274-
fs = output.output.function_space()
275-
f = type(output.output)(fs)
276-
output.add_tlm_output(
277-
type(output.output).assign(f.sub(self.sub_idx), tlm_input)
278-
)
262+
def evaluate_tlm_component(self, inputs, tlm_inputs, block_variable, idx, prepared=None):
263+
sub_tlm = tlm_inputs[0]
264+
parent_in = tlm_inputs[1]
265+
266+
if sub_tlm is None and parent_in is None:
267+
return None
268+
269+
output = self.get_outputs()[0].output
270+
parent_out = type(output)(output.function_space())
271+
272+
if parent_in is not None:
273+
parent_out.assign(parent_in)
274+
if sub_tlm is not None:
275+
parent_out.sub(self.sub_idx).assign(sub_tlm)
276+
277+
return parent_out
279278

280279
def evaluate_hessian_component(self, inputs, hessian_inputs, adj_inputs,
281280
block_variable, idx,
282281
relevant_dependencies, prepared=None):
283-
return hessian_inputs[0]
282+
if idx == 0:
283+
return hessian_inputs[0].subfunctions[self.sub_idx].copy(deepcopy=True)
284+
else:
285+
hessian_inputs[0].subfunctions[self.sub_idx].zero()
286+
return hessian_inputs[0]
284287

285288
def recompute_component(self, inputs, block_variable, idx, prepared):
286289
sub_func = inputs[0]

firedrake/preconditioners/asm.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from firedrake.preconditioners.base import PCBase
55
from firedrake.petsc import PETSc
66
from firedrake.dmhooks import get_function_space
7+
from firedrake.mesh import DistributedMeshOverlapType
78
from firedrake.logging import warning
89
from tinyasm import _tinyasm as tinyasm
910
from mpi4py import MPI
@@ -164,6 +165,8 @@ def get_patches(self, V):
164165
opts = PETSc.Options(self.prefix)
165166
depth = opts.getInt("construct_dim", default=0)
166167
ordering = opts.getString("mat_ordering_type", default="natural")
168+
validate_overlap(mesh_unique, depth, "star")
169+
167170
# Accessing .indices causes the allocation of a global array,
168171
# so we need to cache these for efficiency
169172
V_local_ises_indices = tuple(iset.indices for iset in V.dof_dset.local_ises)
@@ -241,8 +244,11 @@ def get_patches(self, V):
241244
ises = []
242245
if depth != -1:
243246
(start, end) = mesh_dm.getDepthStratum(depth)
247+
patch_dim = depth
244248
else:
245249
(start, end) = mesh_dm.getHeightStratum(height)
250+
patch_dim = mesh_dm.getDimension() - height
251+
validate_overlap(mesh_unique, patch_dim, "vanka")
246252

247253
for seed in range(start, end):
248254
# Only build patches over owned DoFs
@@ -469,6 +475,7 @@ def get_patches(self, V):
469475
else:
470476
continue
471477

478+
validate_overlap(mesh_unique, base_depth, "star")
472479
start, end = mesh_dm.getDepthStratum(base_depth)
473480
for seed in range(start, end):
474481
# Only build patches over owned DoFs
@@ -524,3 +531,26 @@ def get_patches(self, V):
524531
iset = PETSc.IS().createGeneral(indices, comm=PETSc.COMM_SELF)
525532
ises.append(iset)
526533
return ises
534+
535+
536+
def validate_overlap(mesh, patch_dim, patch_type):
537+
if patch_type == "python":
538+
return
539+
patch_depth = {"pardecomp": 0, "star": 1, "vanka": 2}[patch_type]
540+
541+
tdim = mesh.topology_dm.getDimension()
542+
overlap_entity, overlap_depth = mesh._distribution_parameters["overlap_type"]
543+
overlap_dim = {
544+
DistributedMeshOverlapType.VERTEX: 0,
545+
DistributedMeshOverlapType.FACET: tdim-1,
546+
DistributedMeshOverlapType.NONE: tdim,
547+
}[overlap_entity]
548+
549+
if mesh.comm.size > 1:
550+
if overlap_dim > patch_dim:
551+
patch_entity = {0: "vertex", 1: "edge", 2: "face", tdim: "cell"}[patch_dim]
552+
warning(f"{overlap_entity} does not support {patch_entity}-patches. "
553+
"Did you forget to set overlap_type in your mesh's distribution_parameters?")
554+
if overlap_depth < patch_depth:
555+
warning(f"Mesh overlap depth of {overlap_depth} does not support {patch_type}-patches. "
556+
"Did you forget to set overlap_type in your mesh's distribution_parameters?")

firedrake/preconditioners/patch.py

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from firedrake.preconditioners.base import PCBase, SNESBase, PCSNESBase
2+
from firedrake.preconditioners.asm import validate_overlap
23
from firedrake.petsc import PETSc
34
from firedrake.cython.patchimpl import set_patch_residual, set_patch_jacobian
45
from firedrake.solving_utils import _SNESContext
@@ -784,15 +785,24 @@ def initialize(self, obj):
784785
if mesh_unique.cell_set._extruded:
785786
raise NotImplementedError("Not implemented on extruded meshes")
786787

787-
if "overlap_type" not in mesh_unique._distribution_parameters:
788-
if mesh.comm.size > 1:
789-
# Want to do
790-
# warnings.warn("You almost surely want to set an overlap_type in your mesh's distribution_parameters.")
791-
# but doesn't warn!
792-
PETSc.Sys.Print("Warning: you almost surely want to set an overlap_type in your mesh's distribution_parameters.")
788+
# Validate the mesh overlap
789+
prefix = (obj.getOptionsPrefix() or "") + "patch_"
790+
opts = PETSc.Options(prefix)
791+
petsc_prefix = self._petsc_prefix
792+
patch_type = opts.getString(f"{petsc_prefix}construct_type")
793+
patch_dim = opts.getInt(f"{petsc_prefix}construct_dim", -1)
794+
patch_codim = opts.getInt(f"{petsc_prefix}construct_codim", -1)
795+
if patch_dim != -1:
796+
assert patch_codim == -1, "Cannot set both dim and codim"
797+
elif patch_codim != -1:
798+
assert patch_dim == -1, "Cannot set both dim and codim"
799+
patch_dim = self.plex.getDimension() - patch_codim
800+
else:
801+
patch_dim = 0
802+
validate_overlap(mesh_unique, patch_dim, patch_type)
793803

794804
patch = obj.__class__().create(comm=mesh.comm)
795-
patch.setOptionsPrefix((obj.getOptionsPrefix() or "") + "patch_")
805+
patch.setOptionsPrefix(prefix)
796806
self.configure_patch(patch, obj)
797807
patch.setType("patch")
798808

@@ -948,6 +958,8 @@ def view(self, pc, viewer=None):
948958

949959
class PatchPC(PCBase, PatchBase):
950960

961+
_petsc_prefix = "pc_patch_"
962+
951963
def configure_patch(self, patch, pc):
952964
(A, P) = pc.getOperators()
953965
patch.setOperators(A, P)
@@ -960,6 +972,9 @@ def applyTranspose(self, pc, x, y):
960972

961973

962974
class PatchSNES(SNESBase, PatchBase):
975+
976+
_petsc_prefix = "snes_patch_"
977+
963978
def configure_patch(self, patch, snes):
964979
patch.setTolerances(max_it=1)
965980
patch.setConvergenceTest("skip")

0 commit comments

Comments
 (0)