Commit a5a1a27acf595c74c8b607bfd953194055310a38

Authored by Jürgen Knödlseder
1 parent a11d1205

Use MigMatrixNoTheta2cut_offaxis and AngularPSF2DEtrue_offaxis histograms to com…

…pute PSF and energy dispersion IRFs (#2135)
ChangeLog
1   -2017-06-23
  1 +2017-06-27
2 2  
3 3 * Bug fix version 1.3.1 released
4 4 ================================
5 5  
  6 + Use MigMatrixNoTheta2cut_offaxis and AngularPSF2DEtrue_offaxis histograms to
  7 + compute PSF and energy dispersion IRFs (#2135)
6 8 Properly forward working log file pointer in ctobssim::set_mc_id_names() (#2123)
7 9 Correct computation of standard deviations in cssrcdetect
8 10 csobsselect accepts an observation container upon construction
... ...
1 1 New Features and Important Changes in ctools 1.3.1
2 2  
3   -23 June 2017
  3 +27 June 2017
4 4  
5 5  
6 6 Introduction
... ... @@ -122,6 +122,10 @@ The csobsselect script now accepts an observation container upon construction.
122 122  
123 123 The standard deviation computation in cssrcdetect has been corrected.
124 124  
  125 +The csroot2caldb script now uses the MigMatrixNoTheta2cut_offaxis and
  126 +AngularPSF2DEtrue_offaxis ROOT histograms to compute the energy dispersion matrix
  127 +and the PSF shape (#2135).
  128 +
125 129  
126 130 Examples
127 131 --------
... ...
cscripts/csroot2caldb.py
... ... @@ -29,7 +29,7 @@ from cscripts import calutils
29 29  
30 30 # Optional ROOT import
31 31 try:
32   - from ROOT import TFile
  32 + from ROOT import TFile, TH2F, TH3F
33 33 _has_root = True
34 34 except ImportError:
35 35 _has_root = False
... ... @@ -651,6 +651,78 @@ class csroot2caldb(ctools.cscript):
651 651 # Return
652 652 return
653 653  
  654 + def _root2psf_get_r68_and_r80(self, tfile):
  655 + """
  656 + Generates 68% and 80% containment radii histograms from
  657 + AngularPSF2DEtrue_offaxis histogram
  658 +
  659 + Parameters
  660 + ----------
  661 + tfile : `~ROOT.TFile`
  662 + ROOT file
  663 +
  664 + Returns
  665 + -------
  666 + r68, r80 : Tuple of `~ROOT.THF2`
  667 + 68% and 80% containment radius ROOT histograms
  668 + """
  669 + # Get relevant ROOT histograms
  670 + psf = tfile.Get('AngularPSF2DEtrue_offaxis')
  671 +
  672 + # Extract axes
  673 + energies = psf.GetXaxis()
  674 + dists = psf.GetYaxis()
  675 + offsets = psf.GetZaxis()
  676 +
  677 + # Extract number of bins in histogram
  678 + neng = energies.GetNbins()
  679 + ndist = dists.GetNbins()
  680 + noffset = offsets.GetNbins()
  681 +
  682 + # Create r68 and r80 histograms
  683 + r68 = TH2F('AngRes68Etrue_offaxis',
  684 + 'Angular resolution (68% containment)',
  685 + neng, energies.GetBinLowEdge(1), energies.GetBinUpEdge(neng),
  686 + noffset, offsets.GetBinLowEdge(1), offsets.GetBinUpEdge(noffset))
  687 + r80 = TH2F('AngRes80Etrue_offaxis',
  688 + 'Angular resolution (80% containment)',
  689 + neng, energies.GetBinLowEdge(1), energies.GetBinUpEdge(neng),
  690 + noffset, offsets.GetBinLowEdge(1), offsets.GetBinUpEdge(noffset))
  691 +
  692 + # Loop over all energy and offset angle bins
  693 + for ieng in range(neng):
  694 + for ioff in range(noffset):
  695 +
  696 + # Compute PDF integral
  697 + pdf_integral = 0.0
  698 + for idist in range(ndist):
  699 + pdf_integral += psf.GetBinContent(ieng+1,idist+1,ioff+1)
  700 +
  701 + # Compute 68% containment radius
  702 + pdf_68 = 0.0
  703 + r68_angle = 0.0
  704 + for idist in range(ndist):
  705 + pdf_68 += psf.GetBinContent(ieng+1,idist+1,ioff+1)
  706 + if pdf_68 > 0.68*pdf_integral:
  707 + r68_angle = dists.GetBinLowEdge(idist+1)
  708 + break
  709 +
  710 + # Compute 80% containment radius
  711 + pdf_80 = 0.0
  712 + r80_angle = 0.0
  713 + for idist in range(ndist):
  714 + pdf_80 += psf.GetBinContent(ieng+1,idist+1,ioff+1)
  715 + if pdf_80 > 0.80*pdf_integral:
  716 + r80_angle = dists.GetBinLowEdge(idist+1)
  717 + break
  718 +
  719 + # Set histogram values
  720 + r68.SetBinContent(ieng+1,ioff+1,r68_angle)
  721 + r80.SetBinContent(ieng+1,ioff+1,r80_angle)
  722 +
  723 + # Return
  724 + return r68, r80
  725 +
654 726 def _root2psf_gauss(self, tfile, irf, ds):
655 727 """
656 728 Translate ROOT to CALDB point spread function extension
... ... @@ -677,7 +749,8 @@ class csroot2caldb(ctools.cscript):
677 749 'Generate Gaussian point spread function extension')
678 750  
679 751 # Get relevant ROOT histograms
680   - r68 = tfile.Get('AngRes_offaxis')
  752 + #r68 = tfile.Get('AngRes_offaxis')
  753 + r68, _ = self._root2psf_get_r68_and_r80(tfile)
681 754  
682 755 # Extract number of bins in histogram
683 756 neng = r68.GetXaxis().GetNbins()
... ... @@ -757,8 +830,9 @@ class csroot2caldb(ctools.cscript):
757 830 'Generate King point spread function extension')
758 831  
759 832 # Get relevant ROOT histograms
760   - r68 = tfile.Get('AngRes_offaxis')
761   - r80 = tfile.Get('AngRes80_offaxis')
  833 + #r68 = tfile.Get('AngRes_offaxis')
  834 + #r80 = tfile.Get('AngRes80_offaxis')
  835 + r68, r80 = self._root2psf_get_r68_and_r80(tfile)
762 836  
763 837 # Extract number of bins in histogram
764 838 neng = r68.GetXaxis().GetNbins()
... ... @@ -869,6 +943,80 @@ class csroot2caldb(ctools.cscript):
869 943 # Return
870 944 return
871 945  
  946 + def _root2edisp_get_migra(self, tfile):
  947 + """
  948 + Generates migration matrix histogram from AngularPSF2DEtrue_offaxis
  949 + histogram
  950 +
  951 + Parameters
  952 + ----------
  953 + tfile : `~ROOT.TFile`
  954 + ROOT file
  955 +
  956 + Returns
  957 + -------
  958 + migra : `~ROOT.TH3F`
  959 + Migration matrix
  960 + """
  961 + # Get relevant ROOT histograms
  962 + matrix = tfile.Get('MigMatrixNoTheta2cut_offaxis')
  963 +
  964 + # Extract axes
  965 + ereco = matrix.GetXaxis()
  966 + etrue = matrix.GetYaxis()
  967 + offsets = matrix.GetZaxis()
  968 +
  969 + # Extract number of bins in histogram
  970 + nereco = ereco.GetNbins()
  971 + netrue = etrue.GetNbins()
  972 + noffset = offsets.GetNbins()
  973 +
  974 + # Set number of migration bins
  975 + nmigra = 300
  976 +
  977 + # Create migra histograms
  978 + migra = TH3F('EestOverEtrue_offaxis',
  979 + 'Migration',
  980 + netrue, etrue.GetBinLowEdge(1), etrue.GetBinUpEdge(netrue),
  981 + nmigra, 0.0, 3.0,
  982 + noffset, offsets.GetBinLowEdge(1), offsets.GetBinUpEdge(noffset))
  983 +
  984 + # Loop over true energies
  985 + for ietrue in range(netrue):
  986 +
  987 + # Get true energy in TeV
  988 + e_true = math.pow(10.0, migra.GetXaxis().GetBinCenter(ietrue+1))
  989 +
  990 + # Loop over migration values
  991 + for imigra in range(nmigra):
  992 +
  993 + # Get migration value
  994 + migration = migra.GetYaxis().GetBinCenter(imigra+1)
  995 +
  996 + # Compute reconstructed energy in TeV
  997 + e_reco = e_true * migration
  998 +
  999 + # Continue only if reconstructed energy is positive
  1000 + if e_reco > 0.0:
  1001 +
  1002 + # Get reconstructed bin
  1003 + ireco = ereco.FindFixBin(math.log10(e_reco))
  1004 +
  1005 + # Continue only if bin is valid
  1006 + if ireco > 0 and ireco <= nereco:
  1007 +
  1008 + # Loop over offset angles
  1009 + for ioff in range(noffset):
  1010 +
  1011 + # Get bin value
  1012 + value = matrix.GetBinContent(ireco,ietrue+1,ioff+1)
  1013 +
  1014 + # Set bin value
  1015 + migra.SetBinContent(ietrue+1,imigra+1,ioff+1,value)
  1016 +
  1017 + # Return
  1018 + return migra
  1019 +
872 1020 def _root2edisp(self, tfile, irf, ds):
873 1021 """
874 1022 Translate ROOT to CALDB energy dispersion extension
... ... @@ -889,7 +1037,8 @@ class csroot2caldb(ctools.cscript):
889 1037 self._log_header1(gammalib.TERSE, 'Generate energy dispersion extension')
890 1038  
891 1039 # Get relevant ROOT histograms
892   - matrix = tfile.Get('EestOverEtrue_offaxis')
  1040 + matrix = self._root2edisp_get_migra(tfile)
  1041 + #matrix = tfile.Get('EestOverEtrue_offaxis')
893 1042  
894 1043 # Write boundary keywords
895 1044 self._set_cif_keywords(ds['HDU_EDISP'], irf['EDISP_NAME'],
... ...