Skip to main content

prophys: probabilistic-physics modelling toolkit

A differentiable, JAX-native DSL for spatial probability and risk models.

python license status

Overview

prophys lets you describe an uncertainty structure (geometry, physics, distributions) as a symbolic Python model, and compiles it into a single differentiable JAX graph with log_prob, sample, expectation, tail-risk metrics, gradient-based calibration, and design optimization.

It is not a distribution library like NumPyro or Distrax. It is the layer above one. The distinguishing capability is that geometry, interpolated fields, physics surrogates, and probability live in the same differentiable graph: a pipeline route vertex, an emission abatement fraction, or a copula correlation can all be trained or optimized with the same jax.grad pass that evaluates the model.

It combines:

  • A symbolic expression core (Expr, Param, Input, RandomVariable) with NumPy-style operator overloading. Models are built with ordinary arithmetic and compile to pure jax.numpy.
  • Differentiable geometry structures in shared coordinate frames: PointList, LineList, Polygon/PolygonList (signed distance, containment, area), Polyhedron (3D halfspace volumes), raster Fields with bilinear interpolation, and evaluation Grids.
  • Transformations: linear/affine/polynomial, smoothable PiecewiseLinear, Decay, Logistic dose-response, and interpolated TableLookup1D/2D characteristic curves.
  • Distributions: 12+ univariate families, circular (VonMises, WrappedGaussian), multivariate Gaussian (Cholesky-parameterized), mixtures, empirical/KDE, and Gaussian copulas with always-valid learnable correlation.
  • Probabilistic inputs anywhere in the graph: a RandomVariable (e.g. wind speed/direction) can feed the physics, not just the output noise. The compiled model marginalizes it by reparameterized Monte Carlo with gradients intact.
  • A training engine (Optax): calibrate one attribute, finetune the whole model jointly across attributes with shared parameters, fit_distribution for standalone/multivariate distribution learning, with trainable/frozen parameter control.
  • Design optimization with penalty constraints, where bounded parameters are constrained structurally (sigmoid/softplus bijectors) rather than by projection.
  • A standardized export format (ModelPackage): quantized PMF, histogram, or JAX-free sampler representations, JSON round-trippable, consumer-agnostic.

Installation

pip install prophys

Ships as a prebuilt binary wheel, including the compiled native core (prophys._core), so no Rust toolchain or compilation step is needed.

Free tier / licensing: model calls touching up to 250 structural objects (points, polygon vertices, segments, raster cells, ...) run without any license. This does not count Monte-Carlo sample counts, observation counts, or training iterations, only declared model structure. Larger models require a signed license (set via the PROPHYS_LICENSE environment variable). Contact RhineQC GmbH to obtain one.

With optional extras:

pip install "prophys[viz]"        # matplotlib plotting helpers (prophys.plot)
pip install "prophys[geo]"        # shapely/pyproj geodata import
pip install "prophys[inference]"  # NumPyro bridge

Requirements: Python ≥ 3.11 (JAX and Optax install automatically as dependencies). Python 3.10 is not supported: jaxlib has not published a cp310 wheel since 0.9.0.

Quick Start

import jax
import jax.numpy as jnp
import optax
import prophys as prp

# Geometry in a shared frame: the pipeline route (optimizable) and a receptor
site = prp.Frame("site", units="m")
route = prp.Polyline(
    prp.Param("route", shape=(4, 2), init=jnp.array([[0.0, 0.0], [300.0, 60.0], [650.0, -30.0], [900.0, 0.0]])),
    site,
)
house = prp.Point(jnp.array([500.0, 250.0]), site)

# Physics: a leak can occur anywhere along the route, so its location is a
# continuous, reparameterized random variable pushed through the route's
# differentiable point_at(t), not a hand-picked set of candidate points
leak_frac = prp.RandomVariable("leak_frac", prp.Uniform(low=0.0, high=1.0))
leak_point = route.point_at(leak_frac)

# Gas dispersion from the leak to the house, then concentration -> a
# probability of health issues (dose-response curve)
distance = prp.norm(house.coords[0] - leak_point)
concentration = prp.Param("emission_rate", init=1.5) * prp.exp(-distance / 150.0)
health_risk = prp.PiecewiseLinear([0.0, 0.05, 0.2, 0.5], [0.0, 0.05, 0.3, 0.85], smooth=0.02)(concentration)

# Probabilistic attribute + standardized model object
incident = prp.UncertainAttribute("health_incident", prp.Bernoulli(prob=prp.clip(health_risk, 1e-4, 1 - 1e-4)))
model = prp.ProbabilityModel(incident)
compiled = model.compile(mode="opt", n_samples=200)

# Probability of a health incident, marginalized over every leak location
# along the route, with a gradient with respect to every vertex of the route
p_incident = compiled.expectation("health_incident")
grad_wrt_route = jax.grad(
    lambda params: compiled.expectation("health_incident", params=params)
)(compiled.default_params())

# Calibrate against observations ...
result = prp.calibrate(compiled, "health_incident", observations, n_steps=300)

# ... or optimize the route itself, directly against the marginalized
# probability, with plain JAX/optax (prp.optimize is only a convenience
# wrapper around the same pattern, not required)
opt = optax.adam(0.05)
raw_params = compiled.default_params()
opt_state = opt.init(raw_params)

for _ in range(200):
    loss, grads = jax.value_and_grad(
        lambda params: compiled.expectation("health_incident", params=params)
    )(raw_params)
    updates, opt_state = opt.update(grads, opt_state)
    raw_params = optax.apply_updates(raw_params, updates)

Uncertainty at the inputs, not just the output

wind_speed = prp.RandomVariable("v", prp.Weibull(scale=6.0, concentration=2.0))
wind_dir   = prp.RandomVariable("phi", prp.VonMises(loc=prp.deg2rad(35.0), kappa=3.0))

# Any expression downstream of these is a random quantity. The compiled
# model marginalizes them via reparameterized Monte Carlo, inside one
# JAX trace, so gradients flow back through the marginalization.

Training the model

# Fit one attribute
prp.calibrate(compiled, "exposure", observations)

# Jointly train the entire model. Shared parameters pool information
# across every attribute's observations
prp.finetune(compiled, {"exposure": obs_e, "complaints": obs_c}, frozen=["emission_rate"])

# Learn a standalone (also multivariate) distribution from data
mvn = prp.MultivariateGaussian(
    mean=prp.Param("mu", shape=(2,), init=jnp.zeros(2)),
    cholesky=prp.Param("L", shape=(2, 2), init=jnp.eye(2)),
)
prp.fit_distribution(mvn, data)

Export

pkg = compiled.export()      # quantized PMF / histogram / JAX-free sampler
pkg.save("model.json")       # versioned, consumer-agnostic interchange format

Downstream consumers implement their own import against the documented ModelPackage shape. prophys carries no consumer-specific dependencies.

Examples

  • examples/gas_dispersion/: a complete community-health-risk model. Gaussian plume physics, wind as random inputs, terrain-corrected effective stack height, dose-response calibration, and constrained abatement optimization. Every primitive family appears once.

Documentation

Full docs are at docs.rhineqc.com/distribution/prophys, covering concepts (symbolic graphs, frames, eval/opt modes, marginalization), the full structure/distribution/transformation catalogs with plots, calibration and design optimization, a step-by-step worked example, and the export format specification.

License

prophys is proprietary software by RhineQC GmbH. It is intended for internal or explicitly licensed distribution.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

prophys-0.2.0-cp311-abi3-win_amd64.whl (660.2 kB view details)

Uploaded CPython 3.11+Windows x86-64

prophys-0.2.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (717.6 kB view details)

Uploaded CPython 3.11+manylinux: glibc 2.17+ x86-64

prophys-0.2.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (658.6 kB view details)

Uploaded CPython 3.11+manylinux: glibc 2.17+ ARM64

prophys-0.2.0-cp311-abi3-macosx_11_0_arm64.whl (630.8 kB view details)

Uploaded CPython 3.11+macOS 11.0+ ARM64

prophys-0.2.0-cp311-abi3-macosx_10_12_x86_64.whl (663.3 kB view details)

Uploaded CPython 3.11+macOS 10.12+ x86-64

File details

Details for the file prophys-0.2.0-cp311-abi3-win_amd64.whl.

File metadata

  • Download URL: prophys-0.2.0-cp311-abi3-win_amd64.whl
  • Upload date:
  • Size: 660.2 kB
  • Tags: CPython 3.11+, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for prophys-0.2.0-cp311-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 9357a2a606ae059c5049ff439a17a8c8330c6e14e616481b75c3ae874891cd61
MD5 e1b7182605629312ec237ed530df345f
BLAKE2b-256 be44d3ff6c424f2e08e3b43507ffa5f4e6c17d681819d4be73c78f5fc8d0ebde

See more details on using hashes here.

File details

Details for the file prophys-0.2.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for prophys-0.2.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 45707362a7cd4c4f1ece3c7cecb01ecdb8f7e71632d2b9fcbdda84a0c9e6d401
MD5 ff60ed294108b17cdc9ca4f7fc530144
BLAKE2b-256 688a343f3ac5c041d905f75c35144786902d1e744faf8698072ab3666b1f9c6a

See more details on using hashes here.

File details

Details for the file prophys-0.2.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for prophys-0.2.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 2b3661670c9cae261192cd644e2899d92f94606b6c974f9395ca48133622c6f6
MD5 bb062e300f143f498794bd6c148ce219
BLAKE2b-256 83671f10b9e6a3b52d6a4b2781ed7987c4a9627e41316f63caed5e9e0966e6d0

See more details on using hashes here.

File details

Details for the file prophys-0.2.0-cp311-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for prophys-0.2.0-cp311-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 1387fb983f8d33d12909f187c68db16e9b8538086415660148f6608d11f62540
MD5 a67d27b595df7eef66fcc9e3810ced61
BLAKE2b-256 5dcae4250d74f696e1b8eec27553e89bbe6526f8fcf81dd46c63f58267217b35

See more details on using hashes here.

File details

Details for the file prophys-0.2.0-cp311-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for prophys-0.2.0-cp311-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 36d5768b41932de8f93b0a3931a1beb915c01499ab84b84e5219d83e190e9b51
MD5 93c69ecd48e1e57d64a4f618f3a0c0d0
BLAKE2b-256 fecace4211437d6812a0876c5b83998a47da72e2bf4bc37823c59df31aa898d4

See more details on using hashes here.

Release history Release notifications | RSS feed

0.3.0

5 files

This release

0.2.0 This release

5 files

0.1.0

5 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