diff --git a/firedrake/cython/dmcommon.pyx b/firedrake/cython/dmcommon.pyx index b5e0777dfe..b67c0c21ec 100644 --- a/firedrake/cython/dmcommon.pyx +++ b/firedrake/cython/dmcommon.pyx @@ -2120,6 +2120,8 @@ def mark_entity_classes_using_cell_dm(PETSc.DM swarm): PetscInt nswarmCells, swarmCell, blocksize PetscInt *swarmParentCells = NULL PetscDataType ctype = PETSC_DATATYPE_UNKNOWN + const char *cellid = NULL + PETSc.PetscDMSwarmCellDM celldm plex = swarm.getCellDM() get_height_stratum(plex.dm, 0, &cStart, &cEnd) @@ -2145,14 +2147,16 @@ def mark_entity_classes_using_cell_dm(PETSc.DM swarm): for ilabel, op2class in enumerate([b"pyop2_core", b"pyop2_owned", b"pyop2_ghost"]): CHKERR(DMCreateLabel(swarm.dm, op2class)) CHKERR(DMGetLabel(swarm.dm, op2class, &swarm_labels[ilabel])) - CHKERR(DMSwarmGetField(swarm.dm, b"DMSwarm_cellid", &blocksize, &ctype, &swarmParentCells)) + CHKERR(DMSwarmGetCellDMActive(swarm.dm, &celldm)) + CHKERR(DMSwarmCellDMGetCellID(celldm, &cellid)) + CHKERR(DMSwarmGetField(swarm.dm, cellid, &blocksize, &ctype, &swarmParentCells)) assert ctype == PETSC_INT assert blocksize == 1 CHKERR(DMSwarmGetLocalSize(swarm.dm, &nswarmCells)) for swarmCell in range(nswarmCells): plex_cell_class = plex_cell_classes[swarmParentCells[swarmCell] - cStart] CHKERR(DMLabelSetValue(swarm_labels[plex_cell_class], swarmCell, label_value)) - CHKERR(DMSwarmRestoreField(swarm.dm, b"DMSwarm_cellid", &blocksize, &ctype, &swarmParentCells)) + CHKERR(DMSwarmRestoreField(swarm.dm, cellid, &blocksize, &ctype, &swarmParentCells)) CHKERR(PetscFree(plex_cell_classes)) diff --git a/firedrake/cython/petschdr.pxi b/firedrake/cython/petschdr.pxi index 9a0bff609d..750a3c3714 100644 --- a/firedrake/cython/petschdr.pxi +++ b/firedrake/cython/petschdr.pxi @@ -79,6 +79,8 @@ cdef extern from "petscdm.h" nogil: cdef extern from "petscdmswarm.h" nogil: int DMSwarmGetLocalSize(PETSc.PetscDM,PetscInt*) int DMSwarmGetCellDM(PETSc.PetscDM, PETSc.PetscDM*) + int DMSwarmGetCellDMActive(PETSc.PetscDM, PETSc.PetscDMSwarmCellDM*) + int DMSwarmCellDMGetCellID(PETSc.PetscDMSwarmCellDM, const char *[]) int DMSwarmGetField(PETSc.PetscDM,const char[],PetscInt*,PetscDataType*,void**) int DMSwarmRestoreField(PETSc.PetscDM,const char[],PetscInt*,PetscDataType*,void**) diff --git a/firedrake/mesh.py b/firedrake/mesh.py index 8a0f8ec8a9..30e24a1cd8 100644 --- a/firedrake/mesh.py +++ b/firedrake/mesh.py @@ -1966,14 +1966,15 @@ def _renumber_entities(self, reorder): if reorder: swarm = self.topology_dm parent = self._parent_mesh.topology_dm - swarm_parent_cell_nums = swarm.getField("DMSwarm_cellid").ravel() + cell_id_name = swarm.getCellDMActive().getCellID() + swarm_parent_cell_nums = swarm.getField(cell_id_name).ravel() parent_renum = self._parent_mesh._dm_renumbering.getIndices() pStart, _ = parent.getChart() parent_renum_inv = np.empty_like(parent_renum) parent_renum_inv[parent_renum - pStart] = np.arange(len(parent_renum)) # Use kind = 'stable' to make the ordering deterministic. perm = np.argsort(parent_renum_inv[swarm_parent_cell_nums - pStart], kind='stable').astype(IntType) - swarm.restoreField("DMSwarm_cellid") + swarm.restoreField(cell_id_name) perm_is = PETSc.IS().create(comm=swarm.comm) perm_is.setType("general") perm_is.setIndices(perm) @@ -3557,11 +3558,9 @@ def _pic_swarm_in_mesh( #. ``parentcellextrusionheight`` which contains the extrusion height of the immersed vertex in the parent mesh cell. - Another three are required for proper functioning of the DMSwarm: + Another two are required for proper functioning of the DMSwarm: #. ``DMSwarmPIC_coor`` which contains the coordinates of the point. - #. ``DMSwarm_cellid`` the DMPlex cell within which the DMSwarm point is - located. #. ``DMSwarm_rank``: the MPI rank which owns the DMSwarm point. .. note:: @@ -3794,7 +3793,6 @@ def _dmswarm_create( # These are created by default for a PIC DMSwarm default_fields = [ ("DMSwarmPIC_coor", gdim, RealType), - ("DMSwarm_cellid", 1, IntType), ("DMSwarm_rank", 1, IntType), ] @@ -3853,12 +3851,6 @@ def _dmswarm_create( # Set to Particle In Cell (PIC) type if not isinstance(plex, PETSc.DMSwarm): swarm.setType(PETSc.DMSwarm.Type.PIC) - else: - # This doesn't work where we embed a DMSwarm in a DMSwarm, instead - # we register some default fields manually - for name, size, dtype in default_fields: - if name == "DMSwarmPIC_coor" or name == "DMSwarm_cellid": - swarm.registerField(name, size, dtype=dtype) # Register any fields for name, size, dtype in swarm.default_extra_fields + swarm.other_fields: @@ -3872,14 +3864,15 @@ def _dmswarm_create( # Add point coordinates. This amounts to our own implementation of # DMSwarmSetPointCoordinates because Firedrake's mesh coordinate model # doesn't always exactly coincide with that of DMPlex: in most cases the - # plex_parent_cell_nums (DMSwarm_cellid field) and parent_cell_nums - # (parentcellnum field), the latter being the numbering used by firedrake, - # refer fundamentally to the same cells. For extruded meshes the DMPlex - # dimension is based on the topological dimension of the base mesh. + # plex_parent_cell_nums and parent_cell_nums (parentcellnum field), the + # latter being the numbering used by firedrake, refer fundamentally to the + # same cells. For extruded meshes the DMPlex dimension is based on the + # topological dimension of the base mesh. # NOTE ensure that swarm.restoreField is called for each field too! swarm_coords = swarm.getField("DMSwarmPIC_coor").reshape((num_vertices, gdim)) - swarm_parent_cell_nums = swarm.getField("DMSwarm_cellid").ravel() + cell_id_name = swarm.getCellDMActive().getCellID() + swarm_parent_cell_nums = swarm.getField(cell_id_name).ravel() field_parent_cell_nums = swarm.getField("parentcellnum").ravel() field_reference_coords = swarm.getField("refcoord").reshape((num_vertices, tdim)) field_global_index = swarm.getField("globalindex").ravel() @@ -3903,7 +3896,7 @@ def _dmswarm_create( swarm.restoreField("refcoord") swarm.restoreField("parentcellnum") swarm.restoreField("DMSwarmPIC_coor") - swarm.restoreField("DMSwarm_cellid") + swarm.restoreField(cell_id_name) if extruded: field_base_parent_cell_nums = swarm.getField("parentcellbasenum").ravel() diff --git a/firedrake/preconditioners/asm.py b/firedrake/preconditioners/asm.py index f3eaa037d9..f91261586d 100644 --- a/firedrake/preconditioners/asm.py +++ b/firedrake/preconditioners/asm.py @@ -29,7 +29,7 @@ def initialize(self, pc): # Get context from pc _, P = pc.getOperators() dm = pc.getDM() - self.prefix = pc.getOptionsPrefix() + self._prefix + self.prefix = (pc.getOptionsPrefix() or "") + self._prefix # Extract function space and mesh to obtain plex and indexing functions V = get_function_space(dm) diff --git a/firedrake/preconditioners/assembled.py b/firedrake/preconditioners/assembled.py index 4d9710867b..b2f1ede79a 100644 --- a/firedrake/preconditioners/assembled.py +++ b/firedrake/preconditioners/assembled.py @@ -37,7 +37,7 @@ def initialize(self, pc): if not context.on_diag: raise ValueError("Only makes sense to invert diagonal block") - prefix = pc.getOptionsPrefix() + prefix = pc.getOptionsPrefix() or "" options_prefix = prefix + self._prefix mat_type = PETSc.Options().getString(options_prefix + "mat_type", "aij") diff --git a/firedrake/preconditioners/bddc.py b/firedrake/preconditioners/bddc.py index 5fb1fca51a..57580b6f86 100644 --- a/firedrake/preconditioners/bddc.py +++ b/firedrake/preconditioners/bddc.py @@ -42,7 +42,7 @@ def initialize(self, pc): # Get context from pc _, P = pc.getOperators() dm = pc.getDM() - self.prefix = pc.getOptionsPrefix() + self._prefix + self.prefix = (pc.getOptionsPrefix() or "") + self._prefix V = get_function_space(dm) diff --git a/firedrake/preconditioners/facet_split.py b/firedrake/preconditioners/facet_split.py index 4c8e654ce4..2d49f9e908 100644 --- a/firedrake/preconditioners/facet_split.py +++ b/firedrake/preconditioners/facet_split.py @@ -41,7 +41,7 @@ def get_indices(self, V, W): def initialize(self, pc): from firedrake import FunctionSpace, TestFunction, TrialFunction, split - prefix = pc.getOptionsPrefix() + prefix = pc.getOptionsPrefix() or "" options_prefix = prefix + self._prefix options = PETSc.Options(options_prefix) mat_type = options.getString("mat_type", "submatrix") diff --git a/firedrake/preconditioners/fdm.py b/firedrake/preconditioners/fdm.py index 1b6aa9c9aa..4e28f73a19 100644 --- a/firedrake/preconditioners/fdm.py +++ b/firedrake/preconditioners/fdm.py @@ -121,7 +121,7 @@ def initialize(self, pc): Citations().register(self._citation) self.comm = pc.comm Amat, Pmat = pc.getOperators() - prefix = pc.getOptionsPrefix() + prefix = pc.getOptionsPrefix() or "" options_prefix = prefix + self._prefix options = PETSc.Options(options_prefix) diff --git a/firedrake/preconditioners/gtmg.py b/firedrake/preconditioners/gtmg.py index a1014f0baf..1d76a13e60 100644 --- a/firedrake/preconditioners/gtmg.py +++ b/firedrake/preconditioners/gtmg.py @@ -31,7 +31,7 @@ def initialize(self, pc): if not isinstance(ctx, _SNESContext): raise ValueError("Don't know how to get form from %r" % ctx) - prefix = pc.getOptionsPrefix() + prefix = pc.getOptionsPrefix() or "" options_prefix = prefix + self._prefix opts = PETSc.Options() diff --git a/firedrake/preconditioners/hiptmair.py b/firedrake/preconditioners/hiptmair.py index 858a07d0d5..f292579eb5 100644 --- a/firedrake/preconditioners/hiptmair.py +++ b/firedrake/preconditioners/hiptmair.py @@ -41,7 +41,7 @@ def initialize(self, pc): appctx = self.get_appctx(pc) fcp = appctx.get("form_compiler_parameters") - prefix = pc.getOptionsPrefix() + prefix = pc.getOptionsPrefix() or "" options_prefix = prefix + self._prefix opts = PETSc.Options() @@ -156,7 +156,7 @@ def coarsen(self, pc): else: raise ValueError("Hiptmair decomposition not available for", element) - prefix = pc.getOptionsPrefix() + prefix = pc.getOptionsPrefix() or "" options_prefix = prefix + self._prefix opts = PETSc.Options(options_prefix) domain = opts.getString("mg_coarse_restriction_domain", "") diff --git a/firedrake/preconditioners/hypre_ads.py b/firedrake/preconditioners/hypre_ads.py index 5affcf8c1f..13dc0d1a50 100644 --- a/firedrake/preconditioners/hypre_ads.py +++ b/firedrake/preconditioners/hypre_ads.py @@ -16,7 +16,7 @@ class HypreADS(PCBase): def initialize(self, obj): A, P = obj.getOperators() appctx = self.get_appctx(obj) - prefix = obj.getOptionsPrefix() + prefix = obj.getOptionsPrefix() or "" V = get_function_space(obj.getDM()) mesh = V.mesh() diff --git a/firedrake/preconditioners/hypre_ams.py b/firedrake/preconditioners/hypre_ams.py index dc610e005d..9616b142b9 100644 --- a/firedrake/preconditioners/hypre_ams.py +++ b/firedrake/preconditioners/hypre_ams.py @@ -37,7 +37,7 @@ def initialize(self, obj): Citations().register("Kolev2009") A, P = obj.getOperators() appctx = self.get_appctx(obj) - prefix = obj.getOptionsPrefix() + prefix = obj.getOptionsPrefix() or "" V = get_function_space(obj.getDM()) mesh = V.mesh() diff --git a/firedrake/preconditioners/patch.py b/firedrake/preconditioners/patch.py index 6d2bced79f..093827d69e 100644 --- a/firedrake/preconditioners/patch.py +++ b/firedrake/preconditioners/patch.py @@ -715,7 +715,7 @@ def __call__(self, pc): raise NotImplementedError("Sorry, plane smoothers not yet implemented in complex mode") dm = pc.getDM() context = dm.getAttr("__firedrake_ctx__") - prefix = pc.getOptionsPrefix() + prefix = pc.getOptionsPrefix() or "" sentinel = object() sweeps = PETSc.Options(prefix).getString("pc_patch_construct_ps_sweeps", default=sentinel) if sweeps == sentinel: @@ -789,7 +789,7 @@ def initialize(self, obj): PETSc.Sys.Print("Warning: you almost surely want to set an overlap_type in your mesh's distribution_parameters.") patch = obj.__class__().create(comm=mesh.comm) - patch.setOptionsPrefix(obj.getOptionsPrefix() + "patch_") + patch.setOptionsPrefix((obj.getOptionsPrefix() or "") + "patch_") self.configure_patch(patch, obj) patch.setType("patch") @@ -924,7 +924,7 @@ def destroy(self, obj): self.patch.destroy() def user_construction_op(self, obj, *args, **kwargs): - prefix = obj.getOptionsPrefix() + prefix = obj.getOptionsPrefix() or "" sentinel = object() usercode = PETSc.Options(prefix).getString("%s_patch_construct_python_type" % self._objectname, default=sentinel) if usercode == sentinel: diff --git a/firedrake/preconditioners/pcd.py b/firedrake/preconditioners/pcd.py index 12e60ed51e..dbc4671720 100644 --- a/firedrake/preconditioners/pcd.py +++ b/firedrake/preconditioners/pcd.py @@ -45,7 +45,7 @@ def initialize(self, pc): from firedrake.assemble import assemble, get_assembler if pc.getType() != "python": raise ValueError("Expecting PC type python") - prefix = pc.getOptionsPrefix() + "pcd_" + prefix = (pc.getOptionsPrefix() or "") + "pcd_" # we assume P has things stuffed inside of it _, P = pc.getOperators() diff --git a/firedrake/preconditioners/pmg.py b/firedrake/preconditioners/pmg.py index 48df37d615..c5eb1ccaac 100644 --- a/firedrake/preconditioners/pmg.py +++ b/firedrake/preconditioners/pmg.py @@ -106,7 +106,7 @@ def initialize(self, obj): if test.function_space() != trial.function_space(): raise NotImplementedError("test and trial spaces must be the same") - prefix = obj.getOptionsPrefix() + prefix = obj.getOptionsPrefix() or "" options_prefix = prefix + self._prefix pdm = PETSc.DMShell().create(comm=obj.comm) pdm.setOptionsPrefix(options_prefix) @@ -119,7 +119,7 @@ def initialize(self, obj): default_mat_type = "matfree" # Get the coarse degree from PETSc options - copts = PETSc.Options(ppc.getOptionsPrefix() + ppc.getType() + "_coarse_") + copts = PETSc.Options((ppc.getOptionsPrefix() or "") + ppc.getType() + "_coarse_") self.coarse_degree = copts.getInt("degree", default=1) self.coarse_mat_type = copts.getString("mat_type", default=default_mat_type) self.coarse_pmat_type = copts.getString("pmat_type", default=self.coarse_mat_type) @@ -443,7 +443,7 @@ class PMGPC(PCBase, PMGBase): def configure_pmg(self, pc, pdm): odm = pc.getDM() ppc = PETSc.PC().create(comm=pc.comm) - ppc.setOptionsPrefix(pc.getOptionsPrefix() + self._prefix) + ppc.setOptionsPrefix((pc.getOptionsPrefix() or "") + self._prefix) ppc.setType("mg") ppc.setOperators(*pc.getOperators()) ppc.setDM(pdm) @@ -458,7 +458,7 @@ def configure_pmg(self, pc, pdm): # other way to get PETSc to know this at the right time. max_levels = odm.getRefineLevel() + 1 if max_levels > 1: - opts = PETSc.Options(pc.getOptionsPrefix() + "pmg_") + opts = PETSc.Options((pc.getOptionsPrefix() or "") + "pmg_") if opts.getString("mg_coarse_pc_type") == "mg": opts["mg_coarse_pc_mg_levels"] = min(opts.getInt("mg_coarse_pc_mg_levels", max_levels), max_levels) return ppc @@ -479,7 +479,7 @@ class PMGSNES(SNESBase, PMGBase): def configure_pmg(self, snes, pdm): odm = snes.getDM() psnes = PETSc.SNES().create(comm=snes.comm) - psnes.setOptionsPrefix(snes.getOptionsPrefix() + self._prefix) + psnes.setOptionsPrefix((snes.getOptionsPrefix() or "") + self._prefix) psnes.setType("fas") psnes.setDM(pdm) psnes.setTolerances(max_it=1) @@ -503,7 +503,7 @@ def configure_pmg(self, snes, pdm): # other way to get PETSc to know this at the right time. max_levels = odm.getRefineLevel() + 1 if max_levels > 1: - opts = PETSc.Options(snes.getOptionsPrefix() + "pfas_") + opts = PETSc.Options((snes.getOptionsPrefix() or "") + "pfas_") if opts.getString("fas_coarse_pc_type") == "mg": opts["fas_coarse_pc_mg_levels"] = min(opts.getInt("fas_coarse_pc_mg_levels", max_levels), max_levels) if opts.getString("fas_coarse_snes_type") == "fas": diff --git a/firedrake/slate/static_condensation/hybridization.py b/firedrake/slate/static_condensation/hybridization.py index 5db160b443..63edd7cbd7 100644 --- a/firedrake/slate/static_condensation/hybridization.py +++ b/firedrake/slate/static_condensation/hybridization.py @@ -43,7 +43,7 @@ def initialize(self, pc): from ufl.algorithms.replace import replace # Extract the problem context - prefix = pc.getOptionsPrefix() + "hybridization_" + prefix = (pc.getOptionsPrefix() or "") + "hybridization_" _, P = pc.getOperators() self.ctx = P.getPythonContext() diff --git a/firedrake/slate/static_condensation/scpc.py b/firedrake/slate/static_condensation/scpc.py index c4bda6dc27..9ba54b778d 100644 --- a/firedrake/slate/static_condensation/scpc.py +++ b/firedrake/slate/static_condensation/scpc.py @@ -36,7 +36,7 @@ def initialize(self, pc): from firedrake.parloops import par_loop, INC from ufl import dx - prefix = pc.getOptionsPrefix() + "condensed_field_" + prefix = (pc.getOptionsPrefix() or "") + "condensed_field_" A, P = pc.getOperators() self.cxt = A.getPythonContext() if not isinstance(self.cxt, ImplicitMatrixContext): @@ -49,7 +49,7 @@ def initialize(self, pc): if len(W) > 3: raise NotImplementedError("Only supports up to three function spaces.") - elim_fields = PETSc.Options().getString(pc.getOptionsPrefix() + elim_fields = PETSc.Options().getString((pc.getOptionsPrefix() or "") + "pc_sc_eliminate_fields", None) if elim_fields: diff --git a/pyproject.toml b/pyproject.toml index e8c4d0ec6c..a11607e2df 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ dependencies = [ "libsupermesh", # NOTE: If changing the PETSc/SLEPc version then firedrake-configure also needs # changing (as well as other references to petsc4py and slepc4py here) - "petsc4py==3.22.2", + "petsc4py==3.23.0", "numpy", "packaging", "pkgconfig", @@ -84,7 +84,7 @@ ci = [ "pytest-split", # needed for firedrake-run-split-tests "pytest-timeout", "pytest-xdist", - "slepc4py==3.22.2", + "slepc4py==3.23.0", "torch", # requires passing '--extra-index-url' to work "vtk", ] @@ -98,7 +98,7 @@ docker = [ # Used in firedrake-vanilla container "pytest-split", # needed for firedrake-run-split-tests "pytest-timeout", "pytest-xdist", - "slepc4py==3.22.2", + "slepc4py==3.23.0", ] # Dependencies needed to build the docs docs = [ @@ -134,7 +134,7 @@ requires = [ "pkgconfig", "pybind11", "setuptools>61.2", - "petsc4py==3.22.2", + "petsc4py==3.23.0", "rtree>=1.2", ] build-backend = "setuptools.build_meta" diff --git a/scripts/firedrake-configure b/scripts/firedrake-configure index 130e0d2f01..66bf29c38e 100755 --- a/scripts/firedrake-configure +++ b/scripts/firedrake-configure @@ -41,7 +41,7 @@ ARCH_COMPLEX = FiredrakeArch.COMPLEX # NOTE: When updating this variable corresponding changes must be made inside # pyproject.toml -SUPPORTED_PETSC_VERSION = "v3.22.2" +SUPPORTED_PETSC_VERSION = "v3.23.0" def main(): diff --git a/tests/firedrake/regression/test_matrix_prefix.py b/tests/firedrake/regression/test_matrix_prefix.py index b3abf296d4..9a43d6f64b 100644 --- a/tests/firedrake/regression/test_matrix_prefix.py +++ b/tests/firedrake/regression/test_matrix_prefix.py @@ -32,9 +32,7 @@ def test_matrix_prefix_solver(options_prefix): assert factor.getType() == DEFAULT_DIRECT_SOLVER for A in pc.getOperators(): - pfx = A.getOptionsPrefix() - if pfx is None: - pfx = "" + pfx = A.getOptionsPrefix() or "" assert pfx == solver.options_prefix diff --git a/tests/firedrake/vertexonly/test_swarm.py b/tests/firedrake/vertexonly/test_swarm.py index d3f5680041..4bd5cde939 100644 --- a/tests/firedrake/vertexonly/test_swarm.py +++ b/tests/firedrake/vertexonly/test_swarm.py @@ -218,8 +218,9 @@ def test_pic_swarm_in_mesh(parentmesh, redundant, exclude_halos): nptslocal = len(localpointcoords) nptsglobal = MPI.COMM_WORLD.allreduce(nptslocal, op=MPI.SUM) # Get parent PETSc cell indices on current MPI rank - localparentcellindices = np.copy(swarm.getField("DMSwarm_cellid").ravel()) - swarm.restoreField("DMSwarm_cellid") + cell_id = swarm.getCellDMActive().getCellID() + localparentcellindices = np.copy(swarm.getField(cell_id).ravel()) + swarm.restoreField(cell_id) # also get the global coordinate numbering globalindices = np.copy(swarm.getField("globalindex").ravel()) @@ -242,7 +243,6 @@ def test_pic_swarm_in_mesh(parentmesh, redundant, exclude_halos): # Check swarm fields are correct default_fields = [ ("DMSwarmPIC_coor", parentmesh.geometric_dimension(), RealType), - ("DMSwarm_cellid", 1, IntType), ("DMSwarm_rank", 1, IntType), ] default_extra_fields = [ @@ -378,8 +378,9 @@ def test_pic_swarm_in_mesh(parentmesh, redundant, exclude_halos): ): swarm.setPointCoordinates(localpointcoords, redundant=False, mode=PETSc.InsertMode.INSERT_VALUES) - petsclocalparentcellindices = np.copy(swarm.getField("DMSwarm_cellid").ravel()) - swarm.restoreField("DMSwarm_cellid") + cell_id = swarm.getCellDMActive().getCellID() + petsclocalparentcellindices = np.copy(swarm.getField(cell_id).ravel()) + swarm.restoreField(cell_id) if exclude_halos: assert np.all(petsclocalparentcellindices == localparentcellindices) elif parentmesh.comm.size > 1: