Skip to content

What's New

Unreleased

Mesh Force and Torque Rewrite

calc_force_mesh() (and Mesh.get_force_torque()) no longer loop over mesh triangles in Python. All sub-triangle centroids are now packed up front, each source magnet's field is evaluated in a single batched call, and the force/torque accumulation runs in a parallel Numba kernel. Results are unchanged.


Distance Cutoff for Mesh Fields: r_cut

Mesh.get_field() accepts an optional r_cut argument. Triangles whose centroid is farther than r_cut from an evaluation point are skipped:

Bx, By, Bz = magnet.get_field(X, Y, Z, r_cut=40.0)

The default, np.inf, performs no culling and is exact.

r_cut is an approximation, not a free speedup

Because surface charges largely cancel at a distance, discarding them costs far more accuracy than the raw triangle count suggests. On a 10 000-triangle bunny evaluated over ±70 mm, r_cut=40 mm is 8× faster but carries a 37% nRMSE, while an r_cut accurate to ~2% is only 1.1× faster. See 3D Magnets → Distance cutoff for the full measured trade-off table, and validate against an r_cut=np.inf reference before relying on it.


Multi-Magnet Fused Mesh Field

pymagnet.magnets.get_total_field_mesh() evaluates several Mesh magnets in a single parallel pass over the evaluation points instead of one pass per magnet:

from pymagnet import get_total_field_mesh

B = get_total_field_mesh([m1, m2], X, Y, Z)

It returns a Field3 object and is numerically identical to summing the individual get_field() calls. Note that on current benchmarks it is not yet measurably faster than the sequential sum for large meshes.


Parallel Mesh Kernel Race Condition Fixed

A race condition in the parallel mesh field kernel has been fixed, and the kernel now parallelises over evaluation points rather than triangles.


Faster Cylinder Field

Cylinder field evaluation now converts cylindrical to Cartesian components directly from x/rho and y/rho, avoiding arctan2, cos and sin calls per point. Behaviour on the symmetry axis (rho = 0) is unchanged.


v0.5.1

TOML Configuration System

Pymagnet now supports a declarative TOML-based configuration system for defining and running simulations without writing Python code. Define your magnets, grids, plots, and force calculations in a .toml file and run them from the command line or Python API.

pymagnet my_simulation.toml
from pymagnet.config import run, load, validate

result = run("my_simulation.toml")

See Configuration for full documentation and examples.


Numba Parallel Mesh Acceleration

Field calculations for STL mesh magnets are now parallelised using Numba's prange, achieving up to 247x speedup on multi-core systems. This makes complex non-convex geometries practical for interactive use.


slice3D() Utility

A new slice3D() function generates planar evaluation grids in 3D space, supporting xy, xz, and yz planes with configurable bounds and offset values. This simplifies creating cross-sectional field visualisations.

import pymagnet as pm

points = pm.slice3D(plane="xz", max1=30, max2=30, slice_value=5.0, num_points=100)

Mesh Force and Torque Calculations

Force and torque calculations now support STL mesh magnets via calc_force_mesh(). The mesh surface is subdivided into smaller triangles for improved numerical integration accuracy.


NaN Handling in 3D Field Summation

Fixed a critical bug where NaN values from field singularities (e.g. inside magnets) could propagate and corrupt the entire field array in multi-magnet systems. NaN values are now zeroed before accumulation and the interior mask is reapplied after summation.


Python 3.13+ and NumPy 2.0+

The minimum Python version has been bumped to 3.13. NumPy 2.0.1+ and Numba 0.60-0.64 are now required.


Optional Plotting Dependencies

Matplotlib and plotly are now optional dependencies. Install with plotting support using:

pip install pymagnet[plots]

The library will raise a clear error if plotting functions are called without the required packages installed.


CI/CD with GitHub Actions

Automated testing and release workflows have been added via GitHub Actions, with Ruff linting and pre-commit hooks for code quality.