Commit e27b5c3455652aba9fe756f83bd3c70cd210630b
1 parent
12b82d2a
Implement csroot2caldb background template generation.
Showing
4 changed files
with
129 additions
and
84 deletions
ChangeLog
| 1 | -2016-04-22 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu> | 1 | +2016-04-25 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu> |
| 2 | 2 | ||
| 3 | * Version 1.1.0 released | 3 | * Version 1.1.0 released |
| 4 | ======================== | 4 | ======================== |
| 5 | 5 | ||
| 6 | + Add "bgdoversample" and "bgdinfill" parameters to csroot2caldb | ||
| 6 | Add csobsdef.pntdef() method (#1771) | 7 | Add csobsdef.pntdef() method (#1771) |
| 7 | Add ctmapcube tool (#1760) | 8 | Add ctmapcube tool (#1760) |
| 8 | Add "seed" parameter to cspull (#1755) | 9 | Add "seed" parameter to cspull (#1755) |
NEWS
| 1 | New Features and Important Changes in ctools 1.1.0 | 1 | New Features and Important Changes in ctools 1.1.0 |
| 2 | 2 | ||
| 3 | -22 April 2016 | 3 | +25 April 2016 |
| 4 | 4 | ||
| 5 | 5 | ||
| 6 | Introduction | 6 | Introduction |
| @@ -198,7 +198,12 @@ support energy dispersion for stacked analysis (#1724). | @@ -198,7 +198,12 @@ support energy dispersion for stacked analysis (#1724). | ||
| 198 | 198 | ||
| 199 | Add csworkflow script that executes an arbitrary analysis workflow (#1508). | 199 | Add csworkflow script that executes an arbitrary analysis workflow (#1508). |
| 200 | 200 | ||
| 201 | -Transformed cta_root2caldb into csroot2caldb script. | 201 | +Transformed cta_root2caldb into csroot2caldb script. The parameters |
| 202 | +"bgdoversample" and "bgdinfill" have been added to the parameter file to | ||
| 203 | +provide more control over the background template generation. The background | ||
| 204 | +template is now generated using linear interpolation, and the | ||
| 205 | +"bgdoversample" allows to generate the background template at a finer | ||
| 206 | +sampling than the spatial sampling in the ROOT file. | ||
| 202 | 207 | ||
| 203 | Add csobsdef.pntdef() method to set directly a pointing definition from a | 208 | Add csobsdef.pntdef() method to set directly a pointing definition from a |
| 204 | gammalib.GCsv object (#1771). | 209 | gammalib.GCsv object (#1771). |
cscripts/csroot2caldb.par
| @@ -17,16 +17,18 @@ | @@ -17,16 +17,18 @@ | ||
| 17 | # | 17 | # |
| 18 | # Input parameters | 18 | # Input parameters |
| 19 | #================= | 19 | #================= |
| 20 | -infile, f, a, irf.root,,, "Input ROOT file" | ||
| 21 | -outdir, s, h, ,,, "Output CALDB directory" | ||
| 22 | -inst, s, a, prod3,,, "Instrument name" | ||
| 23 | -id, s, a, South_50h,,, "Instrument Response Function identifier" | ||
| 24 | -version, s, a, prod3,,, "Instrument Response Function version" | ||
| 25 | -analysis, s, a, DESY,,, "Instrument Response Function analysis" | ||
| 26 | -psftype, s, h, Gauss,Gauss|King,, "Point spread function type" | ||
| 27 | -rebin, b, h, no,,, "Rebin" | ||
| 28 | -eascale, r, h, 1.0,,, "Scaling factor for effective areas" | ||
| 29 | -bgdscale, r, h, 1.0,,, "Scaling factor for background rates" | 20 | +infile, f, a, irf.root,,, "Input ROOT file" |
| 21 | +outdir, s, h, ,,, "Output CALDB directory" | ||
| 22 | +inst, s, a, prod3,,, "Instrument name" | ||
| 23 | +id, s, a, South_50h,,, "Instrument Response Function identifier" | ||
| 24 | +version, s, a, prod3,,, "Instrument Response Function version" | ||
| 25 | +analysis, s, a, DESY,,, "Instrument Response Function analysis" | ||
| 26 | +psftype, s, h, Gauss,Gauss|King,, "Point spread function type" | ||
| 27 | +rebin, b, h, no,,, "Rebin" | ||
| 28 | +eascale, r, h, 1.0,,, "Scaling factor for effective areas" | ||
| 29 | +bgdscale, r, h, 1.0,,, "Scaling factor for background rates" | ||
| 30 | +bgdoversample, i, h, 1,,, "Spatial oversampling factor for background template" | ||
| 31 | +bgdinfill, b, h, no,,, "Infill of background template?" | ||
| 30 | 32 | ||
| 31 | # | 33 | # |
| 32 | # Standard parameters | 34 | # Standard parameters |
cscripts/csroot2caldb.py
| @@ -73,16 +73,18 @@ class csroot2caldb(ctools.cscript): | @@ -73,16 +73,18 @@ class csroot2caldb(ctools.cscript): | ||
| 73 | Get parameters from parfile. | 73 | Get parameters from parfile. |
| 74 | """ | 74 | """ |
| 75 | # Query parameters | 75 | # Query parameters |
| 76 | - self["infile"].filename() | ||
| 77 | - self["outdir"].string() | ||
| 78 | - self["inst"].string() | ||
| 79 | - self["id"].string() | ||
| 80 | - self["analysis"].string() | ||
| 81 | - self["version"].string() | ||
| 82 | - self["psftype"].string() | ||
| 83 | - self["rebin"].boolean() | ||
| 84 | - self["eascale"].real() | ||
| 85 | - self["bgdscale"].real() | 76 | + self['infile'].filename() |
| 77 | + self['outdir'].string() | ||
| 78 | + self['inst'].string() | ||
| 79 | + self['id'].string() | ||
| 80 | + self['analysis'].string() | ||
| 81 | + self['version'].string() | ||
| 82 | + self['psftype'].string() | ||
| 83 | + self['rebin'].boolean() | ||
| 84 | + self['eascale'].real() | ||
| 85 | + self['bgdscale'].real() | ||
| 86 | + self['bgdoversample'].integer() | ||
| 87 | + self['bgdinfill'].boolean() | ||
| 86 | 88 | ||
| 87 | # Write input parameters into logger | 89 | # Write input parameters into logger |
| 88 | if self._logTerse(): | 90 | if self._logTerse(): |
| @@ -545,7 +547,7 @@ class csroot2caldb(ctools.cscript): | @@ -545,7 +547,7 @@ class csroot2caldb(ctools.cscript): | ||
| 545 | 547 | ||
| 546 | # Create background | 548 | # Create background |
| 547 | #self._root2bgd(file) | 549 | #self._root2bgd(file) |
| 548 | - self._root2bgd3D(file, bgdscale=self["bgdscale"].real()) | 550 | + self._root2bgd3D(file) |
| 549 | 551 | ||
| 550 | # Return | 552 | # Return |
| 551 | return | 553 | return |
| @@ -912,34 +914,34 @@ class csroot2caldb(ctools.cscript): | @@ -912,34 +914,34 @@ class csroot2caldb(ctools.cscript): | ||
| 912 | # Return | 914 | # Return |
| 913 | return | 915 | return |
| 914 | 916 | ||
| 915 | - def _root2bgd3D(self, file, bgdscale=1.0): | 917 | + def _root2bgd3D(self, file): |
| 916 | """ | 918 | """ |
| 917 | - Translate ROOT to CALDB background extension. The following ROOT | ||
| 918 | - histograms are used: | ||
| 919 | - | 919 | + Translate ROOT to CALDB background extension. |
| 920 | + | ||
| 921 | + The following ROOT histograms are used: | ||
| 920 | BGRatePerSqDeg_offaxis -> BGD | 922 | BGRatePerSqDeg_offaxis -> BGD |
| 921 | 923 | ||
| 922 | - Parameters: | ||
| 923 | - file - ROOT file. | ||
| 924 | - Keywords: | ||
| 925 | - scale - Background rate scaling factor | 924 | + Parameters |
| 925 | + ---------- | ||
| 926 | + file : `~ROOT.TFile` | ||
| 927 | + ROOT file. | ||
| 926 | """ | 928 | """ |
| 927 | # Continue only if background HDU has been opened | 929 | # Continue only if background HDU has been opened |
| 928 | if self._hdu_bgd != None: | 930 | if self._hdu_bgd != None: |
| 929 | 931 | ||
| 930 | # Allocate ROOT 2D array | 932 | # Allocate ROOT 2D array |
| 931 | array = TH2F() | 933 | array = TH2F() |
| 932 | - file.GetObject("BGRatePerSqDeg_offaxis", array) | 934 | + file.GetObject('BGRatePerSqDeg_offaxis', array) |
| 933 | 935 | ||
| 934 | # Set boundaries | 936 | # Set boundaries |
| 935 | - bounds = self._make_3D(array, self._hdu_bgd, None, "deg") | 937 | + bounds = self._make_3D(array, self._hdu_bgd, None, 'deg') |
| 936 | for b in bounds: | 938 | for b in bounds: |
| 937 | self._bgd_bounds.append(b) | 939 | self._bgd_bounds.append(b) |
| 938 | - self._set_cif_keywords(self._hdu_bgd, self._bgd_name, \ | 940 | + self._set_cif_keywords(self._hdu_bgd, self._bgd_name, |
| 939 | self._bgd_bounds, self._bgd_desc) | 941 | self._bgd_bounds, self._bgd_desc) |
| 940 | 942 | ||
| 941 | # BGD (reconstructed energy) | 943 | # BGD (reconstructed energy) |
| 942 | - self._make_3D(array, self._hdu_bgd, "BGD", "1/s/MeV/sr", scale=bgdscale) | 944 | + self._make_3D(array, self._hdu_bgd, 'BGD', '1/s/MeV/sr') |
| 943 | 945 | ||
| 944 | # Return | 946 | # Return |
| 945 | return | 947 | return |
| @@ -1038,40 +1040,76 @@ class csroot2caldb(ctools.cscript): | @@ -1038,40 +1040,76 @@ class csroot2caldb(ctools.cscript): | ||
| 1038 | # Return boundary information | 1040 | # Return boundary information |
| 1039 | return bounds | 1041 | return bounds |
| 1040 | 1042 | ||
| 1041 | - def _make_3D(self, array, hdu, name, unit, scale=1.0): | 1043 | + def _make_3D(self, array, hdu, name, unit): |
| 1042 | """ | 1044 | """ |
| 1043 | - Make 3D cube as function of DETX, DETY and energy from a | 1045 | + Generate background 3D cube |
| 1046 | + | ||
| 1047 | + Generates 3D cube as function of DETX, DETY and energy from a | ||
| 1044 | ROOT 2D histogram. If the HDU has already the energy and | 1048 | ROOT 2D histogram. If the HDU has already the energy and |
| 1045 | offset angle columns, this method will simply add another data | 1049 | offset angle columns, this method will simply add another data |
| 1046 | - column. | ||
| 1047 | - If name==None, the method will not append any data column. | ||
| 1048 | - | ||
| 1049 | - Parameters: | ||
| 1050 | - array - ROOT 2D histogram. | ||
| 1051 | - hdu - FITS HDU. | ||
| 1052 | - name - Data column name. | ||
| 1053 | - unit - Data unit. | ||
| 1054 | - Keywords: | ||
| 1055 | - scale - Scaling factor for histogram values. | 1050 | + column. If name==None, the method will not append any data column. |
| 1051 | + | ||
| 1052 | + Parameters | ||
| 1053 | + ---------- | ||
| 1054 | + array : `~ROOT.TH2F` | ||
| 1055 | + ROOT 2D histogram. | ||
| 1056 | + hdu : `~gammalib.GFitsHDU` | ||
| 1057 | + FITS HDU. | ||
| 1058 | + name : str | ||
| 1059 | + Data column name. | ||
| 1060 | + unit : str | ||
| 1061 | + Data unit. | ||
| 1056 | """ | 1062 | """ |
| 1063 | + # Get User parameters | ||
| 1064 | + scale = self['bgdscale'].real() | ||
| 1065 | + oversample = self['bgdoversample'].integer() | ||
| 1066 | + infill = self['bgdinfill'].boolean() | ||
| 1067 | + | ||
| 1057 | # Set constants | 1068 | # Set constants |
| 1058 | deg2sr = 0.01745329*0.01745329 | 1069 | deg2sr = 0.01745329*0.01745329 |
| 1059 | 1070 | ||
| 1060 | # Extract energy and offset angle vectors | 1071 | # Extract energy and offset angle vectors |
| 1061 | - energies = array.GetXaxis() | ||
| 1062 | - neng = energies.GetNbins() | ||
| 1063 | - offsets = array.GetYaxis() | ||
| 1064 | - noffset = offsets.GetNbins() | ||
| 1065 | - ewidth = [] # in MeV | 1072 | + energies = array.GetXaxis() |
| 1073 | + neng = energies.GetNbins() | ||
| 1074 | + offsets = array.GetYaxis() | ||
| 1075 | + noffset = offsets.GetNbins() | ||
| 1076 | + theta_max = offsets.GetBinUpEdge(noffset) # Maximum theta | ||
| 1077 | + ewidth = [] # in MeV | ||
| 1066 | for ieng in range(neng): | 1078 | for ieng in range(neng): |
| 1067 | - ewidth.append(pow(10.0, energies.GetBinUpEdge(ieng+1) +6.0) - \ | 1079 | + ewidth.append(pow(10.0, energies.GetBinUpEdge(ieng+1) +6.0) - |
| 1068 | pow(10.0, energies.GetBinLowEdge(ieng+1)+6.0)) | 1080 | pow(10.0, energies.GetBinLowEdge(ieng+1)+6.0)) |
| 1069 | 1081 | ||
| 1082 | + # Optionally fill all empty bins by the preceding value that occur | ||
| 1083 | + # for all offset angles between the first and the last non zero | ||
| 1084 | + # bin | ||
| 1085 | + if infill: | ||
| 1086 | + for ioff in range(noffset): | ||
| 1087 | + i_start = -1 | ||
| 1088 | + i_stop = -1 | ||
| 1089 | + value = 0.0 | ||
| 1090 | + for ieng in range(neng): | ||
| 1091 | + if array.GetBinContent(ieng+1,ioff+1) > 0.0: | ||
| 1092 | + i_start = ieng | ||
| 1093 | + value = array.GetBinContent(ieng+1,ioff+1) | ||
| 1094 | + break | ||
| 1095 | + for ieng in range(neng-1, -1, -1): | ||
| 1096 | + if array.GetBinContent(ieng+1,ioff+1) > 0.0: | ||
| 1097 | + i_stop = ieng | ||
| 1098 | + break | ||
| 1099 | + if i_start > -1 and i_stop > -1: | ||
| 1100 | + for ieng in range(i_start, i_stop+1): | ||
| 1101 | + if array.GetBinContent(ieng+1,ioff+1) == 0.0: | ||
| 1102 | + array.SetBinContent(ieng+1,ioff+1,value) | ||
| 1103 | + print('Background infill ieng=%d ioff=%d value=%f' % | ||
| 1104 | + (ieng,ioff,value)) | ||
| 1105 | + else: | ||
| 1106 | + value = array.GetBinContent(ieng+1,ioff+1) | ||
| 1107 | + | ||
| 1070 | # Build DETX and DETY axes | 1108 | # Build DETX and DETY axes |
| 1071 | ndet = array.GetYaxis().GetNbins() | 1109 | ndet = array.GetYaxis().GetNbins() |
| 1072 | - ndets = 2*ndet | 1110 | + ndets = 2*ndet*oversample |
| 1073 | det_max = array.GetYaxis().GetBinUpEdge(ndet) | 1111 | det_max = array.GetYaxis().GetBinUpEdge(ndet) |
| 1074 | - det_bin = det_max/float(ndet) | 1112 | + det_bin = det_max/float(ndet*oversample) |
| 1075 | dets_lo = [] | 1113 | dets_lo = [] |
| 1076 | dets_hi = [] | 1114 | dets_hi = [] |
| 1077 | dets2 = [] | 1115 | dets2 = [] |
| @@ -1084,36 +1122,36 @@ class csroot2caldb(ctools.cscript): | @@ -1084,36 +1122,36 @@ class csroot2caldb(ctools.cscript): | ||
| 1084 | dets2.append(det_val*det_val) | 1122 | dets2.append(det_val*det_val) |
| 1085 | 1123 | ||
| 1086 | # Append DETX_LO column | 1124 | # Append DETX_LO column |
| 1087 | - if not hdu.contains("DETX_LO"): | ||
| 1088 | - hdu.append(gammalib.GFitsTableFloatCol("DETX_LO", 1, ndets)) | ||
| 1089 | - hdu["DETX_LO"].unit("deg") | 1125 | + if not hdu.contains('DETX_LO'): |
| 1126 | + hdu.append(gammalib.GFitsTableFloatCol('DETX_LO', 1, ndets)) | ||
| 1127 | + hdu['DETX_LO'].unit('deg') | ||
| 1090 | for i in range(ndets): | 1128 | for i in range(ndets): |
| 1091 | - hdu["DETX_LO"][0,i] = dets_lo[i] | 1129 | + hdu['DETX_LO'][0,i] = dets_lo[i] |
| 1092 | 1130 | ||
| 1093 | # Append DETX_HI column | 1131 | # Append DETX_HI column |
| 1094 | - if not hdu.contains("DETX_HI"): | ||
| 1095 | - hdu.append(gammalib.GFitsTableFloatCol("DETX_HI", 1, ndets)) | ||
| 1096 | - hdu["DETX_HI"].unit("deg") | 1132 | + if not hdu.contains('DETX_HI'): |
| 1133 | + hdu.append(gammalib.GFitsTableFloatCol('DETX_HI', 1, ndets)) | ||
| 1134 | + hdu['DETX_HI'].unit('deg') | ||
| 1097 | for i in range(ndets): | 1135 | for i in range(ndets): |
| 1098 | - hdu["DETX_HI"][0,i] = dets_hi[i] | 1136 | + hdu['DETX_HI'][0,i] = dets_hi[i] |
| 1099 | 1137 | ||
| 1100 | # Append DETY_LO column | 1138 | # Append DETY_LO column |
| 1101 | - if not hdu.contains("DETY_LO"): | ||
| 1102 | - hdu.append(gammalib.GFitsTableFloatCol("DETY_LO", 1, ndets)) | ||
| 1103 | - hdu["DETY_LO"].unit("deg") | 1139 | + if not hdu.contains('DETY_LO'): |
| 1140 | + hdu.append(gammalib.GFitsTableFloatCol('DETY_LO', 1, ndets)) | ||
| 1141 | + hdu['DETY_LO'].unit('deg') | ||
| 1104 | for i in range(ndets): | 1142 | for i in range(ndets): |
| 1105 | - hdu["DETY_LO"][0,i] = dets_lo[i] | 1143 | + hdu['DETY_LO'][0,i] = dets_lo[i] |
| 1106 | 1144 | ||
| 1107 | # Append DETY_HI column | 1145 | # Append DETY_HI column |
| 1108 | - if not hdu.contains("DETY_HI"): | ||
| 1109 | - hdu.append(gammalib.GFitsTableFloatCol("DETY_HI", 1, ndets)) | ||
| 1110 | - hdu["DETY_HI"].unit("deg") | 1146 | + if not hdu.contains('DETY_HI'): |
| 1147 | + hdu.append(gammalib.GFitsTableFloatCol('DETY_HI', 1, ndets)) | ||
| 1148 | + hdu['DETY_HI'].unit('deg') | ||
| 1111 | for i in range(ndets): | 1149 | for i in range(ndets): |
| 1112 | - hdu["DETY_HI"][0,i] = dets_hi[i] | 1150 | + hdu['DETY_HI'][0,i] = dets_hi[i] |
| 1113 | 1151 | ||
| 1114 | # Append ENERG_LO and ENERG_HI columns | 1152 | # Append ENERG_LO and ENERG_HI columns |
| 1115 | - self._append_column(hdu, "ENERG_LO", "TeV", energies, log=True) | ||
| 1116 | - self._append_column(hdu, "ENERG_HI", "TeV", energies, log=True) | 1153 | + self._append_column(hdu, 'ENERG_LO', 'TeV', energies, log=True) |
| 1154 | + self._append_column(hdu, 'ENERG_HI', 'TeV', energies, log=True) | ||
| 1117 | 1155 | ||
| 1118 | # Append array column | 1156 | # Append array column |
| 1119 | if name != None and not hdu.contains(name): | 1157 | if name != None and not hdu.contains(name): |
| @@ -1125,12 +1163,11 @@ class csroot2caldb(ctools.cscript): | @@ -1125,12 +1163,11 @@ class csroot2caldb(ctools.cscript): | ||
| 1125 | for ieng in range(neng): | 1163 | for ieng in range(neng): |
| 1126 | index = ix + (iy + ieng * ndets) * ndets | 1164 | index = ix + (iy + ieng * ndets) * ndets |
| 1127 | theta = math.sqrt(dets2[ix] + dets2[iy]) | 1165 | theta = math.sqrt(dets2[ix] + dets2[iy]) |
| 1128 | - ioff = offsets.FindBin(theta) | ||
| 1129 | - if ioff > 0 and ioff <= noffset: | ||
| 1130 | - binsq = array.GetBinContent(ieng+1,ioff) | ||
| 1131 | - if binsq >= 0: | ||
| 1132 | - value = binsq / deg2sr / (ewidth[ieng]) | ||
| 1133 | - hdu[name][0,index] = value * scale | 1166 | + if theta < theta_max: |
| 1167 | + binsq = array.Interpolate(energies.GetBinCenter(ieng+1), | ||
| 1168 | + theta) | ||
| 1169 | + value = binsq / deg2sr / (ewidth[ieng]) | ||
| 1170 | + hdu[name][0,index] = value * scale | ||
| 1134 | 1171 | ||
| 1135 | # Debugging | 1172 | # Debugging |
| 1136 | if False: | 1173 | if False: |
| @@ -1144,13 +1181,13 @@ class csroot2caldb(ctools.cscript): | @@ -1144,13 +1181,13 @@ class csroot2caldb(ctools.cscript): | ||
| 1144 | if ioff == 0: | 1181 | if ioff == 0: |
| 1145 | peak = value | 1182 | peak = value |
| 1146 | peaksq = binsq | 1183 | peaksq = binsq |
| 1147 | - print(pow(10.0, energies.GetBinLowEdge(ieng+1))+ \ | 1184 | + print(pow(10.0, energies.GetBinLowEdge(ieng+1))+ |
| 1148 | pow(10.0, energies.GetBinUpEdge(ieng+1)), sum, peak, peaksq) | 1185 | pow(10.0, energies.GetBinUpEdge(ieng+1)), sum, peak, peaksq) |
| 1149 | 1186 | ||
| 1150 | # Collect boundary information | 1187 | # Collect boundary information |
| 1151 | - bd_detx = "DETX(%.2f-%.2f)deg" % (-det_max, det_max) | ||
| 1152 | - bd_dety = "DETY(%.2f-%.2f)deg" % (-det_max, det_max) | ||
| 1153 | - bd_eng = "ENERG(%.4f-%.2f)TeV" % \ | 1188 | + bd_detx = 'DETX(%.2f-%.2f)deg' % (-det_max, det_max) |
| 1189 | + bd_dety = 'DETY(%.2f-%.2f)deg' % (-det_max, det_max) | ||
| 1190 | + bd_eng = 'ENERG(%.4f-%.2f)TeV' % \ | ||
| 1154 | (pow(10.0, energies.GetBinLowEdge(1)), | 1191 | (pow(10.0, energies.GetBinLowEdge(1)), |
| 1155 | pow(10.0, energies.GetBinUpEdge(neng))) | 1192 | pow(10.0, energies.GetBinUpEdge(neng))) |
| 1156 | bounds = [bd_detx, bd_dety, bd_eng] | 1193 | bounds = [bd_detx, bd_dety, bd_eng] |