Performing a classical On/Off analysis

In this tutorial you will learn to perform a classical On/Off analysis of the data.

We start by importing the gammalib, ctools, and cscripts Python modules.


In [1]:
import gammalib
import ctools
import cscripts

We will also use matplotlib to display the results.


In [2]:
%matplotlib inline
import matplotlib.pyplot as plt

And finally we add to our path the directory containing the example plotting scripts provided with the ctools installation.


In [3]:
import sys
import os
sys.path.append(os.environ['CTOOLS']+'/share/examples/python/')

Classical analysis without background model

Preparation of the On/Off binned data

The first step for a classical analysis is to bin the events in bins of energy for an On (signal) region, and one or several Off (background regions).

We will use the event selection performed in the previous tutorial.


In [4]:
obsfile = 'obs_crab_selected.xml'
phagen  = cscripts.csphagen()
phagen['inobs']         = obsfile
phagen['inmodel']       = 'NONE' # assume that the source is pointlike
phagen['ebinalg']       = 'LOG'
phagen['emin']          = 0.66
phagen['emax']          = 30.0
phagen['enumbins']      = 20
phagen['coordsys']      = 'CEL'
phagen['ra']            = 83.63
phagen['dec']           = 22.01
phagen['rad']           = 0.2
phagen['bkgmethod']     = 'REFLECTED'
phagen['use_model_bkg'] = False
phagen['maxoffset']     = 2.0
phagen['stack']         = True
phagen['outobs']        = 'obs_crab_onoff.xml'
phagen['outmodel']      = 'onoff_model.xml'
phagen.execute()

Note that we have used the hidden parameter use_model_bkg to specify that no background model should be used in the computation of the background normalisation factor, which is simply assumed to be the ratio of the solid angles of On/Off regions.

Let us peek at the resulting set of On/Off observations.


In [5]:
print(phagen.obs()[0])


=== GCTAOnOffObservation ===
 Name ......................: 
 Identifier ................: 
 Instrument ................: HESSOnOff
 Statistic .................: wstat
 Ontime ....................: 6313.8117676 s
 Livetime ..................: 6313.8117676 s
 Deadtime correction .......: 1
=== GPha ===
 Exposure ..................: 6313.8117676 s
 Number of bins ............: 20
 Energy range ..............: 660 GeV - 30 TeV
 Observation energy range ..: 660.693448007596 GeV - 100 TeV
 Total number of counts ....: 576
 Underflow counts ..........: 0
 Overflow counts ...........: 1
 Outflow counts ............: 0
=== GPha ===
 Exposure ..................: 6313.8117676 s
 Number of bins ............: 20
 Energy range ..............: 660 GeV - 30 TeV
 Observation energy range ..: 660.693448007596 GeV - 100 TeV
 Total number of counts ....: 772
 Underflow counts ..........: 0
 Overflow counts ...........: 4
 Outflow counts ............: 0
=== GArf ===
 Number of bins ............: 61
 Energy range ..............: 330 GeV - 36.000002048 TeV
=== GRmf ===
 Number of true energy bins : 61
 Number of measured bins ...: 20
 True energy range .........: 330 GeV - 36.000002048 TeV
 Measured energy range .....: 660 GeV - 30 TeV

Note that the instrument is now HESSOnOff, to signify that we are dealing with On/Off observations. Since we have no background model the statistic has been set to WSTAT. The script has also created a model for the On region.


In [6]:
print(phagen.obs().models())


=== GModels ===
 Number of models ..........: 1
 Number of parameters ......: 6
=== GModelSky ===
 Name ......................: Dummy
 Instruments ...............: all
 Observation identifiers ...: all
 Model type ................: PointSource
 Model components ..........: "PointSource" * "PowerLaw" * "Constant"
 Number of parameters ......: 6
 Number of spatial par's ...: 2
  RA .......................: 83.63 deg (fixed,scale=1)
  DEC ......................: 22.01 deg (fixed,scale=1)
 Number of spectral par's ..: 3
  Prefactor ................: 1e-18 +/- 0 [0,infty[ ph/cm2/s/MeV (free,scale=1e-18,gradient)
  Index ....................: -2 +/- 0 [10,-10]  (free,scale=-2,gradient)
  PivotEnergy ..............: 1000000 MeV (fixed,scale=1000000,gradient)
 Number of temporal par's ..: 1
  Normalization ............: 1 (relative value) (fixed,scale=1,gradient)
 Number of scale par's .....: 0

Since we do not have specified any input model the script has placed a point source named Dummy, at the center of the On region with a power law spectrum. We will rename this source as Crab. At this point you can also modify the spectral model, e.g., to use more appropriate parameter values or a different spectral shape.


In [7]:
phagen.obs().models()['Dummy'].name('Crab')

Likelihood fit and residuals

We can now fit this model to the data.


In [8]:
like = ctools.ctlike(phagen.obs())
like.run()

Let's look at the results from the optimisation and the fitted model.


In [9]:
print(like.opt())
print(like.obs().models())


=== GOptimizerLM ===
 Optimized function value ..: 15.746
 Absolute precision ........: 0.005
 Acceptable value decrease .: 2
 Optimization status .......: converged
 Number of parameters ......: 6
 Number of free parameters .: 2
 Number of iterations ......: 11
 Lambda ....................: 0.0001
=== GModels ===
 Number of models ..........: 1
 Number of parameters ......: 6
=== GModelSky ===
 Name ......................: Crab
 Instruments ...............: all
 Observation identifiers ...: all
 Model type ................: PointSource
 Model components ..........: "PointSource" * "PowerLaw" * "Constant"
 Number of parameters ......: 6
 Number of spatial par's ...: 2
  RA .......................: 83.63 deg (fixed,scale=1)
  DEC ......................: 22.01 deg (fixed,scale=1)
 Number of spectral par's ..: 3
  Prefactor ................: 4.61852950191309e-17 +/- 2.97687577951453e-18 [0,infty[ ph/cm2/s/MeV (free,scale=1e-18,gradient)
  Index ....................: -2.63298373450669 +/- 0.0795120102122515 [10,-10]  (free,scale=-2,gradient)
  PivotEnergy ..............: 1000000 MeV (fixed,scale=1000000,gradient)
 Number of temporal par's ..: 1
  Normalization ............: 1 (relative value) (fixed,scale=1,gradient)
 Number of scale par's .....: 0

The fit has properly converged and the results are consistent with those obtained with the unbinned analysis.

We will also check the spectral residuals.


In [10]:
residuals = 'residuals_classical_nobkg.fits'
res = cscripts.csresspec(like.obs())
res['components'] = True
res['algorithm']  = 'SIGNIFICANCE'
res['outfile']    = residuals
res.execute()
from show_residuals import plot_residuals
plot_residuals(residuals,'',0)


Classical analysis with a background model

Preparation of the On/Off binned data

If a background model is available this can be used to compute the expected background rates for different observations as a function of energy and normalise the number of background counts between On and Off regions. Here we will use the background model derived using csbkgmodel.


In [11]:
srcmodel   = os.environ['CTOOLS']+'/share/models/crab_nobkg.xml'
bkgmodel   = 'bkgmodel.xml'
startmodel = 'model_classical_bkg.xml'
merge = cscripts.csmodelmerge()
merge['inmodels'] = srcmodel + ' ' + bkgmodel
merge['outmodel'] = startmodel
merge.execute()

Now we can run csphagen using this model including the background in input. Note that since the background model is defined per observation we will not stack the observations together.


In [12]:
phagen = cscripts.csphagen()
phagen['inobs']         = obsfile
phagen['inmodel']       = startmodel
phagen['srcname']       = 'Crab'
phagen['ebinalg']       = 'LOG'
phagen['emin']          = 0.66
phagen['emax']          = 30.0
phagen['enumbins']      = 20
phagen['coordsys']      = 'CEL'
phagen['ra']            = 83.63
phagen['dec']           = 22.01
phagen['rad']           = 0.2
phagen['bkgmethod']     = 'REFLECTED'
phagen['use_model_bkg'] = True
phagen['maxoffset']     = 2.0
phagen['stack']         = False # treat observations separately in joint likelihood fit
phagen.run()

Likelihood fit and residuals

We will now fit the model to the data and look at the results.


In [13]:
like = ctools.ctlike(phagen.obs())
like.run()
print(like.opt())
print(like.obs().models())


=== GOptimizerLM ===
 Optimized function value ..: -2417.944
 Absolute precision ........: 0.005
 Acceptable value decrease .: 2
 Optimization status .......: converged
 Number of parameters ......: 86
 Number of free parameters .: 42
 Number of iterations ......: 29
 Lambda ....................: 0.0001
=== GModels ===
 Number of models ..........: 5
 Number of parameters ......: 86
=== GModelSky ===
 Name ......................: Crab
 Instruments ...............: all
 Observation identifiers ...: all
 Model type ................: PointSource
 Model components ..........: "PointSource" * "PowerLaw" * "Constant"
 Number of parameters ......: 6
 Number of spatial par's ...: 2
  RA .......................: 83.6331 [-360,360] deg (fixed,scale=1)
  DEC ......................: 22.0145 [-90,90] deg (fixed,scale=1)
 Number of spectral par's ..: 3
  Prefactor ................: 4.44907776007907e-17 +/- 2.98566064292929e-18 [1e-24,1e-14] ph/cm2/s/MeV (free,scale=1e-17,gradient)
  Index ....................: -2.64019099792601 +/- 0.0844654299892131 [-0,-5]  (free,scale=-1,gradient)
  PivotEnergy ..............: 1000000 [10000,1000000000] MeV (fixed,scale=1000000,gradient)
 Number of temporal par's ..: 1
  Normalization ............: 1 (relative value) (fixed,scale=1,gradient)
 Number of scale par's .....: 0
=== GCTAModelBackground ===
 Name ......................: Background_023523
 Instruments ...............: HESSOnOff
 Observation identifiers ...: 023523
 Model type ................: CTABackground
 Model components ..........: "Multiplicative" * "NodeFunction" * "Constant"
 Number of parameters ......: 20
 Number of spatial par's ...: 3
  1:Normalization ..........: 1 [0.001,1000]  (fixed,scale=1,gradient)
  2:Grad_DETX ..............: 0.0881748792818854 +/- 0 deg^-1 (free,scale=1,gradient)
  2:Grad_DETY ..............: -0.000701218995455618 +/- 0 deg^-1 (free,scale=1,gradient)
 Number of spectral par's ..: 16
  Energy0 ..................: 700000 [7e-05,infty[ MeV (fixed,scale=700000)
  Intensity0 ...............: 1.89896487985208 +/- 3.09950981249023 [1.00182541969977e-13,infty[ ph/cm2/s/MeV (free,scale=0.00100182541969977,gradient)
  Energy1 ..................: 1197413.67463685 [0.000119741367463685,infty[ MeV (fixed,scale=1197413.67463685)
  Intensity1 ...............: 0.754995013333362 +/- 0.267674756209559 [3.21240099713853e-14,infty[ ph/cm2/s/MeV (free,scale=0.000321240099713853,gradient)
  Energy2 ..................: 2048285.01172474 [0.000204828501172474,infty[ MeV (fixed,scale=2048285.01172474)
  Intensity2 ...............: 1.17347310940125 +/- 0.327498259113055 [1.03007170346199e-14,infty[ ph/cm2/s/MeV (free,scale=0.000103007170346199,gradient)
  Energy3 ..................: 3503777.83227556 [0.000350377783227556,infty[ MeV (fixed,scale=3503777.83227556)
  Intensity3 ...............: 1.39420069744212 +/- 0.404449186550592 [3.30297405342054e-15,infty[ ph/cm2/s/MeV (free,scale=3.30297405342054e-05,gradient)
  Energy4 ..................: 5993530.69893743 [0.000599353069893743,infty[ MeV (fixed,scale=5993530.69893743)
  Intensity4 ...............: 1.32748213047069 +/- 0.551998524503437 [1.05911438600856e-15,infty[ ph/cm2/s/MeV (free,scale=1.05911438600856e-05,gradient)
  Energy5 ..................: 10252479.454662 [0.0010252479454662,infty[ MeV (fixed,scale=10252479.454662)
  Intensity5 ...............: 1.53590487400556 +/- 0.862929853325373 [3.39610080039421e-16,infty[ ph/cm2/s/MeV (free,scale=3.39610080039421e-06,gradient)
  Energy6 ..................: 17537798.7113509 [0.00175377987113509,infty[ MeV (fixed,scale=17537798.7113509)
  Intensity6 ...............: 1.26422194838399 +/- 1.34653218966622 [1.08897592165697e-16,infty[ ph/cm2/s/MeV (free,scale=1.08897592165697e-06,gradient)
  Energy7 ..................: 30000000 [0.003,infty[ MeV (fixed,scale=30000000)
  Intensity7 ...............: 6.77476052324258 +/- 8.56245789647827 [3.49185323889972e-17,infty[ ph/cm2/s/MeV (free,scale=3.49185323889972e-07,gradient)
 Number of temporal par's ..: 1
  Normalization ............: 1 (relative value) (fixed,scale=1,gradient)
=== GCTAModelBackground ===
 Name ......................: Background_023526
 Instruments ...............: HESSOnOff
 Observation identifiers ...: 023526
 Model type ................: CTABackground
 Model components ..........: "Multiplicative" * "NodeFunction" * "Constant"
 Number of parameters ......: 20
 Number of spatial par's ...: 3
  1:Normalization ..........: 1 [0.001,1000]  (fixed,scale=1,gradient)
  2:Grad_DETX ..............: 0.0153166143265463 +/- 0 deg^-1 (free,scale=1,gradient)
  2:Grad_DETY ..............: -0.00908019181469828 +/- 0 deg^-1 (free,scale=1,gradient)
 Number of spectral par's ..: 16
  Energy0 ..................: 700000 [7e-05,infty[ MeV (fixed,scale=700000)
  Intensity0 ...............: 1.30442623250239 +/- 0.615959779856916 [9.62519069451052e-14,infty[ ph/cm2/s/MeV (free,scale=0.000962519069451052,gradient)
  Energy1 ..................: 1197413.67463685 [0.000119741367463685,infty[ MeV (fixed,scale=1197413.67463685)
  Intensity1 ...............: 0.566084707224135 +/- 0.189571117408801 [2.95441986174209e-14,infty[ ph/cm2/s/MeV (free,scale=0.000295441986174209,gradient)
  Energy2 ..................: 2048285.01172474 [0.000204828501172474,infty[ MeV (fixed,scale=2048285.01172474)
  Intensity2 ...............: 0.955930666245828 +/- 0.272410595459555 [9.068492247571e-15,infty[ ph/cm2/s/MeV (free,scale=9.068492247571e-05,gradient)
  Energy3 ..................: 3503777.83227556 [0.000350377783227556,infty[ MeV (fixed,scale=3503777.83227556)
  Intensity3 ...............: 1.91071527979174 +/- 0.589677088986724 [2.78354314866283e-15,infty[ ph/cm2/s/MeV (free,scale=2.78354314866283e-05,gradient)
  Energy4 ..................: 5993530.69893743 [0.000599353069893743,infty[ MeV (fixed,scale=5993530.69893743)
  Intensity4 ...............: 0.796340097360303 +/- 0.511186601597472 [8.54399193266454e-16,infty[ ph/cm2/s/MeV (free,scale=8.54399193266454e-06,gradient)
  Energy5 ..................: 10252479.454662 [0.0010252479454662,infty[ MeV (fixed,scale=10252479.454662)
  Intensity5 ...............: 1.31629202714156 +/- 0.980251656539197 [2.62254954375342e-16,infty[ ph/cm2/s/MeV (free,scale=2.62254954375342e-06,gradient)
  Energy6 ..................: 17537798.7113509 [0.00175377987113509,infty[ MeV (fixed,scale=17537798.7113509)
  Intensity6 ...............: 2.27556128029012 +/- 3.06865755885414 [8.04982748537824e-17,infty[ ph/cm2/s/MeV (free,scale=8.04982748537824e-07,gradient)
  Energy7 ..................: 30000000 [0.003,infty[ MeV (fixed,scale=30000000)
  Intensity7 ...............: 2.4708674312253e-17 +/- 1.05696632580831e-13 [2.4708674312253e-17,infty[ ph/cm2/s/MeV (free,scale=2.4708674312253e-07,gradient)
 Number of temporal par's ..: 1
  Normalization ............: 1 (relative value) (fixed,scale=1,gradient)
=== GCTAModelBackground ===
 Name ......................: Background_023559
 Instruments ...............: HESSOnOff
 Observation identifiers ...: 023559
 Model type ................: CTABackground
 Model components ..........: "Multiplicative" * "NodeFunction" * "Constant"
 Number of parameters ......: 20
 Number of spatial par's ...: 3
  1:Normalization ..........: 1 [0.001,1000]  (fixed,scale=1,gradient)
  2:Grad_DETX ..............: 0.018749400342 +/- 0 deg^-1 (free,scale=1,gradient)
  2:Grad_DETY ..............: -0.126640342510319 +/- 0 deg^-1 (free,scale=1,gradient)
 Number of spectral par's ..: 16
  Energy0 ..................: 700000 [7e-05,infty[ MeV (fixed,scale=700000)
  Intensity0 ...............: 0.885669706791242 +/- 0.219147786869672 [8.7418891142236e-14,infty[ ph/cm2/s/MeV (free,scale=0.00087418891142236,gradient)
  Energy1 ..................: 1197413.67463685 [0.000119741367463685,infty[ MeV (fixed,scale=1197413.67463685)
  Intensity1 ...............: 1.12011463147092 +/- 0.162106623373511 [2.69181956755491e-14,infty[ ph/cm2/s/MeV (free,scale=0.000269181956755491,gradient)
  Energy2 ..................: 2048285.01172474 [0.000204828501172474,infty[ MeV (fixed,scale=2048285.01172474)
  Intensity2 ...............: 0.747992399165037 +/- 0.145060618647741 [8.28870337932099e-15,infty[ ph/cm2/s/MeV (free,scale=8.28870337932099e-05,gradient)
  Energy3 ..................: 3503777.83227556 [0.000350377783227556,infty[ MeV (fixed,scale=3503777.83227556)
  Intensity3 ...............: 0.750550500933036 +/- 0.184075541493125 [2.55227373106486e-15,infty[ ph/cm2/s/MeV (free,scale=2.55227373106486e-05,gradient)
  Energy4 ..................: 5993530.69893743 [0.000599353069893743,infty[ MeV (fixed,scale=5993530.69893743)
  Intensity4 ...............: 0.804148948547538 +/- 0.258602777342412 [7.85901111449516e-16,infty[ ph/cm2/s/MeV (free,scale=7.85901111449516e-06,gradient)
  Energy5 ..................: 10252479.454662 [0.0010252479454662,infty[ MeV (fixed,scale=10252479.454662)
  Intensity5 ...............: 0.947268446501844 +/- 0.33090320971996 [2.4199620497598e-16,infty[ ph/cm2/s/MeV (free,scale=2.4199620497598e-06,gradient)
  Energy6 ..................: 17537798.7113509 [0.00175377987113509,infty[ MeV (fixed,scale=17537798.7113509)
  Intensity6 ...............: 0.510924531144191 +/- 0.330349647333246 [7.45159440158635e-17,infty[ ph/cm2/s/MeV (free,scale=7.45159440158635e-07,gradient)
  Energy7 ..................: 30000000 [0.003,infty[ MeV (fixed,scale=30000000)
  Intensity7 ...............: 1.98644760587573 +/- 1.95978734590705 [2.29450949990163e-17,infty[ ph/cm2/s/MeV (free,scale=2.29450949990163e-07,gradient)
 Number of temporal par's ..: 1
  Normalization ............: 1 (relative value) (fixed,scale=1,gradient)
=== GCTAModelBackground ===
 Name ......................: Background_023592
 Instruments ...............: HESSOnOff
 Observation identifiers ...: 023592
 Model type ................: CTABackground
 Model components ..........: "Multiplicative" * "NodeFunction" * "Constant"
 Number of parameters ......: 20
 Number of spatial par's ...: 3
  1:Normalization ..........: 1 [0.001,1000]  (fixed,scale=1,gradient)
  2:Grad_DETX ..............: 0.0290076925442388 +/- 0 deg^-1 (free,scale=1,gradient)
  2:Grad_DETY ..............: 0.165459453396994 +/- 0 deg^-1 (free,scale=1,gradient)
 Number of spectral par's ..: 16
  Energy0 ..................: 700000 [7e-05,infty[ MeV (fixed,scale=700000)
  Intensity0 ...............: 1.15673248048702 +/- 0.961419402688181 [9.64800822522881e-14,infty[ ph/cm2/s/MeV (free,scale=0.000964800822522881,gradient)
  Energy1 ..................: 1197413.67463685 [0.000119741367463685,infty[ MeV (fixed,scale=1197413.67463685)
  Intensity1 ...............: 0.995573238520915 +/- 0.167640057372438 [3.05783271724063e-14,infty[ ph/cm2/s/MeV (free,scale=0.000305783271724063,gradient)
  Energy2 ..................: 2048285.01172474 [0.000204828501172474,infty[ MeV (fixed,scale=2048285.01172474)
  Intensity2 ...............: 0.97430603880028 +/- 0.15455196754381 [9.6914727976462e-15,infty[ ph/cm2/s/MeV (free,scale=9.6914727976462e-05,gradient)
  Energy3 ..................: 3503777.83227556 [0.000350377783227556,infty[ MeV (fixed,scale=3503777.83227556)
  Intensity3 ...............: 0.748497898296835 +/- 0.15953787473352 [3.07160834724385e-15,infty[ ph/cm2/s/MeV (free,scale=3.07160834724385e-05,gradient)
  Energy4 ..................: 5993530.69893743 [0.000599353069893743,infty[ MeV (fixed,scale=5993530.69893743)
  Intensity4 ...............: 0.725418936580643 +/- 0.203356640612422 [9.735133179293e-16,infty[ ph/cm2/s/MeV (free,scale=9.735133179293e-06,gradient)
  Energy5 ..................: 10252479.454662 [0.0010252479454662,infty[ MeV (fixed,scale=10252479.454662)
  Intensity5 ...............: 1.11101986414082 +/- 0.366485282801602 [3.08544603688196e-16,infty[ ph/cm2/s/MeV (free,scale=3.08544603688196e-06,gradient)
  Energy6 ..................: 17537798.7113509 [0.00175377987113509,infty[ MeV (fixed,scale=17537798.7113509)
  Intensity6 ...............: 1.39697833190385 +/- 0.57861299733536 [9.77899025229569e-17,infty[ ph/cm2/s/MeV (free,scale=9.77899025229569e-07,gradient)
  Energy7 ..................: 30000000 [0.003,infty[ MeV (fixed,scale=30000000)
  Intensity7 ...............: 1.25607862208781 +/- 0.917860648895514 [3.09934606573553e-17,infty[ ph/cm2/s/MeV (free,scale=3.09934606573553e-07,gradient)
 Number of temporal par's ..: 1
  Normalization ............: 1 (relative value) (fixed,scale=1,gradient)

Results for the spectrum of the Crab nebula are once again consistent with those obtained before. Note how the spatial parameters of the background model, although formally free, have not been optimised (their errors are 0), since we are running a spectral analysis only.

Since we have provided a background model to csphagen the statistic was set by default to CSTAT, i.e. the background model was also used in the fit. You may also specify as statistic in ctlike WSTAT. In this case the spectral model for the background would be derived from the data during the fit, and the impact of the model used above would extend only to the computation of the background normalisation factor between On and Off regions. Using an a-priori background model on the other hand can be advantageous to avoid intrinsic biases of WSTAT when the counting statistics are limited.

Let's check the residuals for the first of the 4 observations.


In [14]:
residuals = 'residuals_classical_bkgmod.fits'
res = cscripts.csresspec(like.obs())
res['components'] = True
res['algorithm']  = 'SIGNIFICANCE'
res['outfile']    = residuals
res['stack']      = False
res.execute()
from show_residuals import plot_residuals
plot_residuals(residuals,'',0)


As expected the spectral residuals are not as good as in the first analysis in which the model was derived from the data during the fit itself, but the models still satisfactorily reproduce the data. Of course the total background coincides with the background model of the specific observation considered.


In [ ]: