bayes_spec

bayes_spec: A Bayesian Spectral Line Modeling Framework for Astrophysics - Published in JOSS (2024)

https://github.com/tvwenger/bayes_spec

Science Score: 95.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
    Found .zenodo.json file
  • DOI references
    Found 1 DOI reference(s) in JOSS metadata
  • Academic publication links
    Links to: joss.theoj.org
  • Committers with academic emails
    1 of 3 committers (33.3%) from academic institutions
  • Institutional organization owner
  • JOSS paper metadata
    Published in Journal of Open Source Software

Scientific Fields

Economics Social Sciences - 40% confidence
Last synced: 4 months ago · JSON representation

Repository

A Bayesian Spectral Line Modeling Framework

Basic Info
  • Host: GitHub
  • Owner: tvwenger
  • License: mit
  • Language: Python
  • Default Branch: main
  • Size: 59.9 MB
Statistics
  • Stars: 11
  • Watchers: 1
  • Forks: 4
  • Open Issues: 0
  • Releases: 17
Created over 1 year ago · Last pushed 6 months ago
Metadata Files
Readme License Codemeta

README.md

bayes_spec <!-- omit in toc -->

publish tests codecov Documentation Status status

A Bayesian Spectral Line Modeling Framework for Astrophysics

bayes_spec is a framework for user-defined, cloud-based models of astrophysical systems (e.g., the interstellar medium) that enables spectral line simulation and statistical inference. Built in the pymc probabilistic programming library, bayes_spec uses Monte Carlo Markov Chain techniques to fit user-defined models to data. The user-defined models can be a simple line profile (e.g., a Gaussian profile) or a complicated physical model. The models are "cloud-based", meaning there can be multiple "clouds" or "components" each with a unique set of the model parameters. bayes_spec includes algorithms to estimate the optimal number of components in a given dataset.

Read below to get started, and check out the tutorials and guides here: https://bayes-spec.readthedocs.io.

Installation

Basic Installation

Install with pip in a conda virtual environment: ``` conda create --name bayesspec -c conda-forge pymc pip conda activate bayesspec

Due to a bug in arviz, this fork is temporarily necessary

See: https://github.com/arviz-devs/arviz/issues/2437

pip install git+https://github.com/tvwenger/arviz.git@plotpairreferencelabels pip install bayesspec ```

Development Installation

Alternatively, download and unpack the latest release, or fork the repository and contribute to the development of bayes_spec!

Install in a conda virtual environment: ``` cd /path/to/bayes_spec conda env create -f environment.yml

or, if you would like to use CUDA (nvidia GPU) samplers:

conda env create -f environment-cuda.yml

conda activate bayes_spec-dev pip install -e . ```

Quick Start

Here we demonstrate how to use bayes_spec to fit a simple Gaussian line profile model to a synthetic spectrum. For more details, see the Usage section as well as the documentation and tutorials.

```python

Generate data structure

import numpy as np from bayes_spec import SpecData

velocityaxis = np.linspace(-250.0, 250.0, 501) # km s-1 noise = 1.0 # K brightnessdata = noise * np.random.randn(len(velocityaxis)) # K observation = SpecData(velocityaxis, brightnessdata, noise, ylabel=r"Brightness Temperature $TB$ (K)", xlabel=r"LSR Velocity $V_{\rm LSR}$ (km s$^{-1})$") data = {"observation": observation}

Prepare a three cloud GaussLine model with polynomial baseline degree = 2

from bayes_spec.models import GaussModel

model = GaussModel(data, nclouds=3, baselinedegree=2) model.addpriors() model.addlikelihood()

Evaluate the model for a given set of parameters to generate a synthetic "observation"

simbrightness = model.model.observation.eval({ "fwhm": [25.0, 40.0, 35.0], # FWHM line width (km/s) "linearea": [250.0, 125.0, 175.0], # line area (K km/s) "velocity": [-35.0, 10.0, 55.0], # velocity (km/s) "baselineobservationnorm": [-0.5, -2.0, 3.0], # normalized baseline coefficients })

Pack data structure with synthetic "observation"

observation = SpecData(velocityaxis, simbrightness, noise, ylabel=r"Brightness Temperature $TB$ (K)", xlabel=r"LSR Velocity $V{\rm LSR}$ (km s$^{-1})$") data = {"observation": observation}

Initialize the model with the synthetic observation

model = GaussModel(data, nclouds=3, baselinedegree=2) model.addpriors() model.addlikelihood()

Draw posterior samples via MCMC

model.sample()

Solve labeling degeneracy

model.solve()

Draw posterior predictive samples

from bayesspec.plots import plotpredictive

posterior = model.sampleposteriorpredictive(thin=100) axes = plotpredictive(model.data, posterior.posteriorpredictive) axes.ravel()[0].figure.show()

visualize posterior distribution

from bayesspec.plots import plotpair

axes = plotpair(model.trace.solution0, model.cloud_deterministics, labeller=model.labeller) axes.ravel()[0].figure.show()

get posterior summary statistics

import arviz as az

print(az.summary(model.trace.solution_0)) ```

posterior predictive

Posterior predictive samples for a three-cloud GaussLine model fit to a synthetic spectrum. The black line represents the synthetic spectrum, and each colored line is one posterior predictive sample.

posterior pair

Projections of the posterior distribution for a three-cloud GaussLine model fit to a synthetic spectrum. The free model parameters are the integrated line area, $\int TB dV$, the full-width at half-maximum line width, $\Delta V$, and the line-center velocity, $V{\rm LSR}$. The line amplitude, $T_B$, is a derived quantity. The three posterior modes correspond to the three clouds in this model.

Usage

bayes_spec assumes that the source of spectral line emission can be decomposed into a series of "clouds" or "components", each of which are defined by a unique set of model parameters. For a simple line profile model (like a Gaussian profile), these parameters might be the Gaussian amplitude, center velocity, and line width. For a more complicated model, they might be the optical depth, excitation temperature, and velocity of the cloud. bayes_spec also supports hyper-parameters: parameters that influence both non-cloud based features in the data (e.g., spectral baseline structure) as well as overall cloud properties (e.g., a property assumed shared among all clouds) or physical relationships (e.g., an empirical scaling law).

Users are responsible for defining and testing their models. Here we briefly describe how to do this, but see Syntax & Examples for some practical demonstrations. Additional tips and tricks can be found in the documentation: https://bayes-spec.readthedocs.io/en/stable/tips.html

Users must specify the following:

  1. The data
  2. Model parameters and hyper-parameters
  3. The parameter and hyper-parameter prior distributions
  4. Derived quantities (called "deterministics") that should be saved (e.g., for inference)
  5. The relationship between the model parameters and spectral observations (i.e., the likelihood)

Data Format

Data must be packaged within a bayes_spec.SpecData object. SpecData takes three arguments: the spectral axis (i.e., frequency, velocity), the brightness data (e.g., brightness temperature, flux density), and the noise (in the same units as the brightness data). The noise can either be a scalar value, in which case it is assumed constant across the spectrum, or an array of the same length as the brightness_data.

```python from bayes_spec import SpecData

spec = SpecData(spectralaxis, brightnessdata, noise, xlabel="Velocity", ylabel="Brightness Temperature") ```

The spectral and brightness data are accessed via spec.spectral and spec.brightness, respectively. The noise is accessed via spec.noise.

The data are passed to a bayes_spec model in a dictionary, which allows multiple spectra to be included in a single model. For example, if a model is constrained by both an emission-line spectrum and an absorption-line spectrum, then this dictionary might look something like this:

```python emission = SpecData(emissionspecaxis, emissiondata, emissionnoise, xlabel="Velocity", ylabel="Brightness Temperature") absorption = SpecData(absorptionspecaxis, absorptiondata, absorptionnoise, xlabel="Velocity", ylabel="Optical Depth")

data = {"emission": emission, "absorption": absorption} ```

The keys of this data dictionary ("emission" and "absorption" in this case) are important, you must remember them and use the same keys in your model definition.

Internally, SpecData normalizes both the spectral axis and the data. Generally, this is only relevant for the polynomial baseline model, which is fit to the normalized data.

Model Specification

Model specification is made though a class that extends the bayes_spec.BaseModel base model class definition. This class must include three methods: __init__, which initializes the model, and add_priors, which adds the priors to the model, and add_likelihood, which adds the likelihood to the model. These priors and likelihood are specified following the usual pymc syntax. See the definition of GaussModel for an example. Alternatively, the class can extend an existing bayes_spec model, which is convenient for similar models with, for example, added complexity. See the definition of GaussNoiseModel, which extends GaussLine.

A step-by-step guide for creating bayes_spec models can be found in the documentation: https://bayes-spec.readthedocs.io/en/stable/models.html

Algorithms

Posterior Sampling: Variational Inference

bayes_spec can sample from an approximation of model posterior distribution using variational inference (VI). The benefit of VI is that it is fast, but the downside is that it often fails to capture complex posterior topologies. We recommend only using VI for quick model tests or MCMC initialization. Draw posterior samples using VI via model.fit().

Posterior Sampling: MCMC

bayes_spec can also use MCMC to sample the posterior distribution. MCMC sampling tends to be much slower but also more accurate. Draw posterior samples using MCMC via model.sample(). Since bayes_spec uses pymc for sampling, several pymc samplers are available, including GPU samplers (see "other samplers" example notebook).

Posterior Sampling: SMC

Finally, bayes_spec implements Sequential Monte Carlo (SMC) sampling via model.sample_smc(). SMC can significantly improve performance for degenerate models with multi-modal posterior distributions, although it struggles with high dimensional models and models that suffer from a strong labeling degeneracy (see "other samplers" example notebook).

Posterior Clustering: Gaussian Mixture Models

Assuming that we have drawn posterior samples via MCMC or SMC using multiple independent Markov chains, then it is possible that each chain disagrees on the order of clouds. This is known as the labeling degeneracy. For some models (e.g., optically thin radiative transfer), the order of clouds along the line-of-sight is arbitrary so each chain may converge to a different label order.

It is also possible that the model solution is degenerate, the posterior distribution is strongly multi-modal, and each chain converges to different, unique solutions.

bayes_spec uses Gaussian Mixture Models (GMMs) to break the labeling degeneracy and identify unique solutions. After sampling, execute model.solve() to fit a GMM to the posterior samples of each chain individually. Unique solutions are identified by discrepant GMM fits, and we break the labeling degeneracy by adopting the most common cloud order amongst chains. The user defines which parameters are used for the GMM clustering.

Optimization

bayes_spec can optimize the number of clouds in addition to the other model parameters. The Optimize class will use VI, MCMC, and/or SMC to estimate the preferred number of clouds.

Models

bayes_spec provides two basic models for convenience.

bayes_spec.models.GaussModel

GaussModel is a Gaussian line profile model. The model assumes that the emission of each cloud is a Gaussian-shaped spectral line. The SpecData key must be "observation". The following diagram demonstrates the relationship between the free parameters (empty ellipses), deterministic quantities (rectangles), model predictions (filled ellipses), and observations (filled, round rectangles). Many of the parameters are internally normalized (and thus have names like _norm). The subsequent tables describe the model parameters in more detail.

gauss model

| Cloud Parameter
variable | Parameter | Units | Prior, where
($p0, p1, \dots$) = prior_{variable} | Default
prior_{variable} | | :---------------------------- | :------------------------------------------ | :--------- | :--------------------------------------------------------------- | :---------------------------- | | line_area | Integrated line area | K km s-1 | $\int T{B, \rm H} dV \sim {\rm Gamma}(\alpha=2.0, \beta=1.0/p)$ | 100.0 | | fwhm | FWHM line width | km s-1 | $\Delta V{\rm H} \sim {\rm Gamma}(\alpha=3.0, \beta=2.0/p)$ | 20.0 | | | velocity | Center velocity | km s-1 | $V{\rm LSR, H} \sim {\rm Normal}(\mu=p0, \sigma=p1)$ | [0.0, 25.0] | | `baselinecoeffs| Normalized polynomial baseline coefficients || $\beta_i \sim {\rm Normal}(\mu=0.0, \sigma=p_i)$ |[1.0]*(baseline_degree + 1)` |

bayes_spec.models.GaussNoiseModel

GaussNoiseModel extends GaussModel to add an additional free parameter: the spectral rms noise. The SpecData key must be "observation".

gauss noise model

| Hyper Parameter
variable | Parameter | Units | Prior, where
($p0, p1, \dots$) = prior_{variable} | Default
prior_{variable} | | :---------------------------- | :----------------- | :---- | :------------------------------------------------------- | :---------------------------- | | rms | Spectral rms noise | K | ${\rm rms} \sim {\rm HalfNormal}(\sigma=p)$ | 1.0 |

ordered_velocity

An additional parameter to set_priors for these models is ordered_velocity. By default, this parameter is False, in which case the order of the clouds is arbitrary. Sampling from these models can be challenging due to the labeling degeneracy: if the order of clouds does not matter (i.e., the emission is optically thin), then each Markov chain could decide on a different, equally-valid order of clouds.

If we assume that the emission is optically thin (and thus the order of clouds really is arbitrary), then we can set ordered_velocity=True, in which case the order of clouds is restricted to be increasing with velocity. This assumption can drastically improve sampling efficiency. When ordered_velocity=True, the velocity prior is defined differently:

| Cloud Parameter
variable | Parameter | Units | Prior, where
($p0, p1, \dots$) = prior_{variable} | Default
prior_{variable} | | :---------------------------- | :-------------- | :------- | :----------------------------------------------------------------------- | :---------------------------- | | velocity | Center velocity | km s-1 | $Vi \sim p0 + \sum0^{i-1} Vi + {\rm Gamma}(\alpha=2, \beta=1.0/p_1)$ | [0.0, 25.0] |

Syntax & Examples

See the various tutorial notebooks under docs/source/notebooks. Tutorials and the full API are available here: https://bayes-spec.readthedocs.io.

Feedback, Issues, and Contributing

If you have questions about bayes_spec, then please consider starting a discussion on GitHub.

Should you find any issues or encounter any problems with bayes_spec, then please submit an issue on GitHub.

Anyone is welcome to contribute to the development of bayes_spec via GitHub. Please consider submitting a pull request for any bug fixes or new features!

License and Copyright

Copyright(C) 2024 by Trey V. Wenger; tvwenger@gmail.com This code is licensed under MIT license (see LICENSE for details)

Owner

  • Name: Trey Wenger
  • Login: tvwenger
  • Kind: user
  • Location: Madison, Wisconsin, USA
  • Company: University of Wisconsin-Madison

Astrophysicist

JOSS Publication

bayes_spec: A Bayesian Spectral Line Modeling Framework for Astrophysics
Published
November 01, 2024
Volume 9, Issue 103, Page 7201
Authors
Trey V. Wenger ORCID
NSF Astronomy & Astrophysics Postdoctoral Fellow, University of Wisconsin-Madison, USA
Editor
Ivelina Momcheva ORCID
Tags
astronomy astrophysics spectroscopy Bayesian models

CodeMeta (codemeta.json)

{
  "@context": "https://raw.githubusercontent.com/codemeta/codemeta/master/codemeta.jsonld",
  "@type": "Code",
  "author": [
    {
      "@id": "https://orcid.org/0000-0003-0640-7787",
      "@type": "Person",
      "email": "tvwenger@gmail.com",
      "name": "Trey Wenger",
      "affiliation": "University of Wisconsin-Madison"
    }
  ],
  "identifier": "",
  "codeRepository": "https://github.com/tvwenger/bayes_spec",
  "datePublished": "2024-08-15",
  "dateModified": "2024-08-15",
  "dateCreated": "2024-08-15",
  "description": "A Bayesian Spectral Line Modeling Framework for Astrophysics",
  "keywords": "Python, astronomy, astrophysics, spectroscopy, Bayesian models",
  "license": "MIT",
  "title": "bayes_spec",
  "version": ""
}

GitHub Events

Total
  • Create event: 26
  • Issues event: 23
  • Release event: 8
  • Watch event: 7
  • Delete event: 19
  • Issue comment event: 20
  • Push event: 15
  • Pull request event: 28
  • Fork event: 1
Last Year
  • Create event: 26
  • Issues event: 23
  • Release event: 8
  • Watch event: 7
  • Delete event: 19
  • Issue comment event: 20
  • Push event: 15
  • Pull request event: 28
  • Fork event: 1

Committers

Last synced: 5 months ago

All Time
  • Total Commits: 63
  • Total Committers: 3
  • Avg Commits per committer: 21.0
  • Development Distribution Score (DDS): 0.048
Past Year
  • Commits: 59
  • Committers: 3
  • Avg Commits per committer: 19.667
  • Development Distribution Score (DDS): 0.051
Top Committers
Name Email Commits
Trey Wenger t****r@g****m 60
Warrick Ball w****l@g****m 2
larryshamalama l****g@m****a 1
Committer Domains (Top 20 + Academic)

Issues and Pull Requests

Last synced: 4 months ago

All Time
  • Total issues: 30
  • Total pull requests: 54
  • Average time to close issues: 28 days
  • Average time to close pull requests: about 2 hours
  • Total issue authors: 7
  • Total pull request authors: 3
  • Average comments per issue: 1.23
  • Average comments per pull request: 0.5
  • Merged pull requests: 53
  • Bot issues: 0
  • Bot pull requests: 0
Past Year
  • Issues: 30
  • Pull requests: 54
  • Average time to close issues: 28 days
  • Average time to close pull requests: about 2 hours
  • Issue authors: 7
  • Pull request authors: 3
  • Average comments per issue: 1.23
  • Average comments per pull request: 0.5
  • Merged pull requests: 53
  • Bot issues: 0
  • Bot pull requests: 0
Top Authors
Issue Authors
  • tvwenger (14)
  • victorliu1231 (5)
  • kbwestfall (5)
  • ConorMacBride (4)
  • larryshamalama (2)
  • bcappa (1)
  • danabalser (1)
Pull Request Authors
  • tvwenger (94)
  • warrickball (4)
  • larryshamalama (2)
Top Labels
Issue Labels
documentation (6) installation (3) enhancement (1)
Pull Request Labels

Packages

  • Total packages: 1
  • Total downloads:
    • pypi 108 last-month
  • Total dependent packages: 0
  • Total dependent repositories: 0
  • Total versions: 17
  • Total maintainers: 1
pypi.org: bayes-spec

A Bayesian Spectral Line Modeling Framework for Astrophysics

  • Homepage: https://github.com/tvwenger/bayes_spec
  • Documentation: https://bayes-spec.readthedocs.io/
  • License: The MIT License (MIT) Copyright (c) 2024 Trey V. Wenger Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  • Latest release: 1.9.0
    published 6 months ago
  • Versions: 17
  • Dependent Packages: 0
  • Dependent Repositories: 0
  • Downloads: 108 Last month
Rankings
Dependent packages count: 10.5%
Average: 34.9%
Dependent repos count: 59.2%
Maintainers (1)
Last synced: 4 months ago

Dependencies

environment.yml pypi
requirements.txt pypi
  • arviz *
  • graphviz *
  • matplotlib *
  • numpy *
  • pymc >=5
  • pytensor *
  • scikit-learn *
  • scipy *
setup.py pypi