The following tutorial shows a way of performing binned likelihood with energy dispersion. Technical details can be found here. This tutorial assumes that you've gone through the standard binned likelihood analysis thread. You can also watch a video tutorial.
You can download this tutorial as a Jupyter notebook and run it interactively. Please see the instructions for using the notebooks with the Fermitools.
For this thread we use the same data extracted for the binned likelihood thread with the following selections:
We've provided direct links to the event files as well as the spacecraft data file if you don't want to take the time to use the download server. For more information on how to download LAT data please see the Extract LAT Data tutorial.
You'll first need to make a file list with the names of your input event files:
[user@localhost]$ ls *PH*.fits > binned_events.txt
In the following analysis we've assumed that you've named your list of data files binned_events.txt.
You could follow the binned likelihood tutorial to perform your event selections using gtlike, gtmktime etc. directly from the command line, and then use pylikelihood later. But we're going to go ahead and use python. The gt_apps module provides methods to call these tools from within python.
So, let's jump into python:
[user@localhost]$ python
Type "help", "copyright", "credits" or "license" for more information.
>>>
We first import the gt_apps module to gain access to the tools.
>>> import gt_apps as my_apps
Start by running gtselect (called 'filter' in python).
>>> my_apps.filter['evclass'] = 128
>>> my_apps.filter['evtype'] = 3
>>> my_apps.filter['ra'] = 193.98
>>> my_apps.filter['dec'] = -5.82
>>> my_apps.filter['rad'] = 15
>>> my_apps.filter['emin'] = 100
>>> my_apps.filter['emax'] = 500000
>>> my_apps.filter['zmax'] = 90
>>> my_apps.filter['tmin'] = 239557417
>>> my_apps.filter['tmax'] = 302572802
>>> my_apps.filter['infile'] = '@binned_events.txt'
>>> my_apps.filter['outfile'] = '3C279_filtered.fits'
Once this is done, we can run gtselect:
>>> my_apps.filter.run()
Now, we need to find the GTIs. This is accessed within python via the maketime object:
>>> my_apps.maketime['scfile'] = 'L181126210218F4F0ED2738_SC00.fits'
>>> my_apps.maketime['filter'] = '(DATA_QUAL>0)&&(LAT_CONFIG==1)'
>>> my_apps.maketime['roicut'] = 'no'
>>> my_apps.maketime['evfile'] = '3C279_filtered.fits'
>>> my_apps.maketime['outfile'] = '3C279_filtered_gti.fits'
>>> my_apps.maketime.run()
We can now compute the livetime cube.
>>> my_apps.expCube['evfile'] = '3C279_filtered_gti.fits'
>>> my_apps.expCube['scfile'] = 'L181126210218F4F0ED2738_SC00.fits'
>>> my_apps.expCube['outfile'] = '3C279_ltcube.fits'
>>> my_apps.expCube['zmax'] = 90
>>> my_apps.expCube['dcostheta'] = 0.025
>>> my_apps.expCube['binsz'] = 1
>>> my_apps.expCube.run()
>>> my_apps.evtbin['evfile'] = '3C279_filtered_gti.fits'
>>> my_apps.evtbin['outfile'] = '3C279_ccube.fits'
>>> my_apps.evtbin['scfile'] = 'NONE'
>>> my_apps.evtbin['algorithm'] = 'CCUBE'
>>> my_apps.evtbin['nxpix'] = 100
>>> my_apps.evtbin['nypix'] = 100
>>> my_apps.evtbin['binsz'] = 0.2
>>> my_apps.evtbin['coordsys'] = 'CEL'
>>> my_apps.evtbin['xref'] = 193.98
>>> my_apps.evtbin['yref'] = -5.82
>>> my_apps.evtbin['axisrot'] = 0
>>> my_apps.evtbin['proj'] = 'AIT'
>>> my_apps.evtbin['ebinalg'] = 'LOG'
>>> my_apps.evtbin['emin'] = 100
>>> my_apps.evtbin['emax'] = 500000
>>> my_apps.evtbin['enumbins'] = 37
>>> my_apps.evtbin.run()
>>> from GtApp import GtApp
>>> expCube2= GtApp('gtexpcube2','Likelihood')
>>> expCube2['infile'] = '3C279_ltcube.fits'
>>> expCube2['cmap'] = 'none'
>>> expCube2['outfile'] = '3C279_BinnedExpMap.fits'
>>> expCube2['irfs'] = 'P8R3_SOURCE_V3'
>>> expCube2['evtype'] = '3'
>>> expCube2['nxpix'] = 1800
>>> expCube2['nypix'] = 900
>>> expCube2['binsz'] = 0.2
>>> expCube2['coordsys'] = 'CEL'
>>> expCube2['xref'] = 193.98
>>> expCube2['yref'] = -5.82
>>> expCube2['axisrot'] = 0
>>> expCube2['proj'] = 'AIT'
>>> expCube2['ebinalg'] = 'LOG'
>>> expCube2['emin'] = 100
>>> expCube2['emax'] = 500000
>>> expCube2['enumbins'] = 37
>>> expCube2.run()
The sourcemaps step convolves the LAT response with your source model generating maps for each source in the model for use in the likelihood calculation. We use the same XML file as in the standard binned likelihood analysis. Go ahead and download the XML file to your working directory. You should also download the recommended models for a normal point source analysis gll_iem_v07.fits and iso_P8R3_SOURCE_V3_v1.txt.
>>> my_apps.srcMaps['expcube'] = '3C279_ltcube.fits'
>>> my_apps.srcMaps['cmap'] = '3C279_ccube.fits'
>>> my_apps.srcMaps['srcmdl'] = '3C279_input_model.xml'
>>> my_apps.srcMaps['bexpmap'] = '3C279_BinnedExpMap.fits'
>>> my_apps.srcMaps['outfile'] = '3C279_srcmap.fits'
>>> my_apps.srcMaps['irfs'] = 'P8R3_SOURCE_V3'
>>> my_apps.srcMaps['evtype'] = '3'
>>> my_apps.srcMaps.run()
First, import the BinnedAnalysis library. Then, create a likelihood object for the dataset. For more details on the pyLikelihood module, check out the pyLikelihood Usage Notes. Initially, we will do an analysis without weights
>>> import pyLikelihood
>>> from BinnedAnalysis import *
>>> obs = BinnedObs(srcMaps='3C279_srcmap.fits',binnedExpMap='3C279_BinnedExpMap.fits',
expCube='3C279_ltcube.fits',irfs='CALDB')
>>> like = BinnedAnalysis(obs,'3C279_input_model.xml',optimizer='NewMinuit')
Perform the fit and print out the results
>>> likeobj=pyLike.NewMinuit(like.logLike)
>>> like.fit(verbosity=0,covar=True,optObject=likeobj)
>>> 75689.458
Check that NewMinuit converged. If you get anything other than '0', then NewMinuit didn't converged.
>>> print(likeobj.getRetCode())
>>> 0
Print TS for 3C 279 (4FGL J1256.1-0547)
>>> like.Ts('4FGL J1256.1-0547')
>>> 27810.844
Now, we will repeat the likelihood analysis but turning energy dispersion on this time .
>>> import pyLikelihood
>>> from BinnedAnalysis import *
At this point, you have to create a BinnedConfig object and pass that object to BinnedAnalusis. For the appropriate choice of edisp_bins, please read this.
>>> conf = BinnedConfig(edisp_bins=-2)
>>> obs2 = BinnedObs(srcMaps='3C279_srcmap.fits',binnedExpMap='
3C279_BinnedExpMap.fits',
expCube='3C279_ltcube.fits',irfs='CALDB')
>>> like2 = BinnedAnalysis(obs2,'3C279_input_model.xml',optimizer='NewMinuit',config=conf)
Perform the fit and print out the results
>>> likeobj2=pyLike.NewMinuit(like2.logLike)
>>> like2.fit(verbosity=0,covar=True,optObject=likeobj2)
>>> 75785.905
>>> print(likeobj2.getRetCode())
>>> 0
>>> like2.Ts('4FGL J1256.1-0547')
>>> 27643.552
After verifying that the fit converged, we see that the TS including energy dispersion is a bit lower than what we found neglecting energy dispersion. The effect is most relevant at energies < 300 MeV, but also induces a smaller systematic offset at higher energies. Please refer to a more complete explanation here.
The FSSC Team 12/8/2020