Skip to main content

spice logo

SPICE: SPectral Integration Compiled Engine

A comprehensive Python library for modeling and analyzing stellar spectra with inhomogeneous surfaces, supporting rotation, pulsations, spots, and binary star systems.

The paper is submitted and available as a preprint.

Installation

Install from PyPI:

pip install stellar-spice

For PHOEBE integration support:

pip install stellar-spice[phoebe]

For zarr-backed model-atmosphere grid interpolation (LazyZarrInterpolator and friends):

pip install stellar-spice[grid]

Documentation

📖 Read the full documentation for detailed API reference and tutorials.

Key Features

🌟 Stellar Surface Modeling

  • Mesh-based stellar surfaces using icosphere discretization
  • Inhomogeneous temperature distributions across stellar surfaces
  • Surface gravity variations accounting for rotation and shape distortions
  • Line-of-sight velocity calculations for Doppler shift effects

🔄 Stellar Rotation

  • Solid-body (rigid) rotation with a configurable axis and equatorial velocity
  • Rotational broadening effects on spectral lines
  • Surface velocity field calculations
  • Time-dependent spectral variations due to rotation

🌊 Stellar Pulsations

  • Spherical harmonic pulsation modes (l, m modes)
  • Fourier series parameterization for complex pulsation patterns
  • Multi-mode pulsations with different periods and amplitudes
  • Surface displacement and velocity calculations

🌑 Stellar Spots

  • Spherical harmonic spot modeling for complex spot distributions
  • Temperature contrast between spots and photosphere
  • Time-evolving spot patterns
  • Spot-induced spectral variations

⭐ Binary Star Systems

  • Full orbital dynamics with Keplerian orbits
  • Mutual eclipses and occultations resolved on the projected meshes
  • PHOEBE integration — import Roche-lobe geometry and tidally distorted binary meshes computed by PHOEBE

📊 Spectral Synthesis

  • Blackbody radiation for basic stellar modeling
  • Model-atmosphere grid interpolation from precomputed, zarr-backed grids
  • Analytic line-profile emulators (Gaussian and physical)
  • Transformer-Payne integration for ML-based spectral synthesis
  • Custom spectral models via the SpectrumEmulator interface

🔍 Synthetic Photometry

  • Multiple passband support (Johnson, Stromgren, Gaia, etc.)
  • AB magnitude system calculations
  • Bolometric luminosity computations
  • Time-series photometry for variable stars

🎯 Advanced Features

  • JAX-based computations for fast, differentiable calculations
  • GPU acceleration support
  • 3D visualization of stellar surfaces and binary systems
  • Animation capabilities for time-evolving systems
  • Occlusion handling for complex geometries

Quick Start

Basic Stellar Model

import numpy as np
from spice.models import IcosphereModel
from spice.models.mesh_transform import add_rotation
from spice.spectrum import simulate_observed_flux, Blackbody

bb = Blackbody()

# Create a solar-like star
star = IcosphereModel.construct(
    n_vertices=1000,                 # Mesh resolution (number of vertices)
    radius=1.0,                      # Solar radii
    mass=1.0,                        # Solar masses
    parameters=bb.solar_parameters,
    parameter_names=bb.parameter_names,
)

# Add solid-body rotation (equatorial velocity in km/s)
star = add_rotation(star, rotation_velocity=2.0)

# Generate the disc-integrated spectrum. simulate_observed_flux expects *log10*
# wavelengths and returns an (n_wavelengths, 2) array whose columns are the
# disc-integrated emulator channels (flux and continuum; column 0 is the flux).
wavelengths = np.logspace(3, 4, 1000)            # 1000-10000 Å
flux = simulate_observed_flux(bb.intensity, star, np.log10(wavelengths))

Binary Star System

import numpy as np
import jax.numpy as jnp
from spice.models import IcosphereModel, Binary
from spice.models.binary import add_orbit, evaluate_orbit_at_times
from spice.models.mesh_view import get_mesh_view
from spice.spectrum import simulate_observed_flux, Blackbody, AB_passband_luminosity
from spice.spectrum.filter import GaiaG

bb = Blackbody()
los = jnp.array([0.0, 1.0, 0.0])  # line of sight

# Create binary components (cast to the line of sight for occlusion handling)
primary = get_mesh_view(
    IcosphereModel.construct(1000, 1.0, 1.0, bb.solar_parameters, bb.parameter_names), los)
secondary = get_mesh_view(
    IcosphereModel.construct(1000, 0.8, 0.8, bb.solar_parameters, bb.parameter_names), los)

# Assemble the system
binary = Binary.from_bodies(primary, secondary)

# Add orbital elements
binary = add_orbit(
    binary,
    P=1.0,                    # orbital period [years]
    ecc=0.1,                  # eccentricity
    T=0.0,                    # time of periastron passage [years]
    i=np.pi / 3,              # inclination [rad]
    omega=0.0,                # argument of periastron [rad]
    Omega=0.0,                # longitude of the ascending node [rad]
    mean_anomaly=0.0,         # mean anomaly at the reference time [rad]
    reference_time=0.0,       # reference time [years]
    vgamma=0.0,               # systemic velocity [km/s]
    orbit_resolution_points=50,
)

# Evaluate the orbit across phases (eclipses/occlusions resolved internally)
times = jnp.linspace(0.0, 1.0, 100)
primaries, secondaries = evaluate_orbit_at_times(binary, times)

# Combined Gaia G-band light curve
wavelengths = np.linspace(900, 40000, 1000)
gaia_g = GaiaG()
light_curve = [
    AB_passband_luminosity(
        gaia_g,
        wavelengths,
        simulate_observed_flux(bb.intensity, p1, np.log10(wavelengths))[:, 0]
        + simulate_observed_flux(bb.intensity, p2, np.log10(wavelengths))[:, 0],
    )
    for p1, p2 in zip(primaries, secondaries)
]

PHOEBE Integration

import numpy as np
import phoebe
from phoebe.parameters.dataset import _mesh_columns
from spice.models import PhoebeBinary
from spice.models.binary import evaluate_orbit
from spice.models.phoebe_utils import PhoebeConfig
from spice.spectrum import simulate_observed_flux, Blackbody

bb = Blackbody()

# Build a PHOEBE binary and compute a mesh dataset (standard PHOEBE workflow)
b = phoebe.default_binary()
times = np.linspace(0, 1, 10)
b.add_dataset('mesh', compute_times=times, columns=_mesh_columns, dataset='mesh01')
b.run_compute(coordinates='uvw', overwrite=True)

# Wrap the PHOEBE meshes for SPICE (PHOEBE models are read-only inside SPICE)
config = PhoebeConfig(b, 'mesh01')
pb = PhoebeBinary.construct(config, ['teff', 'logg', 'abun'])

# Evaluate the components at a snapshot time, then synthesise the spectrum
primary, secondary = evaluate_orbit(pb, config.times[0])
wavelengths = np.logspace(3, 4, 1000)
flux = simulate_observed_flux(bb.intensity, primary, np.log10(wavelengths))

Performance

  • JAX-powered computations for fast, vectorized operations
  • GPU acceleration support for large-scale calculations
  • Efficient mesh operations with optimized occlusion algorithms
  • Memory-efficient spectral synthesis for time-series data

Known internals caveat

Mesh area conventions (slated for cleanup)

MeshModel currently exposes two area arrays that follow different unit conventions:

Property Convention Sum over the mesh
m.areas / m.base_areas unit-sphere normalised ≈ 4π for any R
m.cast_areas / m.visible_cast_areas physical R⊙² ≈ 4π R² / ≈ π R²

Any code that integrates over the stellar surface must apply the matching cgs prefactor:

  • simulate_observed_flux integrates m.visible_cast_areas (already in R⊙²) and applies only the dimensionless dilution (R⊙ / pc)² / d_pc².
  • simulate_monochromatic_luminosity integrates m.areas (unit-sphere) and applies R² × R⊙²[cm²] to convert to cgs.

If you add a new integrator over either array, mirror the matching pattern. This convention asymmetry is a known maintainability hazard and is slated for future cleanup: once m.areas is normalised the same way as m.visible_cast_areas, the cgs prefactor in simulate_monochromatic_luminosity should be reduced to R⊙²[cm²] only, matching the structure of simulate_observed_flux.

Citation

If you use stellar-spice in your research, please cite:

@misc{spice,
      title={SPICE -- modelling synthetic spectra of stars with non-homogeneous surfaces}, 
      author={M. Jabłońska, T. Różański, L. Casagrande, H. Shah, P. A. Kołaczek-Szymański, M. Rychlicki and Yuan-Sen Ting},
      year={2025},
      eprint={2511.10998},
      archivePrefix={arXiv},
      primaryClass={astro-ph.SR},
      url={https://arxiv.org/abs/2511.10998}, 
}

Contributing

We welcome contributions! Please see our contributing guidelines for details.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

  • Built with JAX for fast, differentiable computations
  • Integrates with PHOEBE for binary star modeling
  • Uses Transformer-Payne for ML-based spectral synthesis

A preprint describing SPICE is available on arXiv. See Citation if you use it in your work.

Metadata

Release files for stellar-spice 1.8.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for stellar-spice 1.8.0
File Size Uploaded
stellar_spice-1.8.0.tar.gz 595.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for stellar-spice 1.8.0
File Interpreter ABI Platform
stellar_spice-1.8.0-py3-none-any.whl Python 3 none any Details

Total release size: 1.2 MB

Release files / stellar_spice-1.8.0.tar.gz

Download URL stellar_spice-1.8.0.tar.gz
Size 595.5 kB
Tags Source
SHA-256 checksum
How to use checksums
f9be0a6a4b119aea6a820f823f3504585528a2e41ac72dd41d7f920f62278f78
BLAKE2b-256 checksum
How to use checksums
ae5c35a6c4d638fae86e18dcccd6ab2ca701242c258183ad741d44e635449bc7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 27, 2026.

Transparency log

Release files / stellar_spice-1.8.0-py3-none-any.whl

Download URL stellar_spice-1.8.0-py3-none-any.whl
Size 591.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
48e8734c0cb41e2ea9ce471e229f19dfe31d245177a8f8bcafa91438ef5be9cd
BLAKE2b-256 checksum
How to use checksums
916aeaad5b0fe5d22c74f150c84b7660ced3303846e7fc09fb170337cf17e91e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 27, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.8.0 This release

2 release files

1.6.1

2 release files

1.5.7

2 release files

1.5.6

2 release files

1.5.5

2 release files

1.5.4

2 release files

1.5.3

2 release files

1.5.2

2 release files

1.5.1

2 release files

1.5.0

2 release files

1.4.2

2 release files

1.4.1

2 release files

1.4.0

2 release files

1.3.1

2 release files

1.3.0

2 release files

1.2.3

2 release files

1.2.2

2 release files

1.2.1

2 release files

1.2

2 release files

1.1

2 release files

1.0

2 release 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