Commit a5a1a27acf595c74c8b607bfd953194055310a38
1 parent
a11d1205
Use MigMatrixNoTheta2cut_offaxis and AngularPSF2DEtrue_offaxis histograms to com…
…pute PSF and energy dispersion IRFs (#2135)
Showing
3 changed files
with
162 additions
and
7 deletions
ChangeLog
| 1 | -2017-06-23 | 1 | +2017-06-27 |
| 2 | 2 | ||
| 3 | * Bug fix version 1.3.1 released | 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 | Properly forward working log file pointer in ctobssim::set_mc_id_names() (#2123) | 8 | Properly forward working log file pointer in ctobssim::set_mc_id_names() (#2123) |
| 7 | Correct computation of standard deviations in cssrcdetect | 9 | Correct computation of standard deviations in cssrcdetect |
| 8 | csobsselect accepts an observation container upon construction | 10 | csobsselect accepts an observation container upon construction |
NEWS
| 1 | New Features and Important Changes in ctools 1.3.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 | Introduction | 6 | Introduction |
| @@ -122,6 +122,10 @@ The csobsselect script now accepts an observation container upon construction. | @@ -122,6 +122,10 @@ The csobsselect script now accepts an observation container upon construction. | ||
| 122 | 122 | ||
| 123 | The standard deviation computation in cssrcdetect has been corrected. | 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 | Examples | 130 | Examples |
| 127 | -------- | 131 | -------- |
cscripts/csroot2caldb.py
| @@ -29,7 +29,7 @@ from cscripts import calutils | @@ -29,7 +29,7 @@ from cscripts import calutils | ||
| 29 | 29 | ||
| 30 | # Optional ROOT import | 30 | # Optional ROOT import |
| 31 | try: | 31 | try: |
| 32 | - from ROOT import TFile | 32 | + from ROOT import TFile, TH2F, TH3F |
| 33 | _has_root = True | 33 | _has_root = True |
| 34 | except ImportError: | 34 | except ImportError: |
| 35 | _has_root = False | 35 | _has_root = False |
| @@ -651,6 +651,78 @@ class csroot2caldb(ctools.cscript): | @@ -651,6 +651,78 @@ class csroot2caldb(ctools.cscript): | ||
| 651 | # Return | 651 | # Return |
| 652 | return | 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 | def _root2psf_gauss(self, tfile, irf, ds): | 726 | def _root2psf_gauss(self, tfile, irf, ds): |
| 655 | """ | 727 | """ |
| 656 | Translate ROOT to CALDB point spread function extension | 728 | Translate ROOT to CALDB point spread function extension |
| @@ -677,7 +749,8 @@ class csroot2caldb(ctools.cscript): | @@ -677,7 +749,8 @@ class csroot2caldb(ctools.cscript): | ||
| 677 | 'Generate Gaussian point spread function extension') | 749 | 'Generate Gaussian point spread function extension') |
| 678 | 750 | ||
| 679 | # Get relevant ROOT histograms | 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 | # Extract number of bins in histogram | 755 | # Extract number of bins in histogram |
| 683 | neng = r68.GetXaxis().GetNbins() | 756 | neng = r68.GetXaxis().GetNbins() |
| @@ -757,8 +830,9 @@ class csroot2caldb(ctools.cscript): | @@ -757,8 +830,9 @@ class csroot2caldb(ctools.cscript): | ||
| 757 | 'Generate King point spread function extension') | 830 | 'Generate King point spread function extension') |
| 758 | 831 | ||
| 759 | # Get relevant ROOT histograms | 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 | # Extract number of bins in histogram | 837 | # Extract number of bins in histogram |
| 764 | neng = r68.GetXaxis().GetNbins() | 838 | neng = r68.GetXaxis().GetNbins() |
| @@ -869,6 +943,80 @@ class csroot2caldb(ctools.cscript): | @@ -869,6 +943,80 @@ class csroot2caldb(ctools.cscript): | ||
| 869 | # Return | 943 | # Return |
| 870 | return | 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 | def _root2edisp(self, tfile, irf, ds): | 1020 | def _root2edisp(self, tfile, irf, ds): |
| 873 | """ | 1021 | """ |
| 874 | Translate ROOT to CALDB energy dispersion extension | 1022 | Translate ROOT to CALDB energy dispersion extension |
| @@ -889,7 +1037,8 @@ class csroot2caldb(ctools.cscript): | @@ -889,7 +1037,8 @@ class csroot2caldb(ctools.cscript): | ||
| 889 | self._log_header1(gammalib.TERSE, 'Generate energy dispersion extension') | 1037 | self._log_header1(gammalib.TERSE, 'Generate energy dispersion extension') |
| 890 | 1038 | ||
| 891 | # Get relevant ROOT histograms | 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 | # Write boundary keywords | 1043 | # Write boundary keywords |
| 895 | self._set_cif_keywords(ds['HDU_EDISP'], irf['EDISP_NAME'], | 1044 | self._set_cif_keywords(ds['HDU_EDISP'], irf['EDISP_NAME'], |