Skip to content
ย 
ย 

Latest commit

ย 

History

535 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Mefikit

Mefikit logo

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:

๐Ÿ’ก Why Mefikit?

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

โœจ Key Features

๐Ÿงฉ Mesh and Field Core

  • Unified, ergonomic UMesh structure:
    • Supports mixed element types in the same mesh
    • Named fields of doubles over elements or nodes
    • Dict-like fields / groups mappings: 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, ...)

๐Ÿง  Expression DSL for Fields & Mesh Queries (python and rust)

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.

๐Ÿ”„ Input/Output Support

  • Built-in (python and rust) support for major file formats, driven by the file extension in mf.UMesh.read / mf.UMesh.write:
    • json and yaml with serde
    • vtk / vtu
    • vtkhdf
    • CGNS
    • med
  • Python in memory conversions (UMesh methods, available when the optional io dependencies are installed):
    • to_pyvista() โ€” PyVista
    • to_mc() โ€” medcoupling
    • to_meshio() โ€” meshio

๐Ÿงฎ High-Level mesh operations (Python and rust)

  • ๐Ÿ—๏ธ Mesh Builders

    • build_cmesh(*axes) - Builds a structured grid mesh (1d, 2d or 3d) of SEG2, QUAD4 or HEX8 cells.
    • 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 mesh
    • crack โ€“ Introduce topological cracks along internal faces.
    • connected_components โ€“ Split the mesh in connected meshes
    • polyze / unpolyze โ€“ Change the elements topology
  • ๐Ÿ“ Geometric operations

    • snap - To snap nodes of one mesh on another mesh nodes
    • merge_nodes - Merges duplicated nodes
    • overlay โ€“ 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 assignment
    • mf.transfer.MovingLeastSquares โ€“ MLS regression on the k nearest source cells
    • mf.transfer.InverseDistance โ€“ Inverse-distance weighted average
    • mf.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_update call that transfers a field:

    op = mf.transfer.MovingLeastSquares(m_src, m_tgt, k=10)
    op.apply_update(m_src, "temperature", m_tgt)

๐Ÿง  Element traits & geometry (rust only)

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_simplexes WIP)
  • Equivalence classes of elements (symmetry, WIP)

๐Ÿงช Developer Notes

๐Ÿ“ Project Structure

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

Rust core library

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 --release

This will create a release build of the library in the target/release directory.

Memory model: Mesh Ownership, Views, and Shared Coordinates

  • 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.

API philosophy: Explicit is better than implicit

  • Out-of-place functional API for heavy op (UMeshView or &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.

Python package

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 --uv

You can then run:

uv run pytest

uv 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.

Mefibook

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 serve

Jupyter-notebooks are executed and converted to markdown using the following:

uv run make notebooks

uv 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.

Contributing

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 files

This 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.

Releasing

Releases are automated with release-plz using the standard release-plz workflow on GitHub:

  1. Merge your work into master (e.g. a pull request from dev, or a direct push). master is the only branch release-plz looks at.
  2. The release-plz workflow opens a release PR that bumps the crate versions in crates/*/Cargo.toml, updates Cargo.lock and appends the generated changes to CHANGELOG.md. Review it (you can polish the changelog or the version) and merge it.
  3. release-plz then releases that version: cargo publish to crates.io, a vX.Y.Z git tag and a GitHub Release with the changelog.
  4. The tag triggers the Maturin-CI workflow, 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_TOKEN secret: a crates.io token scoped to publish-new and publish-update (or set up trusted publishing).
  • Add the RELEASE_PLZ_TOKEN secret: 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 the Maturin-CI workflow.

Benchmarks

The crates/mefikit/benches/ directory contains Mefikit benchmarks. They use the Criterion framework.

To launch the benchmarks, run:

cargo bench

To view results as a static and local website:

firefox ./target/criterion/report/index.html

A convenient CLI tool to visualize a summary of the results is critcmp:

cargo install critcmp
critcmp --list

If a new benchmark source file filename.rs is added inside benches/, Cargo.toml must be adapted accordingly:

[[bench]]
name = "filename"
harness = false

Note 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_example

License

Licensed under either of:

at your option.

Contribution

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.

About

Mesh and Fields Kit

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages