Documentation: jacotay7.github.io/pyturb
Fast, GPU-optional atmospheric turbulence for adaptive optics.
pyturb generates the optical path differences (OPD) that an adaptive-optics
system sees through the atmosphere: full layered turbulence for a
representative sky, with per-layer wind, frozen-flow time evolution,
off-axis directions, and standard site profiles. It runs on NumPy by default
and switches to CUDA (via CuPy) with a single argument.
pip install pyturb # CPU (NumPy + SciPy)
pip install pyturb[cuda12] # + CuPy for CUDA 12.x
pip install pyturb[cuda11] # + CuPy for CUDA 11.x
pip install pyturb[accel] # + Numba, faster CPU frozen flowimport pyturb
atm = pyturb.Atmosphere.from_profile(
"paranal-median", seeing=0.8, zenith_angle=30, diameter=8.0, n=512, seed=1
)
print(atm.r0, atm.theta0, atm.tau0) # Fried param, isoplanatic angle, tau0
for t, opd in atm.frames(dt=1e-3, steps=2000):
... # (512, 512) OPD [m], frozen flow
ensemble = atm.sample(256) # (256, 512, 512) Monte-Carlo OPDs
atm = pyturb.Atmosphere.from_profile("paranal-median", seeing=0.8, device="gpu")
for t, opd in atm.frames(dt=1e-3, steps=2000):
... # cupy arrays, ~3,200 fps at 512^2See Quickstart for
off-axis/tomography, boiling, LGS, non-periodic frozen flow, and the
lower-level PhaseScreen/InfinitePhaseScreen building blocks; and
Concepts for r0, L0, Cn²,
θ0 and τ0 if you're new to AO.
Full 9-layer Paranal atmosphere, closed-loop OPD frames/s, on an RTX 5090
(GPU) and a 32-core CPU (pyturb[accel]). The exact raw artifact and invocation
are versioned with the benchmarks:
| screen | GPU spectral | GPU extrude | GPU Monte-Carlo screens/s | CPU spectral | CPU extrude |
|---|---|---|---|---|---|
| 256² | 3,219 | 4,489 | 104,981 | 1,014 | 2,571 |
| 512² | 3,133 | 1,733 | 29,789 | 283 | 324 |
| 1024² | 1,492 | 602 | 5,970 | 70 | 62 |
The Monte-Carlo column is Atmosphere.sample() — the full 9-layer atmosphere.
Layers that share an outer scale are drawn as one aggregate screen (their PSDs
add exactly), so a uniform-L0 profile costs one FFT, not nine: sample() now
runs at nearly the single-layer PhaseScreen.generate rate (30,629 512²
screens/s on the GPU, 108,054 at 256²). All Monte-Carlo figures are batched,
device-resident throughput (a batch of 64 kept on the GPU); a single default
call, or one that copies its result back to the host, is lower. Run
python -c "import pyturb; pyturb.benchmark()" on your own machine, or
python benchmarks/bench_suite.py for the full per-use-case sweep. A
head-to-head against aotools, soapy and HCIPy lives in
Comparison.
- Layered
Atmosphere— named site profiles (paranal-median,mauna-kea,keck,las-campanas, HV 5/7, ...) or a customCn²(h)model, summed to pupil OPD with per-layer wind and airmass/zenith scaling. - Two frozen-flow engines —
engine="spectral"(default): exact sub-pixel shift-theorem translation, all layers in one FFT, periodic.engine="extrude": Assémat–Wilson row extrusion, unbounded and non-periodic. Both use fused CUDA/Numba kernels on the hot path. - Off-axis / tomography —
atm.opd(t, directions=[...])batches several guide-star directions through one call. - Boiling — temporal decorrelation on top of frozen flow (
tau_boil). - LGS cone effect — finite-range sodium beacon focal anisoplanatism
(
lgs_altitude). - Chromatic OPD — achromatic by default;
dispersion="edlen"/"ciddor"for the dry-air/water-vapour term. - Diagnostics (
pyturb.analysis) — Zernike decomposition, Noll (1976) mode variances, temporal PSD + power-law fit, angular decorrelation. - I/O —
pyturb.save/pyturb.loadfor FITS (optional astropy) and.npz, with provenance metadata. - GPU-optional — every class takes
device="gpu"(CuPy); the GPU path is statistically identical to CPU (validated against the same theory to numerical precision). CuPy and NumPy have independent RNG streams, so a givenseeddraws a different realisation on each backend — the guarantee is matched statistics, not a bit-for-bit copy. - Validated against theory — structure function, Zernike spectrum, temporal PSD and angular decorrelation checked against analytic predictions in CI; see Validation.
See the API reference for every public function and class, and Interop for recipes with HCIPy, poppy, and DM-fitting loops.
MIT
