Skip to content

pyop3 - #3318

Merged
connorjward merged 1234 commits into
mainfrom
connorjward/pyop3
Oct 21, 2026
Merged

pyop3#3318
connorjward merged 1234 commits into
mainfrom
connorjward/pyop3

Conversation

@connorjward

@connorjward connorjward commented Jan 11, 2024 •

Copy link
Copy Markdown
Contributor

This PR entirely replaces PyOP2 with pyop3. It represents the culmination of 5 years of work.

Motivation

The Firedrake team is in the business of designing software abstractions. For many years now it has been clear that the design of PyOP2 isn't quite right. In PyOP2's view of the world there is no such thing as a mesh (or anything that looks remotely like one) and whole bunch of assumptions are baked right into the abstraction: no loop nesting allowed, no (proper) map composition allowed, only specific types of indirection maps are permitted, that are near impossible to work around once encountered. pyop3 is a fundamental and complete rewrite of PyOP2 to address all of these issues.

pyop3 can be thought of as 2 major pieces:

  1. A new abstraction for data layouts that is 'mesh aware'. It becomes possible to ask questions such as 'where are all of the DoFs that lie in the closure of this cell'.
  2. A DSL for expressing computations over these data structures. A much richer set of operations are supported including nested loops and arbitrary map composition.

This is very abstract and so I like to describe pyop3 in an alternative way: pyop3 is like numpy but for unstructured mesh data.

To learn more about pyop3 my thesis is the canonical reference.

Benefits

Replacing PyOP2 with pyop3 will enable a broad swathe of new research to occur because some operations should now become so much easier to express and experiment with. A non-exhaustive list may be found here.

In addition to enabling lots of new technologies, another very significant benefit to integrating pyop3 is the reduction in technical debt and code complexity. Many complex pieces of preexisting Firedrake code have been simplified and/or centralised into very few functions. For example, extruded meshes are now just the same as regular meshes. These changes reduce special-casing throughout Firedrake, making everything more composable!

Further, the current work on GPU support in Firedrake and FUSE both depend on pyop3.

Key changes

PyOP2 is gone

Obviously. Anywhere that you explicitly use the PyOP2 API (i.e. from pyop2 import op2) will have to be replaced with pyop3 (import pyop3 as op3). If you use PyOP2 indirectly (e.g. function.dat.data, mesh.cell_set, V.dof_dset) then some things will be expected to work (e.g. function.dat.data) but others have no equivalent pyop3 object and thus no longer exist.

Extruded meshes are now DMPlexs

Extruded meshes are now fully fledged PETSc DMPlex objects, instead of hybrid objects where only Firedrake knew about the extrusion. This simplifies an awful lot of code and will enable things like submeshing extruded meshes.

Breaking API changes

mesh.interior_facets and mesh.exterior_facets are now AxisTrees, not _Facets

Instead of mesh.exterior_facets.unique_markers and mesh.interior_facets.unique_markers you should use mesh.facet_markers.

Other attributes of _Facets are also available via the mesh with new names.

function_space.cell_node_map is now a pyop3 Map instead of a PyOP2 one

This means that it will not work as expected. In particular V.cell_node_map() will now raise an error because pyop3 maps expect arguments.

It is common practice for downstream packages to inspect function_space.cell_node_map().values. Instead you should simply do function_space.cell_node_list.

Support for variable layer extruded meshes is dropped

The functionality appeared not to be used by the community (e.g. thetisproject/thetis#405) and porting the functionality would have been a large amount of work. Eventually the functionality will be recoverable via Submesh.

API deprecations

.sub() expects a tuple instead of integer for tensor spaces.

For example, to get the (1, 1) component of a 2x2 tensor function space one should now pass f.sub((1, 1)) instead of f.sub(3). The latter will continue to work for now but a warning is raised.

ASMExtrudedStarPC is being deprecated

Now that extruded meshes are just meshes, you should just use ASMStarPC. To manage the fact that until now ASMStarPC on an extruded mesh would give column patches, a new column option has been added.

Known issues

There are a number of things that are known to be currently broken with pyop3 and we hope to fix them in due course.

  1. Performance is currently a fair bit slower than previous. This is expected to (a) be predominantly in the setup parts of the code, and hence amortize over long running simulations, and (b) will be addressed over time.
  2. 4D extrusion is not currently supported
  3. ASMExtrudedStarPC does not work in 3D (see https://gitlab.com/petsc/petsc/-/work_items/1946)
  4. MATIS and FDM and BDDC preconditioners have bugs that will be fixed in later PRs

Disabled tests

The tests that are disabled in this PR and that will need subsequent fixing are:

  • regression/test_moore_spence.py (in complex mode)
  • regression/test_bddc.py
  • regression/test_fdm.py (only some)
  • regression/test_assemble.py::test_matis (only some)
  • regression/test_mass_lumping.py (4D extrusion test case)
  • regression/test_adjoint_operators.py::test_init_constant_diff_mesh
  • external_operators/test_jax_operator.py::test_mixed_space_bcs
  • external_operators/test_pytorch_operator.py::test_mixed_space_bcs

@connorjward connorjward changed the title pyop3 (WIP) pyop3 Mar 21, 2024
connorjward and others added 8 commits July 13, 2026 15:49
- bddc.py: dof_dset no longer exists on FunctionSpace; use the new
  V.lgmap()/V.template_vec accessors instead of V.dof_dset.lgmap and
  V.dof_dset.layout_vec.
- fdm.py broken_function(): op2 is no longer imported in this file
  (only pyop3), switch to READ/WRITE from firedrake.parloops. Also
  fix the manual loopy kernel to use 2D (dof, component) indexing,
  which par_loop now requires unconditionally, and pass dtype=val.dtype
  to Function() since make_dat now asserts on dtype mismatches (this
  function is routinely called with integer index/lgmap arrays).
- Re-enable tests/firedrake/regression/test_bddc.py (was fully
  module-skipped with "pyop3 TODO").

Verified serially: BDDCPC solves, test_create_matis (4/4),
test_vertex_dofs (8/8 @ nprocs=3), test_bddc_cellwise_fdm (12/12 @
nprocs=1, including condense=True since that config uses
fdm_pc_use_amat=False and so never reaches FDMPC.condense()).

Still broken/out of scope of this commit:
- FDMPC.condense() (matrix-free static condensation, fdm_pc_use_amat=True)
  was never ported to pyop3 and still raises NotImplementedError.
- assemble(..., mat_type="is") + DirichletBC fails in parallel (nprocs>1)
  with "Matrix is missing diagonal entry" from MatZeroRowsColumnsLocal.
  This is a core assemble.py bug unrelated to preconditioners.
* Do not bind MPI jobs so full utilisation achieved - don't run jobs on
  the same cores
* Try to kill subprocesses upon SIGINT
* Don't error if errcode files don't exist
Assembly is not automatically flushed.
Uncovered a serious and subtle parallel bug.
The previous method didn't work for restricted function spaces.
Needed to fix mixed field_ises and local_ises as they were putting the
restricted DoFs in the wrong place. Same fix needed for
_restricted_section (which is a sucky hack).
Need to adopt a singleton pattern for frozenrecords because I spawn so
many of them. Currently cleaning up the record_setup/record_id bits.
* Only check for equivalence if debug checks are enabled
* Fast determination of slice vs index array
* Avoid using ISes as they are much slower than numpy arrays
* Use Axis.as_tree() to take advantage of caching
* Complex fixes
* Cleanups in CI core.yml
* Fixes for RFS with indirection map compression
* Point to petsctools main now fix is merged
dham
dham previously approved these changes Oct 20, 2026
@sghelichkhani

Copy link
Copy Markdown
Contributor

@connorjward this is what Claude Code came up with for the pyop3 memory growth in #5534: #5538

* Have to skip a UID test. I cannot solve it for the life of me and my
  machine has somehow STOPPED reproducing it.
* Avoid caching issue with loopy translation units.
Comment thread .github/workflows/core.yml Outdated
Comment thread .github/workflows/core.yml Outdated
Comment thread .github/workflows/core.yml Outdated
Comment thread .github/workflows/core.yml Outdated
Co-authored-by: Connor Ward <c.ward20@imperial.ac.uk>
@connorjward
connorjward merged commit 3554b11 into main Oct 21, 2026
6 of 9 checks passed
@connorjward
connorjward deleted the connorjward/pyop3 branch October 21, 2026 15:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:complex Run the test suite in complex mode ci:cuda Run the test suite with a CUDA-enabled build ci:int64 Do a 64 bit integer build ci:macos Run the test suite on the Mac runners pyop3

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants