prophys Documentation

prophys logo

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

prophys lets you describe an uncertainty structure with geometry, physics, and probability distributions. It offers a symbolic Python DSL, and compiles models into a jit/grad/vmap-able model with calibration, design optimization, and a standardized export format. It is not a distribution library like NumPyro or Distrax but rather sits in the layer above one, combining differentiable geometry (distances to polygons, point sets, lines, 3D exclusion volumes, voxel fields, unstructured meshes, directed networks), transformations, differentiable discrete design decisions, and probabilistic attributes, including directional climatologies like wind/wave roses, in a single compiled graph.

Every number it reports comes with the uncertainty of the number: a Monte-Carlo standard error on each sampled statistic, a standard error and interval on each fitted parameter, a variance decomposition over the uncertain inputs, predictive scores and calibration diagnostics on the fitted model, and a run manifest recording exactly what produced the result.

prophys is proprietary software by RhineQC GmbH.

_images/compare_heavy_tails.png

Distribution catalog. Gaussian, Weibull, Gamma, Beta, circular (VonMises), multivariate, mixtures, and Gaussian copulas — all differentiable. Browse the catalog →

_images/gas_dispersion_risk_map.png

A complete worked model. A gas-dispersion community health-risk model exercising every primitive family end to end. See the example →

Networks, discrete design, and cascades. A distribution-grid reinforcement model: directed-graph topology, differentiable binary reinforcement decisions, and a multi-hop fault cascade, jointly optimized against continuous substation siting. See the example →

One toolkit, many domains

prophys is not a physics package for one vertical — the same primitives that built the gas-dispersion example also built the electric-grid cascade, and compose just as directly into wake models, catastrophe pricing, or tail-risk layers. What the library actually offers is differentiability and joint calibration/optimization over geometry + physics + uncertainty, whatever the domain:

Pipeline-leak dispersion & health risk

A Gaussian plume with the leak location a reparameterized draw anywhere along the route, wind as upstream RandomVariables, expected-and-tail exposure, dose-response calibration, and abatement optimized by gradient.

Example: Pipeline-Leak Community Health Risk
Power-grid fault cascades

A directed Network cascade where each line’s reinforcement is a differentiable BinaryState — discrete topology decisions and continuous substation siting optimized in one gradient pass.

Example: Distribution-Grid Reinforcement
Wind & wave climatologies

DirectionalMixture couples sector weights, circular spread, and per-sector intensity (e.g. Weibull wind speeds) — a calibratable wind rose feeding turbine-siting or fatigue-load models.

Distributions
Flood & catastrophe pricing

Terrain rasters and portfolio Polygons under a GaussianCopula coupling hazard marginals — spatially correlated loss, differentiable end to end for pricing sensitivities.

Distributions
Insurance tail risk

Heavy-tailed severity (Gumbel, LogNormal, mixtures) with quantile()/cvar() on any compiled attribute — attachment points and layer structures tuned by gradient.

Training & Design Optimization
FEM/CFD surrogate ingestion

Solver outputs land in a Mesh (P1 barycentric) or voxel Field3D and become differentiable model inputs — calibrate a simulated stress or concentration field against point observations.

Structures
Pipeline & route safety

A Polyline’s route is a Param; a leak location is a continuous, reparameterized draw along it via point_at — siting and leak-exposure liability optimized jointly, not approximated by a hand-picked grid of candidate leak points.

Structures
Concepts

Symbolic graphs, frames, eval vs. opt mode, and Monte-Carlo marginalization explained.

Concepts
Structures

Point, Line, Polygon, Polyhedron, Field, Grid, Network, Field3D, and Mesh — every differentiable geometry primitive.

Structures
Distributions

Univariate, circular, multivariate, mixture, and copula distributions, with plots.

Distributions
Transformations

Linear, piecewise-linear, decay, logistic, and table-lookup transforms.

Transformations
Calibration & Design

Fit parameters to observations and optimize design variables with Optax, entirely through gradients.

Training & Design Optimization
Uncertainty & Error

Monte-Carlo standard errors on every sampled statistic, and standard errors, intervals and profile likelihoods on every fitted parameter.

Uncertainty & Error
Sensitivity

Exact local derivatives and elasticities by autodiff, and global Sobol variance decomposition over the uncertain inputs.

Sensitivity Analysis
Validation

AIC/BIC, WAIC and PSIS-LOO, PIT calibration, CRPS, and posterior predictive checks — with model-to-model comparison.

Model Validation
Posterior Inference

NUTS over the compiled model through NumPyro, with convergence diagnostics and draws that feed every predictive score.

Posterior Inference
Reading Data

CSV with laboratory non-detects, wind roses, rasters and NetCDF, read into prophys objects with units checked at the boundary.

Reading Data
Export Format

The standardized, consumer-agnostic ModelPackage interchange format, with a run manifest recording what produced it.

Export Format

Minimal Working Example

import prophys as prp
import jax.numpy as jnp

site = prp.Frame("site")
houses = prp.PointList(jnp.array([[0.0, 0.0], [200.0, 0.0]]), site)
turbines = prp.PointList(prp.Param("pos", shape=(2, 2), init=jnp.array([[80.0, 80.0], [150.0, 20.0]])), site)

distance = houses.closest_distance(turbines, mode="opt", tau=2.0)
level = prp.Param("base", init=100.0) - 20 * prp.log10(distance)

acceptance = prp.UncertainAttribute("acceptance_drop", prp.Weibull(scale=1.0 + level, concentration=prp.Param("k", init=2.0)))
model = prp.ProbabilityModel(acceptance)
compiled = model.compile(mode="opt")

print(compiled.expectation("acceptance_drop"))

Where To Start