Skip to main content

pantometry for Python

Coupled physics whose conservation audit is an exception you can catch.

pip install pantometry        # wheels for linux, macos and windows; abi3, so 3.10 upward
import pantometry

sim = pantometry.Simulation(schedule="multirate", conservation_tolerance=1e-9)
sim.add_heater("element", watts=2.0, reserve_j=6.0)
sim.add_bar("bar", length_m=0.020, cells=41, area_m2=1e-4)

for _ in range(8):
    sim.advance(0.5)          # raises pantometry.Violation if the books do not close

print(sim.temperature("bar"))     # 294.39 K
print(sim.profile("bar")[:3])     # warmer at the fed end

Several bodies and the drop between them

add_lump gives you one temperature for a whole assembly. The number that decides whether a motor survives is the winding, which is hotter than the case by however much the joint between them resists — so for that, a network:

sim = pantometry.Simulation(schedule="staggered")
sim.add_heater("losses", watts=6.0, reserve_j=5_400.0)
sim.add_network("motor",
    nodes=[{"name": "winding", "material": "copper", "volume_m3": 18e-6,
            "thickness_m": 2e-3, "initial_k": 298.15},
           {"name": "case", "material": "aluminium", "volume_m3": 220e-6,
            "thickness_m": 4e-3, "initial_k": 298.15,
            "ambient_k": 298.15, "area_m2": 0.042}],   # both keys, or neither
    links=[{"from": "winding", "to": "case", "w_per_k": 0.9}],
    absorbing="winding")

for _ in range(900):
    sim.advance(1.0)

dict(sim.node_temperatures("motor"))     # {'winding': 311.2, 'case': 304.9}
sim.heat_flow_w("motor", "winding", "case")   # 5.585 W crossing the joint

material is any name in the kernel's catalogue, and this line no longer lists them — it used to say five, the binding accepted those same five against a catalogue of nine, and listing them here made a fourth copy of a spelling that had already gone stale three times. The error message names them, and it is generated from the catalogue, so it is right by construction. A node with ambient_k and area_m2 loses heat to still air; a node with neither is interior. Giving one without the other is refused rather than quietly producing a node that looks like it is cooling and is not.

Names are resolved once, when the network is built, so a link to a node that does not exist raises before any stepping happens and lists the nodes that do. That matters more here than it looks: a link adds +q to one node and −q to another in the same sum, so a missing or misdirected link passes the conservation audit at machine precision and simply reports the wrong temperature forever.

temperature() refuses a network rather than averaging it — the reason to build one is that its nodes differ, so a mean would describe no part of it.

Why this rather than numpy

Write physics in numpy and a wrong model runs happily, producing plausible output. There is no signal; you find out when somebody notices the answer is silly.

Every advance here either moves the clock or raises, and the exception is addressable rather than a sentence to parse:

try:
    sim.advance(0.5)
except pantometry.Violation as v:
    v.quantity     # 'energy'
    v.site         # 'bus (published but not consumed)'
    v.before, v.after, v.scale, v.tolerance
    sim.time       # unchanged — a refused step does not advance the clock

Be clear about what it catches. Quantities appearing or vanishing, amounts left unclaimed on the bus, and a domain refusing a step it cannot take. It does not catch a model that is internally consistent and physically wrong. For that, check against something the library did not compute — which is what heat_capacity_j_per_k is exported for, and what tests/test_pantometry.py does throughout.

What crosses the boundary, and what does not

Values cross as SI floats with the unit in the parameter name: length_m, watts, initial_k. pantometry's dimensional types are a compile-time thing — Length + Time does not compile in Rust — and Python cannot have that. A runtime Quantity wrapper would cost an allocation and a check per operation to catch, at run time, a class of error a Python caller mostly does not make, because it passes values in and reads them out rather than doing algebra on them. So the types stay on the Rust side and the units stay in the names.

What crosses instead is the audit, which is the part worth having.

What this cannot do

You cannot run an ensemble from Python, and it is not an oversight. Ensemble exists to run many independent samples across threads, and a Python sample function cannot: the GIL serialises it. A binding for it would look parallel, measure slower than a plain Python loop because of the crossing cost, and have nothing left of the one thing it is for. Write the sampler in Rust, or loop in Python and accept one core.

You cannot write a domain in Python. That means calling back into the interpreter from inside the step loop, holding the GIL across it, and deciding what an exception raised mid-sweep does to a half-advanced simulation. All three are answerable and none cheaply, so this binds the physics the library has and says so rather than shipping a subtly wrong version of that.

So: enough to run and audit coupled physics from Python, not enough to extend it. The extending lives in Rust, and the workspace is where.

A Simulation is also bound to the thread that created it. Domain is not Send, and the binding says so rather than asking the kernel for a bound it does not offer.

There is no scene or view binding. The Rust side has pantometry-scene for capturing a run and pantometry-view for drawing one; neither crosses. Nothing forbids it in principle — the reason is that a Python caller already has matplotlib, pandas and every plotting stack there is, and what they want from this side is the numbers: profile, node_temperatures, temperature, ledger. Handing them an SVG instead would be the worse half of both worlds. If you want the HTML report, run the scene from Rust.

Building

Its own cargo workspace, deliberately. This one resolves fifteen external crates where the library resolves twelve, seven of them pyo3's and appearing nowhere in the library, plus a libpython link — and the library's lockfile, licence allow-list and WebAssembly jobs are promises that should not have to accommodate a Python extension.

cd bindings/python
pip install "maturin>=1.7,<2.0"
maturin build --release          # an abi3 wheel: one build serves 3.10 upward
pip install target/wheels/pantometry-*.whl
python tests/test_pantometry.py

maturin develop works too, in a virtualenv. CI builds the wheel, installs it and runs those tests on every commit — because "it compiles" proves neither half of "pip install then import".

Metadata

Release files for pantometry 0.18.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pantometry 0.18.0
File Size Uploaded
pantometry-0.18.0.tar.gz 1.4 MB Details

Built distributions (wheels)

Table of built distributions (wheels) for pantometry 0.18.0
File
pantometry-0.18.0-cp310-abi3-win_amd64.whl CPython 3.10 abi3 Windows x86-64 Details
pantometry-0.18.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.10 abi3 Linux glibc 2.17+ x86-64 Details
pantometry-0.18.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.10 abi3 Linux glibc 2.17+ ARM64 Details
pantometry-0.18.0-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details
pantometry-0.18.0-cp310-abi3-macosx_10_12_x86_64.whl CPython 3.10 abi3 macOS 10.12+ x86-64 Details

Total release size: 3.2 MB

Release files / pantometry-0.18.0.tar.gz

Download URL pantometry-0.18.0.tar.gz
Size 1.4 MB
Tags Source
SHA-256 checksum
How to use checksums
d218b82fa6d406ccc7641596ca8c1dad6e6ae1917971921707a0d62f0b91380f
BLAKE2b-256 checksum
How to use checksums
41aaa463f8d6b5c1ebd1abedf3a6a182dd90e0150656a34aa55b1897a26a69d6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 28, 2026.

Transparency log

Release files / pantometry-0.18.0-cp310-abi3-win_amd64.whl

Download URL pantometry-0.18.0-cp310-abi3-win_amd64.whl
Size 254.0 kB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
93a262707b68a495cb3eebdf9f143ab85f799d6673fd86a3e97b7ffbfc4c0303
BLAKE2b-256 checksum
How to use checksums
e444e1cffcbf0c9c5b603a8e19f58e3d0bb39ddcc52a42586926fadc13630769
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 28, 2026.

Transparency log

Release files / pantometry-0.18.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL pantometry-0.18.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 408.3 kB
Tags CPython 3.10 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
e8a98f8a54b7d808d9b001c81e3407c5175e48a2b38aaa16b0d6fdb71ff1285b
BLAKE2b-256 checksum
How to use checksums
5fd04e607428de3653c2c42a5027a50f22045a7c276ddd3563060d2716d60734
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 28, 2026.

Transparency log

Release files / pantometry-0.18.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL pantometry-0.18.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 390.8 kB
Tags CPython 3.10 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
d813045c7c99fc8717bd2c77e92559cdd9692c88f4a00d62be5bc3181629a98d
BLAKE2b-256 checksum
How to use checksums
3f5db27f65a0be2b87fff5fbbc51c225d8187103e82ddd4a85586c4c8be1dfb5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 28, 2026.

Transparency log

Release files / pantometry-0.18.0-cp310-abi3-macosx_11_0_arm64.whl

Download URL pantometry-0.18.0-cp310-abi3-macosx_11_0_arm64.whl
Size 355.4 kB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
cf8841c6af9576ed0d7ca1c9125c711a76529eefdd6b7b276c8f92c1cd0f7574
BLAKE2b-256 checksum
How to use checksums
344cf433a747a7b3720a0f859adaaa6a92399b27fe68f8f3085aae3e97bad63c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 28, 2026.

Transparency log

Release files / pantometry-0.18.0-cp310-abi3-macosx_10_12_x86_64.whl

Download URL pantometry-0.18.0-cp310-abi3-macosx_10_12_x86_64.whl
Size 360.1 kB
Tags CPython 3.10 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
84cfad0b72685973086a75a75d6dc50286a413e9a7dc34391ee1711b41c28815
BLAKE2b-256 checksum
How to use checksums
87d8d6387b12d73558f4d4541fc7f124644a30cce69f6c947394b50e67aca140
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 28, 2026.

Transparency log

Release history Release notifications | RSS feed

0.22.0

6 release files

0.21.0

6 release files

This release

0.18.0 This release

6 release files

0.17.0

6 release files

0.16.0

6 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page