Commit 169cd9220db83b8260e6d32e36d75fdc5f8d8242
1 parent
32febe17
Implement normalization of 2D histograms on 1D histograms
Showing
2 changed files
with
104 additions
and
4 deletions
cscripts/csroot2caldb.par
| ... | ... | @@ -24,6 +24,7 @@ id, s, a, South_50h,,, "Instrument Response Function identifier" |
| 24 | 24 | version, s, a, prod3,,, "Instrument Response Function version" |
| 25 | 25 | analysis, s, a, DESY,,, "Instrument Response Function analysis" |
| 26 | 26 | psftype, s, h, Gauss,Gauss|King,, "Point spread function type" |
| 27 | +norm1d, b, h, no,,, "Normalize on 1D histograms" | |
| 27 | 28 | rebin, b, h, no,,, "Rebin" |
| 28 | 29 | eascale, r, h, 1.0,,, "Scaling factor for effective areas" |
| 29 | 30 | bgdscale, r, h, 1.0,,, "Scaling factor for background rates" | ... | ... |
cscripts/csroot2caldb.py
| ... | ... | @@ -27,7 +27,7 @@ from datetime import datetime |
| 27 | 27 | |
| 28 | 28 | # Optional ROOT import |
| 29 | 29 | try: |
| 30 | - from ROOT import TFile, TH2F, TH3F | |
| 30 | + from ROOT import TFile, TH1F, TH2F, TH3F | |
| 31 | 31 | _has_root = True |
| 32 | 32 | except: |
| 33 | 33 | _has_root = False |
| ... | ... | @@ -80,6 +80,7 @@ class csroot2caldb(ctools.cscript): |
| 80 | 80 | self['analysis'].string() |
| 81 | 81 | self['version'].string() |
| 82 | 82 | self['psftype'].string() |
| 83 | + self['norm1d'].boolean() | |
| 83 | 84 | self['rebin'].boolean() |
| 84 | 85 | self['eascale'].real() |
| 85 | 86 | self['bgdscale'].real() |
| ... | ... | @@ -570,11 +571,23 @@ class csroot2caldb(ctools.cscript): |
| 570 | 571 | # Continue only if effective area HDU has been opened |
| 571 | 572 | if self._hdu_ea != None: |
| 572 | 573 | |
| 574 | + # Get User parameters | |
| 575 | + norm1d = self['norm1d'].boolean() | |
| 576 | + | |
| 573 | 577 | # Allocate ROOT 2D arrays |
| 574 | 578 | etrue = TH2F() |
| 575 | 579 | ereco = TH2F() |
| 576 | - file.GetObject("EffectiveAreaEtrue_offaxis", etrue) | |
| 577 | - file.GetObject("EffectiveArea_offaxis", ereco) | |
| 580 | + file.GetObject('EffectiveAreaEtrue_offaxis', etrue) | |
| 581 | + file.GetObject('EffectiveArea_offaxis', ereco) | |
| 582 | + | |
| 583 | + # Normalize 2D histogram on on-axis 1D histogram | |
| 584 | + if norm1d: | |
| 585 | + etrue_1D = TH1F() | |
| 586 | + ereco_1D = TH1F() | |
| 587 | + file.GetObject('EffectiveAreaEtrue', etrue_1D) | |
| 588 | + file.GetObject('EffectiveArea', ereco_1D) | |
| 589 | + self._renorm_onaxis(etrue, etrue_1D) | |
| 590 | + self._renorm_onaxis(ereco, ereco_1D) | |
| 578 | 591 | |
| 579 | 592 | # Rebin etrue histogram |
| 580 | 593 | if rebin: |
| ... | ... | @@ -929,10 +942,19 @@ class csroot2caldb(ctools.cscript): |
| 929 | 942 | # Continue only if background HDU has been opened |
| 930 | 943 | if self._hdu_bgd != None: |
| 931 | 944 | |
| 945 | + # Get User parameters | |
| 946 | + norm1d = self['norm1d'].boolean() | |
| 947 | + | |
| 932 | 948 | # Allocate ROOT 2D array |
| 933 | 949 | array = TH2F() |
| 934 | 950 | file.GetObject('BGRatePerSqDeg_offaxis', array) |
| 935 | 951 | |
| 952 | + # Normalize 2D histogram on on-axis 1D histogram | |
| 953 | + if norm1d: | |
| 954 | + array_1D = TH1F() | |
| 955 | + file.GetObject('BGRatePerSqDeg', array_1D) | |
| 956 | + self._renorm_onaxis(array, array_1D) | |
| 957 | + | |
| 936 | 958 | # Set boundaries |
| 937 | 959 | bounds = self._make_3D(array, self._hdu_bgd, None, 'deg') |
| 938 | 960 | for b in bounds: |
| ... | ... | @@ -970,7 +992,7 @@ class csroot2caldb(ctools.cscript): |
| 970 | 992 | hdu[name].unit(unit) |
| 971 | 993 | |
| 972 | 994 | # Do we have a LO axis? If not we have a HI axis |
| 973 | - if name[-2:] == "LO": | |
| 995 | + if name[-2:] == 'LO': | |
| 974 | 996 | low = True |
| 975 | 997 | else: |
| 976 | 998 | low = False |
| ... | ... | @@ -988,6 +1010,83 @@ class csroot2caldb(ctools.cscript): |
| 988 | 1010 | # Return |
| 989 | 1011 | return |
| 990 | 1012 | |
| 1013 | + def _renorm_onaxis(self, hist2D, hist1D): | |
| 1014 | + """ | |
| 1015 | + Renormalise 2D histogram (energy,offset) on 1D histogram (energy) | |
| 1016 | + | |
| 1017 | + This method makes sure that a 2D histogram has the same onaxis values | |
| 1018 | + as the corresponding 1D histogram. | |
| 1019 | + | |
| 1020 | + Parameters | |
| 1021 | + ---------- | |
| 1022 | + hist2D : `~ROOT.TH2F` | |
| 1023 | + ROOT 2D histogram. | |
| 1024 | + hist1D : `~ROOT.TH1F` | |
| 1025 | + ROOT 1D histogram. | |
| 1026 | + """ | |
| 1027 | + # Get 2D dimensions | |
| 1028 | + neng = hist2D.GetXaxis().GetNbins() | |
| 1029 | + noffset = hist2D.GetYaxis().GetNbins() | |
| 1030 | + | |
| 1031 | + # Continue only if the 1D and 2D histograms have the same number | |
| 1032 | + # of energy bins | |
| 1033 | + if neng != hist1D.GetXaxis().GetNbins(): | |
| 1034 | + # Write header | |
| 1035 | + if self._logTerse(): | |
| 1036 | + self._log('Difference in energy binning between 2D histogram' | |
| 1037 | + ' "%s" and 1D histogram "%s".\n' % | |
| 1038 | + (hist2D.GetName(), hist1D.GetName())) | |
| 1039 | + else: | |
| 1040 | + # Write header | |
| 1041 | + if self._logTerse(): | |
| 1042 | + self._log('Renormalize 2D histogram "%s" on 1D histogram "%s".\n' % | |
| 1043 | + (hist2D.GetName(), hist1D.GetName())) | |
| 1044 | + | |
| 1045 | + # Get a copy of 2D histogram | |
| 1046 | + hist2D_copy = hist2D.Clone() | |
| 1047 | + | |
| 1048 | + # Divide 2D histogram by onaxis values to remove the energy | |
| 1049 | + # dependence | |
| 1050 | + for ieng in range(neng): | |
| 1051 | + onaxis = hist1D.GetBinContent(ieng+1) | |
| 1052 | + if onaxis > 0.0: | |
| 1053 | + for ioff in range(noffset): | |
| 1054 | + value = hist2D.GetBinContent(ieng+1,ioff+1) / onaxis | |
| 1055 | + hist2D.SetBinContent(ieng+1,ioff+1,value) | |
| 1056 | + | |
| 1057 | + # Smooth in energy direction to reduce statistical fluctuations | |
| 1058 | + for ieng in range(neng): | |
| 1059 | + for ioff in range(noffset): | |
| 1060 | + if ieng == 0: | |
| 1061 | + value = (2.0 * hist2D.GetBinContent(ieng+1,ioff+1) + | |
| 1062 | + 1.0 * hist2D.GetBinContent(ieng+2,ioff+1)) / 3.0 | |
| 1063 | + elif ieng == neng-1: | |
| 1064 | + value = (2.0 * hist2D.GetBinContent(ieng+1,ioff+1) + | |
| 1065 | + 1.0 * hist2D.GetBinContent(ieng+0,ioff+1)) / 3.0 | |
| 1066 | + else: | |
| 1067 | + value = (2.0 * hist2D.GetBinContent(ieng+1,ioff+1) + | |
| 1068 | + 1.0 * hist2D.GetBinContent(ieng+0,ioff+1) + | |
| 1069 | + 1.0 * hist2D.GetBinContent(ieng+2,ioff+1)) / 4.0 | |
| 1070 | + hist2D_copy.SetBinContent(ieng+1,ioff+1,value) | |
| 1071 | + | |
| 1072 | + # Normalize now for an onaxis value of 1 | |
| 1073 | + for ieng in range(neng): | |
| 1074 | + onaxis = hist2D_copy.GetBinContent(ieng+1,1) | |
| 1075 | + if onaxis > 0.0: | |
| 1076 | + for ioff in range(noffset): | |
| 1077 | + value = hist2D_copy.GetBinContent(ieng+1,ioff+1) / onaxis | |
| 1078 | + hist2D_copy.SetBinContent(ieng+1,ioff+1,value) | |
| 1079 | + | |
| 1080 | + # Put back the energy dependence | |
| 1081 | + for ieng in range(neng): | |
| 1082 | + onaxis = hist1D.GetBinContent(ieng+1) | |
| 1083 | + for ioff in range(noffset): | |
| 1084 | + value = hist2D_copy.GetBinContent(ieng+1,ioff+1) * onaxis | |
| 1085 | + hist2D.SetBinContent(ieng+1,ioff+1,value) | |
| 1086 | + | |
| 1087 | + # Return | |
| 1088 | + return | |
| 1089 | + | |
| 991 | 1090 | def _make_2D(self, array, hdu, name, unit, scale=1.0): |
| 992 | 1091 | """ |
| 993 | 1092 | Make 2D matrix as function of energy and offset angle from a | ... | ... |