A Quick Start Tutorial#
This tutorial provides a quick start guide to using ELISA to fit a spectral model to X-ray spectral data. The tutorial is divided into three sections:
Load Data and Define Spectral Model
Bayesian Fit
Maximum Likelihood Fit
The data used in this tutorial is from the Insight-HXMT observation of the Crab Nebula. The spectra are obtained by the Low Energy (LE), the Medium Energy (ME), and the High Energy (HE) telescopes. The spectral model used in this tutorial is a power-law model modified by a photoelectric absorption.
The tutorial demonstrates how to fit the spectral model to the data using both Bayesian and Maximum Likelihood methods.
1. Load Data and Define Spectral Model#
from elisa import BayesFit, Data, MaxLikeFit
from elisa.models import PhAbs, PowerLaw
LE = Data(
erange=[1.5, 10],
specfile='data/P011160500104_LE.pi',
backfile='data/P011160500104_LE.bak',
respfile='data/P011160500104_LE.rsp',
group='opt',
)
ME = Data(
erange=[10, 35],
specfile='data/P011160500104_ME.pi',
backfile='data/P011160500104_ME.bak',
respfile='data/P011160500104_ME.rsp',
group='opt',
)
HE = Data(
erange=[28, 250],
specfile='data/P011160500104_HE.pi',
backfile='data/P011160500104_HE.bak',
respfile='data/P011160500104_HE.rsp',
group='opt',
)
data = [LE, ME, HE]
model = PhAbs() * PowerLaw()
/home/docs/checkouts/readthedocs.org/user_builds/astro-elisa/conda/v0.2.3/lib/python3.12/site-packages/elisa/util/config.py:80: Warning: only 2 CPUs available, will use 1 CPUs
warnings.warn(msg, Warning)
/tmp/ipykernel_3307/205821572.py:4: Warning: spectrum data/P011160500104_LE.bak has zero statistical errors, which may lead to wrong result under Gaussian statistics, consider grouping the spectrum
LE = Data(
/tmp/ipykernel_3307/205821572.py:12: Warning: spectrum data/P011160500104_ME.bak has zero statistical errors, which may lead to wrong result under Gaussian statistics, consider grouping the spectrum
ME = Data(
/tmp/ipykernel_3307/205821572.py:20: Warning: spectrum data/P011160500104_HE.bak has zero statistical errors, which may lead to wrong result under Gaussian statistics, consider grouping the spectrum
HE = Data(
2. Bayesian Fit#
Bayesian Fit
| Data | Model | Statistic |
|---|---|---|
| LE | PhAbs * PowerLaw | pgstat |
| ME | PhAbs * PowerLaw | pgstat |
| HE | PhAbs * PowerLaw | pgstat |
| No. | Component | Parameter | Value | Prior |
|---|---|---|---|---|
| 1 | PhAbs | nH | 1 | Uniform(0, 1e+06) |
| 2 | PowerLaw | alpha | 1.01 | Uniform(-3, 10) |
| 3 | PowerLaw | K | 1 | Uniform(1e-10, 1e+10) |
Run the No-U-Turn Sampler#
/home/docs/checkouts/readthedocs.org/user_builds/astro-elisa/conda/v0.2.3/lib/python3.12/site-packages/arviz/stats/stats.py:1652: UserWarning: For one or more samples the posterior variance of the log predictive densities exceeds 0.4. This could be indication of WAIC starting to fail.
See http://arxiv.org/abs/1507.04544 for details
warnings.warn(
Posterior Result
Parameters
| Parameter | Mean | StdDev | Median | 68.3% Quantile | ESS | Rhat |
|---|---|---|---|---|---|---|
| PhAbs.nH | 0.355 | 0.0092 | 0.355 | [-0.00924, 0.00945] | 1803 | N/A |
| PowerLaw.alpha | 2.12 | 0.0022 | 2.12 | [-0.00227, 0.00212] | 2017 | N/A |
| PowerLaw.K | 8.9 | 0.0461 | 8.9 | [-0.0476, 0.046] | 1856 | N/A |
Statistics
| Data | Statistic | Mean | Median | Channels |
|---|---|---|---|---|
| LE | pgstat | 122.14 | 121.56 | 96 |
| ME | pgstat | 18.00 | 17.56 | 17 |
| HE | pgstat | 30.65 | 30.04 | 28 |
| Total | stat/dof | 170.80/138 | 170.18/138 | 141 |
Information Criterion
| Method | Deviance | p |
|---|---|---|
| LOOIC | 175.20 ± 22.77 | 4.15 |
| WAIC | 175.15 ± 22.76 | 4.12 |
Pareto k Diagnostic
| Range | Flag | Count | Pct. |
|---|---|---|---|
| (-Inf, 0.70] | good | 141 | 100.0% |
| (0.70, 1] | bad | 0 | 0.0% |
| (1, Inf) | very bad | 0 | 0.0% |
Plot the Trace of Sampler#
fig = posterior.plot.plot_trace()
Plot of Spectral Fit and Residuals#
fig = posterior.plot()
Goodness of Fit: Quantile-Quantile Plot#
fig = posterior.plot.plot_qq(detrend=False)
Goodness of Fit: Probability Integral Transform ECDF Plot#
fig = posterior.plot.plot_pit(detrend=False)
Plot Marginal Posterior Distribution#
fig = posterior.plot.plot_corner()
Calculate Credible Intervals of Parameters#
ci = posterior.ci()
ci
CredibleInterval(median={'PhAbs.nH': 0.35468305783170384, 'PowerLaw.alpha': 2.118439713044811, 'PowerLaw.K': 8.902595929877329}, intervals={'PhAbs.nH': (0.345448912867953, 0.3641243930036606), 'PowerLaw.alpha': (2.116175518266008, 2.1205576309978933), 'PowerLaw.K': (8.854995319667175, 8.948625836633322)}, errors={'PhAbs.nH': (-0.009234144963750857, 0.009441335171956777), 'PowerLaw.alpha': (-0.0022641947788031302, 0.002117917953082138), 'PowerLaw.K': (-0.047600610210153604, 0.04602990675599372)}, cl=np.float64(0.6826894921370859), method='ETI', dist={'PhAbs.nH': array([[0.35307594, 0.35265833, 0.35399535, ..., 0.36013947, 0.36016573,
0.35814949]], shape=(1, 5000)), 'PowerLaw.alpha': array([[2.12020645, 2.12094415, 2.11882787, ..., 2.11864643, 2.12070248,
2.11706934]], shape=(1, 5000)), 'PowerLaw.K': array([[8.93632502, 8.94852556, 8.9081469 , ..., 8.93408391, 8.92631465,
8.87832211]], shape=(1, 5000))})
ci.median
{'PhAbs.nH': 0.35468305783170384,
'PowerLaw.alpha': 2.118439713044811,
'PowerLaw.K': 8.902595929877329}
ci.errors
{'PhAbs.nH': (-0.009234144963750857, 0.009441335171956777),
'PowerLaw.alpha': (-0.0022641947788031302, 0.002117917953082138),
'PowerLaw.K': (-0.047600610210153604, 0.04602990675599372)}
3. Maximum Likelihood Fit#
Maximum Likelihood Fit
| Data | Model | Statistic |
|---|---|---|
| LE | PhAbs * PowerLaw | pgstat |
| ME | PhAbs * PowerLaw | pgstat |
| HE | PhAbs * PowerLaw | pgstat |
| No. | Component | Parameter | Value | Bound |
|---|---|---|---|---|
| 1 | PhAbs | nH | 0.35 | (0, 1e+06) |
| 2 | PowerLaw | alpha | 1.01 | (-3, 10) |
| 3 | PowerLaw | K | 1 | (1e-10, 1e+10) |
Use Levenberg-Marquardt algorithm to find the MLE#
mle = fit2.mle(method='lm')
mle
MLE Result
Parameters
| Parameter | MLE | Error |
|---|---|---|
| PhAbs.nH | 0.3543 | 0.009225 |
| PowerLaw.alpha | 2.118 | 0.002194 |
| PowerLaw.K | 8.9 | 0.0461 |
Fit Statistics
| Data | Statistic | Value | Channels |
|---|---|---|---|
| LE | pgstat | 120.24 | 96 |
| ME | pgstat | 17.62 | 17 |
| HE | pgstat | 29.97 | 28 |
| Total | stat/dof | 167.83/138 | 141 |
Information Criterion
| Method | Value |
|---|---|
| AIC | 174.00 |
| BIC | 182.67 |
Fit Status
| Migrad | |
|---|---|
| FCN = 167.8 (χ²/ndof = 1.2) | Nfcn = 98, Ngrad = 1 |
| EDM = 2.3e-08 (Goal: 0.0002) | time = 3.2 sec |
| Valid Minimum | Below EDM threshold (goal x 10) |
| No parameters at limit | Below call limit |
| Hesse ok | Covariance accurate |
Plot of Spectral Fit and Residuals#
fig = mle.plot()
Goodness of Fit: Quantile-Quantile Plot#
fig = mle.plot.plot_qq(detrend=False)
Goodness of Fit: Probability Integral Transform ECDF Plot#
fig = mle.plot.plot_pit(detrend=False)
Calculate Confidence Intervals of Parameters#
ci = mle.ci()
ci
ConfidenceInterval(mle={'PhAbs.nH': 0.35429926252127875, 'PowerLaw.alpha': 2.1183203931005345, 'PowerLaw.K': 8.899948343483342}, se={'PhAbs.nH': 0.00922543955714701, 'PowerLaw.alpha': 0.002193915753357573, 'PowerLaw.K': 0.04610361194426487}, intervals={'PhAbs.nH': (0.3450776689087919, 0.36352855437839926), 'PowerLaw.alpha': (2.1161287517819476, 2.1205165866293942), 'PowerLaw.K': (8.8539784987533, 8.94618633190051)}, errors={'PhAbs.nH': (-0.009221593612486867, 0.009229291857120514), 'PowerLaw.alpha': (-0.0021916413185869565, 0.002196193528859691), 'PowerLaw.K': (-0.04596984473004184, 0.046237988417168197)}, cl=np.float64(0.6826894921370859), method='profile', status={'PowerLaw.K': {'valid': (True, True), 'at_limit': (False, False), 'at_max_fcn': (False, False), 'new_min': (False, False)}, 'PowerLaw.alpha': {'valid': (True, True), 'at_limit': (False, False), 'at_max_fcn': (False, False), 'new_min': (False, False)}, 'PhAbs.nH': {'valid': (True, True), 'at_limit': (False, False), 'at_max_fcn': (False, False), 'new_min': (False, False)}})
ci.mle
{'PhAbs.nH': 0.35429926252127875,
'PowerLaw.alpha': 2.1183203931005345,
'PowerLaw.K': 8.899948343483342}
ci.errors
{'PhAbs.nH': (-0.009221593612486867, 0.009229291857120514),
'PowerLaw.alpha': (-0.0021916413185869565, 0.002196193528859691),
'PowerLaw.K': (-0.04596984473004184, 0.046237988417168197)}