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 | 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 | ... | ... |
NEWS
| 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'], | ... | ... |