Fermi Analysis Chain

Here is a schematic diagram of the analysis chain we will be following. This is mainly for reference, and also to convince you that there are a lot of inputs that are needed to properly analyze gamma-ray data.

Analysis Configuration

Here are some details of the analysis configuration. These are also provided mainly for reference.

LAT Photon and Pointing data

The Fermi-LAT records individual gamma-ray interactions. The basic data format is a photon list.


In [1]:
# Basic setup
%load_ext autoreload
%autoreload 2
%matplotlib osx
import numpy as np
import astropy.io.fits as pf


/Users/pjm/lsst/DarwinX86/anaconda/2.1.0-4-g35ca374/lib/python2.7/site-packages/IPython/kernel/__init__.py:13: ShimWarning: The `IPython.kernel` package has been deprecated. You should import from ipykernel or jupyter_client instead.
  "You should import from ipykernel or jupyter_client instead.", ShimWarning)

In [2]:
# Ok, now let's open an event data file at take a look

# !wget -O data/test_events_0000.fits http://www.slac.stanford.edu/~echarles/temp_stats/test_events_0000.fits
f_evt = pf.open("data/test_events_0000.fits")
f_evt.info()


Filename: data/test_events_0000.fits
No.    Name         Type      Cards   Dimensions   Format
0    PRIMARY     PrimaryHDU      31   ()              
1    EVENTS      BinTableHDU    164   5706R x 25C   [E, E, E, E, E, E, E, E, E, D, J, J, I, 3I, I, 32X, I, D, E, E, E, E, E, 1J, 1E]   
2    GTI         BinTableHDU     46   1R x 2C      [D, D]   

That file is a simulation of 1 day of data from a fairly small region of the sky. It isn't particularly interesting, but it is useful to see the data structures. Note that hdu[0] is an empty image (required by FITS standard), hdu[1] is the event data table and hdu[1] is a set of Good Time Intervals (actually, just a single interval in this case).


In [3]:
f_evt[1].columns


Out[3]:
ColDefs(
    name = 'ENERGY'; format = 'E'; unit = 'MeV'
    name = 'RA'; format = 'E'; unit = 'deg'
    name = 'DEC'; format = 'E'; unit = 'deg'
    name = 'L'; format = 'E'; unit = 'deg'
    name = 'B'; format = 'E'; unit = 'deg'
    name = 'THETA'; format = 'E'; unit = 'deg'
    name = 'PHI'; format = 'E'; unit = 'deg'
    name = 'ZENITH_ANGLE'; format = 'E'; unit = 'deg'
    name = 'EARTH_AZIMUTH_ANGLE'; format = 'E'; unit = 'deg'
    name = 'TIME'; format = 'D'; unit = 's'
    name = 'EVENT_ID'; format = 'J'
    name = 'RUN_ID'; format = 'J'
    name = 'RECON_VERSION'; format = 'I'
    name = 'CALIB_VERSION'; format = '3I'
    name = 'EVENT_CLASS'; format = 'I'
    name = 'EVENT_TYPE'; format = '32X'
    name = 'CONVERSION_TYPE'; format = 'I'
    name = 'LIVETIME'; format = 'D'; unit = 's'
    name = 'DIFRSP0'; format = 'E'
    name = 'DIFRSP1'; format = 'E'
    name = 'DIFRSP2'; format = 'E'
    name = 'DIFRSP3'; format = 'E'
    name = 'DIFRSP4'; format = 'E'
    name = 'MC_SRC_ID'; format = '1J'
    name = 'MCENERGY'; format = '1E'
)

The first several columns are the reconstruction energy of the photon and the reconstructed coordinates in several refernces frames ( J2000, Galactic, Instrument frame, Earth centered frame ), and the arrival time of the photon.

The last two columns are the "Monte Carlo Truth" i.e., what we actually generated in the simulations. Obviously these wouldn't be there if we were looking at flight data.


In [4]:
# Ok, now let's take a glance at the spacecraft pointing history

# !wget -O data/test_scData_0000.fits  http://www.slac.stanford.edu/~echarles/temp_stats/test_scData_0000.fits

f_ptg = pf.open("data/test_scData_0000.fits")
f_ptg.info()


Filename: data/test_scData_0000.fits
No.    Name         Type      Cards   Dimensions   Format
0    PRIMARY     PrimaryHDU      28   ()              
1    SC_DATA     BinTableHDU    161   2881R x 30C   [D, D, 3E, E, E, D, E, E, E, E, E, E, L, E, E, E, E, E, E, E, J, B, I, D, D, D, D, D, E, E]   

Ok, in this case we just have one table. This is the pointing information from the spacecraft.


In [6]:
f_ptg[1].columns


Out[6]:
ColDefs(
    name = 'START'; format = 'D'; unit = 's'
    name = 'STOP'; format = 'D'; unit = 's'
    name = 'SC_POSITION'; format = '3E'; unit = 'm'
    name = 'LAT_GEO'; format = 'E'; unit = 'deg'
    name = 'LON_GEO'; format = 'E'; unit = 'deg'
    name = 'RAD_GEO'; format = 'D'; unit = 'm'
    name = 'RA_ZENITH'; format = 'E'; unit = 'deg'
    name = 'DEC_ZENITH'; format = 'E'; unit = 'deg'
    name = 'B_MCILWAIN'; format = 'E'; unit = 'Gauss'
    name = 'L_MCILWAIN'; format = 'E'; unit = 'Earth_Radii'
    name = 'GEOMAG_LAT'; format = 'E'; unit = 'deg'
    name = 'LAMBDA'; format = 'E'; unit = 'deg'
    name = 'IN_SAA'; format = 'L'
    name = 'RA_SCZ'; format = 'E'; unit = 'deg'
    name = 'DEC_SCZ'; format = 'E'; unit = 'deg'
    name = 'RA_SCX'; format = 'E'; unit = 'deg'
    name = 'DEC_SCX'; format = 'E'; unit = 'deg'
    name = 'RA_NPOLE'; format = 'E'; unit = 'deg'
    name = 'DEC_NPOLE'; format = 'E'; unit = 'deg'
    name = 'ROCK_ANGLE'; format = 'E'; unit = 'deg'
    name = 'LAT_MODE'; format = 'J'
    name = 'LAT_CONFIG'; format = 'B'
    name = 'DATA_QUAL'; format = 'I'
    name = 'LIVETIME'; format = 'D'; unit = 's'
    name = 'QSJ_1'; format = 'D'
    name = 'QSJ_2'; format = 'D'
    name = 'QSJ_3'; format = 'D'
    name = 'QSJ_4'; format = 'D'
    name = 'RA_SUN'; format = 'E'; unit = 'deg'
    name = 'DEC_SUN'; format = 'E'; unit = 'deg'
)

The pointing information is given in 30s intervals (since the LAT doesn't slew very quickly this is generally good enough to calculate the exposure and instrument response, on the instrument the pointing information is update at ~5Hz, and that is what is used for the direction assignment of the individual photons).

Binning and Visualizing Counts Data

If we were actually running the analysis chain, at this point we would run the gtbin tool to make a binned counts map of a small region of the sky around Draco. (The region is actually 10x10 degrees, for the LAT that is "small", for HST that would be "absolutely gigantic"). That output of gtbin is the "draco_ccube.fits" file in the remote data area.


In [7]:
#!wget -O data/draco_ccube.fits http://www.slac.stanford.edu/~echarles/temp_stats/draco_ccube.fits

f_ccube = pf.open("data/draco_ccube.fits")
f_ccube.info()


Filename: data/draco_ccube.fits
No.    Name         Type      Cards   Dimensions   Format
0    PRIMARY     PrimaryHDU     145   (100, 100, 24)   int32   
1    EBOUNDS     BinTableHDU     43   24R x 3C     [I, 1E, 1E]   
2    GTI         BinTableHDU     50   33851R x 2C   [D, D]   

So, this is a series of 24 images, showing the counts maps for 1/8 of a decade energy bins running from 500 MeV to 500 GeV. Here examples of the counts maps at 500MeV, 5GeV and 50GeV. The images are smoothed to 0.3 degrees and the Fermi Catalog sources in the region have been overlaid. At the higher energies we can see the individual photons.

Livetime and observing profiles

Recall that the LAT is a very wide field-of-view instrument, (we see gamma-rays out to 80 degrees away from the LAT boresight). The instrumental response changes signifcantly accross the field-of-view, so we have to keep track of how much time any given direction in the sky spends at a particular direction in the instrument frame. We refer to this as the "observing profile" ($t_{obs}$), as an example, here is the observing profile for draco.

In fact, we actually want to keep track of the observing profile for every direction in the sky. We call this a "Livetime cube" and the there is a LAT analysis tool gtltcube that builds this for us. The output of the gtltcube file is the "ltcube_6year.fits" file in the remote data area.


In [8]:
# Let's take a peek at the livetime cube file:

#! wget -O data/draco_ccube.fits http://www.slac.stanford.edu/~echarles/temp_stats/ltcube_6year.fits
f_ltcube = pf.open("data/ltcube_6year.fits")
f_ltcube.info()


Filename: data/ltcube_6year.fits
No.    Name         Type      Cards   Dimensions   Format
0    PRIMARY     PrimaryHDU      27   ()              
1    EXPOSURE    BinTableHDU     61   49152R x 3C   [40E, E, E]   
2    WEIGHTED_EXPOSURE  BinTableHDU     61   49152R x 3C   [40E, E, E]   
3    CTHETABOUNDS  BinTableHDU     33   40R x 2C     [E, E]   
4    GTI         BinTableHDU     46   33851R x 2C   [D, D]   

The main things here are the "EXPOSURE" and "WEIGHTED_EXPSOURE" tables. They are more or less the same (I'm not going to talk about the differences). What those tables contain is a observing time as a function of off-axis angle (i.e., the observing time for 40 different bins in $\cos \theta$) for every direction in a HEALPix pixelization of the sky (i.e., each of the 49152 rows in the table).

Instrument Response Functions

The next step of the analysis is to combine the livetime cube with the tabulated parameterizations of the instrument response as a function of the off-axis angle.

Here is the effective collection area as a function of energy and off-axis angle.

Here is a plot of the 68% and 95% containment radii of the LAT point-spread function as a function of energy. At low energy (< 1GeV) the PSF is dominated by multiple Coulomb scattering of the converted electron and positron. At high energies the PSF is dominated the the pitch of strips in the LAT tracker.

Finally, here is a plot of the 68% containment width of the energy dispersion function. The LAT does best around 1-10 GeV where the majority of the gamma-ray energy is deposited in the LAT calorimeter.

Note that the energy resolution is smaller than the bins size we are using (1/8 decade = 30%) over the entire energy range of our analysis (500 MeV to 500 GeV). In fact, we will be ignoring the energy resolution in our analysis, and assuming that the reconstructed energy is the true energy of the incident gamma-ray.

Exposure

We calculate the exposure by integrating the product of the effective area as of function of energy and off-axis angle and the observing profile over the LAT field of view:

Here $E$ is the photon energy, $\hat{p}$ and $\hat{v}$ are the photon direction in celestial coordinates and in the instrument frame, respectively. The variable $s$ indicates the particular event selection that we are using. The LAT team makes several different photon data sets with increasingly stringent selection criteria. The different data sets are optimized for different types of analysis. For example, when analyzing a short duration transient such as a Gamma-Ray Burst, we use much looser event selection criteria than when analyzing the large-scale diffuse gamma-ray backgrounds.

Normally we would use the tool gtexpcube2 to calculate the exposure as a function of direction and position. You can find the "draco_bexmap.fits" file in the remove data directory.


In [9]:
# Let's peek inside the exposure file:

#! wget -O data/draco_ccube.fits http://www.slac.stanford.edu/~echarles/temp_stats/draco_bexmap.fits
f_expmap = pf.open("data/draco_bexmap.fits")
f_expmap.info()


Filename: data/draco_bexmap.fits
No.    Name         Type      Cards   Dimensions   Format
0    PRIMARY     PrimaryHDU      53   (360, 180, 25)   float32   
1    ENERGIES    BinTableHDU     13   25R x 1C     [1D]   
2    GTI         BinTableHDU     18   33851R x 2C   [D, D]   

The first HDU in the file is an image, note that it is very different from the counts cube image. It is actually an image of the entire sky (360 x 180 1x1 degree pixels) and it is calculated at the edges of the energy bins (so there are 25 layers instead of 24).

Here in an example of the all sky binned exposure map at 5GeV, the green box is the Draco ROI.

If we focus on the Draco ROI we see that the exposure varies very little across the ROI.

The gradiations in color are about 1% variations in the exposure.

Observation averaged point-spread function

Since the LAT PSF varies with incidence angle and energy we also have to compute the observation averaged PSF:

Keep in mind that the PSF varies very strongly with energy.

Building model maps

We will be fitting for gamma-ray emission from Draco by hypothesis testing; in particular we will test the likelihood of a model that includes emission from Draco against the likelihood of a model that does not.

What we actually calculate is the predicted model counts from each source in our model in each pixel for each energy bin. We get this by convolving a flux model of the source with the instrument response:

In fact, since we will be fitting the spectral parameters of sources that we have spatial templates for, then it makes sense to seperate the model into spectral and spatial components. In fact we can compute a spectrum-independent prefactor:

For point sources the templates are simply exposure-weighted images of the PSF. For extended sources the tempatles are the exposure-weighted convolution of the true intensity, $\tilde{S_{i}}(\hat{p})$, with the PSF.

By design, in both cases we can construct the expected counts maps for each source by multiplying the templates by the source spectrum:

We refer to the templates as "source maps" and we have a tool gtsrcmaps to compute them.

Here are some examples of the templates (i.e., the $d_{j}$ for different sources in our model:

Source 500 MeV 5 GeV
Galactic Diffuse
Isotropic
Point Source
Draco

I've put the point source on a log scale so that you can see long tails of the PSF.


In [10]:
# Let's look inside a source map file

# wget -O data/draco_ccube.fits http://www.slac.stanford.edu/~echarles/temp_stats/draco_srcmap.fits

f_srcmap = pf.open("data/draco_srcmap.fits")
f_srcmap.info()


Filename: data/draco_srcmap.fits
No.    Name         Type      Cards   Dimensions   Format
0    PRIMARY     PrimaryHDU      59   (100, 100, 24)   float32   
1    GTI         BinTableHDU     33   33851R x 2C   [D, D]   
2    EBOUNDS     BinTableHDU     38   24R x 3C     [I, 1E, 1E]   
3    3FGL J1411.1+3717  ImageHDU        24   (100, 100, 25)   float32   
4    3FGL J1415.2+4832  ImageHDU        24   (100, 100, 25)   float32   
5    3FGL J1418.5+3543  ImageHDU        24   (100, 100, 25)   float32   
6    3FGL J1419.8+3819  ImageHDU        24   (100, 100, 25)   float32   
7    3FGL J1422.4+3227  ImageHDU        24   (100, 100, 25)   float32   
8    3FGL J1424.9+3615  ImageHDU        24   (100, 100, 25)   float32   
9    3FGL J1426.2+3402  ImageHDU        24   (100, 100, 25)   float32   
10   3FGL J1428.5+4240  ImageHDU        24   (100, 100, 25)   float32   
11   3FGL J1434.1+4203  ImageHDU        24   (100, 100, 25)   float32   
12   3FGL J1438.7+3710  ImageHDU        24   (100, 100, 25)   float32   
13   3FGL J1439.2+3931  ImageHDU        24   (100, 100, 25)   float32   
14   3FGL J1440.1+4955  ImageHDU        24   (100, 100, 25)   float32   
15   3FGL J1442.0+4348  ImageHDU        24   (100, 100, 25)   float32   
16   3FGL J1442.6+5156  ImageHDU        24   (100, 100, 25)   float32   
17   3FGL J1448.0+3608  ImageHDU        24   (100, 100, 25)   float32   
18   3FGL J1450.9+5200  ImageHDU        24   (100, 100, 25)   float32   
19   3FGL J1454.5+5124  ImageHDU        24   (100, 100, 25)   float32   
20   3FGL J1458.7+3719  ImageHDU        24   (100, 100, 25)   float32   
21   3FGL J1500.6+4750  ImageHDU        24   (100, 100, 25)   float32   
22   3FGL J1503.7+4759  ImageHDU        24   (100, 100, 25)   float32   
23   3FGL J1506.1+3728  ImageHDU        24   (100, 100, 25)   float32   
24   3FGL J1506.3+4332  ImageHDU        24   (100, 100, 25)   float32   
25   3FGL J1508.6+2709  ImageHDU        24   (100, 100, 25)   float32   
26   3FGL J1514.1+2940  ImageHDU        24   (100, 100, 25)   float32   
27   3FGL J1514.8+4446  ImageHDU        24   (100, 100, 25)   float32   
28   3FGL J1516.7+3648  ImageHDU        24   (100, 100, 25)   float32   
29   3FGL J1517.0+2637  ImageHDU        24   (100, 100, 25)   float32   
30   3FGL J1520.3+4209  ImageHDU        24   (100, 100, 25)   float32   
31   3FGL J1521.8+4340  ImageHDU        24   (100, 100, 25)   float32   
32   3FGL J1522.1+3144  ImageHDU        24   (100, 100, 25)   float32   
33   3FGL J1531.8+4704  ImageHDU        24   (100, 100, 25)   float32   
34   3FGL J1532.0+3018  ImageHDU        24   (100, 100, 25)   float32   
35   3FGL J1533.5+3416  ImageHDU        24   (100, 100, 25)   float32   
36   3FGL J1534.4+5323  ImageHDU        24   (100, 100, 25)   float32   
37   3FGL J1535.0+3721  ImageHDU        24   (100, 100, 25)   float32   
38   3FGL J1535.7+3920  ImageHDU        24   (100, 100, 25)   float32   
39   3FGL J1539.5+2746  ImageHDU        24   (100, 100, 25)   float32   
40   3FGL J1544.0+4938  ImageHDU        24   (100, 100, 25)   float32   
41   3FGL J1613.8+3410  ImageHDU        24   (100, 100, 25)   float32   
42   3FGL J1615.8+4712  ImageHDU        24   (100, 100, 25)   float32   
43   3FGL J1616.4+4631  ImageHDU        24   (100, 100, 25)   float32   
44   3FGL J1616.8+4111  ImageHDU        24   (100, 100, 25)   float32   
45   3FGL J1625.9+4125  ImageHDU        24   (100, 100, 25)   float32   
46   3FGL J1626.1+3512  ImageHDU        24   (100, 100, 25)   float32   
47   3FGL J1630.2+3733  ImageHDU        24   (100, 100, 25)   float32   
48   3FGL J1632.8+3838  ImageHDU        24   (100, 100, 25)   float32   
49   3FGL J1635.2+3809  ImageHDU        24   (100, 100, 25)   float32   
50   3FGL J1635.3+4257  ImageHDU        24   (100, 100, 25)   float32   
51   3FGL J1639.8+4125  ImageHDU        24   (100, 100, 25)   float32   
52   draco       ImageHDU        24   (100, 100, 25)   float32   
53   gll_iem_v06  ImageHDU        24   (100, 100, 25)   float32   
54   isodiff     ImageHDU        24   (100, 100, 25)   float32   

Note that this file include the binned counts data, and that there is one set of image templates for each source near the draco ROI. Note also that the source maps are actually computed at the edges of the energy bins (i.e., there are 25 layers instead of 24), this is done to improve the accuracy of the numerical integration when making the model maps.

Simply put, this file contains everything needed to do the likelihood fitting except for the spectra of the various sources.

Likelihood fitting

There are 9 point sources in the Draco ROI, and several others that are outside the ROI, but close enough that they might contribute some photons to the ROI, because the 95% containment of the LAT PSF is several degrees across at 500MeV.

We are not going to fit every source in the ROI. Rather we are going to fix all of the point-sources to the value in the 3FGL catalog (which largely overlaps with the time range of our analysis). Also, in the higher energy bins we don't really have the statistics need to distinguish the Galactic diffuse emission from the isotropic emission and they become degenerate. So we are only going to fit for the fluxes of Draco and the Galactic diffuse emission. Finally, to simplify things we are only going to fit the normalization of the fluxes, not the other spectral parameters.

In fact, we've already fit there parameters of all the sources in the region to establish a basline model. You can find the results of that fitting in three places:

An XML file describing the sources in the ROI.

A text file with a python dictionary giving the paramaters of all the sources in the ROI.

A FITS file giving the number of counts attributed to each source in each energy bin.

Finally, you can find a FITS file giving the best-fit model counts in each pixel / energy bin in the remote data area.


In [ ]:
#!wget -O data/draco_mcube.fits http://www.slac.stanford.edu/~echarles/temp_stats/draco_mcube.fits

Fitting for the target source

We are not going to re-fit every source in the ROI. Rather we are going to fix all of the point-sources to the values in the baseline fit (that are mainly taken from the 3FGL catalog which largely overlaps with the time range of our analysis). Also, in the higher energy bins we don't really have the statistics needed to distinguish the Galactic diffuse emission from the isotropic emission and they become degenerate. So we are only going to fit for the fluxes of Draco and the Galactic diffuse emission. Finally, to simplify things we are only going to fit the normalization of the fluxes, not the other spectral parameters.

To set us up to do this, I've made the file draco_srcTemplates.fits in the data directory.


In [11]:
f_tmpl = pf.open("data/draco_srcTemplates.fits")
f_tmpl.info()


Filename: data/draco_srcTemplates.fits
No.    Name         Type      Cards   Dimensions   Format
0    PRIMARY     PrimaryHDU      59   (100, 100, 24)   float32   
1    GTI         BinTableHDU     33   33851R x 2C   [D, D]   
2    EBOUNDS     BinTableHDU     38   24R x 3C     [I, 1E, 1E]   
3    FIXED       ImageHDU        61   (100, 100, 24)   float64   
4    DRACO       ImageHDU        61   (100, 100, 24)   float64   
5    GLL_IEM_V06  ImageHDU        61   (100, 100, 24)   float64   

This file is similar to the source map file, but I've merged all of the fixed source into a single template. Also, I've actually done the integration over the energy bins, so the templates have 24 energy layers instead of 25. This is fine because we will only be fitting the normalization of the Draco and GLL_IEM_V06 (i.e., Galactic diffuse) templates.

Let's move on the likelihood fitting example now.