Skip to main content

rheplicant — digital twin for the RHINO experiment

RHEPLICANT

Documentation Status

A REPLICa of an ANTenna — a JAX model of a radio telescope, run as a digital twin. Built for RHINO, a horn antenna measuring the 21 cm global signal, and domain-agnostic underneath: horns, dipoles and dishes alike. (JAX + Equinox.) Documentation: rheplicant.readthedocs.io

A RHEPLICANT twin is one pure function from sky and instrument parameters to raw data. Because every stage — foregrounds, ionosphere, beam, receiver reflections, gain drifts, digitisation — is differentiable, the same twin that simulates an observation also calibrates it: gradients, Bayesian posteriors, Fisher forecasts, and neural surrogates all run through the instrument model itself, with no re-implementation.

from rheplicant.radio import assemble, GlobalSignalOperator, ForegroundOperator, GainOperator

twin = assemble(GlobalSignalOperator(...), ForegroundOperator(...), GainOperator(...))
observation = twin(state)          # simulate — and differentiate, fit, sample

First deployed for RHINO (a horn antenna targeting the 21 cm global signal); the core is domain-agnostic by construction.

Four things it is built to do

1 · Forward modelling Simulate what any stage of the experiment would produce — a sky, a receiver output, a processed product. Where you stop is a property of the graph.
2 · Bayesian inference Read the same twin backwards. Free any subset of what it contains; the noise model is the likelihood; the engine follows from the model's structure.
3 · Neural surrogates Replace an expensive stage with a trained network and leave the graph's shape untouched — or amortize the posterior itself.
4 · Streaming evidence Keep a campaign after its recordings are archived: compress each night to a fixed-size likelihood factor, then discard the data.

None of the four is a separate mode. They all read the same twin object, which is what makes the calibration you fit the simulator you trust.

Two nouns

State — the complete scientific context: data, coordinates, environment, randomness, metadata. It organises references to buffers rather than the buffers themselves, so a derived state allocates the shell and nothing else (48 bytes, with a 16 MB array shared rather than copied). JAX arrays are immutable, which is what makes sharing safe.

Operator — one step, State in and State out. Sky models, instrument effects, calibration, filtering and neural networks are all the same kind of thing, each carrying its physical parameters as differentiable leaves.

state.data always references what the instrument has produced so far. For example: the sky engine produces the (n_time, n_freq) antenna temperature, the antenna's ohmic loss produces that array after loss, the receiver produces a system temperature. Nothing is written in place — each stage hands back a new State whose data points at its own result, while the fields it did not touch go on pointing where they already did.

The sky map itself is not in state.data — it is a parameter of the sky model, differentiable like every other, which is why a map can be inferred rather than merely assumed.

Three ways to join them — and you rarely write any

Cascade (Pipeline) for sequential effects, sum (SumOperator) for independent contributions that add, switch (SelectOperator) for alternatives with one selected per time sample. There is no fourth.

You normally write none of them. Declare the operators you want and assemble reads the canonical signal path — the template that says which operators exist and what joins them — to decide the composition. Reach for the three combinators directly only when building a structure the template does not describe.

The name

RHEPLICANT is REPLICANT wearing RHINO's horn. REPLICANT is itself a portmanteau of REPLICa and ANTenna — a digital twin is a replica, and this one is of a radio antenna — the two words overlapping on their shared A. Slip an H in behind the first letter and R… becomes RH…, the mark of RHINO, the horn antenna the framework was first built for:

R E P L I C A            replica
            A N T         antenna
─────────────────
R E P L I C A N T        replicant
  + H  →  RH…            (for RHINO)
─────────────────
R H E P L I C A N T      rheplicant

One-line gloss: a differentiable replica of a radio antenna — first, of RHINO.

Philosophy

  1. Everything is an operator acting on a state. One contract, State in, State out, covers sky models, instrument effects, processing, filters and neural networks alike.
  2. The twin is a differentiable function. Every physical parameter is a pytree leaf, so jit/grad/vmap apply to the whole instrument, and a systematic becomes something you infer rather than correct for.
  3. Composition is physics, implicit in the signal path. Chains, sums and switches are read off the canonical graph, so assemble builds the right structure from a set of operators and partial models come free.
  4. Purity everywhere. Immutable states, randomness as data, no hidden side effects — which is what makes the twin safe to transform at all.
  5. Forward models never contain inference. One seam turns any twin into f(params) -> prediction, and a ParameterSpace re-parameterizes without ever editing an operator.
  6. Interfaces first, physics second. A placeholder body may ship; its contract may not be one. Real physics replaces bodies, never interfaces.
  7. Loud failure over silent wrongness. Chasing 0.1 % systematics, a wrong number is worse than an exception.
  8. The core is domain-agnostic. rheplicant.core never imports the radio layer, and a test enforces it.

Each is argued at length in the documentation; Status says which operators are still placeholders.

Install

# limTOD carries the sky engines and is a dependency, not an extra. It is on
# PyPI as of 1.10.0, so it comes with the install.
pip install rheplicant
pip install "rheplicant[cal]"     # + the noise-wave model (rhino-cal-jax)

# or, for development:
git clone https://github.com/RHINO-Experiment/rheplicant
cd rheplicant && uv sync --frozen   # NOT plain `uv sync` -- see below

Requires Python ≥ 3.11, jax ≥ 0.5, equinox ≥ 0.13. Distribution and import name are the same: rheplicant. Full instructions, the four extras and the two-session test split are on the install page.

Seeing it work

The snippet above is the whole shape of it: provide operators, let the graph compose them, call the result. What that twin then plugs into — gradients, NUTS posteriors, Fisher forecasts, exact conjugate draws, neural surrogates — is one worked example carried end to end in the guided tour, and fourteen runnable scripts with measured wall clocks in examples/.

What is in the box

Layer What lives there
Core State, the three combinators, SignalGraph + assemble, and Assembly.replace_node / .without to swap or drop a stage by node id. Domain-agnostic — a test enforces the layering.
Radio A 32-node canonical signal path for a single-antenna experiment, a modular sky engine (a differentiable limTOD port plus a drift-scan m-mode fast path agreeing with it to roundoff), and linear analysis filters.
Inference One noise model read by the likelihood, the weights, the Fisher matrix and the NumPyro scale alike; gradient and conjugate engines; SamplingPlan to partition a model into blocks whose engine is derived rather than restated; streaming evidence for campaigns whose data is gone.

Per-operator detail is the operator catalog; every signature is the API reference.

Documentation

rheplicant.readthedocs.io — the guided tour, the operator catalog, the inference rules, the tutorials, the API, the architecture decisions and the changelog, with a sidebar that lists them. Build it locally with cd docs && ../.venv/bin/python -m sphinx -n -b html . _build/html.

Design decisions D1–D32 and the physics roadmap are in DESIGN.md; what arrived when is in CHANGELOG.md.

Status

The architecture and inference layer are complete and tested end-to-end (2767 tests, 82.0 % coverage, jit+grad+vmap through the full twin; assembly is regression-tested bitwise against hand-built composition). Radio operator physics is deliberately placeholder where the docstring says so — 15 of the 28 concrete rheplicant.radio operator classes — pending ports from limTOD and friends. The other twelve no longer carry that wording: the sky engines are real (a general differentiable limTOD port and a drift-scan m-mode fast path that agrees with it to float64 roundoff while running ~1000x faster on RHINO's geometry — see sky engines), and so are the horizon split, the horn's ohmic loss, the noise-wave reflection terms of the noise-wave data model, the CW calibration tone, and the separable-basis antenna temperature; the Touchstone and RHINO-HDF5 readers are an ingestion layer, not a stand-in for one.

Three of the fifteen are load-bearing even so. ReceiverOperator, GainOperator and CalLoadOperator have placeholder bodies — no flicker, no measured band shape, no load reflection or telemetry — but real shape and contract: the receiver module's unit_mean_bandpass / unit_mean_free are the bandpass/gain identifiability convention, the gain's exact linearity in gain is what Latent(..., linear=True) claims about it, and CWCalibrationOperator.must_precede == ('bandpass', 'gain') names the two nodes the first two occupy. Conventions: degrees in public APIs, radians internally; strings in meta (static), numbers in coords/env/aux (traced); one seed reproduces a run.

No CI yet, and the suite is two pytest sessions rather than one — the evidence layer needs float64 while eighteen tests elsewhere assert refusals that only float32 forces, and jax_enable_x64 is process-global. Plain pytest runs both for you. That split is also why the reported coverage is 82 % rather than the 99.7 % it was before the evidence layer landed: the second session runs --no-cov, so its 467 passing tests contribute nothing to the default report, and 1091 of its 1111 uncovered statements are the nine files that session covers.

uv sync and uv run need --frozen. Commands, reasons and the rest of the setup are in Install.

Developers and maintainers

  • Zheng Zhang
  • Phil Bull
  • Jordan Norris
  • Rashi Srivastava

License

MIT

Download files

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

Source Distribution

rheplicant-0.2.0.tar.gz (2.3 MB view details)

Uploaded Source

Built Distribution

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

rheplicant-0.2.0-py3-none-any.whl (443.2 kB view details)

Uploaded Python 3

File details

Details for the file rheplicant-0.2.0.tar.gz.

File metadata

  • Download URL: rheplicant-0.2.0.tar.gz
  • Upload date:
  • Size: 2.3 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for rheplicant-0.2.0.tar.gz
Algorithm Hash digest
SHA256 c39f91275b237ec47d486da19c5477300f169fabb8f49c8bf738a902563c884f
MD5 4379c56e5444e91bce2a3b9f022b8876
BLAKE2b-256 ece65914052a382dd408c34150547e29d004be554bfbb0a0fdd255ee4289d288

See more details on using hashes here.

Provenance

The following attestation bundles were made for rheplicant-0.2.0.tar.gz:

Publisher: publish.yml on RHINO-Experiment/rheplicant

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rheplicant-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: rheplicant-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 443.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for rheplicant-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e187cb24de7774360e3eb663bca95149e590a3dca0d48ff26a898642854d11a9
MD5 d4e5debcee84cfe6fd1d0a08934bebee
BLAKE2b-256 64ab1b3c0f22864347955f93526d0351fc7012f36d2c2d8c295d936021cc05ed

See more details on using hashes here.

Provenance

The following attestation bundles were made for rheplicant-0.2.0-py3-none-any.whl:

Publisher: publish.yml on RHINO-Experiment/rheplicant

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 files

0.1.4

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 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