API Reference (spotgp)

Contents

API Reference (spotgp)#

Lightcurve Model#

class spotgp.lightcurve.LightcurveModel(peq=4.0, kappa=0.0, inc=1.5707963267948966, nspot=None, tau_spot=None, tem=2, tdec=2, alpha_max=0.1, fspot=0, lspot=5, long=[0, 6.283185307179586], lat=[-1.5707963267948966, 1.5707963267948966], tsim=28, tsamp=0.02, limb_darkening=False, tmax=None, rotate=True, grow=True, nspot_rate=None)[source]#

Bases: object

JAX-accelerated star with spots and its lightcurve.

Same interface as the numpy version but uses JAX for vectorized computation across all spots simultaneously.

Parameters:
  • peq (float) – Equatorial period of the star.

  • kappa (float) – Differential rotation shear.

  • inc (float) – Inclination of the star.

  • nspot (int) – Number of spots.

  • tau_spot (float, optional) – Timescale for both emergence and decay of the spots. Defaults to None.

  • tem (float, optional) – Emergence timescale of the spots. Defaults to 2.

  • tdec (float, optional) – Decay timescale of the spots. Defaults to 2.

  • alpha_max (float, optional) – Maximum angular area of the spots. Defaults to 0.1.

  • fspot (float, optional) – Spot contrast fraction. Defaults to 0.

  • lspot (float, optional) – Spot lifetime. Defaults to 5.

  • long (list, optional) – Range of spot longitudes. Defaults to [0, 2*pi].

  • lat (list, optional) – Range of spot latitudes. Defaults to [0, pi].

  • tsim (float, optional) – End simulation time. Defaults to 28.

  • tsamp (float, optional) – Sampling cadence. Defaults to 0.02.

  • limb_darkening (bool, optional) – Flag to enable limb darkening. Defaults to False.

classmethod from_spot_model(spot_model: SpotEvolutionModel, nspot: int = None, *, nspot_rate: float = None, **kwargs)[source]#

Construct a LightcurveModel from a SpotEvolutionModel.

Parameters:
  • spot_model (SpotEvolutionModel) – Fully configured spot evolution model.

  • nspot (int, optional) – Total number of spots to simulate.

  • nspot_rate (float, optional) – Spot emergence rate [spots/day]. The actual number of spots is max(1, int(nspot_rate * tsim)). Exactly one of nspot or nspot_rate must be provided.

  • **kwargs – Forwarded to LightcurveModel.__init__ (e.g. tsim, tsamp, lat, long).

Return type:

LightcurveModel

classmethod from_hparam(hparam: dict, nspot: int = None, *, nspot_rate: float = None, **kwargs)[source]#

Construct a LightcurveModel from a GPSolver-compatible hparam dict.

Accepts the same raw hparam dict that GPSolver/AnalyticKernel take, including all amplitude modes (sigma_k, nspot_rate, or nspot), and both symmetric (tau) and asymmetric (tau_em + tau_dec) envelopes. This removes the need to manually decompose the dict in scripts.

Parameters:
  • hparam (dict) – Raw hyperparameter dict. Must contain peq, kappa, inc, lspot, tau_spot (or tau_em/tau_dec), and an amplitude specification.

  • nspot (int, optional) – Total number of spots to simulate.

  • nspot_rate (float, optional) – Spot emergence rate [spots/day]. Exactly one of nspot or nspot_rate must be provided.

  • **kwargs – Forwarded to LightcurveModel.__init__ (e.g. tsim, tsamp, lat, long).

Return type:

LightcurveModel

Flux(teval)[source]#

Compute the full lightcurve using JAX vmap over all spots.

Instead of a Python loop over nspot, all spots are computed in parallel via JAX’s vmap.

plot_lightcurve(show_spots=True, show_title=True)[source]#

Plot the lightcurve.

animate_lightcurve(fps=30, duration=10.0, outfile=None, dpi=150, show_spots=True, show_grid=True, show_params=True, figsize=(14, 5.5), save_last_frame=None, show_dr=True, label_size=18)[source]#

Animate the starspot evolution with two panels: a 2D projection of the rotating star (left) and the lightcurve (right).

Parameters:
  • fps (int) – Frames per second (default 30).

  • duration (float) – Animation duration in seconds (default 10).

  • outfile (str or None) – Output file path (.mp4 or .gif). If None, returns the animation object without saving.

  • dpi (int) – Resolution (default 150).

  • show_spots (bool) – If True, show individual spot contributions on the lightcurve panel (default True).

  • show_grid (bool) – If True, draw latitude/longitude grid on the star (default True).

  • show_params (bool) – If True, show parameter annotation on the lightcurve panel (default True).

  • figsize (tuple) – Figure size (default (14, 5.5)).

  • save_last_frame (str or None) – If provided, save the last frame of the animation as a static image to this file path (e.g. “frame.png”).

  • show_dr (bool) – If True, color the stellar disk by latitude-dependent rotation frequency and display a colorbar (default True).

  • label_size (int or float) – Font size for all labels, tick marks, and text in the plot (default 18).

Returns:

anim – The animation object.

Return type:

matplotlib.animation.FuncAnimation

animate_butterfly(fps=30, duration=10.0, outfile=None, dpi=150, show_spots=True, show_grid=True, show_params=True, figsize=(18, 5.5), save_last_frame=None, show_dr=True, label_size=18)[source]#

Animate the starspot evolution with three panels: a 2D projection of the rotating star (left), the lightcurve (center), and a butterfly diagram of spot latitude vs. time (right).

Parameters:
  • fps (int) – Frames per second (default 30).

  • duration (float) – Animation duration in seconds (default 10).

  • outfile (str or None) – Output file path (.mp4 or .gif). If None, returns the animation object without saving.

  • dpi (int) – Resolution (default 150).

  • show_spots (bool) – If True, show individual spot contributions on the lightcurve panel (default True).

  • show_grid (bool) – If True, draw latitude/longitude grid on the star (default True).

  • show_params (bool) – If True, show parameter annotation above the figure (default True).

  • figsize (tuple) – Figure size (default (18, 5.5)).

  • save_last_frame (str or None) – If provided, save the last frame of the animation as a static image to this file path (e.g. “frame.png”).

  • show_dr (bool) – If True, color the stellar disk by latitude-dependent rotation frequency and display a colorbar (default True).

  • label_size (int or float) – Font size for all labels, tick marks, and text in the plot (default 18).

Returns:

anim – The animation object.

Return type:

matplotlib.animation.FuncAnimation

Analytic Kernel#

class spotgp.analytic_kernel.AnalyticKernel(model_or_hparam, n_harmonics=3, n_lat=64, lat_range=None, quadrature='trapezoid')[source]#

Bases: object

JAX-accelerated analytic GP kernel for stellar rotation variability.

Parameters:
  • model_or_hparam (SpotEvolutionModel or dict) – Either a SpotEvolutionModel instance (new API) or a raw hparam dict (backward-compatible old API).

  • n_harmonics (int) – Number of Fourier harmonics for the visibility function (default 3).

  • n_lat (int) – Number of latitude quadrature points (default 64).

  • lat_range (tuple) – (min, max) latitude in radians (default (-pi/2, pi/2)).

  • quadrature (str) – Latitude integration method: “trapezoid” or “gauss-legendre”.

omega0(phi)[source]#

Latitude-dependent rotation angular frequency [rad/day].

R_Gamma(lag)[source]#

Autocorrelation of the squared envelope (delegates to envelope).

cn_squared(phi)[source]#

Squared Fourier visibility coefficients at latitude phi.

kernel_single_latitude(lag, phi)[source]#

Single-spot kernel at a fixed latitude.

kernel(lag, lat_dist=None)[source]#

Full GP kernel averaged over latitude.

Uses jax.lax.scan for memory-efficient accumulation: only one lag-sized buffer is live at a time — O(M) instead of O(n_lat·M).

When the visibility function is an EdgeOnVisibilityFunction, the latitude-averaged |c_n|^2 are known constants and the latitude loop is bypassed entirely.

Parameters:
  • lag (array_like) – Time lags [days]. Can be 1D or 2D.

  • lat_dist (callable or None) – Latitude probability density. If None, uniform.

Returns:

K

Return type:

ndarray, same shape as lag input.

kernel_solid_body(lag, lat_dist=None)[source]#

Kernel for solid-body rotation (kappa=0).

compute_psd(omega, lat_dist=None)[source]#

Analytic power spectral density.

Parameters:
  • omega (array_like) – Angular frequencies [rad/day].

  • lat_dist (callable or None) – Latitude probability density.

Returns:

  • freq (ndarray [cycles/day])

  • power (ndarray)

build_jax(n_lag=256)[source]#

Pre-compile and warm up JAX JIT computation for this kernel.

jax.lax.scan (used inside kernel()) triggers XLA compilation on its first call for a given array shape. That compilation can take several seconds and is easy to mistake for slow runtime. Call build_jax() once after constructing the kernel to pay that cost upfront — subsequent calls to kernel() and compute_psd() with the same shape will be fast.

Parameters:

n_lag (int) – Length of the dummy lag array used to drive compilation (default 256). The actual value does not matter as long as it is representative of the sizes you will use at runtime.

Returns:

self – Returns self so the call can be chained: ak = AnalyticKernel(model).build_jax().

Return type:

AnalyticKernel

Numerical Kernel#

class spotgp.numerical_kernel.NumericalKernel(model_or_hparam, tsim=20, tsamp=0.05, nsim=1000.0, verbose=True)[source]#

Bases: object

Gaussian Process for Stellar Rotation

Parameters:
  • hparam (dict) –

    Dict of hyperparameters. Required keys: peq, kappa, inc, lspot, tau_spot, alpha_max. For the kernel amplitude, provide EITHER:

    • sigma_k : overall amplitude prefactor, OR

    • nspot + fspot : number of spots and spot contrast, from which sigma_k is computed as sqrt(N_spot) * (1 - f_spot) / pi.

    Note: nspot is always required for the numerical simulations.

  • tsim (float) – Simulation time (default: 20).

  • tsamp (float) – Time sampling (default: 0.05).

  • nsim (int) – Number of simulations (default: 1e3).

  • verbose (bool) – Whether to print verbose output (default: True).

get_acf()[source]#
compute_psd(tarr=None, freq_min=None, freq_max=None, normalization='psd', nsims=100)[source]#
plot_autocorrelation()[source]#

Plot the autocorrelation function.

Returns: - fig: matplotlib Figure object

spotgp.numerical_kernel.generate_sims(theta, nsim=1000.0, **kwargs)[source]#

Generate synthetic lightcurves for a given set of parameters.

Parameters:
  • theta (tuple) – Tuple containing peq, kappa, inc, and nspot parameters.

  • nsim (int, optional) – Number of simulations. Defaults to 1000.

  • **kwargs – Additional arguments for the StarSpot class.

Returns:

Array of synthetic lightcurves.

Return type:

numpy.ndarray

spotgp.numerical_kernel.avg_covariance_tlag(K)[source]#

GP Solver#

class spotgp.gp_solver.GPSolver(data_or_x, y=None, yerr=None, model_or_hparam=None, kernel_type='analytic', mean=None, fit_sigma_n=False, bounds=None, log_prior=None, matrix_solver='cholesky_banded', bandwidth=None, save_dir=None, **kernel_kwargs)[source]#

Bases: object

JAX-accelerated Gaussian Process solver for stellar lightcurves.

Handles covariance matrix construction, Cholesky factorization, log-likelihood evaluation, prediction, MAP estimation, and mass matrix computation.

Parameters:
  • data_or_x (TimeSeriesData or array_like, shape (N,)) – Either a TimeSeriesData object, or observation times [days]. When a TimeSeriesData is passed, y and yerr must be None (they are read from the data object).

  • y (array_like, shape (N,), optional) – Observed flux values. Required when data_or_x is an array.

  • yerr (array_like, shape (N,) or float, optional) – Measurement uncertainties (1-sigma). Required when data_or_x is an array.

  • model_or_hparam (SpotEvolutionModel or dict) – Either a SpotEvolutionModel (new API) or a raw hparam dict (backward-compatible old API).

  • kernel_type ({"analytic"}) – Which kernel to use (default: “analytic”).

  • mean (float or callable or None) – Mean function.

  • fit_sigma_n (bool) – If True, include white noise amplitude sigma_n as a free parameter for optimization/sampling (default False).

  • bounds (dict or None) – Parameter bounds for optimization. If None, uses defaults.

  • log_prior (callable or None) – Custom log-prior function f(theta_arr) -> scalar. If None, uses soft uniform within bounds.

  • kernel_kwargs (dict) – Extra kwargs forwarded to the kernel constructor.

DEFAULT_BOUNDS = {'a_spot': (1e-06, 1.0), 'inc': (0.01, 3.1315926535897933), 'kappa': (0.001, 0.999), 'lat_max': (0.0, 1.5707963267948966), 'lat_min': (0.0, 1.5707963267948966), 'lspot': (0.1, 20.0), 'n_sn': (-10.0, 10.0), 'nspot_rate': (0.001, 10.0), 'peq': (0.5, 50.0), 'sigma_k': (1e-06, 1.0), 'sigma_n': (1e-06, 0.1), 'sigma_sn': (0.05, 10.0), 'tau_dec': (0.05, 10.0), 'tau_em': (0.05, 10.0), 'tau_spot': (0.05, 10.0)}#
build_jax(recompute=True)[source]#

Pre-compile and warm up all JAX JIT functions for this solver.

_build_logposterior() creates four @jax.jit-decorated functions (log_posterior, neg_log_posterior, grad_log_posterior, grad_neg_log_posterior) that each trigger a separate XLA compilation on their first call. Combined with the banded Cholesky solver, that can add up to 10–30 s of invisible overhead before a fit or MCMC run starts.

Call build_jax() once after constructing the solver to pay that cost upfront.

Returns:

self – Returns self so the call can be chained: gp = GPSolver(...).build_jax().

Return type:

GPSolver

log_likelihood()[source]#

Marginal log-likelihood of the data under the GP.

Returns:

logL – log p(y | X, theta)

Return type:

float

predict(xpred, return_cov=False)[source]#

Predictive distribution at new input locations.

Parameters:
  • xpred (array_like, shape (M,)) – Prediction times.

  • return_cov (bool) – If True, return full predictive covariance.

Returns:

  • mu_pred (ndarray, shape (M,))

  • var_pred (ndarray, shape (M,) or (M, M))

plot_prediction(theta=None, n_points=2000, n_sigma=(1, 2), ax=None, data_color='k', model_color='r', show_legend=True, xlim=None, ylim=None, model_label='GP mean', data_label='Data')[source]#

Plot the GP posterior mean and uncertainty bands over the data.

If theta is provided the GP is temporarily updated to those hyperparameters before predicting, so the prediction reflects the given parameter values rather than whatever was last set internally.

Parameters:
  • theta (dict or array_like, shape (6,), optional) – Kernel parameters. Accepts a physical dict with keys from KERNEL_HPARAM_KEYS, a sampling-space dict with log_- prefixed keys (e.g. log_sigma_k), or a length-6 array. If None, uses the current internal hyperparameters.

  • n_points (int) – Number of prediction points spanning the data baseline.

  • n_sigma (int or sequence of int) – Which sigma levels to shade. E.g. (1, 2) draws both ±1σ and ±2σ bands (default). Pass a single int for one band.

  • ax (matplotlib Axes, optional) – Axes to plot on. If None, creates a new figure.

  • data_color (str) – Colors for data points and model curve/bands.

  • model_color (str) – Colors for data points and model curve/bands.

  • show_legend (bool) – Whether to draw a legend.

  • xlim (tuple, optional) – Limits for the x-axis. If None, defaults to the data range.

  • ylim (tuple, optional) – Limits for the y-axis. If None, defaults to the data range.

Returns:

ax

Return type:

matplotlib Axes

sample_prior(xpred, n_samples=1, rng=None)[source]#

Draw samples from the GP prior.

sample_posterior(xpred, n_samples=1, rng=None)[source]#

Draw samples from the GP posterior.

sample_lightcurves(theta=None, xpred=None, n_samples=5, n_points=2000, source='prior', rng=None)[source]#

Sample lightcurves from the GP prior or posterior.

Parameters:
  • theta (dict or array_like, optional) – Kernel parameters. Accepts a physical dict with keys from param_keys, a sampling-space dict with log_-prefixed keys, or a flat array matching param_keys. If None, uses the current internal hyperparameters.

  • xpred (array_like, optional) – Times at which to evaluate the samples. If None, uses n_points evenly spaced times spanning the data baseline.

  • n_samples (int) – Number of lightcurve samples to draw (default 5).

  • n_points (int) – Number of prediction points when xpred is None (default 2000).

  • source ({'prior', 'posterior'}) – Whether to sample from the GP prior or posterior (default ‘prior’).

  • rng (numpy.random.Generator, optional) – Random number generator for reproducibility.

Returns:

  • xpred (ndarray, shape (M,)) – Prediction times.

  • samples (ndarray, shape (n_samples, M)) – Sampled lightcurves.

plot_samples(theta=None, xpred=None, n_samples=5, n_points=2000, source='prior', rng=None, ax=None, show_data=True, data_color='k', sample_alpha=0.7, sample_lw=1.0, cmap='tab10', show_legend=True, xlim=None, ylim=None)[source]#

Plot sampled lightcurves from the GP prior or posterior.

Parameters:
  • theta (dict or array_like, optional) – Kernel parameters (see sample_lightcurves).

  • xpred (array_like, optional) – Prediction times. If None, n_points evenly spaced.

  • n_samples (int) – Number of samples to draw and plot (default 5).

  • n_points (int) – Number of prediction points when xpred is None.

  • source ({'prior', 'posterior'}) – Sample from the GP prior or posterior (default ‘prior’).

  • rng (numpy.random.Generator, optional) – Random number generator for reproducibility.

  • ax (matplotlib Axes, optional) – Axes to plot on. If None, creates a new figure.

  • show_data (bool) – Whether to overlay the observed data (default True).

  • data_color (str) – Color for data points (default ‘k’).

  • sample_alpha (float) – Opacity for sample curves (default 0.7).

  • sample_lw (float) – Line width for sample curves (default 1.0).

  • cmap (str) – Matplotlib colormap name for sample colors (default ‘tab10’).

  • show_legend (bool) – Whether to draw a legend (default True).

  • xlim (tuple, optional) – Axis limits.

  • ylim (tuple, optional) – Axis limits.

Returns:

ax

Return type:

matplotlib Axes

compute_acf(tlags=None, n_bins=50, normalize=True)[source]#

Compute the empirical autocorrelation function of the data.

Delegates to self.data.compute_acf().

Parameters:
  • tlags (array_like, optional) – Bin edges for time lags [days]. If provided, n_bins is inferred as len(tlags) - 1. If None, n_bins linearly spaced bins from 0 to half the baseline are used.

  • n_bins (int) – Number of lag bins (used when tlags is None, default 50).

  • normalize (bool) – If True (default), normalize so ACF(0) ~ 1.

Returns:

  • lag_centers (ndarray, shape (n_bins,)) – Bin centers.

  • acf (ndarray, shape (n_bins,)) – Empirical ACF at each bin center.

compute_kernel(tlags)[source]#

Evaluate the analytic kernel at the given time lags.

Parameters:

tlags (array_like, shape (M,)) – Time lags [days].

Returns:

K – Kernel values at each lag.

Return type:

ndarray, shape (M,)

fit_acf(theta0=None, keys=None, tlags=None, n_bins=50, method='L-BFGS-B', maxiter=500, ftol=0, gtol=1e-08, disp=False, nopt=1, ncore=None, rng=None, _save=True)[source]#

Fit the analytic kernel to the empirical ACF via least-squares.

Minimizes sum_i (ACF_data(lag_i) - K(lag_i; theta))^2 over the kernel hyperparameters, using JAX gradients and scipy.

Parameters:
  • theta0 (dict or array_like, optional) –

    Starting point. Can be:
    • None: uses self.theta0 (kernel params only, no sigma_n).

    • dict: values for any subset of kernel keys set the starting point. If keys is not given, the dict keys that overlap with KERNEL_HPARAM_KEYS are treated as the free variables; the rest are held fixed. Extra keys not in KERNEL_HPARAM_KEYS are ignored.

    • array_like: full kernel theta vector (6 elements).

  • keys (list of str, optional) – Which parameters to vary during optimization. Overrides the automatic inference from a dict theta0. Parameters not listed are held fixed at their current values. If None and theta0 is not a dict, all kernel parameters are varied.

  • tlags (array_like, optional) – Bin edges for compute_acf. If None, linearly spaced from 0 to half the baseline with n_bins+1 edges.

  • n_bins (int) – Number of lag bins (used when tlags is None).

  • method (str) – Scipy optimizer method.

  • maxiter (int) – Maximum iterations.

  • ftol (float) – Function-value convergence tolerance (default 0, disabled).

  • gtol (float) – Gradient-norm convergence tolerance (default 1e-8).

  • disp (bool) – If True, print optimizer convergence messages (default False).

  • nopt (int) – Number of independent optimisation trials (default 1). When > 1, fit_acf_parallel is called and the best result across all trials is returned.

  • ncore (int or None) – Number of parallel workers. Only used when nopt > 1.

  • rng (numpy.random.Generator, optional) – RNG for random starting points. Only used when nopt > 1.

Returns:

  • theta_dict (dict) – Full dictionary of all kernel hyperparameters (fixed + optimized).

  • result (scipy.optimize.OptimizeResult) – Full optimizer output.

fit_acf_parallel(nopt=10, ncore=None, keys=None, tlags=None, n_bins=50, method='nelder-mead', maxiter=500, ftol=0, gtol=1e-08, disp=False, return_all=False, rng=None)[source]#

Run fit_acf from multiple random starting points in parallel.

Starting points are drawn uniformly within the kernel parameter bounds.

Parameters:
  • nopt (int) – Number of independent optimization trials (default 10).

  • ncore (int or None) – Number of parallel workers. If None, uses nopt or the number of available CPUs, whichever is smaller.

  • keys (list of str, optional) – Free parameters (forwarded to fit_acf).

  • tlags – Forwarded to fit_acf.

  • n_bins – Forwarded to fit_acf.

  • method (str) – Optimizer method (default “nelder-mead”).

  • maxiter – Forwarded to fit_acf.

  • ftol – Forwarded to fit_acf.

  • gtol – Forwarded to fit_acf.

  • disp – Forwarded to fit_acf.

  • return_all (bool) – If True, return all solutions sorted by objective value. If False (default), return only the best solution.

  • rng (numpy.random.Generator, optional) – Random number generator for reproducibility.

Returns:

  • theta_best (dict (or list of dict if return_all=True)) – Best-fit kernel hyperparameters.

  • result_best (scipy.optimize.OptimizeResult) – (or list of OptimizeResult if return_all=True)

fit_acf_psd(theta0=None, keys=None, tlags=None, n_bins=50, n_freq=200, dt_kernel=None, acf_weight=1.0, psd_weight=1.0, method='L-BFGS-B', maxiter=500, ftol=0, gtol=1e-08, disp=False)[source]#

Fit kernel parameters jointly to the empirical ACF and PSD.

Minimizes a weighted sum of two normalized mean-squared-error terms:

loss = acf_weight * acf_loss + psd_weight * psd_loss

where

acf_loss = mean((ACF_data - K_model)^2) / mean(ACF_data^2)

is the relative MSE of the kernel against the empirical ACF (unnormalized autocovariance), and

psd_loss = mean((PSD_data_norm - PSD_model_norm)^2)

is the MSE between the Lomb-Scargle periodogram and the analytic kernel PSD, both normalized to unit integral so the comparison is independent of overall amplitude.

The model PSD is computed via a direct cosine transform of the kernel evaluated on a uniform lag grid, making it fully differentiable with respect to the kernel parameters.

Parameters:
  • theta0 (dict or array_like, optional) – Starting point in self.param_keys space (sampling space, with log_-prefixed keys where applicable). Follows the same convention as fit_map: None uses self.theta0, a dict overrides named entries and infers free keys, an array is used directly.

  • keys (list of str, optional) – Parameters to vary during optimization (names from self.param_keys). Defaults to all kernel parameters (first 6 entries of self.param_keys, i.e. excluding sigma_n if present).

  • tlags (array_like, optional) – Bin edges for the empirical ACF. If None, n_bins+1 edges linearly spaced from 0 to half the baseline.

  • n_bins (int) – Number of ACF lag bins when tlags is None (default 50).

  • n_freq (int) – Number of frequency points for the Lomb-Scargle periodogram (default 200).

  • dt_kernel (float, optional) – Uniform lag spacing [days] for evaluating the analytic kernel before the direct cosine transform. Defaults to one-fifth of the median data spacing.

  • acf_weight (float) – Weight for the ACF loss term (default 1.0).

  • psd_weight (float) – Weight for the PSD loss term (default 1.0).

  • method (str) – Scipy optimizer method (default "L-BFGS-B").

  • maxiter (int) – Maximum optimizer iterations (default 500).

  • ftol (float) – Convergence tolerances forwarded to scipy.

  • gtol (float) – Convergence tolerances forwarded to scipy.

  • disp (bool) – Print optimizer messages if True.

Returns:

  • theta_dict (dict) – Best-fit parameters in self.param_keys space.

  • result (scipy.optimize.OptimizeResult)

plot_acf(theta=None, tlags=None, n_bins=50, ax=None, normalize=False, data_color='k', model_color='r', show_legend=True, xlim=None, ylim=None, model_label='Analytic ACF', data_label='Data ACF')[source]#

Plot the empirical ACF and optionally the analytic kernel.

Parameters:
  • theta (dict or array_like, shape (6,), optional) – Kernel parameters. Accepts a physical dict with keys from KERNEL_HPARAM_KEYS, a sampling-space dict with log_- prefixed keys (e.g. log_sigma_k), or a length-6 array. If provided, the analytic kernel is overplotted.

  • tlags (array_like, optional) – Bin edges for compute_acf. If None, linearly spaced from 0 to half the baseline with n_bins+1 edges.

  • n_bins (int) – Number of lag bins (used when tlags is None).

  • ax (matplotlib Axes, optional) – Axes to plot on. If None, creates a new figure.

  • normalize (bool) – If True (default), normalize both curves by the data variance so ACF(0) ≈ 1.

  • xlim (tuple, optional) – Limits for the x-axis. If None, defaults to the data range.

  • ylim (tuple, optional) – Limits for the y-axis. If None, defaults to the data range.

Returns:

ax

Return type:

matplotlib Axes

plot_psd(theta=None, n_freq=500, dt_kernel=None, ax=None, data_color='k', model_color='r', show_legend=True, xlim=None, ylim=None, model_label='Analytic PSD', data_label='Data Lomb-Scargle')[source]#

Plot the empirical PSD (Lomb-Scargle) and optionally the analytic kernel PSD (FFT of the autocovariance function).

Both curves are normalized so their integral over positive frequencies equals the data variance, making them directly comparable.

Parameters:
  • theta (dict or array_like, shape (6,), optional) – Kernel parameters. Accepts a physical dict with keys from KERNEL_HPARAM_KEYS, a sampling-space dict with log_- prefixed keys (e.g. log_sigma_k), or a length-6 array. If provided, the analytic kernel PSD is overplotted.

  • n_freq (int) – Number of frequency points for the Lomb-Scargle periodogram.

  • dt_kernel (float, optional) – Time step [days] for evaluating the analytic kernel on a uniform grid before FFT. Defaults to one-fifth of the median data spacing.

  • ax (matplotlib Axes, optional) – Axes to plot on. If None, creates a new figure.

  • data_color (str) – Colors for the data and model curves.

  • model_color (str) – Colors for the data and model curves.

  • show_legend (bool) – Whether to draw a legend.

  • xlim (tuple, optional) – Limits for the x-axis. If None, defaults to the data range.

  • ylim (tuple, optional) – Limits for the y-axis. If None, defaults to the data range.

Returns:

ax

Return type:

matplotlib Axes

plot_covariance_matrix(theta=None, ax=None, cmap='RdBu_r', show_colorbar=True, vmax=None, nbins=50, show=False, filename='covariance_matrix.png')[source]#

Plot the GP covariance matrix K (signal only, no noise).

Entries outside the banded support are set to zero, matching the cholesky_banded approximation. The matrix is binned to nbins x nbins before plotting. The bandwidth boundary is drawn as dashed lines, and band width plus matrix sparsity are annotated.

Parameters:
  • theta (dict or array_like, optional) – Kernel hyperparameters. Accepts a physical dict with keys from param_keys, a sampling-space dict with log_-prefixed keys, or a raw array. If None, uses the current self.hparam values.

  • ax (matplotlib Axes, optional) – Axes to plot on. If None, a new figure is created.

  • cmap (str, optional) – Colormap name. Defaults to "RdBu_r" (diverging, centred at zero).

  • show_colorbar (bool, optional) – Whether to add a colorbar. Default True.

  • vmax (float, optional) – Symmetric color scale limit [-vmax, vmax]. If None, uses the maximum absolute value of the banded matrix.

  • nbins (int, optional) – Bin the N x N matrix down to nbins x nbins by averaging non-overlapping blocks before plotting. Default 50.

  • show (bool, optional) – If True, call plt.show(). Default False.

  • filename (str, optional) – Filename used when saving to save_dir. Default "covariance_matrix.png".

Returns:

ax

Return type:

matplotlib Axes

get_theta()[source]#

Return the current kernel hyperparameters as a dictionary.

Returns:

theta – Keys and values for all kernel (and optionally noise) hyperparameters, e.g. {“peq”: 5.0, “kappa”: 0.2, …}.

Return type:

dict

update_hparam(hparam)[source]#

Update hyperparameters and rebuild kernel and covariance.

Accepts a SpotEvolutionModel, an hparam dict (legacy keys like lspot), or a theta-style dict whose keys match self.spot_model.param_keys (e.g. tau_em, lat_min).

fit_map(theta0=None, keys=None, method='L-BFGS-B', maxiter=500, ftol=0, gtol=1e-08, disp=False, nopt=1, ncore=None, rng=None, _save=True)[source]#

Find the maximum a posteriori (MAP) estimate.

Uses scipy.optimize.minimize with JAX-computed gradients. When nopt > 1, delegates to fit_map_parallel which runs nopt independent trials from random starting points (drawn uniformly within the bounds) and returns the best result.

Parameters:
  • theta0 (dict or array_like, optional) –

    Starting point. Can be:
    • None: uses self.theta0 (current hyperparameters).

    • dict: values for any subset of param_keys set the starting point. If keys is not given, the dict keys that overlap with self.param_keys are treated as the free variables to optimize; the rest are held fixed. Extra keys not in param_keys are ignored.

    • array_like: full theta vector (length n_params).

    Ignored when nopt > 1 (starting points are randomised).

  • keys (list of str, optional) – Which parameters to vary during optimization. Overrides the automatic inference from a dict theta0. Parameters not listed are held fixed at their current values. If None and theta0 is not a dict, all parameters are varied.

  • method (str) – Scipy optimizer method (default “L-BFGS-B”).

  • maxiter (int) – Maximum iterations.

  • ftol (float) – Function-value convergence tolerance for L-BFGS-B (default 0, i.e. disabled so that convergence is controlled by gtol).

  • gtol (float) – Gradient-norm convergence tolerance (default 1e-8).

  • disp (bool) – If True, print optimizer convergence messages (default False).

  • nopt (int) – Number of independent optimisation trials (default 1). When > 1, fit_map_parallel is called and the best result across all trials is returned.

  • ncore (int or None) – Number of parallel workers for multi-start runs. If None, uses nopt or the number of available CPUs, whichever is smaller. Only used when nopt > 1.

  • rng (numpy.random.Generator, optional) – RNG for random starting points. Only used when nopt > 1.

Returns:

  • theta_dict (dict) – Full dictionary of all hyperparameters (fixed + optimized).

  • result (scipy OptimizeResult) – Full optimizer output.

fit_map_parallel(nopt=10, ncore=None, keys=None, method='nelder-mead', maxiter=500, ftol=0, gtol=1e-08, disp=False, return_all=False, rng=None, theta0=None, jitter=0.01)[source]#

Run fit_map from multiple random starting points in parallel.

Starting points are drawn uniformly within the parameter bounds.

Parameters:
  • nopt (int) – Number of independent optimization trials (default 10).

  • ncore (int or None) – Number of parallel workers. If None, uses nopt or the number of available CPUs, whichever is smaller.

  • keys (list of str, optional) – Free parameters (forwarded to fit_map).

  • method (str) – Optimizer method (default “nelder-mead”).

  • maxiter – Forwarded to fit_map.

  • ftol – Forwarded to fit_map.

  • gtol – Forwarded to fit_map.

  • disp – Forwarded to fit_map.

  • return_all (bool) – If True, return all solutions sorted by objective value. If False (default), return only the best solution.

  • rng (numpy.random.Generator, optional) – Random number generator for reproducibility.

  • theta0 (dict, optional) – Initial parameter guess to include as one of the starting points. Replaces one random start so the total number of trials stays nopt.

Returns:

  • theta_best (dict (or list of dict if return_all=True)) – Best-fit hyperparameters.

  • result_best (scipy.optimize.OptimizeResult) – (or list of OptimizeResult if return_all=True)

mass_matrix_hessian_map(theta_map=None)[source]#

Estimate the inverse mass matrix from the Hessian of the negative log-likelihood at the MAP.

M^{-1} = H^{-1} where H = d^2(-log L)/d theta^2 at the MAP.

Parameters:

theta_map (array_like, optional) – MAP estimate. If None, calls fit_map() first.

Returns:

inv_mass_matrix

Return type:

jnp.ndarray, shape (n_params, n_params)

mass_matrix_fisher(theta_map=None, eigval_clip=1e-06, white_noise=1e-08)[source]#

Estimate the inverse mass matrix from the Fisher information.

For the GP log-likelihood:

I_{ij} = (1/2) tr(K^{-1} dK/dtheta_i K^{-1} dK/dtheta_j)

When matrix_solver="cholesky_full", the kernel derivatives dK/dtheta_i are computed via JAX forward-mode autodiff (jacfwd) on the full N×N covariance matrix.

When matrix_solver="cholesky_banded", the exact Fisher requires the dense N×N kernel and its inverse, which would defeat the purpose of banded storage. Instead, the Fisher is approximated by the Hessian of the banded negative log-likelihood at the MAP (Fisher ≈ observed information at the MLE).

Parameters:

theta_map (array_like, optional) – Point at which to evaluate Fisher. If None, uses MAP.

Returns:

inv_mass_matrix

Return type:

jnp.ndarray, shape (n_params, n_params)

mass_matrix_laplace(theta_map=None, eigval_clip=1e-06)[source]#

Laplace approximation: inverse mass matrix = inverse Hessian of the negative log-likelihood at the MAP.

The posterior is approximated as:

p(theta | data) ~ N(theta_MAP, H^{-1})

Parameters:

theta_map (array_like, optional) – MAP estimate. If None, calls fit_map() first.

Returns:

inv_mass_matrix

Return type:

jnp.ndarray, shape (n_params, n_params)

laplace_samples(n_samples=1000, rng_key=None)[source]#

Draw samples from the Laplace (Gaussian) approximation to the posterior.

Parameters:
  • n_samples (int)

  • rng_key (jax.random.PRNGKey, optional)

Returns:

samples

Return type:

jnp.ndarray, shape (n_samples, n_params)

plot_pgm(**kwargs)[source]#

Plot the probabilistic graphical model for this GP.

Parameters:

**kwargs – Forwarded to PGModelVis.render() (dpi, node_scale, font_size).

Returns:

fig

Return type:

matplotlib.figure.Figure

Power Spectral Density#

spotgp.psd.compute_psd(y, t=None, dt=None, normalization='psd', freq_min=None, freq_max=None, n_freq=None, samples_per_peak=5)[source]#

Compute the Power Spectral Density of a time series using astropy.timeseries.LombScargle.

Works for both evenly and unevenly sampled data.

Parameters:
  • y (array-like, shape (N,)) – Time series values.

  • t (array-like, shape (N,), optional) – Sample times. If None, integer indices scaled by dt are used.

  • dt (float, optional) – Sampling interval. Used only when t is None (default: 1).

  • normalization ({"psd", "standard", "model", "log"}) – Passed directly to LombScargle.autopower / power.

  • freq_min (float, optional) – Minimum frequency to evaluate.

  • freq_max (float, optional) – Maximum frequency to evaluate.

  • n_freq (int, optional) – Number of frequency grid points.

  • samples_per_peak (float, optional) – Controls the frequency grid density (default 5).

Returns:

  • freq (ndarray) – Frequencies in cycles per unit time.

  • power (ndarray) – PSD evaluated at each frequency.

MCMC Sampler#

class spotgp.mcmc.MCMCSampler(gp)[source]#

Bases: object

Base MCMC sampler for GP hyperparameters.

Wraps a GPSolver object and provides shared storage, diagnostics, summary statistics, corner plots, and dict conversion. Subclasses implement specific sampling algorithms (e.g. NUTS).

Parameters:

gp (GPSolver) – A configured GPSolver instance.

property param_keys#
property n_params#
summary()[source]#

Print summary statistics of the posterior samples.

Returns:

stats – Parameter names mapped to (mean, std, 16%, 50%, 84%).

Return type:

dict

plot_covariance(method='fisher', theta_map=None, n_sigma=2, n_grid=200, samples=None, figsize=None, color='C0', alpha=0.3, true_params=None, savefig=None, **corner_kwargs)[source]#

Corner plot of 2D covariance ellipses from the Hessian or Fisher matrix, with 1D marginal Gaussians on the diagonal.

Uses corner.corner to lay out the figure when MCMC samples are provided, and overlays the Laplace/Fisher Gaussian approximation (ellipses + 1D marginals).

Parameters:
  • method ({"fisher", "hessian_map", "laplace"}) – Which matrix to use for the Gaussian approximation.

  • theta_map (array_like, optional) – Center of the ellipses. If None, uses MAP estimate.

  • n_sigma (float) – Number of sigma for the ellipse contours (default 2).

  • n_grid (int) – Grid resolution for the ellipse curves (default 200).

  • samples (array_like, optional) – If provided, plotted as the corner histogram/contours. If None, the figure is created with empty axes and only the Gaussian approximation is drawn.

  • figsize (tuple, optional) – Figure size.

  • color (str) – Color for Gaussian ellipses and marginals (default “C0”).

  • alpha (float) – Fill alpha for the ellipse interiors (default 0.3).

  • true_params (dict or array_like, optional) – True parameter values to mark with crosshairs.

  • savefig (str, optional) – If provided, save figure to this path.

  • **corner_kwargs – Extra keyword arguments forwarded to corner.corner (e.g. quantiles, show_titles, hist_kwargs).

Returns:

fig, axes

Return type:

matplotlib Figure and 2D array of Axes.

plot_corner_map(samples=None, checkpoint_path=None, cmap='viridis', marker_size=40, savefig=None, true_params=None, **corner_kwargs)[source]#

Corner plot of MCMC samples with MAP solutions overlaid as scatter points colored by their log-likelihood.

Parameters:
  • samples (array_like, optional) – Shape (n_samples, n_params). If None, loads from the checkpoint file.

  • checkpoint_path (str, optional) – Path to checkpoint .npz file containing MAP solutions. If None, uses the default checkpoint file.

  • cmap (str) – Colormap for the MAP scatter points (default “viridis”).

  • marker_size (float) – Marker size for scatter points (default 40).

  • savefig (str, optional) – If provided, save figure to this path.

  • true_params (dict or array_like, optional) – True parameter values to mark with crosshairs.

  • **corner_kwargs – Extra keyword arguments forwarded to corner.corner.

Returns:

fig, axes

Return type:

matplotlib Figure and 2D array of Axes.

to_dict(samples=None)[source]#

Convert samples array to a dict keyed by parameter name.

Parameters:

samples (jnp.ndarray, optional) – Shape (n_samples, n_params). If None, uses self.samples.

Returns:

d – {param_name: array of shape (n_samples,)}

Return type:

dict

class spotgp.mcmc.BlackJAXSampler(gp, save_dir='results', checkpoint_file='mcmc_checkpoint.npz')[source]#

Bases: MCMCSampler

NUTS sampler using the BlackJAX library.

Inherits diagnostics, summary, plotting, and dict conversion from MCMCSampler. Adds run_map, run_warmup, and run_sampling for gradient-based No-U-Turn sampling with dual-averaging step-size adaptation.

When multiple chains are requested, sampling is parallelized across available devices via jax.pmap. Chains are distributed evenly across devices (n_chains must be divisible by jax.device_count()). On a single GPU this behaves identically to the previous jax.vmap implementation.

Parameters:
  • gp (GPSolver) – A configured GPSolver instance.

  • save_dir (str, optional) – Directory for all outputs produced by this sampler (corner plots, covariance plots, etc.). Created automatically if it does not exist. When set, save_checkpoint will default to saving the checkpoint inside this directory.

  • checkpoint_file (str, optional) – Path to the checkpoint file. When provided, overrides the default save_dir/mcmc_checkpoint.npz. If neither checkpoint_file nor save_dir is given, no checkpoint file is set until one is passed to a later method.

run_map(nopt=10, keys=None, checkpoint_file=None, theta0=None, **kwargs)[source]#

Find MAP solutions via parallel multi-start optimization.

Runs GPSolver.fit_map_parallel and stores the results. If the checkpoint file already contains MAP data, loads from it instead of re-running the optimization.

Parameters:
  • nopt (int) – Number of independent optimization restarts (default 10).

  • keys (list of str, optional) – Parameter names to optimize. If None, uses all bounded parameters from GPSolver.

  • theta0 (dict, optional) – Initial parameter guess to include as one of the optimization starting points. Replaces one random start so the total number of restarts stays nopt.

  • checkpoint_file (str, optional) – Path to save/load MAP solutions. If provided, also updates the sampler’s default checkpoint path. Defaults to self._checkpoint_file.

  • **kwargs – Additional keyword arguments passed to GPSolver.fit_map_parallel (e.g. method, maxiter).

Returns:

all_theta_maps – All MAP solutions sorted by objective (best first).

Return type:

list of dict

run_warmup(n_warmup=500, theta_init=None, mass_matrix_method='hessian_map', step_size=None, rng_key=None, target_accept=0.8, progress_bar=False, n_chains=1, checkpoint_file=None, warmup_method='window_adaptation', pathfinder_maxiter=100, pathfinder_maxcor=10, pathfinder_num_elbo=200)[source]#

Run warmup phase: adapt step size and mass matrix.

Supports three warmup strategies:

  • "window_adaptation" (default): BlackJAX’s standard dual-averaging window adaptation of both step size and mass matrix.

  • "pathfinder": multi-path Pathfinder via L-BFGS.

  • "dual_averaging": fixes the mass matrix (from Hessian at MAP) and only adapts the step size.

After warmup, adapted parameters are stored on the sampler and a checkpoint is saved (if checkpoint_file is set).

Parameters:
  • n_warmup (int) – Number of warmup steps (default 500).

  • theta_init (dict or array_like, optional) – Initial position. If None, uses GPSolver’s MAP estimate. Can also be a list of dicts or 2-D array for per-chain starting points.

  • mass_matrix_method ({"hessian_map", "fisher", "laplace", "diagonal", None}) – Method to estimate the mass matrix.

  • step_size (float, optional) – Initial NUTS step size. If None, a heuristic is used.

  • rng_key (jax.random.PRNGKey, optional) – Random key. Default: PRNGKey(0).

  • target_accept (float) – Target acceptance rate (default 0.8).

  • progress_bar (bool) – If True, show progress during window adaptation.

  • n_chains (int) – Number of chains (used to validate device count and store per-chain init positions).

  • checkpoint_file (str, optional) – Override the default checkpoint file path. When set, updates self._checkpoint_file for all subsequent save/load operations. Defaults to save_dir/mcmc_checkpoint.npz when save_dir is set.

  • warmup_method ({"window_adaptation", "pathfinder", "dual_averaging"}) – Warmup strategy.

  • pathfinder_maxiter (int) – Max L-BFGS iterations for Pathfinder (default 100).

  • pathfinder_maxcor (int) – L-BFGS history size for Pathfinder (default 10).

  • pathfinder_num_elbo (int) – Number of ELBO samples for Pathfinder (default 200).

run_sampling(n_samples=1000)[source]#

Run NUTS sampling using adapted parameters from run_warmup.

Must be called after run_warmup (or will use parameters restored from a checkpoint).

Parameters:

n_samples (int) – Number of post-warmup samples per chain (default 1000).

Returns:

  • samples (jnp.ndarray) – Shape (n_samples, n_params) when n_chains=1, or (n_chains, n_samples, n_params) when n_chains > 1.

  • info (dict) – Sampling diagnostics (arrays have a leading chain dimension when n_chains > 1).

save_checkpoint(path=None, append_samples=True, plot_corner=False)[source]#

Save sampler state to disk for later resumption.

When append_samples=True (the default), new samples are appended to any existing samples already stored in path, and self.samples is cleared from memory. This enables a sample-checkpoint-clear loop that keeps memory usage constant.

Parameters:
  • path (str, optional) – File path (saved as .npz). If None, uses the checkpoint_file set in run_warmup, or save_dir/checkpoint.npz if save_dir was set.

  • append_samples (bool) – If True, append current self.samples to any samples already on disk, then clear self.samples from memory. If False, overwrite with only the current in-memory samples.

  • plot_corner (bool) – If True, load all samples currently on disk after saving and write a corner plot to save_dir/corner_plot.png (or alongside the checkpoint file if save_dir is not set).

load_checkpoint(checkpoint_file=None)[source]#

Restore sampler state from a checkpoint file.

Loads only the NUTS state and adapted kernel parameters needed to resume sampling. Samples stored in the file are not loaded into memory — use load_samples to read them later.

Parameters:

checkpoint_file (str, optional) – Path to a .npz checkpoint file. If provided, also updates the sampler’s default checkpoint path. If None, uses the default save_dir/mcmc_checkpoint.npz.

run_smc(n_particles=500, n_mcmc_steps=10, n_adapt_steps=25, target_ess=0.5, target_accept=0.6, rng_key=None, step_size=None, mass_matrix_method='hessian_map', theta_init=None, max_tempering_steps=200, checkpoint_every=10, checkpoint_file=None, particle_batch_size=None, max_num_doublings=10)[source]#

Run adaptive tempered Sequential Monte Carlo.

Starts from the prior and anneals toward the full posterior using an adaptive temperature schedule. At each tempering step, particles are resampled and rejuvenated with NUTS moves. The NUTS step size is re-adapted via dual averaging at each tempering stage using a representative particle.

Parameters:
  • n_particles (int) – Number of SMC particles (default 500).

  • n_mcmc_steps (int) – NUTS rejuvenation steps per tempering stage (default 10).

  • n_adapt_steps (int) – Dual-averaging warmup steps to adapt the NUTS step size at each tempering stage (default 25).

  • target_ess (float) – Target effective sample size as a fraction of n_particles (default 0.5).

  • target_accept (float) – Target NUTS acceptance rate for dual averaging (default 0.6).

  • rng_key (jax.random.PRNGKey, optional) – Random key. Default: PRNGKey(42).

  • step_size (float, optional) – Initial NUTS step size. If None, a heuristic from the mass matrix is used.

  • mass_matrix_method (str, optional) – Method to estimate the inverse mass matrix (default "hessian_map"). Set to None to use an identity matrix.

  • theta_init (dict or array_like, optional) – Reference point for mass matrix estimation. If None, the MAP estimate is used.

  • max_tempering_steps (int) – Safety limit on the number of tempering stages (default 200).

  • checkpoint_every (int) – Save a checkpoint every this many tempering steps (default 10). Set to 0 to disable periodic checkpointing.

  • checkpoint_file (str, optional) – Override the default checkpoint file path.

  • particle_batch_size (int, optional) – Process particles in batches of this size to limit GPU memory usage. When multiple GPUs are visible the batches are distributed across devices via jax.pmap. n_particles must be divisible by this value (and by batch_size * n_devices for multi-GPU). If None, all particles are evaluated at once (original blackjax behavior).

  • max_num_doublings (int, optional) – Maximum NUTS tree depth (default 10). Lower values (e.g. 5-6) reduce peak GPU memory per particle at the cost of shorter trajectories.

Returns:

  • samples (np.ndarray, shape (n_particles, n_params)) – Weighted posterior particles at the final temperature.

  • info (dict) – Diagnostics including tempering schedule and log evidence estimate.

static load_samples(path, flatten_chains=True)[source]#

Read all samples from a checkpoint file without loading the sampler state.

Parameters:
  • path (str) – Path to a .npz checkpoint file.

  • flatten_chains (bool) – If True (default), collapse the chain dimension so the returned array is always (n_total, n_params). Set to False to get the raw (n_chains, n_samples, n_params) array for per-chain diagnostics (e.g. R-hat).

Returns:

samples – Shape (n_total, n_params) when flatten_chains=True, or (n_chains, n_samples, n_params) otherwise.

Return type:

np.ndarray

Spot Model#

class spotgp.spot_model.SpotEvolutionModel(envelope: EnvelopeFunction = <object object>, visibility: VisibilityFunction = <object object>, sigma_k: float = None, nspot_rate: float = None, fspot: float = 0.0, alpha_max: float = None, a_spot: float = None, latitude_distribution: LatitudeDistributionFunction = <object object>)[source]#

Bases: object

Complete statistical spot evolution model.

Combines an EnvelopeFunction (spot size evolution) with a VisibilityFunction (stellar rotation and inclination) and a kernel amplitude parameter sigma_k.

Parameters:
  • envelope (EnvelopeFunction or None) – Spot size envelope (e.g. TrapezoidSymmetricEnvelope). When None the kernel contains only the visibility function (R_Gamma = 1).

  • visibility (VisibilityFunction or None) – Stellar visibility function (peq, kappa, inc). When None the kernel contains only the envelope function.

  • sigma_k (float, optional) – Kernel amplitude prefactor. Provide either sigma_k directly or (nspot_rate, fspot, alpha_max) for the physical parameterization.

  • nspot_rate (float, optional) – Spot emergence rate [spots/day]. Used when sigma_k is not given.

  • fspot (float, optional) – Spot contrast fraction (default 0).

  • alpha_max (float, optional) – Peak spot angular radius [rad]. Used when sigma_k is not given.

  • latitude_distribution (LatitudeDistributionFunction, optional) – Latitude probability density for spot placement and kernel integration. Defaults to a uniform distribution over [-pi/2, pi/2].

Notes

Exactly one of the following amplitude specifications must be supplied:

  • sigma_k directly,

  • (nspot_rate, a_spot) where a_spot = (1 - fspot) * alpha_max**2,

  • (nspot_rate, fspot, alpha_max) (physical parameterization).

property sigma_k: float#

Point estimate (mean) of sigma_k. Backward-compatible float.

property sigma_k_distribution#

The full ParameterDistribution for sigma_k.

property nspot_rate: float#

Spot emergence rate [spots/day], or None if not specified.

property a_spot: float#

Spot contrast-area product (1-f_spot)*alpha_max^2, or None.

property sigma_k_sq_expected: float#

E[sigma_k^2] under the distribution. Exact for DeltaDistribution.

property peq: float#
property kappa: float#
property inc: float#
property lspot: float#
property tau_spot: float#
property use_physical_amplitude: bool#

True when the model uses (nspot_rate, a_spot) instead of sigma_k.

property param_keys: tuple#

Ordered parameter names for the theta vector used in GPSolver.

When both are present, starts with (peq, kappa, inc) from the visibility function, followed by the envelope-specific keys, then the amplitude parameter(s). When the model was constructed with (nspot_rate, a_spot) or (nspot_rate, fspot, alpha_max), the last two keys are ("nspot_rate", "a_spot"); otherwise the last key is ("sigma_k",).

property theta0: ndarray#

Initial parameter vector from current model values.

theta_from_hparam(hparam: dict) ndarray[source]#

Build a theta vector from a (possibly partial) hparam dict. Missing keys fall back to the model’s current values.

get_r_gamma_func()[source]#

Return a JAX-traceable function r_gamma(theta_arr, lag) -> R_Gamma.

The theta_arr layout follows self.param_keys:

[peq, kappa, inc, <envelope params…>, sigma_k]

When envelope is None, returns a function that always yields 1.0 (pure visibility kernel). The R_Gamma function is selected based on the envelope type and captured (together with any precomputed grids) in a closure so that the returned callable is safe to use inside jax.jit.

get_lat_weight_func()[source]#

Return a JAX-traceable function f(theta_arr, phi_grid) -> weights that computes per-node latitude weights from the theta vector.

When the latitude distribution has no free parameters, returns None (the caller should use the static weights precomputed at init).

The theta_arr layout follows self.param_keys.

bandwidth_support(param_keys, bounds_arr) float[source]#

Estimate the kernel support using upper bounds of parameters.

Used by GPSolver._compute_bandwidth to determine the banded Cholesky bandwidth as a compile-time constant.

Parameters:
  • param_keys (sequence of str) – Parameter names in the same order as bounds_arr.

  • bounds_arr (array_like, shape (n_params, 2)) – Lower and upper bounds for each parameter.

to_hparam() dict[source]#

Convert to a flat hparam dict for backward compatibility.

The returned dict is accepted by resolve_hparam and by the old-style constructors of AnalyticKernel, GPSolver, etc.

classmethod from_hparam(hparam: dict) SpotEvolutionModel[source]#

Construct a SpotEvolutionModel from a raw hparam dict.

Accepts the same dict format that resolve_hparam accepts, including all envelope types and amplitude modes.

get_sympy(display=True, compute_symbolic=False)[source]#

Display sympy expressions for the full spot evolution model.

Delegates to EnvelopeFunction.get_sympy() and VisibilityFunction.get_sympy() in sequence.

Requires sympy (pip install sympy).

Parameters:
  • display (bool, optional) – If True (default), render equations as formatted LaTeX in a Jupyter notebook (via IPython.display) or print them as LaTeX strings in a plain terminal.

  • compute_symbolic (bool, optional) – Passed through to EnvelopeFunction.get_sympy(). If True, attempt to derive Gamma_hat and R_Gamma symbolically from sympy_Gamma() when no explicit override exists. Defaults to False.

Returns:

``{“envelope”: envelope_exprs, “visibility”: visibility_exprs,

”latitude”: latitude_exprs}``

where each value is the dict returned by the respective get_sympy() call.

Return type:

dict

Observations#

class spotgp.observations.TimeSeriesData(x, y, yerr, normalize=False, zero_mean=False)[source]#

Bases: object

Container for observed time series data.

Parameters:
  • x (array_like, shape (N,)) – Observation times.

  • y (array_like, shape (N,)) – Observed values (e.g. flux).

  • yerr (array_like, shape (N,) or float) – Measurement uncertainties. A scalar is broadcast to all points.

  • normalize (bool) – If True (default), normalize the flux so that the median is 1 and scale yerr accordingly.

property N: int#

Number of data points.

property baseline: float#

Total time baseline.

property median_dt: float#

Median time step.

normalize()[source]#

Normalize the flux so that the median equals 1.

Divides y and yerr by the median of y. This is idempotent: calling it on already-normalized data (median ~ 1) has negligible effect.

detrend(window)[source]#

Subtract a rolling-median trend from the flux.

A median is computed in a sliding window of width window (in the same units as x, typically days). The trend is subtracted and the global median is added back so the baseline stays near the original level.

Parameters:

window (float) – Window width for the rolling median [same units as x].

sigma_clip(lower=3.0, upper=3.0)[source]#

Remove outliers beyond a sigma threshold.

Masks out points where y falls below mean(y) - |lower| * std(y) or above mean(y) + |upper| * std(y).

Parameters:
  • lower (float) – Number of standard deviations below the mean (default 3).

  • upper (float) – Number of standard deviations above the mean (default 3).

downsample(dt)[source]#

Downsample the time series into non-overlapping bins of width dt.

Within each bin the flux is the inverse-variance weighted mean and the uncertainty is propagated as:

yerr_bin = 1 / sqrt(sum(1 / yerr_i^2))

Bins containing zero points are dropped.

Parameters:

dt (float) – Bin width in the same units as x.

compute_psd(normalization='psd', freq_min=None, freq_max=None, n_freq=None, samples_per_peak=5)[source]#

Compute the Lomb-Scargle power spectral density.

Parameters:
  • normalization (str) – LombScargle normalization mode (default “psd”).

  • freq_min (float, optional) – Frequency bounds.

  • freq_max (float, optional) – Frequency bounds.

  • n_freq (int, optional) – Number of frequency grid points.

  • samples_per_peak (float, optional) – Frequency grid density (default 5).

Returns:

  • freq (ndarray) – Frequencies [cycles per unit time].

  • power (ndarray) – PSD at each frequency.

compute_acf(n_bins=None, max_lag=None)[source]#

Compute the empirical autocorrelation function from irregularly sampled data using binned lag pairs.

For each pair of observations (i, j), the lag |x_i - x_j| and product (y_i - mean)(y_j - mean) are accumulated into bins. The ACF is the mean product in each bin, normalized by the variance.

Parameters:
  • n_bins (int, optional) – Number of lag bins (default: N // 2).

  • max_lag (float, optional) – Maximum lag to compute (default: half the baseline).

Returns:

  • lag_centers (ndarray, shape (n_bins,)) – Center of each lag bin.

  • acf (ndarray, shape (n_bins,)) – Normalized autocorrelation in each bin.

classmethod from_lightkurve(lc, normalize=False, zero_mean=False)[source]#

Create a TimeSeriesData from a lightkurve LightCurve object.

Extracts time, flux, and flux_err arrays, removes NaN entries, and converts Astropy quantities to plain floats if needed.

Parameters:
  • lc (lightkurve.LightCurve) – A LightCurve object (e.g. from lk.search_lightcurve(...).download()).

  • normalize (bool) – If True (default), normalize flux to median of 1.

  • zero_mean (bool) – If True, subtract the mean from the flux.

Return type:

TimeSeriesData

plot(ax=None, color='k', alpha=0.6, marker='.', ms=2, xlabel='Time', ylabel='Flux', **kwargs)[source]#

Plot the time series.

Parameters:
  • ax (matplotlib Axes, optional) – Axes to plot on. If None, creates a new figure.

  • color (plot style options.)

  • alpha (plot style options.)

  • marker (plot style options.)

  • ms (plot style options.)

  • xlabel (str) – Axis labels.

  • ylabel (str) – Axis labels.

  • **kwargs – Extra keyword arguments passed to ax.errorbar.

Returns:

ax

Return type:

matplotlib Axes

plot_psd(ax=None, color='k', lw=1.0, loglog=True, xlabel='Frequency', ylabel='Power', **psd_kwargs)[source]#

Plot the Lomb-Scargle PSD.

Calls compute_psd() if it hasn’t been run yet (or if psd_kwargs are provided to override previous settings).

Parameters:
  • ax (matplotlib Axes, optional)

  • color (plot style options.)

  • lw (plot style options.)

  • loglog (bool) – If True (default), use log-log axes.

  • xlabel (str) – Axis labels.

  • ylabel (str) – Axis labels.

  • **psd_kwargs – Passed to compute_psd().

Returns:

ax

Return type:

matplotlib Axes

plot_acf(ax=None, color='k', lw=1.5, xlabel='Time lag', ylabel='ACF', **acf_kwargs)[source]#

Plot the empirical autocorrelation function.

Calls compute_acf() if it hasn’t been run yet (or if acf_kwargs are provided to override previous settings).

Parameters:
  • ax (matplotlib Axes, optional)

  • color (plot style options.)

  • lw (plot style options.)

  • xlabel (str) – Axis labels.

  • ylabel (str) – Axis labels.

  • **acf_kwargs – Passed to compute_acf().

Returns:

ax

Return type:

matplotlib Axes

Distributions#

class spotgp.distributions.ParameterDistribution[source]#

Bases: object

Base class for a distribution over a scalar kernel parameter.

Subclasses must implement support and __call__.

property support: tuple#

(min, max) range of the parameter.

property mean: float#

numerical via quadrature.

Type:

Mean of the distribution. Default

expectation(func, n_quad=32)[source]#

Compute E[func(x)] under this distribution via Gauss-Legendre quadrature over self.support.

Parameters:
  • func (callable) – Function to take the expectation of.

  • n_quad (int) – Number of quadrature points (default 32).

Return type:

float

sample(n, rng=None)[source]#

Draw n samples via inverse-CDF on the quadrature grid. For quick prototyping; not intended for MCMC.

sympy_pdf()[source]#

Return the sympy expression for the PDF.

Subclasses should override to provide their analytic form. The base implementation returns None (numerical only).

Return type:

sympy.Expr or None

get_sympy(display=True, status=None, var_name='x')[source]#

Display the sympy expression for the distribution PDF.

Parameters:
  • display (bool) – If True (default), render/print the expression.

  • status (str or None, optional) – If provided, appended to the class name header in brackets.

  • var_name (str) – Name of the variable (default “x”).

Returns:

{"pdf": expr_or_None}

Return type:

dict

class spotgp.distributions.DeltaDistribution(value)[source]#

Bases: ParameterDistribution

Degenerate distribution at a fixed value (Dirac delta).

Wraps a plain float so that all code paths can treat parameters uniformly as distributions. expectation(func) returns func(value) with no quadrature overhead.

property support#

(min, max) range of the parameter.

property mean#

numerical via quadrature.

Type:

Mean of the distribution. Default

expectation(func, n_quad=32)[source]#

Compute E[func(x)] under this distribution via Gauss-Legendre quadrature over self.support.

Parameters:
  • func (callable) – Function to take the expectation of.

  • n_quad (int) – Number of quadrature points (default 32).

Return type:

float

sympy_pdf()[source]#

Return the sympy expression for the PDF.

Subclasses should override to provide their analytic form. The base implementation returns None (numerical only).

Return type:

sympy.Expr or None

class spotgp.distributions.UniformDistribution(lo, hi)[source]#

Bases: ParameterDistribution

Uniform distribution over [lo, hi].

Parameters:
  • lo (float) – Lower and upper bounds.

  • hi (float) – Lower and upper bounds.

property support#

(min, max) range of the parameter.

property mean#

numerical via quadrature.

Type:

Mean of the distribution. Default

sympy_pdf()[source]#

Return the sympy expression for the PDF.

Subclasses should override to provide their analytic form. The base implementation returns None (numerical only).

Return type:

sympy.Expr or None

class spotgp.distributions.GaussianDistribution(mu, sigma, clip_sigma=4.0)[source]#

Bases: ParameterDistribution

Truncated Gaussian distribution.

Parameters:
  • mu (float) – Mean.

  • sigma (float) – Standard deviation.

  • clip_sigma (float) – Number of sigma for truncation (default 4).

property support#

(min, max) range of the parameter.

property mean#

numerical via quadrature.

Type:

Mean of the distribution. Default

sympy_pdf()[source]#

Return the sympy expression for the PDF.

Subclasses should override to provide their analytic form. The base implementation returns None (numerical only).

Return type:

sympy.Expr or None

class spotgp.distributions.LogNormalDistribution(mu, sigma, clip_sigma=4.0)[source]#

Bases: ParameterDistribution

Log-normal distribution (positive-valued parameters).

If X ~ LogNormal(mu, sigma), then log(X) ~ Normal(mu, sigma).

Parameters:
  • mu (float) – Mean of log(X).

  • sigma (float) – Std of log(X).

  • clip_sigma (float) – Truncation in log-space (default 4).

property support#

(min, max) range of the parameter.

property mean#

numerical via quadrature.

Type:

Mean of the distribution. Default

sympy_pdf()[source]#

Return the sympy expression for the PDF.

Subclasses should override to provide their analytic form. The base implementation returns None (numerical only).

Return type:

sympy.Expr or None

spotgp.distributions.as_distribution(value)[source]#

Wrap a value as a ParameterDistribution if it isn’t one already.

Parameters:

value (float or ParameterDistribution) – If float, returns a DeltaDistribution. If already a ParameterDistribution, returns it unchanged.

Return type:

ParameterDistribution

spotgp.distributions.is_distributed(value)[source]#

Return True if value is a non-degenerate distribution.

Parameters#

class spotgp.params.EnvelopeSpec(name: str, signature_keys: FrozenSet[str], resolve: Callable[[dict], dict], description: str = '')[source]#

Bases: object

Specification for a spot envelope shape.

name#

Unique identifier (e.g. “trapezoid_symmetric”).

Type:

str

signature_keys#

Keys that identify this envelope in a raw hparam dict. Detection checks signature_keys <= raw.keys(); the most specific match (largest signature) wins.

Type:

frozenset[str]

resolve#

(raw: dict) -> dict Returns additional key-value pairs to merge into the resolved hparam. Must always include "tau_spot" (a scalar timescale) for backward compatibility with modules that require a single timescale value.

Type:

callable

description#

Human-readable summary shown in error messages.

Type:

str

name: str#
signature_keys: FrozenSet[str]#
resolve: Callable[[dict], dict]#
description: str = ''#
class spotgp.params.AmplitudeSpec(name: str, signature_keys: FrozenSet[str], formula: Callable[[dict], float], description: str = '')[source]#

Bases: object

Specification for a kernel amplitude parameterization.

name#

Unique identifier.

Type:

str

signature_keys#

Keys that identify this amplitude mode in a raw hparam dict.

Type:

frozenset[str]

formula#

(raw: dict) -> float Computes sigma_k from the raw dict.

Type:

callable

description#

Human-readable summary shown in error messages.

Type:

str

name: str#
signature_keys: FrozenSet[str]#
formula: Callable[[dict], float]#
description: str = ''#
spotgp.params.register_envelope(spec: EnvelopeSpec, priority: str = 'low') None[source]#

Register an envelope specification.

Parameters:
  • spec (EnvelopeSpec)

  • priority ({"low", "high"}) – “high” prepends (checked first within its specificity tier); “low” appends (default). Specificity (len of signature_keys) always takes precedence over priority.

spotgp.params.register_amplitude(spec: AmplitudeSpec, priority: str = 'low') None[source]#

Register an amplitude specification.

Parameters:
  • spec (AmplitudeSpec)

  • priority ({"low", "high"}) – Same semantics as register_envelope.

spotgp.params.resolve_hparam(raw: dict) dict[source]#

Validate and normalise a raw hyperparameter dict.

Steps#

  1. Checks that base required keys (peq, kappa, inc, lspot) are present.

  2. Auto-detects the envelope type from registered EnvelopeSpecs and merges any derived keys (e.g. scalar tau from tau_em/tau_dec).

  3. Auto-detects the amplitude mode from registered AmplitudeSpecs and injects the computed sigma_k.

The most-specific matching spec (largest signature_keys) wins for both envelope and amplitude detection.

returns:

A new dict containing all original keys plus any keys injected by the envelope and amplitude resolvers. The returned dict always contains "tau_spot" and "sigma_k".

rtype:

dict

raises TypeError:

If raw is not a dict.

raises ValueError:

If required keys are missing, or if no registered spec matches.

Envelope Functions#

class spotgp.envelope.EnvelopeFunction[source]#

Bases: ABC

Abstract base class for spot size envelope functions.

To define a custom envelope, subclass this and implement:

Required:
  • tau_spot (property) : characteristic timescale [days]. Used to set the extent of numerical integration grids.

  • Gamma(t) : normalized envelope, peak = 1.

Optional (numerical defaults are provided):
  • lspot (property) : plateau duration [days]. Default: 0.

  • param_dict (property): {name: value} dict of envelope parameters. Needed for GPSolver to know which parameters to fit. Default: {} (kernel evaluation still works; fitting will not expose envelope parameters).

  • R_Gamma(lag) : autocorrelation ∫ Γ(t)Γ(t+lag)dt. Default: computed via FFT from Gamma.

  • Gamma_hat(omega) : |FT[Gamma]|(ω). Default: computed via FFT from Gamma.

  • Gamma_hat_sq(omega) : |FT[Gamma]|²(ω). Default: Gamma_hat(omega) ** 2.

  • kernel_support() : upper lag bound where R_Gamma is negligible. Default: lspot + 6 * tau_spot.

The numerical defaults are computed lazily: the FFT grids are built once on the first call and cached on the instance, so there is no cost for subclasses that override these methods.

Example

>>> class GaussianEnvelope(EnvelopeFunction):
...     def __init__(self, sigma):
...         self._sigma = float(sigma)
...     @property
...     def tau_spot(self):
...         return self._sigma
...     @property
...     def param_dict(self):
...         return {"tau_spot": self._sigma}
...     def Gamma(self, t):
...         import jax.numpy as jnp
...         return jnp.exp(-0.5 * (t / self._sigma) ** 2)
abstract property tau_spot: float#

Characteristic (scalar) timescale [days].

abstractmethod Gamma(t)[source]#

Normalized spot-size envelope evaluated at relative times t.

t = 0 is the center/peak of the envelope. Must return values in [0, 1] with a peak of 1. Should be JAX-compatible (jnp operations) so that it can be evaluated inside JIT-compiled code.

property lspot: float#

Spot plateau duration [days]. Default 0 (no plateau).

property param_dict: dict#

Envelope parameters as {name: value}.

Override this to expose envelope parameters to GPSolver and SpotEvolutionModel. The default returns an empty dict, which means the envelope shape is fixed (not inferred during GP fitting).

kernel_support() float[source]#

Upper bound on the lag support of R_Gamma [days].

Used by GPSolver to compute the banded-Cholesky bandwidth. Default: lspot + 6 * tau_spot. Override for tighter bounds.

Gamma_integral() float[source]#

Integral of the squared-size envelope: \(\int \Gamma(t)\,dt\).

Used by AnalyticMean to compute the expected flux deficit. Default: numerical quadrature from Gamma(t). Override with a closed-form expression for better accuracy.

R_Gamma(lag)[source]#

Autocorrelation R_Gamma(lag) = ∫ Gamma(t) · Gamma(t + lag) dt.

Default: interpolated from an FFT-based precomputed grid. Override with an analytic expression for better performance.

Gamma_hat(omega)[source]#

Fourier transform magnitude |FT[Gamma]|(omega).

Default: interpolated from an FFT-based precomputed grid. Override with a closed-form expression for better performance.

Gamma_hat_sq(omega)[source]#

|FT[Gamma](omega)|² = Gamma_hat(omega)².

Default: interpolated from an FFT-based precomputed grid.

sympy_Gamma()[source]#

Sympy expression for Gamma(t).

Override in subclasses that have a closed-form envelope. Returns None if no analytic expression is available.

sympy_Gamma_hat()[source]#

Sympy expression for Gamma_hat(omega) = FT[Gamma](omega).

Override in subclasses with a closed-form Fourier transform. Returns None if no analytic form is available.

sympy_R_Gamma()[source]#

Sympy expression for R_Gamma(tau) = integral Gamma(t) Gamma(t+tau) dt.

Override in subclasses with a closed-form autocorrelation. Returns None if no analytic form is available.

get_sympy(display=True, status=None, compute_symbolic=False)[source]#

Retrieve and display sympy expressions for Gamma, Gamma_hat, and R_Gamma.

Prints or renders the LaTeX equation for each function that has a closed-form analytic expression, or ‘[numerical]’ for functions that rely on FFT-based approximations.

Requires sympy (pip install sympy).

Parameters:
  • display (bool, optional) – If True (default), render equations as formatted LaTeX in a Jupyter notebook (via IPython.display) or print them as LaTeX strings in a plain terminal.

  • status (str or None, optional) – If provided, appended to the class name header in brackets, e.g. "user defined" renders as TrapezoidSymmetricEnvelope [user defined].

  • compute_symbolic (bool, optional) – If True, attempt to derive Gamma_hat and R_Gamma symbolically from sympy_Gamma() when no explicit override exists. Can be slow for complex envelopes. Defaults to False.

Returns:

``{“Gamma”: expr_or_None, “Gamma_hat”: expr_or_None,

”R_Gamma”: expr_or_None}``

Return type:

dict

check_functions(n_pts=300, ax=None, show=False)[source]#

Compare analytic overrides of Gamma_hat and R_Gamma to the FFT-based numerical implementations.

Checks whether the subclass has provided analytic overrides for Gamma_hat(omega) and/or R_Gamma(lag). For each override found, evaluates both the analytic and numerical versions on a fine grid, plots the comparison, and computes the RMSE and max absolute error (both normalized by the numerical peak).

Parameters:
  • n_pts (int, optional) – Number of evaluation points on each grid. Default 300.

  • ax (matplotlib Axes or array of Axes, optional) – Axes to plot on. If None, a new figure is created sized to the number of overridden functions.

  • show (bool, optional) – If True, call plt.show() after plotting. Default False.

Returns:

errors – Keys are the names of overridden functions ("Gamma_hat" and/or "R_Gamma"). Each value is a dict with:

  • "rmse" : root-mean-square error (normalized by peak)

  • "max_err" : maximum absolute error (normalized by peak)

Return type:

dict

class spotgp.envelope.TrapezoidSymmetricEnvelope(lspot, tau_spot)[source]#

Bases: EnvelopeFunction

Symmetric trapezoidal envelope.

Shape: linear rise over tau_spot, plateau of lspot, linear decay over tau_spot.

Parameters:
  • lspot (float or ParameterDistribution) – Plateau duration [days].

  • tau_spot (float or ParameterDistribution) – Rise/decay timescale [days].

  • ParameterDistribution (When either parameter is a)

  • R_Gamma

  • the (returns the marginalized autocorrelation integrated over)

  • return (distribution(s). The lspot and tau_spot properties)

  • compatibility. (the distribution means for backward)

property tau_spot: float#

Characteristic (scalar) timescale [days].

property lspot: float#

Spot plateau duration [days]. Default 0 (no plateau).

property lspot_distribution#

The full ParameterDistribution for lspot.

property tau_spot_distribution#

The full ParameterDistribution for tau_spot.

property param_dict: dict#

Envelope parameters as {name: value}.

Override this to expose envelope parameters to GPSolver and SpotEvolutionModel. The default returns an empty dict, which means the envelope shape is fixed (not inferred during GP fitting).

Gamma(t)[source]#

Normalized spot-size envelope evaluated at relative times t.

t = 0 is the center/peak of the envelope. Must return values in [0, 1] with a peak of 1. Should be JAX-compatible (jnp operations) so that it can be evaluated inside JIT-compiled code.

Gamma_hat(omega)[source]#

Fourier transform magnitude |FT[Gamma]|(omega).

Default: interpolated from an FFT-based precomputed grid. Override with a closed-form expression for better performance.

Gamma_hat_sq(omega)[source]#

|FT[Gamma](omega)|² = Gamma_hat(omega)².

Default: interpolated from an FFT-based precomputed grid.

R_Gamma(lag)[source]#

Autocorrelation R_Gamma(lag) = ∫ Gamma(t) · Gamma(t + lag) dt.

Default: interpolated from an FFT-based precomputed grid. Override with an analytic expression for better performance.

kernel_support() float[source]#

Upper bound on the lag support of R_Gamma [days].

Used by GPSolver to compute the banded-Cholesky bandwidth. Default: lspot + 6 * tau_spot. Override for tighter bounds.

Gamma_integral() float[source]#

Integral of the squared-size envelope: \(\int \Gamma(t)\,dt\).

Used by AnalyticMean to compute the expected flux deficit. Default: numerical quadrature from Gamma(t). Override with a closed-form expression for better accuracy.

sympy_Gamma()[source]#

Sympy expression for Gamma(t).

Override in subclasses that have a closed-form envelope. Returns None if no analytic expression is available.

sympy_Gamma_hat()[source]#

Sympy expression for Gamma_hat(omega) = FT[Gamma](omega).

Override in subclasses with a closed-form Fourier transform. Returns None if no analytic form is available.

class spotgp.envelope.TrapezoidAsymmetricEnvelope(lspot: float, tau_em: float, tau_dec: float)[source]#

Bases: EnvelopeFunction

Asymmetric trapezoidal envelope with distinct emergence and decay rates.

Shape: linear rise over tau_em, plateau of lspot, linear decay over tau_dec.

Parameters:
  • lspot (float) – Plateau duration [days].

  • tau_em (float) – Emergence timescale [days].

  • tau_dec (float) – Decay timescale [days].

property tau_spot: float#

Characteristic (scalar) timescale [days].

property tau_em: float#
property tau_dec: float#
property lspot: float#

Spot plateau duration [days]. Default 0 (no plateau).

property param_dict: dict#

Envelope parameters as {name: value}.

Override this to expose envelope parameters to GPSolver and SpotEvolutionModel. The default returns an empty dict, which means the envelope shape is fixed (not inferred during GP fitting).

Gamma(t)[source]#

Normalized spot-size envelope evaluated at relative times t.

t = 0 is the center/peak of the envelope. Must return values in [0, 1] with a peak of 1. Should be JAX-compatible (jnp operations) so that it can be evaluated inside JIT-compiled code.

R_Gamma(lag)[source]#

Autocorrelation R_Gamma(lag) = ∫ Gamma(t) · Gamma(t + lag) dt.

Default: interpolated from an FFT-based precomputed grid. Override with an analytic expression for better performance.

kernel_support() float[source]#

Upper bound on the lag support of R_Gamma [days].

Used by GPSolver to compute the banded-Cholesky bandwidth. Default: lspot + 6 * tau_spot. Override for tighter bounds.

Gamma_integral() float[source]#

Integral of the squared-size envelope: \(\int \Gamma(t)\,dt\).

Used by AnalyticMean to compute the expected flux deficit. Default: numerical quadrature from Gamma(t). Override with a closed-form expression for better accuracy.

sympy_Gamma()[source]#

Sympy expression for Gamma(t).

Override in subclasses that have a closed-form envelope. Returns None if no analytic expression is available.

class spotgp.envelope.SkewedGaussianEnvelope(sigma_sn: float, n_sn: float, lspot: float = 0.0)[source]#

Bases: EnvelopeFunction

Skew-normal (Baranyi et al. 2021) envelope.

Implements Eq. (1) of Baranyi et al. (2021) A&A 653, A59:

Gamma(t) ∝ exp(-t²/(2σ²)) · (1 + erf(n·t / (σ·√2)))

Parameters:
  • sigma_sn (float) – Scale parameter [days].

  • n_sn (float) – Skewness (dimensionless). n_sn < 0: rapid rise / slow decay; n_sn > 0: slow rise / rapid decay; n_sn = 0: Gaussian.

  • lspot (float, optional) – Unused (required by base schema); set to 0 (default).

property tau_spot: float#

Characteristic (scalar) timescale [days].

property sigma_sn: float#
property n_sn: float#
property lspot: float#

Spot plateau duration [days]. Default 0 (no plateau).

property param_dict: dict#

Envelope parameters as {name: value}.

Override this to expose envelope parameters to GPSolver and SpotEvolutionModel. The default returns an empty dict, which means the envelope shape is fixed (not inferred during GP fitting).

Gamma(t)[source]#

JAX-traceable Gamma(t) via interpolation from precomputed grid.

Gamma_hat(omega)[source]#

Fourier transform magnitude |FT[Gamma]|(omega).

Default: interpolated from an FFT-based precomputed grid. Override with a closed-form expression for better performance.

Gamma_hat_sq(omega)[source]#

|FT[Gamma](omega)|² = Gamma_hat(omega)².

Default: interpolated from an FFT-based precomputed grid.

R_Gamma(lag)[source]#

Autocorrelation R_Gamma(lag) = ∫ Gamma(t) · Gamma(t + lag) dt.

Default: interpolated from an FFT-based precomputed grid. Override with an analytic expression for better performance.

kernel_support() float[source]#

Upper bound on the lag support of R_Gamma [days].

Used by GPSolver to compute the banded-Cholesky bandwidth. Default: lspot + 6 * tau_spot. Override for tighter bounds.

class spotgp.envelope.ExponentialEnvelope(tau_spot: float)[source]#

Bases: EnvelopeFunction

Bilateral exponential (double-sided) envelope.

Gamma(t) = exp(-|t| / tau_spot)

This gives a spot that is at peak at t = 0 and decays symmetrically with characteristic timescale tau_spot. There is no plateau (lspot = 0).

Analytical results:

Gamma_hat(omega) = 2*tau_spot / (1 + (omega*tau_spot)²) [Lorentzian] R_Gamma(lag) = (tau_spot + |lag|) * exp(-|lag| / tau_spot)

Parameters:

tau_spot (float) – Decay timescale [days].

property tau_spot: float#

Characteristic (scalar) timescale [days].

property lspot: float#

Spot plateau duration [days]. Default 0 (no plateau).

property param_dict: dict#

Envelope parameters as {name: value}.

Override this to expose envelope parameters to GPSolver and SpotEvolutionModel. The default returns an empty dict, which means the envelope shape is fixed (not inferred during GP fitting).

Gamma(t)[source]#

Normalized spot-size envelope evaluated at relative times t.

t = 0 is the center/peak of the envelope. Must return values in [0, 1] with a peak of 1. Should be JAX-compatible (jnp operations) so that it can be evaluated inside JIT-compiled code.

Gamma_hat(omega)[source]#

|FT[Gamma]| = 2*tau_spot / (1 + (omega*tau_spot)²) (Lorentzian).

Gamma_hat_sq(omega)[source]#

|FT[Gamma](omega)|² = Gamma_hat(omega)².

Default: interpolated from an FFT-based precomputed grid.

R_Gamma(lag)[source]#

R_Gamma(lag) = (tau_spot + |lag|) * exp(-|lag| / tau_spot).

kernel_support() float[source]#

Upper bound on the lag support of R_Gamma [days].

Used by GPSolver to compute the banded-Cholesky bandwidth. Default: lspot + 6 * tau_spot. Override for tighter bounds.

Gamma_integral() float[source]#

Integral of the squared-size envelope: \(\int \Gamma(t)\,dt\).

Used by AnalyticMean to compute the expected flux deficit. Default: numerical quadrature from Gamma(t). Override with a closed-form expression for better accuracy.

sympy_Gamma()[source]#

Sympy expression for Gamma(t).

Override in subclasses that have a closed-form envelope. Returns None if no analytic expression is available.

sympy_Gamma_hat()[source]#

Sympy expression for Gamma_hat(omega) = FT[Gamma](omega).

Override in subclasses with a closed-form Fourier transform. Returns None if no analytic form is available.

sympy_R_Gamma()[source]#

Sympy expression for R_Gamma(tau) = integral Gamma(t) Gamma(t+tau) dt.

Override in subclasses with a closed-form autocorrelation. Returns None if no analytic form is available.

class spotgp.envelope.ExponentialAsymmetricEnvelope(tau_em: float, tau_dec: float)[source]#

Bases: EnvelopeFunction

Asymmetric exponential envelope with separate rise and decay timescales.

Gamma(t) = exp( t / tau_em) for t < 0 (emergence / rise) Gamma(t) = exp(-t / tau_dec) for t >= 0 (decay)

The spot emerges with timescale tau_em and decays with timescale tau_dec. There is no plateau (lspot = 0).

Analytical Fourier transform:

Gamma_hat(omega) = tau_em / (1 + (omega * tau_em)^2)
  • tau_dec / (1 + (omega * tau_dec)^2)

Parameters:
  • tau_em (float) – Emergence (rise) timescale [days].

  • tau_dec (float) – Decay timescale [days].

property tau_spot: float#

max of the two timescales.

Type:

Effective timescale

property lspot: float#

Spot plateau duration [days]. Default 0 (no plateau).

property param_dict: dict#

Envelope parameters as {name: value}.

Override this to expose envelope parameters to GPSolver and SpotEvolutionModel. The default returns an empty dict, which means the envelope shape is fixed (not inferred during GP fitting).

Gamma(t)[source]#

Normalized spot-size envelope evaluated at relative times t.

t = 0 is the center/peak of the envelope. Must return values in [0, 1] with a peak of 1. Should be JAX-compatible (jnp operations) so that it can be evaluated inside JIT-compiled code.

Gamma_hat(omega)[source]#

Sum of two Lorentzians (one per timescale).

kernel_support() float[source]#

Upper bound on the lag support of R_Gamma [days].

Used by GPSolver to compute the banded-Cholesky bandwidth. Default: lspot + 6 * tau_spot. Override for tighter bounds.

Gamma_integral() float[source]#

Integral of the squared-size envelope: \(\int \Gamma(t)\,dt\).

Used by AnalyticMean to compute the expected flux deficit. Default: numerical quadrature from Gamma(t). Override with a closed-form expression for better accuracy.

spotgp.envelope.compute_R_Gamma_numerical(envelope_func, tau_ref, n_grid=4096, extent=12.0)[source]#

Compute R_Gamma(lag) = ∫ Gamma(t) · Gamma(t + lag) dt via FFT.

Parameters:
  • envelope_func (callable) – f(t: np.ndarray) -> np.ndarray, the normalized envelope Gamma(t).

  • tau_ref (float) – Reference timescale [days] setting grid extent and resolution.

  • n_grid (int) – Number of time-grid points (default 4096).

  • extent (float) – Grid half-width in units of tau_ref (default 12.0).

Returns:

  • lag_grid (jnp.ndarray, shape (n_grid,))

  • R_Gamma_vals (jnp.ndarray, shape (n_grid,))

Latitude Distribution#

class spotgp.latitude.LatitudeDistributionFunction[source]#

Bases: object

Base class for starspot latitude distributions.

Defines the probability density p(phi) over stellar latitude phi and the latitude range over which spots are placed.

The default implementation is a uniform distribution over [-pi/2, pi/2]. To define a custom distribution, subclass this class and override __call__ and optionally lat_range.

Examples

Equatorial band (spots confined to |phi| < 30 deg):

>>> class EquatorialBand(LatitudeDistributionFunction):
...     @property
...     def lat_range(self):
...         return (-np.pi / 6, np.pi / 6)
...     def __call__(self, phi):
...         return 1.0

Gaussian centred on the equator:

>>> class GaussianLatitude(LatitudeDistributionFunction):
...     def __init__(self, sigma=np.pi / 6):
...         self.sigma = sigma
...     def __call__(self, phi):
...         return np.exp(-0.5 * (phi / self.sigma) ** 2)
property param_dict: dict#

none.

Type:

Free latitude parameters as {name: value}. Default

property param_keys: tuple#

Ordered parameter names for the theta vector.

property lat_range: tuple#

(min, max) latitude in radians.

sympy_pdf()[source]#

Return the sympy expression for the latitude PDF p(phi).

Subclasses should override this to provide their analytic form. The base implementation returns 1 (uniform distribution).

Returns:

Sympy expression for p(phi), or None if no analytic form exists.

Return type:

sympy.Expr or None

get_sympy(display=True, status=None)[source]#

Display the sympy expression for the latitude PDF p(phi).

Requires sympy (pip install sympy).

Parameters:
  • display (bool, optional) – If True (default), render equations as formatted LaTeX in a Jupyter notebook (via IPython.display) or print them as LaTeX strings in a plain terminal.

  • status (str or None, optional) – If provided, appended to the class name header in brackets, e.g. "default" renders as LatitudeDistributionFunction [default].

Returns:

{"pdf": expr_or_None}

Return type:

dict

class spotgp.latitude.UniformDoubleHemisphereBand(min_lat_deg: float = 0.0, max_lat_deg: float = 90.0)[source]#

Bases: LatitudeDistributionFunction

Uniform distribution confined to min_lat < |phi| < max_lat.

property param_dict: dict#

none.

Type:

Free latitude parameters as {name: value}. Default

property lat_range: tuple#

(min, max) latitude in radians.

sympy_pdf()[source]#

Return the sympy expression for the latitude PDF p(phi).

Subclasses should override this to provide their analytic form. The base implementation returns 1 (uniform distribution).

Returns:

Sympy expression for p(phi), or None if no analytic form exists.

Return type:

sympy.Expr or None

Visibility Functions#

class spotgp.visibility.VisibilityFunction(peq: float, kappa: float, inc: float)[source]#

Bases: object

Stellar visibility function parameterized by rotation and inclination.

The visibility function V(phi, lon) describes the flux contribution from a spot at latitude phi as the star rotates. It is expanded in a Fourier series over rotation harmonics, with coefficients c_n(inc, phi).

Parameters:
  • peq (float) – Equatorial rotation period [days].

  • kappa (float) – Differential rotation shear (dimensionless).

  • inc (float) – Stellar inclination [radians].

property param_dict: dict#

value}.

Type:

Visibility parameters as {name

property param_keys: tuple#

Ordered parameter names.

omega0(phi)[source]#

Latitude-dependent rotation angular frequency [rad/day].

cn_squared(phi, n_harmonics: int = 3)[source]#

Squared Fourier coefficients |c_n|² at stellar latitude phi.

Returns:

cn_sq

Return type:

jnp.ndarray, shape (n_harmonics + 1,)

get_sympy(display=True, status=None)[source]#

Display the sympy expressions for the visibility function.

Renders or prints LaTeX for:
  • omega_0(phi): latitude-dependent rotation angular frequency.

  • a_0, a_1, theta_v: intermediate visibility geometry variables.

  • c_0, c_1: special-case Fourier coefficients.

  • c_n: general Fourier coefficient (n >= 2).

Intermediate symbols are introduced so each equation stays compact and human-readable.

Requires sympy (pip install sympy).

Parameters:
  • display (bool, optional) – If True (default), render equations as formatted LaTeX in a Jupyter notebook (via IPython.display) or print them as LaTeX strings in a plain terminal.

  • status (str or None, optional) – If provided, appended to the class name header in brackets, e.g. "user defined" renders as VisibilityFunction [user defined].

Returns:

``{“omega0”: expr, “a0”: expr, “a1”: expr,

”theta_v”: expr, “c0”: expr, “c1”: expr, “cn”: expr}``

Return type:

dict

class spotgp.visibility.EdgeOnVisibilityFunction(peq: float)[source]#

Bases: VisibilityFunction

Closed-form visibility for edge-on viewing (I = pi/2) with solid-body rotation (kappa = 0) and a uniform latitude distribution.

For this special case, the latitude-averaged squared Fourier coefficients are known analytically (Eq. 68 of Birky et al.):

<|c_0|^2> = 1 / (2 * pi^2) <|c_1|^2> = 1 / 16 <|c_2|^2> = 1 / (9 * pi^2)

and the rotation frequency is latitude-independent:

omega_0 = 2 * pi / P_eq.

This eliminates the need for numerical latitude quadrature, making kernel evaluation significantly faster.

Parameters:

peq (float) – Equatorial rotation period [days].

property param_dict: dict#

value}.

Type:

Visibility parameters as {name

property param_keys: tuple#

Ordered parameter names.

omega0(phi)[source]#

Rotation frequency (latitude-independent for kappa=0).

cn_squared(phi, n_harmonics: int = 3)[source]#

Latitude-averaged |c_n|^2 (independent of phi).

Returns the closed-form coefficients for n = 0, 1, 2 and zero for higher harmonics.

class spotgp.visibility.FullGeometryVisibilityFunction(peq: float, kappa: float, inc: float, alpha_ref: float = 0.1, n_lon: int = 512)[source]#

Bases: VisibilityFunction

Exact projected spot area using the full piecewise geometry (Eq. 5 of Birky et al.), without the small-spot approximation.

The projected area of a circular spot with angular radius alpha at angle beta from the line of sight has three regimes:

  • Fully visible (0 < beta < pi/2 - alpha): A = pi sin^2(alpha) cos(beta)

  • Partially visible (pi/2 - alpha < beta < pi/2 + alpha): A = arccos[cos(alpha) csc(beta)]

    • cos(beta) sin^2(alpha) arccos[-cot(alpha) cot(beta)]

    • cos(alpha) sin(beta) sqrt(1 - cos^2(alpha) csc^2(beta))

  • Hidden (pi/2 + alpha < beta < pi): A = 0

The base VisibilityFunction uses the small-spot limit where A ~ pi alpha^2 cos(beta) and the partial-visibility window vanishes. This subclass retains the exact expressions for use in forward simulations with LightcurveModel.

The Fourier coefficients cn_squared are computed numerically by evaluating the projected area over one rotation period and taking the DFT, rather than using the analytic c_n formulas.

Parameters:
  • peq (float) – Equatorial rotation period [days].

  • kappa (float) – Differential rotation shear (dimensionless).

  • inc (float) – Stellar inclination [radians].

  • alpha_ref (float) – Reference spot angular radius [radians] used for computing Fourier coefficients (default 0.1).

  • n_lon (int) – Number of longitude points for the numerical DFT (default 512).

static projected_area(alpha, beta)[source]#

Exact projected area of a circular spot (Eq. 5 of Birky et al.).

Implements the full piecewise function for a spot of angular radius alpha at angle beta from the line of sight. All three geometric cases (fully visible, partially occluded, hidden) are handled in a branchless JAX-compatible form.

Parameters:
  • alpha (array_like) – Spot angular radius [radians].

  • beta (array_like) – Angle between spot normal and line of sight [radians].

Returns:

A – Projected area (unnormalized; divide by pi for the fractional flux deficit).

Return type:

jnp.ndarray

cos_beta(phi, longitude)[source]#

Cosine of the angle between spot normal and line of sight (Eq. 6).

Parameters:
  • phi (float or array_like) – Spot latitude [radians].

  • longitude (float or array_like) – Spot longitude relative to observer [radians].

Returns:

cos_beta

Return type:

jnp.ndarray

visibility_profile(phi, alpha, n_lon=None)[source]#

Compute the projected area as a function of longitude for a spot at latitude phi with angular radius alpha.

Parameters:
  • phi (float) – Spot latitude [radians].

  • alpha (float) – Spot angular radius [radians].

  • n_lon (int, optional) – Number of longitude grid points (default: self.n_lon).

Returns:

  • lon_grid (jnp.ndarray, shape (n_lon,)) – Longitude values in [0, 2*pi).

  • A (jnp.ndarray, shape (n_lon,)) – Projected area at each longitude.

cn_squared(phi, n_harmonics: int = 3)[source]#

Numerically computed squared Fourier coefficients from the full projected-area profile.

Evaluates the exact projected area over one full rotation at latitude phi using the reference spot size alpha_ref, then extracts harmonics via DFT. The coefficients are normalized by the spot area pi * sin^2(alpha_ref) so they are independent of spot size (consistent with the base class).

Parameters:
  • phi (float) – Spot latitude [radians].

  • n_harmonics (int) – Number of harmonics (default 3).

Returns:

cn_sq

Return type:

jnp.ndarray, shape (n_harmonics + 1,)

Transit Model#

class spotgp.transit.KeplerianOrbit(period, semi_major_axis=None, ecc=0.0, incl=None, impact_param=None, omega=0.0, Omega=0.0, t_periastron=None, t0=None, radius_ratio=0.1, stellar_mass=1.0, stellar_radius=1.0)[source]#

Bases: object

Keplerian orbit for a binary or planetary system.

This class computes the 3-D position of the secondary body relative to the primary (host star) as a function of time. It also provides the projected sky-plane separation needed for transit light curve evaluation.

The parameterization follows the exoplanet package convention: the reference direction is along the line of sight, with the sky plane defined by (x, y) and the z-axis pointing toward the observer. A transit occurs when z > 0 and the sky-plane separation is less than the sum of the stellar and companion radii.

Parameters:
  • period (float) – Orbital period [days].

  • semi_major_axis (float or None) – Semi-major axis in units of stellar radii. If None, it is computed from period and stellar_mass via Kepler’s third law.

  • ecc (float) – Orbital eccentricity (default 0).

  • incl (float or None) – Orbital inclination [rad]. If None, it is computed from impact_param.

  • impact_param (float or None) – Impact parameter (0 = central transit). Ignored when incl is provided directly.

  • omega (float) – Argument of periastron of the secondary [rad] (default 0).

  • Omega (float) – Longitude of the ascending node [rad] (default 0).

  • t_periastron (float or None) – Time of periastron passage [days]. Exactly one of t_periastron and t0 must be given.

  • t0 (float or None) – Reference transit mid-time [days]. If provided instead of t_periastron, the periastron time is derived so that transit center falls at t0.

  • radius_ratio (float) – Companion-to-star radius ratio Rp / R* (default 0.1).

  • stellar_mass (float) – Stellar mass in solar masses (default 1.0). Used only when semi_major_axis is None.

  • stellar_radius (float) – Stellar radius in solar radii (default 1.0). Used for converting semi-major axis to physical units.

Notes

Angles follow the standard celestial mechanics convention:

  • omega is the argument of periastron of the orbiting body.

  • incl = pi/2 corresponds to an edge-on orbit.

get_position(t)[source]#

Compute the 3-D position of the companion relative to the star.

The coordinate system is:

  • x — on the sky, in the direction of increasing right ascension (or equivalently, the descending-node direction when Omega = 0).

  • y — on the sky, toward celestial north (ascending-node direction when Omega = 0).

  • z — along the line of sight, toward the observer.

A transit occurs when z > 0 (companion is in front of star).

Parameters:

t (array_like) – Times [days].

Returns:

x, y, z – Position of the companion in units of stellar radii.

Return type:

jnp.ndarray

get_sky_separation(t)[source]#

Projected sky-plane separation between companion and star.

Parameters:

t (array_like) – Times [days].

Returns:

rho – Sky-plane separation in units of stellar radii.

Return type:

jnp.ndarray

get_radial_velocity(t, K=None)[source]#

Radial velocity of the star due to the companion.

Parameters:
  • t (array_like) – Times [days].

  • K (float or None) – RV semi-amplitude [m/s]. If None, the returned values are in natural units (useful for relative comparison only).

Returns:

rv – Radial velocity [m/s if K is given, else natural units].

Return type:

jnp.ndarray

in_transit(t)[source]#

Boolean mask for times during which a transit is occurring.

A point is in transit when the companion is in front of the star (z > 0) and the sky-plane separation is less than 1 + radius_ratio stellar radii.

Parameters:

t (array_like) – Times [days].

Returns:

mask

Return type:

jnp.ndarray of bool

class spotgp.transit.QuadLimbDarkLightCurve(u1, u2)[source]#

Bases: object

Compute a transit light curve with quadratic limb darkening.

Uses the analytic Mandel & Agol (2002) uniform-source solution with a polynomial limb-darkening correction, following the exoplanet implementation style.

Parameters:
  • u1 (float) – First quadratic limb-darkening coefficient.

  • u2 (float) –

    Second quadratic limb-darkening coefficient.

    The specific intensity profile is:

    \[I(\mu) / I(1) = 1 - u_1 (1 - \mu) - u_2 (1 - \mu)^2\]

    where \(\mu = \cos\theta\) and \(\theta\) is the angle from disk center.

get_light_curve(orbit, t)[source]#

Compute the transit light curve for a Keplerian orbit.

Parameters:
  • orbit (KeplerianOrbit) – Orbital model instance.

  • t (array_like) – Times [days].

Returns:

flux – Relative flux (1.0 = out of transit).

Return type:

jnp.ndarray

class spotgp.transit.SpotTransitModel(orbit, limbdark, spot_model=None)[source]#

Bases: object

Combined stellar variability (spots) + planetary transit model.

The total flux is the product of the spot-modulated stellar flux and the transit flux:

\[F(t) = F_{\mathrm{spots}}(t) \times F_{\mathrm{transit}}(t)\]

This is the standard multiplicative model: the transit removes a fraction of the current stellar brightness (including any spot modulation on the visible hemisphere).

The spot component can be supplied in two ways:

  1. Explicit spots via a LightcurveModel instance — a forward simulation with individual spots drawn from the spot evolution model.

  2. GP-based via a GPSolver instance — draws from the GP prior or posterior to represent the stellar variability stochastically.

Parameters:
get_transit_flux(t)[source]#

Compute the transit light curve alone (no spots).

Parameters:

t (array_like) – Times [days].

Returns:

flux_transit – Relative flux from the transit (1.0 = out of transit).

Return type:

jnp.ndarray

get_spot_flux(t)[source]#

Compute the spot-modulated stellar flux alone (no transit).

Uses whichever spot model was provided at construction time.

Parameters:

t (array_like) – Times [days].

Returns:

flux_spots – Relative flux from stellar variability.

Return type:

ndarray

Raises:

ValueError – If no spot model was provided.

get_light_curve(t)[source]#

Compute the combined spot + transit light curve.

Parameters:

t (array_like) – Times [days].

Returns:

flux – Combined relative flux.

Return type:

jnp.ndarray

sample_light_curves(t, n_samples=5, source='prior', rng=None)[source]#

Draw combined spot + transit light curve samples.

Only available when the spot model is a GPSolver. Each sample draws an independent realization of the spot variability and multiplies it by the deterministic transit model.

Parameters:
  • t (array_like) – Times [days].

  • n_samples (int) – Number of samples to draw (default 5).

  • source ({'prior', 'posterior'}) – Draw from the GP prior or posterior (default 'prior').

  • rng (numpy.random.Generator or None) – Random number generator for reproducibility.

Returns:

  • t (jnp.ndarray, shape (M,)) – Evaluation times.

  • samples (jnp.ndarray, shape (n_samples, M)) – Combined flux samples.

Raises:

TypeError – If the spot model is not a GPSolver.

animate_lightcurve(t=None, fps=30, duration=10.0, outfile=None, dpi=150, show_spots=True, show_grid=True, show_params=True, figsize=(14, 5.5), save_last_frame=None, show_dr=True, label_size=18)[source]#

Animate the spotted star with transiting planet and combined light curve.

Left panel shows the rotating stellar disk with spots and the planet transiting across it. Right panel traces the combined (spots x transit) light curve over time, with the transit-only and spot-only components shown as faint references.

Requires a LightcurveModel as the spot model.

Parameters:
  • t (array_like or None) – Time grid [days]. If None, uses the spot model’s internal grid spot_model.t.

  • fps (int) – Frames per second (default 30).

  • duration (float) – Animation duration in seconds (default 10).

  • outfile (str or None) – Output file path (.mp4 or .gif). If None, returns the animation object without saving.

  • dpi (int) – Resolution (default 150).

  • show_spots (bool) – If True, show individual spot contributions on the light curve panel (default True).

  • show_grid (bool) – If True, draw latitude/longitude grid on the star (default True).

  • show_params (bool) – If True, show parameter annotation above the figure (default True).

  • figsize (tuple) – Figure size (default (14, 5.5)).

  • save_last_frame (str or None) – If provided, save the last frame as a static image.

  • show_dr (bool) – If True, color the stellar disk by differential rotation rate (default True).

  • label_size (int or float) – Font size for labels and tick marks (default 18).

Returns:

anim

Return type:

matplotlib.animation.FuncAnimation

Sensitivity Analysis#

spotgp.sensitivity.sobol_indices(func, bounds, n=1024, param_names=None)[source]#

Estimate first-order and total-order Sobol sensitivity indices.

Uses the Saltelli estimator:

S_i = V[E[Y|X_i]] / V[Y] (first-order) ST_i = E[V[Y|X_~i]] / V[Y] (total-order)

Parameters:
  • func (callable) – Scalar function f(x) where x has shape (k,).

  • bounds (list of (lo, hi) tuples) – Parameter ranges, length k.

  • n (int) – Base sample size. Total model evaluations = n * (k + 2).

  • param_names (list of str, optional) – Names for each parameter.

Returns:

results – ‘S1’ : ndarray (k,) — first-order indices ‘ST’ : ndarray (k,) — total-order indices ‘S1_var’ : ndarray (k,) — bootstrap variance of S1 ‘ST_var’ : ndarray (k,) — bootstrap variance of ST ‘names’ : list of str

Return type:

dict with keys:

Plotting#

spotgp.plotting.crb_corner_plot(cov_crb, param_keys, true_vals, corner_keys, plot_color='steelblue', param_labels=None, panel_size=3.0, base_fontsize=16, gridspec_kw={'hspace': 0.02, 'wspace': 0.02}, title=None)[source]#

Corner plot of Cramer-Rao Bound confidence ellipses.

Diagonal panels show 1D Gaussians with mean +/- std annotations. Lower-triangle panels show 2D confidence ellipses (1-sigma and 2-sigma) with the correlation coefficient printed in the upper right.

Parameters:
  • cov_crb (ndarray, shape (P, P)) – Full CRB covariance matrix over all parameters in param_keys.

  • param_keys (list of str) – Names of all parameters corresponding to rows/columns of cov_crb.

  • true_vals (list or ndarray) – True (or reference) values for all parameters in param_keys.

  • corner_keys (list of str) – Subset of param_keys to include in the corner plot.

  • param_labels (dict, optional) – Mapping from key to display label (supports LaTeX). Defaults to key name.

  • panel_size (float, optional) – Size in inches per panel. Scales the overall figure. Default 3.0.

  • base_fontsize (float, optional) – Base font size at panel_size=3. Scales with panel_size. Default 16.

Returns:

fig, axes

Return type:

Figure and ndarray of Axes