Symbolic Equations with Sympy#
Every major class in spotgp has a get_sympy() method that renders its defining equations as LaTeX. This is useful for:
Inspecting the analytic form of your model
Verifying parameter choices
Including equations in papers or presentations
This tutorial demonstrates get_sympy() for each component class.
import sys
sys.path.append("../..")
import numpy as np
from spotgp import (
TrapezoidSymmetricEnvelope,
TrapezoidAsymmetricEnvelope,
SkewedGaussianEnvelope,
ExponentialEnvelope,
VisibilityFunction,
LatitudeDistributionFunction,
SpotEvolutionModel,
DeltaDistribution,
UniformDistribution,
GaussianDistribution,
LogNormalDistribution,
)
1. Envelope functions#
Each envelope displays \(\Gamma(t)\), \(\hat{\Gamma}(\omega)\), and \(R_\Gamma(\tau)\).
Symmetric trapezoid#
env = TrapezoidSymmetricEnvelope(lspot=10.0, tau_spot=3.0)
env.get_sympy();
Asymmetric trapezoid#
env_asym = TrapezoidAsymmetricEnvelope(lspot=10.0, tau_em=2.0, tau_dec=5.0)
env_asym.get_sympy();
Skewed Gaussian#
env_sn = SkewedGaussianEnvelope(sigma_sn=3.0, n_sn=-2.0)
env_sn.get_sympy();
Exponential#
env_exp = ExponentialEnvelope(tau_spot=3.0)
env_exp.get_sympy();
Deriving symbolic expressions#
Pass compute_symbolic=True to attempt symbolic derivation of \(\hat{\Gamma}(\omega)\) and \(R_\Gamma(\tau)\) from \(\Gamma(t)\) via sympy integration (can be slow for complex envelopes).
See also
This can be useful for custom envelopes where you only have specified the analytic equation for \(\Gamma(t)\). See: Custom Envelope Functions
env_exp.get_sympy(compute_symbolic=True);
2. Visibility function#
Displays the rotation frequency \(\omega_0(\phi)\), intermediate geometry variables (\(a_0\), \(a_1\), \(\theta_v\)), and Fourier coefficients (\(c_0\), \(c_1\), \(c_n\)).
vis = VisibilityFunction(peq=8.0, kappa=0.3, inc=np.pi / 3)
vis.get_sympy();
3. Latitude distribution#
Displays the latitude PDF \(p(\phi)\).
# Default: uniform
lat = LatitudeDistributionFunction()
lat.get_sympy();
import sympy as sp
class GaussianLatitude(LatitudeDistributionFunction):
def __init__(self, sigma_deg=20.0):
self.sigma = np.radians(sigma_deg)
def __call__(self, phi):
return np.exp(-0.5 * (phi / self.sigma) ** 2)
def sympy_pdf(self):
phi = sp.Symbol(r'\phi', real=True)
sigma = sp.Float(self.sigma)
return sp.exp(-sp.Rational(1, 2) * (phi / sigma) ** 2)
lat_gauss = GaussianLatitude(sigma_deg=20.0)
lat_gauss.get_sympy(status="Gaussian, sigma=20 deg");
4. Parameter distributions#
Each ParameterDistribution subclass can display its PDF. The var_name keyword controls the variable symbol.
DeltaDistribution(0.01).get_sympy(var_name=r"\sigma_k");
UniformDistribution(3.0, 12.0).get_sympy(var_name=r"\ell_{\rm spot}");
GaussianDistribution(mu=5.0, sigma=1.0).get_sympy(var_name=r"\tau_{\rm spot}");
LogNormalDistribution(mu=-4.6, sigma=0.3).get_sympy(var_name=r"\sigma_k");
Custom distribution with sympy#
Override sympy_pdf() in your subclass to get LaTeX rendering:
from spotgp import ParameterDistribution
from scipy.special import beta as beta_func
class BetaDistribution(ParameterDistribution):
"""Beta distribution scaled to [lo, hi]."""
def __init__(self, a, b, lo=0.0, hi=1.0):
self.a, self.b = float(a), float(b)
self.lo, self.hi = float(lo), float(hi)
self._B = beta_func(self.a, self.b)
@property
def support(self):
return (self.lo, self.hi)
def __call__(self, x):
t = (x - self.lo) / (self.hi - self.lo)
if t <= 0 or t >= 1:
return 0.0
return t ** (self.a - 1) * (1 - t) ** (self.b - 1) / self._B
def sympy_pdf(self):
x = sp.Symbol("x")
a, b = sp.Float(self.a), sp.Float(self.b)
lo, hi = sp.Float(self.lo), sp.Float(self.hi)
t = (x - lo) / (hi - lo)
return t ** (a - 1) * (1 - t) ** (b - 1) / (
(hi - lo) * sp.beta(a, b))
BetaDistribution(a=2, b=5, lo=2.0, hi=15.0).get_sympy(
var_name=r"\ell_{\rm spot}");
5. Full model#
SpotEvolutionModel.get_sympy() renders all components in sequence: envelope, visibility, and latitude distribution.
model = SpotEvolutionModel(
envelope=TrapezoidSymmetricEnvelope(lspot=10.0, tau_spot=3.0),
visibility=VisibilityFunction(peq=8.0, kappa=0.3, inc=np.pi / 3),
sigma_k=0.01,
latitude_distribution=GaussianLatitude(sigma_deg=20.0),
)
model.get_sympy();
Summary#
Class |
|
|---|---|
|
\(\Gamma(t)\), \(\hat{\Gamma}(\omega)\), \(R_\Gamma(\tau)\) |
|
\(\omega_0(\phi)\), \(a_0\), \(a_1\), \(\theta_v\), \(c_0\), \(c_1\), \(c_n\) |
|
\(p(\phi)\) |
|
\(p(x)\) (with custom |
|
All of the above combined |
To add sympy support to a custom subclass, override sympy_pdf() (for distributions/latitude) or sympy_Gamma() / sympy_Gamma_hat() / sympy_R_Gamma() (for envelopes).