JAX-native astrophysical scene modeling for HWO direct imaging.
skyscapes provides the scene representation that downstream HWO
simulation tools consume — a forward model that runs at variable
fidelity, from analytic sandbox models for fast iteration up to
research-grade physics for retrievals. High-fidelity scene generators
like ExoVista feed into
skyscapes through loaders (from_exovista); skyscapes does not try to
replace them.
- A
Sceneis "everything on the sky that the telescope sees" — oneSystem(a star with planets and optionally a disk) plus optional background sources (zodiacal light, background galaxies, etc.). - Source models (
Star,Planet,Disk, physical models, backgrounds) are composableeqx.Modules — swap any one without touching the rest, or swap the whole class for a higher-fidelity variant. - Loaders bridge external simulation outputs (ExoVista FITS) into the
workspace via
from_exovista(...).
The same Scene flows through both the
coronagraphoto image
simulator and the jaxEDITH
ETC, so the astrophysical content is consistent across all downstream
science products.
- Not a radiative transfer engine. The
ExoJaxPhysicalModelis a thin adapter over ExoJAX; skyscapes does not implement its own RT. - Not an orbit propagator. Orbital mechanics live in
orbix;
Planetcomposes anAbstractOrbitrather than reimplementing one. - Not a simulator. Downstream tools
(coronagraphoto,
jaxEDITH) consume a
Sceneto produce images / count rates.
flowchart LR
src["External sources<br/>ExoVista · spectra · catalogues"]
sky(["<b>skyscapes</b><br/>Scene · System · Star · Planet · Disk · Zodi · PhysicalModel"])
opt["<b>optixstuff</b><br/>OpticalPath"]
cor["<b>coronagraphoto</b><br/>2D image simulation"]
jet["<b>jaxedith</b><br/>Scalar count rates"]
src --> sky
sky --> cor
sky --> jet
opt --> cor
opt --> jet
A Scene composes a System (star + planets + optional disk) with an
optional Zodi background:
- Stars —
Star(wavelength- and time-dependent spectrum, ExoVista- backed) andFlatStar(constant-flux sandbox). - Planets —
Planetowns intrinsic params (Rp_Rearth,Mp_Mearth) and composes anAbstractOrbit(from orbix) with anAbstractPhysicalModel. - Physical models —
LambertianPhysicalModel,GridPhysicalModel(interpolated contrast cubes, used by ExoVista loader),PrecomputedPhysicalModel(cached reflectivity for hot loops), andExoJaxPhysicalModel(full 2-stream RT via ExoJAX). - Disks —
ExovistaDisk,ExovistaParametricDisk,GraterDisk,CompositeDisk. - Backgrounds —
AYOZodi(AYO-convention defaults),LeinertZodi(full position-dependent Leinert+1998),PrecomputedZodi(cached flux array).
Every leaf is an eqx.Module PyTree, so JAX transforms (jit, vmap,
grad) compose end-to-end.
The easiest path is loading an ExoVista FITS file:
from skyscapes import from_exovista
scene = from_exovista("path/to/exovista_system.fits")Building one from scratch:
import jax.numpy as jnp
from orbix.system.orbit import KeplerianOrbit
from skyscapes import Scene, System
from skyscapes.scene import FlatStar, Planet
from skyscapes.physical_model import LambertianPhysicalModel
from skyscapes.background import AYOZodi
star = FlatStar(
Ms_kg=1.989e30,
dist_pc=10.0,
flux_phot_per_nm_m2=1e9,
)
orbit = KeplerianOrbit(
a_AU=jnp.array([1.0]),
e=jnp.array([0.0]),
W_rad=jnp.array([0.0]),
i_rad=jnp.array([jnp.pi / 3]),
w_rad=jnp.array([0.0]),
M0_rad=jnp.array([0.0]),
t0_d=jnp.array([0.0]),
)
physical_model = LambertianPhysicalModel(Ag=jnp.array([0.3]))
planet = Planet(
Rp_Rearth=jnp.array([1.0]),
Mp_Mearth=jnp.array([1.0]),
orbit=orbit,
physical_model=physical_model,
)
zodi = AYOZodi(
wavelengths_nm=jnp.linspace(400, 1000, 60),
surface_brightness_mag=22.0,
)
scene = Scene(
system=System(star=star, planets=(planet,)),
zodi=zodi,
)pip install skyscapesThis package is in early development.