Skip to content

Repository files navigation

jittermap

PyPI License: GPL v3 Documentation Status

Documentation: jittermap.readthedocs.io

The sunspot groups of Carrington rotation 2156 mapped onto a young active Sun, rotating at three labeled inclinations

Overview

Developed by Jamila Taaki (STScI).

jittermap is a Python library for stellar surface mapping from astrometric jitter and photometry. It is the reference implementation of the methods developed in the paper:

Taaki, J. S., Corrales, L., & Hero, A. O. III (2026), "Using Astrometry to Break Degeneracies in Stellar Surface Mapping", ApJ 1003, 226. doi:10.3847/1538-4357/ae66f7 (arXiv:2601.11737)

The forward model, the astrometric/photometric moment kernels, the Wigner rotation formulation, the identifiability results, and the reconstruction approach implemented here are all derived in that paper. If you use jittermap, or code or results derived from it, in published work, please cite the paper (see Citing below).

Astrometric jitter arises when starspots on a rotating stellar surface move in and out of view, shifting the observed photocenter; this jitter is a noise floor for detecting small exoplanets, but it also carries information about the stellar surface itself. An interactive visualizer of how spot jitter contaminates the true reflex motion of a star with an orbiting planet is available at xiaziyna.github.io/astrometry_visualizer.html.

jittermap implements a linear forward model for the astrometric jitter and photometric signals of a rotating star in a spherical-harmonic coordinate system, together with the inverse problem: reconstructing surface-brightness maps (and estimating the stellar inclination) from those time series. Astrometry and photometry probe complementary halves of the surface: photometry measures even-degree spherical harmonic modes, symmetric about the equator, while astrometry measures odd-degree modes. Their joint use breaks degeneracies inherent to either channel alone.

The forward model factors per spherical-harmonic degree l as

y_c(t) = Re[ B(t) C(beta) a_c,l  s_l ],     c in {x, y, photometry}

where s are the complex SH surface coefficients, a_c,l are visible-hemisphere moment kernels, and B(t), C(beta) are Wigner-D rotation blocks for the spin phase and inclination. Both rotation blocks are phase-diagonal modulations of a single fixed matrix per degree, M_l = D^l(pi/2, pi/2, pi/2), which jittermap ships as precomputed numeric tables up to L = 40, with no symbolic algebra or compilation at runtime.

Performance

All of the heavy math is precomputed and cached. The Wigner rotation tables and the moment kernels ship with the package as exact numeric arrays (derived in 50-digit arithmetic, tabulated to L = 40), so the forward model and the inversion reduce to small dense matrix products at runtime and are exact to double precision.

Measured timings (single CPU core):

task time
simulate astrometry + photometry (L=10, 100 epochs) ~20 ms
surface fit, known inclination ~30 ms
surface + inclination fit ~2 s
forward model at L=40 ~0.5 s

The package depends only on numpy, scipy, sympy, and matplotlib, with no compilation step. It models the astrometric jitter channel, which photometry-only mapping tools do not provide. On the photometric channel, where a direct comparison exists, it assembles the L = 30 forward operator about 7x faster than starry v1.2 (2.3 ms vs 16 ms, both warm; see examples/benchmark_vs_starry.py). This throughput is what makes the reconstruction galleries in the paper and the Monte Carlo studies the model was built for practical: thousands of candidate surfaces, inclinations, and noise realizations rather than a single fit.

Installation

pip install jittermap

or, for the development version:

pip install git+https://github.com/xiaziyna/jittermap

Dependencies: numpy, scipy, sympy, matplotlib.

Quickstart

import numpy as np
import jittermap as jm

# A two-spot surface at degree L=10 with light small-scale texture
s_true = jm.multispot_surface([(30, 315, 18.0), (-15, 30, 13.0)], l_max=10,
                              texture_amplitude=0.002, texture_seed=3)

# Forward model: N uniform samples over one rotation, inclination 0.6 rad
times = np.linspace(0, 2 * np.pi, 100, endpoint=False)
fm = jm.ForwardModel(times, l_max=10)
y = fm.observe(s_true, inclination=0.6, channels="xyp", stacked=False)

# Inverse problem: joint astrometry + photometry MAP reconstruction,
# with the inclination estimated by profile grid search
result = jm.reconstruct(y, times, l_max=10, channels="xyp")
print(result.inclination)   # ~0.6
s_hat = result.s_hat

Reconstruction from single channels (channels="xy" for astrometry only, "p" for photometry only) exposes the null spaces of each: photometry alone cannot localize spots in latitude against the inclination ambiguity, while astrometry alone accesses the odd-degree modes photometry misses.

Truth vs joint, astrometry-only and photometry-only reconstructions

Tutorials and documentation

Five executed notebook tutorials in notebooks/ walk through the library and reproduce the key results of the paper:

  1. Surfaces: spherical-harmonic representation, analytic cap spots, GMRF textures, rendering at different inclinations.
  2. Forward model: astrometric jitter and photometric signals vs. inclination and spot latitude (paper Figs. 2–3), including the pole-on circularization worst case.
  3. Kernels: the odd/even selection rules, and a machine-precision demonstration of the photometric null space that astrometry breaks.
  4. Reconstruction: joint vs. single-channel MAP inversion, noise and regularization, and the identifiable subspace.
  5. Inclination & Fourier: the profile objective (photometric inclination ambiguity made visible) and lossless frequency-comb compression.
  6. Truncation: a sharp L = 40 surface and its L = 20 truncation produce the same observable signals to a fraction of a percent, so a modest fit degree captures everything the data can see.

The full documentation (theory summary with the paper's equations mapped to the API, tutorials, examples, API reference) builds with sphinx from docs/ and is ReadTheDocs-ready (.readthedocs.yaml).

Organization

jittermap
├── jittermap
│   ├── harmonics          # surface representation
│   │   ├── indexing.py    #   SH indexing, real-surface transform
│   │   ├── spots.py       #   analytic cap starspots (no external deps)
│   │   └── surfaces.py    #   multi-spot maps, GMRF random textures
│   ├── forward            # surface -> observables
│   │   ├── kernels.py     #   astrometric + photometric moment kernels
│   │   ├── wigner.py      #   Wigner rotation operators (numeric M_l cache)
│   │   ├── design.py      #   design matrices; fast Vandermonde path
│   │   ├── fourier.py     #   frequency-comb compression of uniform sampling
│   │   └── build_cache.py #   cache builder (python -m jittermap.forward.build_cache)
│   ├── inference          # observables -> surface
│   │   ├── inversion.py   #   GMRF-regularized MAP / ridge solvers
│   │   ├── inclination.py #   profile-objective inclination estimation
│   │   └── reconstruct.py #   high-level joint reconstruction
│   ├── star_physics       # beyond the uniform rigid disk
│   │   └── limb_darkening.py  # laws as mu power series; darkened kernel tables
│   ├── plotting
│   │   ├── render.py      #   visible-hemisphere rendering
│   │   ├── panels.py      #   truth-vs-reconstruction comparison figures
│   │   └── animate.py     #   spin animations
│   └── data               # shipped caches: Wigner M_l to L=40, kernels
├── examples
├── notebooks          # executed tutorial notebooks
├── tests
└── docs

Precomputed caches

The Wigner tables (data/wigner, ~0.4 MB) are exact: each M_l is computed from the Wigner sum formula at beta = pi/2 in 50-digit arithmetic and rounded once to complex128. Kernel tables (data/kernels) cover the astrometric and photometric moments to l = 40. Higher degrees are computed on demand and cached per user, or in bulk via

python -m jittermap.forward.build_cache --lmax 60
python -m jittermap.forward.build_cache --photo 60

Citing

jittermap is based on the work in Taaki, Corrales & Hero (2026). If you use this library, any part of its code, or results produced with it in your research, please cite the paper:

Taaki, J. S., Corrales, L., & Hero, A. O. III 2026, "Using Astrometry to Break Degeneracies in Stellar Surface Mapping", The Astrophysical Journal, 1003, 226. doi:10.3847/1538-4357/ae66f7 (arXiv:2601.11737)

@article{Taaki2026jittermap,
  author  = {Taaki, Jamila S. and Corrales, Lia and Hero, Alfred O., III},
  title   = {Using Astrometry to Break Degeneracies in Stellar Surface Mapping},
  journal = {The Astrophysical Journal},
  year    = {2026},
  volume  = {1003},
  number  = {2},
  pages   = {226},
  doi     = {10.3847/1538-4357/ae66f7},
  eprint  = {2601.11737},
  archivePrefix = {arXiv}
}

A machine-readable citation is provided in CITATION.cff; GitHub's "Cite this repository" button uses it directly. jittermap is GPL-3.0 licensed: derivative works must retain the copyright and license notices.

License

jittermap is released under the GNU General Public License v3.0.

About

Map stellar surfaces with astrometry or photometry. Solve for stellar inclinations. Forward model + fast Inversion.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages