Mefikit (Meshes and Fields Kit) is a modern, high-performance library for manipulating unstructured meshes and associated fields and groups. It is designed with a minimal, clear, and efficient interface, focusing on flexibility, correctness, and integration in multi-physics simulations and mesh-based data processing pipelines.
๐ง Mefikit is in early development. Key resources to get started and follow progress:
Mefikit aims to make mesh-based development more direct and less error-prone, without sacrificing performance. It reduces low-level array handling so you can focus on algorithms, physics, and data flow.
For scientific developers, it offers:
- ๐ง Higher-level mesh thinking โ express operations on fields and geometry instead of indices
- ๐งช Fast experimentation โ combine topology, geometry, and fields in a unified API
- ๐ Python โ Rust API โ choice between high level python lib or idiomatic Rust
- ๐ง Early-stage flexibility โ shape core design choices while the project evolves
- โก Performance-oriented core โ efficient execution with high level DSL
- Unified, ergonomic
UMeshstructure:- Supports mixed element types in the same mesh
- Named fields of doubles over elements or nodes
- Dict-like
fields/groupsmappings: selector-based reads and writes, whole-domain or regional reductions, and named element groups
- Python bindings for all high-level tools (
build_cmesh,sel,Field,transfer, ...)
Mefikit provides a compact, composable DSL to work with fields and mesh regions without manual array handling.
T = mf.Field("temperature")
rhoCp = mf.Field("heat_capacity")
V = mf.M # symbolic measure, computed on the fly
mesh.fields["energy"] = rhoCp * T * V # compute & store as a new field
E = mesh.eval(rhoCp * T * V) # or materialize as NumPy dicts
hot = mesh.select(mf.Field("energy") > 1e6) # lazy selection view
hot.mean("energy") # reductions over the selection
submesh = hot.to_mesh() # materialize when needed
domain = mf.sel.bbox(p_min, p_max) | mf.sel.sphere(c, r)
zone = mesh.select(domain & (mf.Field("energy") > 1e6)) # field & space filtering
mesh.groups["inlet"] = domain # named groups via a dict-like mapping
mesh.groups["inlet"].add(mf.sel.rect(q_min, q_max)) # grow it later- Symbolic expressions: build computations without touching raw arrays
- Unified queries: combine fields and geometry (
mf.sel.bbox,mf.sel.sphere,mf.sel.ids, ...) with the boolean operators&,|,^,-and~ - Efficient execution: evaluated in Rust, with optional NumPy output
This avoids manual indexing over unstructured meshes and keeps computations close to the data, while remaining concise and expressive.
- Built-in (python and rust) support for major file formats, driven by the
file extension in
mf.UMesh.read/mf.UMesh.write:jsonandyamlwithserdevtk/vtuvtkhdfCGNSmed
- Python in memory conversions (
UMeshmethods, available when the optionaliodependencies are installed):to_pyvista()โPyVistato_mc()โmedcouplingto_meshio()โmeshio
-
๐๏ธ Mesh Builders
build_cmesh(*axes)- Builds a structured grid mesh (1d, 2d or 3d) ofSEG2,QUAD4orHEX8cells.extrude,extrude_parallel,extrude_curv- Raise the dimension of a mesh along a vector, or along a vector per node (parallel/curved extrusion).
-
๐ง Topological operations
descend/descend_updateโ Build the descending connectivity mesh (faces from volumes, etc)boundaries/boundaries_updateโ Build the boundaries meshcrackโ Introduce topological cracks along internal faces.connected_componentsโ Split the mesh in connected meshespolyze/unpolyzeโ Change the elements topology
-
๐ Geometric operations
snap- To snap nodes of one mesh on another mesh nodesmerge_nodes- Merges duplicated nodesoverlayโ Boolean mesh overlay on 2D meshes:IMPRINT,UNION,INTERSECTION,DIFFERENCE,SYMMETRIC_DIFFERENCE(OverlayOperation)splitโ Split the cells into smaller cells of the same element type
-
๐ Field transfers
mf.transfer.ConstantPiecewiseโ Point-location based assignmentmf.transfer.MovingLeastSquaresโ MLS regression on the k nearest source cellsmf.transfer.InverseDistanceโ Inverse-distance weighted averagemf.transfer.ConservativeP0โ Measure-weighted P0 remapping (2D)mf.transfer.DistanceWeightingโ Weighting schemes for MLS (Constant,InverseDistance(exponent),Gaussian)
The transfers separate the (potentially expensive) geometric precompute performed when the operator is constructed from the
apply_updatecall that transfers a field:op = mf.transfer.MovingLeastSquares(m_src, m_tgt, k=10) op.apply_update(m_src, "temperature", m_tgt)
This element kit provides a nice way to implement new features on elements and
use them to build mesh new operations. It is split between the element_traits
module (generic operations on mesh elements - zero copy views) and the
geometry module (owned geometric primitives).
- Bounding box trees (
spatial_index,SpatiallyIndexable) - Element intersections and cutting (
cut,segment,polygon,polyhedron) - Measures, centroids and point-in tests (
ElementGeo) - Convexity computation (
geometry::convexity) - Descending elements (
ElementTopo::subentities,to_simplexesWIP) - Equivalence classes of elements (
symmetry, WIP)
mefikit/
โโโ crates/
โ โโโ mefikit/ # The rust core library. You can use it as a rust dependency
โ โโโ mefikit-py/ # The PyO3 bindings used to build the python package
โโโ src/ # The python package
โโโ docs/ # The Mefikit Book
crates/mefikit/src/
โโโ mesh/ # Mesh & field data model, the Element API
โโโ element_traits/ # Element toolbox (geo/topo) used to build higher level functionnalities
โโโ geometry/ # Owned geometric primitives (segment, polygon, polyhedron, region)
โโโ tools/ # The home to all high-level functionnalities
โโโ io/ # Readers/writers
To build the library, you need to have Rust installed. You can install Rust using rustup. Once you have Rust installed, you can build the library using the following command:
cargo build --releaseThis will create a release build of the library in the target/release
directory.
UMesh: fully owns its data (coordinates, connectivity, fields, etc.), suitable for storage, transformation, and I/O. Useful to share arrays using copy-on-write. Maximum performance when staying in rust.UMeshView<'a>: read-only view into external or borrowed mesh data; ideal for zero-copy FFI.
- Out-of-place functional API for heavy op (
UMeshViewor&UMesh):descend,boundaries,overlay,split,compute_connected_components, ... - In-place for metadata manipulations and non destructive op (
&mut UMesh):descend_update,boundaries_update,update_field,merge_nodes,snap, ...
Most out-of-place operations also expose an *_update variant that adds the
result to the mesh in-place.
The PyO3 bindings live in the crates/mefikit-py crate (package name
mefipy). They are compiled into the mefikit.mefipy module which is wrapped
by the python package mefikit (in src/).
To build the bindings and the python package please run:
uv tool install maturin
uv run maturin develop --uvYou can then run:
uv run pytestuv won't build the package, it is only in charge of the dependencies.
maturin is the only one parametrized for this. Please run maturin each time
rust mefikit or mefikit-py changed.
docs/
โโโ src/ # The mdbook root dir
โโโ python_examples/ # Python notebooks
The mefibook is a mdbook project. Please refer to the mdbook documentation.
In two lines, you should:
cargo binstall mdbook
mdbook serveJupyter-notebooks are executed and converted to markdown using the following:
uv run make notebooksuv is used here because the notebooks need jupyterlab, mefikit and all its
dependencies to run. As uv won't build mefipy you need to build it first.
If you would like to contribute to the library, please fork the repository
and create a pull request with your changes. We welcome contributions of all
kinds, including bug fixes, new features, and documentation improvements.
Please make sure to follow the coding style and conventions used in the
library. You should use pre-commit for this purpose.
uv tool install prek
prek install
git commit -a # pre-commit runs on your committed filesThis will check the coding style and report any issues.
Please use Conventional Commits for your
commit messages (feat:, fix:, docs:, perf:, refactor:, test:, ...).
The conventional-pre-commit hook enforces it, and the automated release
pipeline uses the commit types to compute the next version and generate the
changelog.
Releases are automated with release-plz using the standard release-plz workflow on GitHub:
- Merge your work into
master(e.g. a pull request fromdev, or a direct push).masteris the only branch release-plz looks at. - The
release-plzworkflow opens a release PR that bumps the crate versions incrates/*/Cargo.toml, updatesCargo.lockand appends the generated changes toCHANGELOG.md. Review it (you can polish the changelog or the version) and merge it. release-plzthen releases that version:cargo publishto crates.io, avX.Y.Zgit tag and a GitHub Release with the changelog.- The tag triggers the
Maturin-CIworkflow, which builds wheels for all platforms and publishes them to PyPI.
The version bump follows the commit types: fix: bumps the patch version,
feat: bumps the minor version (patch before 1.0) and breaking changes bump
the major version (minor before 1.0).
One-time setup:
- In the repository settings, allow GitHub Actions to create and approve pull requests (required for the automatic release PR).
- Add the
CARGO_REGISTRY_TOKENsecret: a crates.io token scoped topublish-newandpublish-update(or set up trusted publishing). - Add the
RELEASE_PLZ_TOKENsecret: a fine-grained GitHub personal access token with read/write access to Contents and Pull requests. It lets the tags pushed by release-plz trigger theMaturin-CIworkflow.
The crates/mefikit/benches/ directory contains Mefikit benchmarks. They use
the Criterion
framework.
To launch the benchmarks, run:
cargo benchTo view results as a static and local website:
firefox ./target/criterion/report/index.htmlA convenient CLI tool to visualize a summary of the results is critcmp:
cargo install critcmp
critcmp --listIf a new benchmark source file filename.rs is added inside benches/,
Cargo.toml must be adapted accordingly:
[[bench]]
name = "filename"
harness = falseNote that filename, in Cargo.toml, is written without the .rs extension.
More information in the Criterion
documentation
You can create flamegraphs to spot performance bottleneck.
cargo flamegraph --profile flame --example name_of_the_exampleLicensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT license (LICENSE-MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Mefikit by you shall be dual licensed as above, without any additional terms or conditions.
