Commit a266b5659e5c9469de5450b7bc21bc26e2e8c14b
1 parent
5cd3af9d
Revise csroot2caldb script (#1828)
Showing
2 changed files
with
723 additions
and
758 deletions
cscripts/csroot2caldb.par
| ... | ... | @@ -5,7 +5,7 @@ |
| 5 | 5 | # ------------------------------------------------------------------------- # |
| 6 | 6 | # # |
| 7 | 7 | # File: csroot2caldb.par # |
| 8 | -# Version: 1.0.0 # | |
| 8 | +# Version: 1.2.0 # | |
| 9 | 9 | # # |
| 10 | 10 | # Author: Juergen Knoedlseder # |
| 11 | 11 | # Jurgen.Knodlseder@irap.omp.eu # |
| ... | ... | @@ -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 | +split, b, h, no,,, "Split IRF components into different files" | |
| 27 | 28 | norm1d, b, h, no,,, "Normalize on 1D histograms" |
| 28 | 29 | rebin, b, h, no,,, "Rebin" |
| 29 | 30 | eascale, r, h, 1.0,,, "Scaling factor for effective areas" | ... | ... |
cscripts/csroot2caldb.py
| ... | ... | @@ -39,7 +39,7 @@ except: |
| 39 | 39 | # ================== # |
| 40 | 40 | class csroot2caldb(ctools.cscript): |
| 41 | 41 | """ |
| 42 | - Generates IRFs in CALDB from a ROOT offaxis performance file. | |
| 42 | + Generates IRFs in CALDB from a ROOT offaxis performance file | |
| 43 | 43 | """ |
| 44 | 44 | |
| 45 | 45 | # Constructor |
| ... | ... | @@ -51,9 +51,8 @@ class csroot2caldb(ctools.cscript): |
| 51 | 51 | self._name = 'csroot2caldb' |
| 52 | 52 | self._version = '1.2.0' |
| 53 | 53 | |
| 54 | - # Initialise some members | |
| 54 | + # Initialise file members | |
| 55 | 55 | self._cif = None |
| 56 | - self._irf = None | |
| 57 | 56 | self._ea = None |
| 58 | 57 | self._psf = None |
| 59 | 58 | self._edisp = None |
| ... | ... | @@ -80,6 +79,7 @@ class csroot2caldb(ctools.cscript): |
| 80 | 79 | self['analysis'].string() |
| 81 | 80 | self['version'].string() |
| 82 | 81 | self['psftype'].string() |
| 82 | + self['split'].boolean() | |
| 83 | 83 | self['norm1d'].boolean() |
| 84 | 84 | self['rebin'].boolean() |
| 85 | 85 | self['eascale'].real() |
| ... | ... | @@ -90,64 +90,66 @@ class csroot2caldb(ctools.cscript): |
| 90 | 90 | # Write input parameters into logger |
| 91 | 91 | if self._logTerse(): |
| 92 | 92 | self._log_parameters() |
| 93 | - self._log("\n") | |
| 93 | + self._log('\n') | |
| 94 | 94 | |
| 95 | 95 | # Return |
| 96 | 96 | return |
| 97 | 97 | |
| 98 | - def _initialise(self): | |
| 99 | - | |
| 100 | - # Set CALDB information | |
| 101 | - self._cal_tel = "CTA" | |
| 102 | - self._cal_inst = self["inst"].string().upper() | |
| 103 | - self._cal_obsid = self["id"].string() | |
| 104 | - self._cal_det = "NONE" | |
| 105 | - self._cal_flt = "NONE" | |
| 106 | - self._cal_class = "BCF" | |
| 107 | - self._cal_type = "DATA" | |
| 108 | - self._cal_qual = 0 # 0=good, 1=bad, 2=dubious, ... | |
| 109 | - self._cal_date = "14/01/30" | |
| 110 | - self._val_date = "2014-01-30" | |
| 111 | - self._val_time = "00:00:00" | |
| 112 | - self._ref_time = 51544.0 | |
| 113 | - self._cal_name = "NAME("+self["id"].string()+")" | |
| 114 | - self._cal_version = "VERSION("+self["version"].string()+")" | |
| 115 | - self._cal_cut = "CLASS(BEST)" | |
| 116 | - self._cal_analysis = "ANALYSIS("+self["analysis"].string()+")" | |
| 117 | - # | |
| 118 | - self._ea_name = "EFF_AREA" | |
| 119 | - self._ea_doc = "CAL/GEN/92-019" | |
| 120 | - self._ea_bounds = [self._cal_name, self._cal_version, | |
| 121 | - self._cal_cut, self._cal_analysis] | |
| 122 | - self._ea_desc = "CTA effective area" | |
| 123 | - # | |
| 124 | - self._psf_name = "RPSF" | |
| 125 | - self._psf_doc = "CAL/GEN/92-020" | |
| 126 | - self._psf_bounds = [self._cal_name, self._cal_version, | |
| 127 | - self._cal_cut, self._cal_analysis] | |
| 128 | - self._psf_desc = "CTA point spread function" | |
| 129 | - # | |
| 130 | - self._edisp_name = "EDISP" | |
| 131 | - self._edisp_doc = "???" | |
| 132 | - self._edisp_bounds = [self._cal_name, self._cal_version, | |
| 133 | - self._cal_cut, self._cal_analysis] | |
| 134 | - self._edisp_desc = "CTA energy dispersion" | |
| 135 | - # | |
| 136 | - self._bgd_name = "BGD" | |
| 137 | - self._bgd_doc = "???" | |
| 138 | - self._bgd_bounds = [self._cal_name, self._cal_version, | |
| 139 | - self._cal_cut, self._cal_analysis] | |
| 140 | - self._bgd_desc = "CTA background" | |
| 141 | - | |
| 142 | - # Create directory structure | |
| 143 | - self._make_dirs() | |
| 144 | - | |
| 145 | - # Return | |
| 146 | - return | |
| 98 | + def _init_metadata(self): | |
| 99 | + """ | |
| 100 | + Initialise dictionary containing the IRF metadata | |
| 147 | 101 | |
| 148 | - def _make_dirs(self): | |
| 102 | + Returns | |
| 103 | + ------- | |
| 104 | + irf : dict | |
| 105 | + IRF metadata dictionary | |
| 149 | 106 | """ |
| 150 | - Generate CALDB directory structure for one observation identifier. | |
| 107 | + # Initialise IRF metadata dictionary | |
| 108 | + irf = {} | |
| 109 | + | |
| 110 | + # Set calibration information | |
| 111 | + cal_name = 'NAME('+self['id'].string()+')' | |
| 112 | + cal_version = 'VERSION('+self['version'].string()+')' | |
| 113 | + cal_cut = 'CLASS(BEST)' | |
| 114 | + cal_analysis = 'ANALYSIS('+self['analysis'].string()+')' | |
| 115 | + | |
| 116 | + # Set IRF information | |
| 117 | + irf['CAL_TEL'] = 'CTA' | |
| 118 | + irf['CAL_INST'] = self['inst'].string().upper() | |
| 119 | + irf['CAL_OBSID'] = self['id'].string() | |
| 120 | + irf['CAL_DET'] = 'NONE' | |
| 121 | + irf['CAL_FLT'] = 'NONE' | |
| 122 | + irf['CAL_CLASS'] = 'BCF' | |
| 123 | + irf['CAL_TYPE'] = 'DATA' | |
| 124 | + irf['CAL_QUAL'] = 0 # 0=good, 1=bad, 2=dubious, ... | |
| 125 | + irf['CAL_DATE'] = '14/01/30' | |
| 126 | + irf['VAL_DATE'] = '2014-01-30' | |
| 127 | + irf['VAL_TIME'] = '00:00:00' | |
| 128 | + irf['REF_TIME'] = 51544.0 | |
| 129 | + irf['EA_NAME'] = 'EFF_AREA' | |
| 130 | + irf['EA_DOC'] = 'CAL/GEN/92-019' | |
| 131 | + irf['EA_BOUNDS'] = [cal_name, cal_version, cal_cut, cal_analysis] | |
| 132 | + irf['EA_DESC'] = 'CTA effective area' | |
| 133 | + irf['PSF_NAME'] = 'RPSF' | |
| 134 | + irf['PSF_DOC'] = 'CAL/GEN/92-020' | |
| 135 | + irf['PSF_BOUNDS'] = [cal_name, cal_version, cal_cut, cal_analysis] | |
| 136 | + irf['PSF_DESC'] = 'CTA point spread function' | |
| 137 | + irf['EDISP_NAME'] = 'EDISP' | |
| 138 | + irf['EDISP_DOC'] = '???' | |
| 139 | + irf['EDISP_BOUNDS'] = [cal_name, cal_version, cal_cut, cal_analysis] | |
| 140 | + irf['EDISP_DESC'] = 'CTA energy dispersion' | |
| 141 | + irf['BGD_NAME'] = 'BGD' | |
| 142 | + irf['BGD_DOC'] = '???' | |
| 143 | + irf['BGD_BOUNDS'] = [cal_name, cal_version, cal_cut, cal_analysis] | |
| 144 | + irf['BGD_DESC'] = 'CTA background' | |
| 145 | + | |
| 146 | + # Return metadata | |
| 147 | + return irf | |
| 148 | + | |
| 149 | + def _make_dirs(self, version, irf): | |
| 150 | + """ | |
| 151 | + Generate CALDB directory structure for one observation identifier | |
| 152 | + | |
| 151 | 153 | The structure is given by |
| 152 | 154 | |
| 153 | 155 | data/<tel>/<inst>/bcf/<obsid> |
| ... | ... | @@ -155,172 +157,193 @@ class csroot2caldb(ctools.cscript): |
| 155 | 157 | where <tel> is "cta" and <inst> is the instrument specified in the |
| 156 | 158 | CALDB constructor (the instrument may be used for different array |
| 157 | 159 | configurations). |
| 160 | + | |
| 161 | + Parameters | |
| 162 | + ---------- | |
| 163 | + version : str | |
| 164 | + Version string | |
| 165 | + irf : dict | |
| 166 | + IRF metadata dictionary | |
| 167 | + | |
| 168 | + Returns | |
| 169 | + ------- | |
| 170 | + dir : dict | |
| 171 | + Directory structure information | |
| 158 | 172 | """ |
| 173 | + # Initialise directory structure dictionary | |
| 174 | + dir = {} | |
| 175 | + | |
| 159 | 176 | # Set base directory |
| 160 | - base_dir = "data" | |
| 161 | - base_dir += "/"+self._cal_tel.lower() | |
| 162 | - base_dir += "/"+self._cal_inst.lower() | |
| 177 | + base_dir = 'data' | |
| 178 | + base_dir += '/'+irf['CAL_TEL'].lower() | |
| 179 | + base_dir += '/'+irf['CAL_INST'].lower() | |
| 163 | 180 | |
| 164 | 181 | # Set directory names |
| 165 | - obs_dir = base_dir+"/bcf/"+self._cal_obsid | |
| 166 | - self._ea_dir = obs_dir | |
| 167 | - self._psf_dir = obs_dir | |
| 168 | - self._edisp_dir = obs_dir | |
| 169 | - self._bgd_dir = obs_dir | |
| 170 | - | |
| 171 | - # Optionally prefix path | |
| 172 | - outdir = self["outdir"].string() | |
| 182 | + obs_dir = base_dir+'/bcf/'+irf['CAL_OBSID'] | |
| 183 | + dir['EA_DIR'] = obs_dir | |
| 184 | + dir['PSF_DIR'] = obs_dir | |
| 185 | + dir['EDISP_DIR'] = obs_dir | |
| 186 | + dir['BGD_DIR'] = obs_dir | |
| 187 | + | |
| 188 | + # Set path to response components. If the "outdir" parameter is set | |
| 189 | + # then prefix the value to the path of the response components | |
| 190 | + outdir = self['outdir'].string() | |
| 173 | 191 | if len(outdir) > 0: |
| 174 | - self._base_path = outdir+"/"+base_dir | |
| 175 | - self._ea_path = outdir+"/"+self._ea_dir | |
| 176 | - self._psf_path = outdir+"/"+self._psf_dir | |
| 177 | - self._edisp_path = outdir+"/"+self._edisp_dir | |
| 178 | - self._bgd_path = outdir+"/"+self._bgd_dir | |
| 192 | + dir['BASE_PATH'] = outdir+'/'+base_dir | |
| 193 | + dir['EA_PATH'] = outdir+'/'+dir['EA_DIR'] | |
| 194 | + dir['PSF_PATH'] = outdir+'/'+dir['PSF_DIR'] | |
| 195 | + dir['EDISP_PATH'] = outdir+'/'+dir['EDISP_DIR'] | |
| 196 | + dir['BGD_PATH'] = outdir+'/'+dir['BGD_DIR'] | |
| 197 | + else: | |
| 198 | + dir['BASE_PATH'] = base_dir | |
| 199 | + dir['EA_PATH'] = dir['EA_DIR'] | |
| 200 | + dir['PSF_PATH'] = dir['PSF_DIR'] | |
| 201 | + dir['EDISP_PATH'] = dir['EDISP_DIR'] | |
| 202 | + dir['BGD_PATH'] = dir['BGD_DIR'] | |
| 203 | + | |
| 204 | + # Set IRF component file names. If the "split" parameter is "yes" then | |
| 205 | + # split the IRF components over several files. | |
| 206 | + if self['split'].boolean(): | |
| 207 | + dir['EA_FILE'] = 'ea_'+version+'.fits' | |
| 208 | + dir['PSF_FILE'] = 'psf_'+version+'.fits' | |
| 209 | + dir['EDISP_FILE'] = 'edisp_'+version+'.fits' | |
| 210 | + dir['BGD_FILE'] = 'bgd_'+version+'.fits' | |
| 179 | 211 | else: |
| 180 | - self._base_path = base_dir | |
| 181 | - self._ea_path = self._ea_dir | |
| 182 | - self._psf_path = self._psf_dir | |
| 183 | - self._edisp_path = self._edisp_dir | |
| 184 | - self._bgd_path = self._bgd_dir | |
| 212 | + dir['EA_FILE'] = 'irf_'+version+'.fits' | |
| 213 | + dir['PSF_FILE'] = 'irf_'+version+'.fits' | |
| 214 | + dir['EDISP_FILE'] = 'irf_'+version+'.fits' | |
| 215 | + dir['BGD_FILE'] = 'irf_'+version+'.fits' | |
| 185 | 216 | |
| 186 | 217 | # Create directory structure |
| 187 | - if not os.path.isdir(self._ea_path): | |
| 188 | - os.makedirs(self._ea_path) | |
| 189 | - if not os.path.isdir(self._psf_path): | |
| 190 | - os.makedirs(self._psf_path) | |
| 191 | - if not os.path.isdir(self._edisp_path): | |
| 192 | - os.makedirs(self._edisp_path) | |
| 193 | - if not os.path.isdir(self._bgd_path): | |
| 194 | - os.makedirs(self._bgd_path) | |
| 195 | - | |
| 196 | - # Return | |
| 197 | - return | |
| 198 | - | |
| 199 | - def _open(self, version, split=False, clobber=True): | |
| 218 | + if not os.path.isdir(dir['EA_PATH']): | |
| 219 | + os.makedirs(dir['EA_PATH']) | |
| 220 | + if not os.path.isdir(dir['PSF_PATH']): | |
| 221 | + os.makedirs(dir['PSF_PATH']) | |
| 222 | + if not os.path.isdir(dir['EDISP_PATH']): | |
| 223 | + os.makedirs(dir['EDISP_PATH']) | |
| 224 | + if not os.path.isdir(dir['BGD_PATH']): | |
| 225 | + os.makedirs(dir['BGD_PATH']) | |
| 226 | + | |
| 227 | + # Return dir | |
| 228 | + return dir | |
| 229 | + | |
| 230 | + def _open(self, irf, dir): | |
| 200 | 231 | """ |
| 201 | - Open existing or create new calibration. The actual version will put | |
| 202 | - all calibrations in the same file, although each part of the response | |
| 203 | - function will have its own logical name. We can thus easily modify | |
| 204 | - the script to put each calibration information in a separate file. | |
| 205 | - | |
| 206 | - Parameters: | |
| 207 | - version - Filename version | |
| 208 | - Keywords: | |
| 209 | - split - Split IRF over several files? | |
| 210 | - clobber - Overwrite existing files? | |
| 211 | - """ | |
| 212 | - # Set calibrate file names | |
| 213 | - if split: | |
| 214 | - self._ea_file = "ea_"+version+".fits" | |
| 215 | - self._psf_file = "psf_"+version+".fits" | |
| 216 | - self._edisp_file = "edisp_"+version+".fits" | |
| 217 | - self._bgd_file = "bgd_"+version+".fits" | |
| 218 | - else: | |
| 219 | - self._ea_file = "irf_"+version+".fits" | |
| 220 | - self._psf_file = "irf_"+version+".fits" | |
| 221 | - self._edisp_file = "irf_"+version+".fits" | |
| 222 | - self._bgd_file = "irf_"+version+".fits" | |
| 232 | + Open existing or create new calibration | |
| 233 | + | |
| 234 | + The actual version will put all calibrations in the same file, although | |
| 235 | + each part of the response function will have its own logical name. We | |
| 236 | + can thus easily modify the script to put each calibration information | |
| 237 | + in a separate file | |
| 223 | 238 | |
| 239 | + Parameters | |
| 240 | + ---------- | |
| 241 | + irf : dict | |
| 242 | + IRF metadata dictionary | |
| 243 | + dir : dir | |
| 244 | + Directory structure dictionary | |
| 245 | + """ | |
| 224 | 246 | # Open calibration database index |
| 225 | - self._cif = gammalib.GFits(self._base_path+"/caldb.indx", True) | |
| 247 | + self._cif = gammalib.GFits(dir['BASE_PATH']+'/caldb.indx', True) | |
| 226 | 248 | |
| 227 | 249 | # If file has no CIF extension than create it now |
| 228 | 250 | try: |
| 229 | - self._hdu_cif = self._cif.table("CIF") | |
| 251 | + self._hdu_cif = self._cif.table('CIF') | |
| 230 | 252 | except: |
| 231 | - self._create_cif() | |
| 232 | - self._hdu_cif = self._cif.table("CIF") | |
| 253 | + self._cif.append(calutils.create_cif_table()) | |
| 254 | + self._hdu_cif = self._cif.table('CIF') | |
| 233 | 255 | |
| 234 | - # Set filenames | |
| 235 | - ea_filename = self._ea_path+"/"+self._ea_file | |
| 236 | - psf_filename = self._psf_path+"/"+self._psf_file | |
| 237 | - edisp_filename = self._edisp_path+"/"+self._edisp_file | |
| 238 | - bgd_filename = self._bgd_path+"/"+self._bgd_file | |
| 256 | + # Set IRF component filenames | |
| 257 | + ea_filename = dir['EA_PATH']+'/'+dir['EA_FILE'] | |
| 258 | + psf_filename = dir['PSF_PATH']+'/'+dir['PSF_FILE'] | |
| 259 | + edisp_filename = dir['EDISP_PATH']+'/'+dir['EDISP_FILE'] | |
| 260 | + bgd_filename = dir['BGD_PATH']+'/'+dir['BGD_FILE'] | |
| 239 | 261 | |
| 240 | - # Open files | |
| 241 | - if split: | |
| 262 | + # Open IRF component files | |
| 263 | + if self['split'].boolean(): | |
| 242 | 264 | self._ea = gammalib.GFits(ea_filename, True) |
| 243 | 265 | self._psf = gammalib.GFits(psf_filename, True) |
| 244 | 266 | self._edisp = gammalib.GFits(edisp_filename, True) |
| 245 | 267 | self._bgd = gammalib.GFits(bgd_filename, True) |
| 246 | 268 | else: |
| 247 | - self._irf = gammalib.GFits(ea_filename, True) | |
| 248 | - self._ea = self._irf | |
| 249 | - self._psf = self._irf | |
| 250 | - self._edisp = self._irf | |
| 251 | - self._bgd = self._irf | |
| 269 | + self._ea = gammalib.GFits(ea_filename, True) | |
| 270 | + self._psf = self._ea | |
| 271 | + self._edisp = self._ea | |
| 272 | + self._bgd = self._ea | |
| 252 | 273 | |
| 253 | 274 | # Open HDUs |
| 254 | 275 | self._hdu_ea = self._open_hdu(self._ea, "EFFECTIVE AREA", |
| 255 | - self._ea_name, self._ea_doc) | |
| 276 | + irf['EA_NAME'], irf['EA_DOC'], irf) | |
| 256 | 277 | self._hdu_psf = self._open_hdu(self._psf, "POINT SPREAD FUNCTION", |
| 257 | - self._psf_name, self._psf_doc) | |
| 278 | + irf['PSF_NAME'], irf['PSF_DOC'], irf) | |
| 258 | 279 | self._hdu_edisp = self._open_hdu(self._edisp, "ENERGY DISPERSION", |
| 259 | - self._edisp_name, self._edisp_doc) | |
| 280 | + irf['EDISP_NAME'], irf['EDISP_DOC'], irf) | |
| 260 | 281 | self._hdu_bgd = self._open_hdu(self._bgd, "BACKGROUND", |
| 261 | - self._bgd_name, self._bgd_doc) | |
| 282 | + irf['BGD_NAME'], irf['BGD_DOC'], irf) | |
| 262 | 283 | |
| 263 | 284 | # Return |
| 264 | 285 | return |
| 265 | 286 | |
| 266 | - def _close(self): | |
| 267 | - """ | |
| 268 | - Close calibration FITS files. | |
| 287 | + def _close(self, irf, dir): | |
| 269 | 288 | """ |
| 270 | - # Add information to CIF. We do this now as before we did not | |
| 271 | - # necessarily have all the information at hand (in particular | |
| 272 | - # about the boundaries) | |
| 273 | - self._add_cif_info() | |
| 274 | - | |
| 275 | - # Close CIF | |
| 276 | - self._close_file(self._cif) | |
| 277 | - | |
| 278 | - # If IRF file exists then close it now. All file pointers will | |
| 279 | - # be set to None | |
| 280 | - if self._irf != None: | |
| 281 | - self._close_file(self._irf) | |
| 282 | - self._ea = None | |
| 283 | - self._psf = None | |
| 284 | - self._edisp = None | |
| 285 | - self._bgd = None | |
| 286 | - | |
| 287 | - # ... otherwise we have split files, so we have to close them all | |
| 288 | - else: | |
| 289 | - self._close_file(self._ea) | |
| 290 | - self._close_file(self._psf) | |
| 291 | - self._close_file(self._edisp) | |
| 292 | - self._close_file(self._bgd) | |
| 289 | + Close calibration FITS files | |
| 293 | 290 | |
| 294 | - # Return | |
| 295 | - return | |
| 296 | - | |
| 297 | - def _close_file(self, file): | |
| 298 | - """ | |
| 299 | - Close one file. | |
| 291 | + Parameters | |
| 292 | + ---------- | |
| 293 | + irf : dict | |
| 294 | + IRF metadata dictionary | |
| 295 | + dir : dict | |
| 296 | + Directory structure dictionary | |
| 300 | 297 | """ |
| 301 | - # If file is open then close it | |
| 302 | - if file != None: | |
| 303 | - file.save(True) | |
| 304 | - file.close() | |
| 305 | - file = None | |
| 306 | - | |
| 298 | + # Add information to CIF. We do this now as before we did not | |
| 299 | + # necessarily have all the information at hand (in particular about | |
| 300 | + # the boundaries) | |
| 301 | + self._add_cif_info(irf, dir) | |
| 302 | + | |
| 303 | + # Save and close CIF | |
| 304 | + self._cif.save(True) | |
| 305 | + self._cif.close() | |
| 306 | + | |
| 307 | + # Close all IRF components. If the files have been split all components | |
| 308 | + # need to be closed, otherwise only the effective area component needs | |
| 309 | + # to be closed as representative for all components. | |
| 310 | + self._ea.save(True) | |
| 311 | + self._ea.close() | |
| 312 | + if self['split'].boolean(): | |
| 313 | + self._psf.save(True) | |
| 314 | + self._edisp.save(True) | |
| 315 | + self._bgd.save(True) | |
| 316 | + self._psf.close() | |
| 317 | + self._edisp.close() | |
| 318 | + self._bgd.close() | |
| 319 | + | |
| 307 | 320 | # Return |
| 308 | 321 | return |
| 309 | 322 | |
| 310 | - def _open_hdu(self, fits, extname, name, doc): | |
| 323 | + def _open_hdu(self, fits, extname, name, doc, irf): | |
| 311 | 324 | """ |
| 312 | 325 | Open HDU |
| 313 | 326 | |
| 314 | - If HDU does not exist then create one. | |
| 315 | - | |
| 316 | - Parameters: | |
| 317 | - fits: FITS file | |
| 318 | - extname: Extension name | |
| 319 | - name: Name string | |
| 320 | - doc: Document string | |
| 327 | + Opens a FITS binary table with given "extname". If HDU does not exist | |
| 328 | + in the FITS file it will be created and appended to the FITS file. | |
| 321 | 329 | |
| 322 | - Returns: | |
| 323 | - FITS table | |
| 330 | + Parameters | |
| 331 | + ---------- | |
| 332 | + fits : `~gammalib.GFits` | |
| 333 | + FITS file | |
| 334 | + extname : str | |
| 335 | + Extension name | |
| 336 | + name : str | |
| 337 | + Name string | |
| 338 | + doc : str | |
| 339 | + Document string | |
| 340 | + irf : dict | |
| 341 | + IRF metadata dictionary | |
| 342 | + | |
| 343 | + Returns | |
| 344 | + ------- | |
| 345 | + table : `~gammalib.GFitsBinTable` | |
| 346 | + FITS binary table | |
| 324 | 347 | """ |
| 325 | 348 | # Create table if it does not yet exist |
| 326 | 349 | if not fits.contains(extname): |
| ... | ... | @@ -332,7 +355,7 @@ class csroot2caldb(ctools.cscript): |
| 332 | 355 | table.extname(extname) |
| 333 | 356 | |
| 334 | 357 | # Set OGIP keywords |
| 335 | - self._set_ogip_keywords(table, doc, ["RESPONSE", name]) | |
| 358 | + self._set_ogip_keywords(table, doc, ['RESPONSE', name], irf) | |
| 336 | 359 | |
| 337 | 360 | # Append table to FITS file |
| 338 | 361 | fits.append(table) |
| ... | ... | @@ -340,650 +363,593 @@ class csroot2caldb(ctools.cscript): |
| 340 | 363 | # Return FITS table |
| 341 | 364 | return fits.table(extname) |
| 342 | 365 | |
| 343 | - def _set_ogip_keywords(self, hdu, hdudoc, hduclas): | |
| 366 | + def _set_ogip_keywords(self, hdu, hdudoc, hduclas, irf): | |
| 344 | 367 | """ |
| 345 | - Set standard OGIP keywords for extension. | |
| 368 | + Set standard OGIP keywords for extension | |
| 346 | 369 | |
| 347 | - Parameters: | |
| 348 | - hdu: Header Data Unit. | |
| 349 | - hdudoc: Documentation reference string | |
| 350 | - hduclas: Array of HDUCLAS fields | |
| 370 | + Parameters | |
| 371 | + ---------- | |
| 372 | + hdu : `~gammalig.GFitsHDU` | |
| 373 | + Header Data Unit | |
| 374 | + hdudoc : str | |
| 375 | + Documentation reference string | |
| 376 | + hduclas : list of str | |
| 377 | + List of HDUCLAS fields | |
| 378 | + irf : dict | |
| 379 | + IRF dictonary | |
| 351 | 380 | """ |
| 352 | 381 | # Set UTC date of file creation |
| 353 | 382 | utc = datetime.utcnow().isoformat()[:19] |
| 354 | 383 | |
| 355 | 384 | # Set keywords |
| 356 | - hdu.card("ORIGIN", "IRAP", "Name of organization making this file") | |
| 357 | - hdu.card("DATE", utc, "File creation date (YYYY-MM-DDThh:mm:ss UTC)") | |
| 358 | - hdu.card("TELESCOP", self._cal_tel, "Name of telescope") | |
| 359 | - hdu.card("INSTRUME", self._cal_inst, "Name of instrument") | |
| 360 | - hdu.card("DETNAM", self._cal_det, "Name of detector") | |
| 361 | - hdu.card("HDUCLASS", "OGIP", "HDU class") | |
| 362 | - hdu.card("HDUDOC", hdudoc, "HDU documentation") | |
| 385 | + hdu.card('ORIGIN', 'IRAP', 'Name of organization making this file') | |
| 386 | + hdu.card('DATE', utc, 'File creation date (YYYY-MM-DDThh:mm:ss UTC)') | |
| 387 | + hdu.card('TELESCOP', irf['CAL_TEL'], 'Name of telescope') | |
| 388 | + hdu.card('INSTRUME', irf['CAL_INST'], 'Name of instrument') | |
| 389 | + hdu.card('DETNAM', irf['CAL_DET'], 'Name of detector') | |
| 390 | + hdu.card('HDUCLASS', 'OGIP', 'HDU class') | |
| 391 | + hdu.card('HDUDOC', hdudoc, 'HDU documentation') | |
| 363 | 392 | for i, item in enumerate(hduclas): |
| 364 | - key = "HDUCLAS%d" % (i+1) | |
| 365 | - hdu.card(key, item, "HDU class") | |
| 366 | - hdu.card("HDUVERS", "1.0.0", "HDU version") | |
| 393 | + key = 'HDUCLAS%d' % (i+1) | |
| 394 | + hdu.card(key, item, 'HDU class') | |
| 395 | + hdu.card('HDUVERS', '1.0.0', 'HDU version') | |
| 367 | 396 | |
| 368 | 397 | # Return |
| 369 | 398 | return |
| 370 | 399 | |
| 371 | - def _create_cif(self): | |
| 400 | + def _add_cif_info(self, irf, dir): | |
| 372 | 401 | """ |
| 373 | - Create Calibration Index File (CIF) extension in CIF FITS file. | |
| 402 | + Add information to CIF extension | |
| 374 | 403 | |
| 375 | - Parameters: | |
| 376 | - None | |
| 377 | - Keywords: | |
| 378 | - None | |
| 404 | + Parameters | |
| 405 | + ---------- | |
| 406 | + irf : dict | |
| 407 | + IRF metadata dictionary | |
| 408 | + dir : dict | |
| 409 | + Directory structure dictionary | |
| 379 | 410 | """ |
| 380 | - # Attach table to FITS file. Note that at this moment the FITS table | |
| 381 | - # gets connected to the FITS file. Yet since nothing was yet written | |
| 382 | - # to the FITS file, we cannot read anything from it. | |
| 383 | - self._cif.append(calutils.create_cif_table()) | |
| 384 | - | |
| 385 | - # Return | |
| 386 | - return | |
| 411 | + # Set list of IRF component names | |
| 412 | + names = ['EA', 'PSF', 'EDISP', 'BGD'] | |
| 413 | + | |
| 414 | + # Initialise CIF row index | |
| 415 | + row = self._hdu_cif.nrows() | |
| 416 | + | |
| 417 | + # Append rows for all components to CIF extension | |
| 418 | + self._hdu_cif.append_rows(len(names)) | |
| 419 | + | |
| 420 | + # Add information for all components | |
| 421 | + for name in names: | |
| 422 | + | |
| 423 | + # Set dictionary keys for this component | |
| 424 | + key_dir = '%s_DIR' % name | |
| 425 | + key_file = '%s_FILE' % name | |
| 426 | + key_name = '%s_NAME' % name | |
| 427 | + key_desc = '%s_DESC' % name | |
| 428 | + key_bounds = '%s_BOUNDS' % name | |
| 429 | + | |
| 430 | + # Set generic information | |
| 431 | + self._hdu_cif['TELESCOP'][row] = irf['CAL_TEL'] | |
| 432 | + self._hdu_cif['INSTRUME'][row] = irf['CAL_INST'] | |
| 433 | + self._hdu_cif['DETNAM'][row] = irf['CAL_DET'] | |
| 434 | + self._hdu_cif['FILTER'][row] = irf['CAL_FLT'] | |
| 435 | + self._hdu_cif['CAL_DEV'][row] = 'ONLINE' | |
| 436 | + self._hdu_cif['CAL_CLAS'][row] = irf['CAL_CLASS'] | |
| 437 | + self._hdu_cif['CAL_DTYP'][row] = irf['CAL_TYPE'] | |
| 438 | + self._hdu_cif['CAL_VSD'][row] = irf['VAL_DATE'] | |
| 439 | + self._hdu_cif['CAL_VST'][row] = irf['VAL_TIME'] | |
| 440 | + self._hdu_cif['REF_TIME'][row] = irf['REF_TIME'] | |
| 441 | + self._hdu_cif['CAL_QUAL'][row] = irf['CAL_QUAL'] | |
| 442 | + self._hdu_cif['CAL_DATE'][row] = irf['CAL_DATE'] | |
| 443 | + | |
| 444 | + # Set component specific information | |
| 445 | + self._hdu_cif['CAL_DIR'][row] = dir[key_dir] | |
| 446 | + self._hdu_cif['CAL_FILE'][row] = dir[key_file] | |
| 447 | + self._hdu_cif['CAL_CNAM'][row] = irf[key_name] | |
| 448 | + self._hdu_cif['CAL_DESC'][row] = irf[key_desc] | |
| 449 | + self._hdu_cif['CAL_XNO'][row] = 1 | |
| 450 | + for i in range(9): | |
| 451 | + if i >= len(irf[key_bounds]): | |
| 452 | + self._hdu_cif['CAL_CBD'][row,i] = 'NONE' | |
| 453 | + else: | |
| 454 | + self._hdu_cif['CAL_CBD'][row,i] = irf[key_bounds][i] | |
| 387 | 455 | |
| 388 | - def _add_cif_info(self): | |
| 389 | - """ | |
| 390 | - Add information to CIF extension. | |
| 391 | - """ | |
| 392 | - # Append 4 rows to CIF extension | |
| 393 | - self._hdu_cif.append_rows(4) | |
| 394 | - | |
| 395 | - # Add generic information for these 4 rows | |
| 396 | - for i in range(4): | |
| 397 | - | |
| 398 | - # Set row number | |
| 399 | - row = i + self._hdu_cif.nrows() - 4 | |
| 400 | - | |
| 401 | - # Set element | |
| 402 | - self._hdu_cif["TELESCOP"][row] = self._cal_tel | |
| 403 | - self._hdu_cif["INSTRUME"][row] = self._cal_inst | |
| 404 | - self._hdu_cif["DETNAM"][row] = self._cal_det | |
| 405 | - self._hdu_cif["FILTER"][row] = self._cal_flt | |
| 406 | - self._hdu_cif["CAL_DEV"][row] = "ONLINE" | |
| 407 | - self._hdu_cif["CAL_CLAS"][row] = self._cal_class | |
| 408 | - self._hdu_cif["CAL_DTYP"][row] = self._cal_type | |
| 409 | - self._hdu_cif["CAL_VSD"][row] = self._val_date | |
| 410 | - self._hdu_cif["CAL_VST"][row] = self._val_time | |
| 411 | - self._hdu_cif["REF_TIME"][row] = self._ref_time | |
| 412 | - self._hdu_cif["CAL_QUAL"][row] = self._cal_qual | |
| 413 | - self._hdu_cif["CAL_DATE"][row] = self._cal_date | |
| 414 | - | |
| 415 | - # Add effective area information | |
| 416 | - row = self._hdu_cif.nrows() - 4 | |
| 417 | - self._hdu_cif["CAL_DIR"][row] = self._ea_dir | |
| 418 | - self._hdu_cif["CAL_FILE"][row] = self._ea_file | |
| 419 | - self._hdu_cif["CAL_CNAM"][row] = self._ea_name | |
| 420 | - self._hdu_cif["CAL_DESC"][row] = self._ea_desc | |
| 421 | - self._hdu_cif["CAL_XNO"][row] = 1 | |
| 422 | - for n in range(9): | |
| 423 | - if n >= len(self._ea_bounds): | |
| 424 | - self._hdu_cif["CAL_CBD"][row, n] = "NONE" | |
| 425 | - else: | |
| 426 | - self._hdu_cif["CAL_CBD"][row, n] = self._ea_bounds[n] | |
| 427 | - | |
| 428 | - # Add point spread function information | |
| 429 | - row = self._hdu_cif.nrows() - 3 | |
| 430 | - self._hdu_cif["CAL_DIR"][row] = self._psf_dir | |
| 431 | - self._hdu_cif["CAL_FILE"][row] = self._psf_file | |
| 432 | - self._hdu_cif["CAL_CNAM"][row] = self._psf_name | |
| 433 | - self._hdu_cif["CAL_DESC"][row] = self._psf_desc | |
| 434 | - self._hdu_cif["CAL_XNO"][row] = 1 | |
| 435 | - for n in range(9): | |
| 436 | - if n >= len(self._psf_bounds): | |
| 437 | - self._hdu_cif["CAL_CBD"][row, n] = "NONE" | |
| 438 | - else: | |
| 439 | - self._hdu_cif["CAL_CBD"][row, n] = self._psf_bounds[n] | |
| 440 | - | |
| 441 | - # Add energy dispersion information | |
| 442 | - row = self._hdu_cif.nrows() - 2 | |
| 443 | - self._hdu_cif["CAL_DIR"][row] = self._edisp_dir | |
| 444 | - self._hdu_cif["CAL_FILE"][row] = self._edisp_file | |
| 445 | - self._hdu_cif["CAL_CNAM"][row] = self._edisp_name | |
| 446 | - self._hdu_cif["CAL_DESC"][row] = self._edisp_desc | |
| 447 | - self._hdu_cif["CAL_XNO"][row] = 1 | |
| 448 | - for n in range(9): | |
| 449 | - if n >= len(self._edisp_bounds): | |
| 450 | - self._hdu_cif["CAL_CBD"][row, n] = "NONE" | |
| 451 | - else: | |
| 452 | - self._hdu_cif["CAL_CBD"][row, n] = self._edisp_bounds[n] | |
| 453 | - | |
| 454 | - # Add background information | |
| 455 | - row = self._hdu_cif.nrows() - 1 | |
| 456 | - self._hdu_cif["CAL_DIR"][row] = self._bgd_dir | |
| 457 | - self._hdu_cif["CAL_FILE"][row] = self._bgd_file | |
| 458 | - self._hdu_cif["CAL_CNAM"][row] = self._bgd_name | |
| 459 | - self._hdu_cif["CAL_DESC"][row] = self._bgd_desc | |
| 460 | - self._hdu_cif["CAL_XNO"][row] = 1 | |
| 461 | - for n in range(9): | |
| 462 | - if n >= len(self._bgd_bounds): | |
| 463 | - self._hdu_cif["CAL_CBD"][row, n] = "NONE" | |
| 464 | - else: | |
| 465 | - self._hdu_cif["CAL_CBD"][row, n] = self._bgd_bounds[n] | |
| 456 | + # Increment row index | |
| 457 | + row += 1 | |
| 466 | 458 | |
| 467 | 459 | # Return |
| 468 | 460 | return |
| 469 | 461 | |
| 470 | - def _set_cif_keywords(self, hdu, name, bounds, desc): | |
| 462 | + def _set_cif_keywords(self, hdu, name, bounds, desc, irf): | |
| 471 | 463 | """ |
| 472 | - Set standard CIF keywords for extension. | |
| 464 | + Set standard CIF keywords for extension | |
| 465 | + | |
| 466 | + Parameters | |
| 467 | + ---------- | |
| 468 | + hdu : `~gammalib.GFitsHDU` | |
| 469 | + FITS HDU | |
| 470 | + name : str | |
| 471 | + Calibration name | |
| 472 | + bounds : list of str | |
| 473 | + Calibration boundaries | |
| 474 | + desc : str | |
| 475 | + Calibration description | |
| 476 | + irf : dict | |
| 477 | + IRF dictionary | |
| 473 | 478 | """ |
| 474 | 479 | # Set standard CIF keywords |
| 475 | - hdu.card("CSYSNAME", "XMA_POL", "") | |
| 476 | - hdu.card("CCLS0001", self._cal_class, "Calibration class") | |
| 477 | - hdu.card("CDTP0001", self._cal_type, "Calibration type") | |
| 478 | - hdu.card("CCNM0001", name, "Calibration name") | |
| 480 | + hdu.card('CSYSNAME', 'XMA_POL', '') | |
| 481 | + hdu.card('CCLS0001', irf['CAL_CLASS'], 'Calibration class') | |
| 482 | + hdu.card('CDTP0001', irf['CAL_TYPE'], 'Calibration type') | |
| 483 | + hdu.card('CCNM0001', name, 'Calibration name') | |
| 479 | 484 | |
| 480 | 485 | # Set boundary keywords |
| 481 | - for n in range(9): | |
| 482 | - keyname = "CBD%d0001" % (n+1) | |
| 483 | - if n >= len(bounds): | |
| 484 | - value = "NONE" | |
| 486 | + for i in range(9): | |
| 487 | + keyname = 'CBD%d0001' % (i+1) | |
| 488 | + if i >= len(bounds): | |
| 489 | + value = 'NONE' | |
| 485 | 490 | else: |
| 486 | - value = bounds[n] | |
| 487 | - hdu.card(keyname, value, "Calibration boundary") | |
| 491 | + value = bounds[i] | |
| 492 | + hdu.card(keyname, value, 'Calibration boundary') | |
| 488 | 493 | |
| 489 | 494 | # Set validity keywords |
| 490 | - hdu.card("CVSD0001", self._val_date, "Calibration validity start date (UTC)") | |
| 491 | - hdu.card("CVST0001", self._val_time, "Calibration validity start time (UTC)") | |
| 492 | - hdu.card("CDEC0001", desc, "Calibration description") | |
| 495 | + hdu.card('CVSD0001', irf['VAL_DATE'], | |
| 496 | + 'Calibration validity start date (UTC)') | |
| 497 | + hdu.card('CVST0001', irf['VAL_TIME'], | |
| 498 | + 'Calibration validity start time (UTC)') | |
| 499 | + hdu.card('CDEC0001', desc, 'Calibration description') | |
| 493 | 500 | |
| 494 | 501 | # Return |
| 495 | 502 | return |
| 496 | 503 | |
| 497 | 504 | |
| 498 | 505 | # ROOT specific private members |
| 499 | - def _root2caldb(self): | |
| 506 | + def _root2caldb(self, irf): | |
| 500 | 507 | """ |
| 501 | - Translate ROOT to CALDB information. | |
| 508 | + Translate ROOT to CALDB information | |
| 502 | 509 | |
| 503 | - Parameters: | |
| 504 | - filename - ROOT 2D performance filename. | |
| 510 | + Parameters | |
| 511 | + ---------- | |
| 512 | + irf : dict | |
| 513 | + IRF dictionary | |
| 505 | 514 | """ |
| 506 | 515 | # Open ROOT performance file |
| 507 | - file = TFile(self["infile"].filename().url()) | |
| 516 | + file = TFile(self['infile'].filename().url()) | |
| 508 | 517 | |
| 509 | 518 | # Create effective area |
| 510 | - self._root2ea(file, rebin=self["rebin"].boolean(), | |
| 511 | - eascale=self["eascale"].real()) | |
| 519 | + self._root2ea(file, irf) | |
| 512 | 520 | |
| 513 | 521 | # Create point spread function |
| 514 | - self._root2psf(file, self["psftype"].string()) | |
| 522 | + self._root2psf(file, irf) | |
| 515 | 523 | |
| 516 | 524 | # Create energy dispersion |
| 517 | - self._root2edisp(file) | |
| 525 | + self._root2edisp(file, irf) | |
| 518 | 526 | |
| 519 | 527 | # Create background |
| 520 | - #self._root2bgd(file) | |
| 521 | - self._root2bgd3D(file) | |
| 528 | + self._root2bgd(file, irf) | |
| 522 | 529 | |
| 523 | 530 | # Return |
| 524 | 531 | return |
| 525 | 532 | |
| 526 | - def _root2ea(self, file, rebin=False, eascale=1.0): | |
| 533 | + def _root2ea(self, file, irf): | |
| 527 | 534 | """ |
| 528 | - Translate ROOT to CALDB effective area extension. The following ROOT | |
| 529 | - histograms are used: | |
| 530 | - | |
| 531 | - EffectiveAreaEtrue_offaxis -> EFFAREA | |
| 532 | - EffectiveArea_offaxis -> EFFAREA_RECO | |
| 533 | - | |
| 534 | - Parameters: | |
| 535 | - file: ROOT file. | |
| 535 | + Translate ROOT to CALDB effective area extension | |
| 536 | + | |
| 537 | + The following ROOT histograms are used: | |
| 538 | + - EffectiveAreaEtrue_offaxis -> EFFAREA | |
| 539 | + - EffectiveArea_offaxis -> EFFAREA_RECO | |
| 536 | 540 | |
| 537 | - Keywords: | |
| 538 | - rebin: Rebin Etrue histogram (useful for Prod1 IFAE runs) | |
| 539 | - eascale: Effective area scaling factor | |
| 541 | + Parameters | |
| 542 | + ---------- | |
| 543 | + file : `~ROOT.TFile` | |
| 544 | + ROOT file | |
| 545 | + irf : dict | |
| 546 | + IRF metadata dictionary | |
| 540 | 547 | """ |
| 541 | - # Continue only if effective area HDU has been opened | |
| 542 | - if self._hdu_ea != None: | |
| 548 | + # Write header | |
| 549 | + if self._logTerse(): | |
| 550 | + self._log('\n') | |
| 551 | + self._log.header1('Generate effective area extension') | |
| 552 | + | |
| 553 | + # Get relevant ROOT histograms | |
| 554 | + etrue = file.Get('EffectiveAreaEtrue_offaxis') | |
| 555 | + ereco = file.Get('EffectiveArea_offaxis') | |
| 556 | + | |
| 557 | + # If requested then normalize the 2D histogram on the on-axis 1D | |
| 558 | + # histogram. This assures that the 2D histogram has the same on-axis | |
| 559 | + # effective area dependence as the 1D histogram. | |
| 560 | + if self['norm1d'].boolean(): | |
| 561 | + etrue_1D = file.Get('EffectiveAreaEtrue') | |
| 562 | + ereco_1D = file.Get('EffectiveArea') | |
| 563 | + self._renorm_onaxis(etrue, etrue_1D) | |
| 564 | + self._renorm_onaxis(ereco, ereco_1D) | |
| 565 | + | |
| 566 | + # If requested then rebin the effective area Etrue histogram. This | |
| 567 | + # increases the number of bins by a factor 10. | |
| 568 | + if self['rebin'].boolean(): | |
| 569 | + etrue.RebinX(10) | |
| 570 | + neng = etrue.GetXaxis().GetNbins() | |
| 571 | + noffset = etrue.GetYaxis().GetNbins() | |
| 572 | + for ioff in range(noffset): | |
| 573 | + for ieng in range(neng): | |
| 574 | + value = etrue.GetBinContent(ieng+1,ioff+1) / 10.0 | |
| 575 | + etrue.SetBinContent(ieng+1,ioff+1,value) | |
| 543 | 576 | |
| 544 | - # Write header | |
| 545 | - if self._logTerse(): | |
| 546 | - self._log('\n') | |
| 547 | - self._log.header1('Generate effective area extension') | |
| 548 | - | |
| 549 | - # Get User parameters | |
| 550 | - norm1d = self['norm1d'].boolean() | |
| 551 | - | |
| 552 | - # Allocate ROOT 2D arrays | |
| 553 | - etrue = TH2F() | |
| 554 | - ereco = TH2F() | |
| 555 | - file.GetObject('EffectiveAreaEtrue_offaxis', etrue) | |
| 556 | - file.GetObject('EffectiveArea_offaxis', ereco) | |
| 557 | - | |
| 558 | - # Normalize 2D histogram on on-axis 1D histogram | |
| 559 | - if norm1d: | |
| 560 | - etrue_1D = TH1F() | |
| 561 | - ereco_1D = TH1F() | |
| 562 | - file.GetObject('EffectiveAreaEtrue', etrue_1D) | |
| 563 | - file.GetObject('EffectiveArea', ereco_1D) | |
| 564 | - self._renorm_onaxis(etrue, etrue_1D) | |
| 565 | - self._renorm_onaxis(ereco, ereco_1D) | |
| 566 | - | |
| 567 | - # Rebin etrue histogram | |
| 568 | - if rebin: | |
| 569 | - etrue.RebinX(10) | |
| 570 | - neng = etrue.GetXaxis().GetNbins() | |
| 571 | - noffset = etrue.GetYaxis().GetNbins() | |
| 572 | - for ioff in range(noffset): | |
| 573 | - for ieng in range(neng): | |
| 574 | - value = etrue.GetBinContent(ieng+1,ioff+1) / 10.0 | |
| 575 | - etrue.SetBinContent(ieng+1,ioff+1,value) | |
| 577 | + # Get effective area multiplicator. This allows renormalising the | |
| 578 | + # effective area. | |
| 579 | + eascale = self['eascale'].real() | |
| 576 | 580 | |
| 577 | - # Scale histograms (if needed) | |
| 578 | - if eascale != 1.0: | |
| 579 | - neng = etrue.GetXaxis().GetNbins() | |
| 580 | - noffset = etrue.GetYaxis().GetNbins() | |
| 581 | - for ioff in range(noffset): | |
| 582 | - for ieng in range(neng): | |
| 583 | - value = etrue.GetBinContent(ieng+1,ioff+1) * eascale | |
| 584 | - etrue.SetBinContent(ieng+1,ioff+1,value) | |
| 585 | - neng = ereco.GetXaxis().GetNbins() | |
| 586 | - noffset = ereco.GetYaxis().GetNbins() | |
| 587 | - for ioff in range(noffset): | |
| 588 | - for ieng in range(neng): | |
| 589 | - value = ereco.GetBinContent(ieng+1,ioff+1) * eascale | |
| 590 | - ereco.SetBinContent(ieng+1,ioff+1,value) | |
| 581 | + # If renormalisation has been requested then do it now | |
| 582 | + if eascale != 1.0: | |
| 583 | + neng = etrue.GetXaxis().GetNbins() | |
| 584 | + noffset = etrue.GetYaxis().GetNbins() | |
| 585 | + for ioff in range(noffset): | |
| 586 | + for ieng in range(neng): | |
| 587 | + value = etrue.GetBinContent(ieng+1,ioff+1) * eascale | |
| 588 | + etrue.SetBinContent(ieng+1,ioff+1,value) | |
| 589 | + neng = ereco.GetXaxis().GetNbins() | |
| 590 | + noffset = ereco.GetYaxis().GetNbins() | |
| 591 | + for ioff in range(noffset): | |
| 592 | + for ieng in range(neng): | |
| 593 | + value = ereco.GetBinContent(ieng+1,ioff+1) * eascale | |
| 594 | + ereco.SetBinContent(ieng+1,ioff+1,value) | |
| 595 | + | |
| 596 | + # Set boundaries (use Ereco boundaries) | |
| 597 | + bounds = self._make_2D(ereco, self._hdu_ea, None, 'm2') | |
| 598 | + for b in bounds: | |
| 599 | + irf['EA_BOUNDS'].append(b) | |
| 591 | 600 | |
| 592 | - # Write boundaries (use Ereco boundaries) | |
| 593 | - bounds = self._make_2D(ereco, self._hdu_ea, None, "m2") | |
| 594 | - for b in bounds: | |
| 595 | - self._ea_bounds.append(b) | |
| 596 | - self._set_cif_keywords(self._hdu_ea, self._ea_name, \ | |
| 597 | - self._ea_bounds, self._ea_desc) | |
| 601 | + # Write boundary keywords | |
| 602 | + self._set_cif_keywords(self._hdu_ea, irf['EA_NAME'], | |
| 603 | + irf['EA_BOUNDS'], irf['EA_DESC'], irf) | |
| 598 | 604 | |
| 599 | - # EFFAREA | |
| 600 | - self._make_2D(etrue, self._hdu_ea, "EFFAREA", "m2") | |
| 605 | + # Create "EFFAREA" data column | |
| 606 | + self._make_2D(etrue, self._hdu_ea, 'EFFAREA', 'm2') | |
| 601 | 607 | |
| 602 | - # EFFAREA_RECO | |
| 603 | - self._make_2D(ereco, self._hdu_ea, "EFFAREA_RECO", "m2") | |
| 608 | + # Create "EFFAREA_RECO" data column | |
| 609 | + self._make_2D(ereco, self._hdu_ea, 'EFFAREA_RECO', 'm2') | |
| 604 | 610 | |
| 605 | 611 | # Return |
| 606 | 612 | return |
| 607 | 613 | |
| 608 | - def _root2psf(self, file, psftype): | |
| 614 | + def _root2psf(self, file, irf): | |
| 609 | 615 | """ |
| 610 | - Translate ROOT to CALDB point spread function extension. | |
| 611 | - Parameters: | |
| 612 | - file - ROOT file. | |
| 613 | - psftype - PSF type (Gauss, King) | |
| 614 | - Keywords: | |
| 615 | - None | |
| 616 | + Translate ROOT to CALDB point spread function extension | |
| 617 | + | |
| 618 | + Parameters | |
| 619 | + ---------- | |
| 620 | + file : `~ROOT.TFile` | |
| 621 | + ROOT file | |
| 622 | + irf : dict | |
| 623 | + IRF metadata dictionary | |
| 616 | 624 | """ |
| 617 | - # Continue only if point spread function HDU has been opened | |
| 618 | - if self._hdu_psf != None: | |
| 625 | + # Write header | |
| 626 | + if self._logTerse(): | |
| 627 | + self._log('\n') | |
| 628 | + self._log.header1('Generate point spread function extension') | |
| 619 | 629 | |
| 620 | - # Write header | |
| 621 | - if self._logTerse(): | |
| 622 | - self._log('\n') | |
| 623 | - self._log.header1('Generate point spread function extension') | |
| 630 | + # King profile PSF | |
| 631 | + if self['psftype'].string() == 'King': | |
| 632 | + self._root2psf_king(file, irf) | |
| 624 | 633 | |
| 625 | - # King profile PSF | |
| 626 | - if psftype == 'King': | |
| 627 | - self._root2psf_king(file) | |
| 628 | - else: | |
| 629 | - self._root2psf_gauss(file) | |
| 634 | + # ... otherwise use Gaussian profile PSF | |
| 635 | + else: | |
| 636 | + self._root2psf_gauss(file, irf) | |
| 630 | 637 | |
| 631 | 638 | # Return |
| 632 | 639 | return |
| 633 | 640 | |
| 634 | - def _root2psf_gauss(self, file): | |
| 641 | + def _root2psf_gauss(self, file, irf): | |
| 635 | 642 | """ |
| 636 | - Translate ROOT to CALDB point spread function extension. The following | |
| 637 | - ROOT histograms are used: | |
| 638 | - | |
| 639 | - 1/(2*pi*SIGMA_1) -> SCALE | |
| 640 | - AngRes_offaxis -> SIGMA_1 (scaling: 1/0.8) | |
| 641 | - 0.0 -> AMPL_2 | |
| 642 | - 0.0 -> SIGMA_2 | |
| 643 | - 0.0 -> AMPL_3 | |
| 644 | - 0.0 -> SIGMA_3 | |
| 645 | - | |
| 646 | - Parameters: | |
| 647 | - file - ROOT file. | |
| 648 | - Keywords: | |
| 649 | - None | |
| 643 | + Translate ROOT to CALDB point spread function extension | |
| 644 | + | |
| 645 | + The following ROOT histograms are used: | |
| 646 | + - 1/(2*pi*SIGMA_1) -> SCALE | |
| 647 | + - AngRes_offaxis -> SIGMA_1 (scaling: 1/0.8) | |
| 648 | + - 0.0 -> AMPL_2 | |
| 649 | + - 0.0 -> SIGMA_2 | |
| 650 | + - 0.0 -> AMPL_3 | |
| 651 | + - 0.0 -> SIGMA_3 | |
| 652 | + | |
| 653 | + Parameters | |
| 654 | + ---------- | |
| 655 | + file : `~ROOT.TFile` | |
| 656 | + ROOT file | |
| 657 | + irf : dict | |
| 658 | + IRF metadata dictionary | |
| 650 | 659 | """ |
| 651 | - # Continue only if point spread function HDU has been opened | |
| 652 | - if self._hdu_psf != None: | |
| 660 | + # Get relevant ROOT histograms | |
| 661 | + r68 = file.Get('AngRes_offaxis') | |
| 653 | 662 | |
| 654 | - # Allocate ROOT 2D array | |
| 655 | - r68 = TH2F() | |
| 663 | + # Extract number of bins in histogram | |
| 664 | + neng = r68.GetXaxis().GetNbins() | |
| 665 | + noffset = r68.GetYaxis().GetNbins() | |
| 656 | 666 | |
| 657 | - # Read 68% containment histogram | |
| 658 | - file.GetObject("AngRes_offaxis", r68) | |
| 659 | - neng = r68.GetXaxis().GetNbins() | |
| 660 | - noffset = r68.GetYaxis().GetNbins() | |
| 667 | + # Converts 68% -> 1 sigma | |
| 668 | + r68_to_sigma = 0.6624305 | |
| 669 | + for ioff in range(noffset): | |
| 670 | + for ieng in range(neng): | |
| 671 | + sigma = r68.GetBinContent(ieng+1,ioff+1) * r68_to_sigma | |
| 672 | + r68.SetBinContent(ieng+1,ioff+1,sigma) | |
| 661 | 673 | |
| 662 | - # Converts 68% -> 1 sigma | |
| 663 | - r68_to_sigma = 0.6624305 | |
| 664 | - for ioff in range(noffset): | |
| 665 | - for ieng in range(neng): | |
| 666 | - sigma = r68.GetBinContent(ieng+1,ioff+1) * r68_to_sigma | |
| 667 | - r68.SetBinContent(ieng+1,ioff+1,sigma) | |
| 674 | + # Compute scale histogram | |
| 675 | + scale = r68.Clone() | |
| 676 | + for ioff in range(noffset): | |
| 677 | + for ieng in range(neng): | |
| 678 | + integral = 2.0 * math.pi * r68.GetBinContent(ieng+1,ioff+1) | |
| 679 | + if integral > 0.0: | |
| 680 | + value = 1.0 / integral | |
| 681 | + else: | |
| 682 | + value = 0.0 | |
| 683 | + scale.SetBinContent(ieng+1,ioff+1,value) | |
| 668 | 684 | |
| 669 | - # Compute scale histogram | |
| 670 | - scale = r68.Clone() | |
| 671 | - for ioff in range(noffset): | |
| 672 | - for ieng in range(neng): | |
| 673 | - integral = 2.0 * math.pi * r68.GetBinContent(ieng+1,ioff+1) | |
| 674 | - if integral > 0.0: | |
| 675 | - value = 1.0 / integral | |
| 676 | - else: | |
| 677 | - value = 0.0 | |
| 678 | - scale.SetBinContent(ieng+1,ioff+1,value) | |
| 685 | + # Set zero histogram | |
| 686 | + zero = r68.Clone() | |
| 687 | + for ioff in range(noffset): | |
| 688 | + for ieng in range(neng): | |
| 689 | + zero.SetBinContent(ieng+1,ioff+1,0.0) | |
| 679 | 690 | |
| 680 | - # Set zero histogram | |
| 681 | - zero = r68.Clone() | |
| 682 | - for ioff in range(noffset): | |
| 683 | - for ieng in range(neng): | |
| 684 | - zero.SetBinContent(ieng+1,ioff+1,0.0) | |
| 691 | + # Set boundaries | |
| 692 | + bounds = self._make_2D(r68, self._hdu_psf, None, 'deg') | |
| 693 | + for b in bounds: | |
| 694 | + irf['PSF_BOUNDS'].append(b) | |
| 695 | + irf['PSF_BOUNDS'].append('PSF(GAUSS)') | |
| 685 | 696 | |
| 686 | - # Set boundaries | |
| 687 | - bounds = self._make_2D(r68, self._hdu_psf, None, "deg") | |
| 688 | - for b in bounds: | |
| 689 | - self._psf_bounds.append(b) | |
| 690 | - self._psf_bounds.append("PSF(GAUSS)") | |
| 691 | - self._set_cif_keywords(self._hdu_psf, self._psf_name, \ | |
| 692 | - self._psf_bounds, self._psf_desc) | |
| 697 | + # Write boundary keywords | |
| 698 | + self._set_cif_keywords(self._hdu_psf, irf['PSF_NAME'], | |
| 699 | + irf['PSF_BOUNDS'], irf['PSF_DESC'], irf) | |
| 693 | 700 | |
| 694 | - # SCALE | |
| 695 | - self._make_2D(scale, self._hdu_psf, "SCALE", "") | |
| 701 | + # Create "SCALE" data column | |
| 702 | + self._make_2D(scale, self._hdu_psf, 'SCALE', '') | |
| 696 | 703 | |
| 697 | - # SIGMA_1 | |
| 698 | - self._make_2D(r68, self._hdu_psf, "SIGMA_1", "deg") | |
| 704 | + # Create "SIGMA_1" data column | |
| 705 | + self._make_2D(r68, self._hdu_psf, 'SIGMA_1', 'deg') | |
| 699 | 706 | |
| 700 | - # AMPL_2 | |
| 701 | - self._make_2D(zero, self._hdu_psf, "AMPL_2", "") | |
| 707 | + # Create "AMPL_2" data column | |
| 708 | + self._make_2D(zero, self._hdu_psf, 'AMPL_2', '') | |
| 702 | 709 | |
| 703 | - # SIGMA_2 | |
| 704 | - self._make_2D(zero, self._hdu_psf, "SIGMA_2", "deg") | |
| 710 | + # Create "SIGMA_2" data column | |
| 711 | + self._make_2D(zero, self._hdu_psf, 'SIGMA_2', 'deg') | |
| 705 | 712 | |
| 706 | - # AMPL_3 | |
| 707 | - self._make_2D(zero, self._hdu_psf, "AMPL_3", "") | |
| 713 | + # Create "AMPL_3" data column | |
| 714 | + self._make_2D(zero, self._hdu_psf, 'AMPL_3', '') | |
| 708 | 715 | |
| 709 | - # SIGMA_3 | |
| 710 | - self._make_2D(zero, self._hdu_psf, "SIGMA_3", "deg") | |
| 716 | + # Create "SIGMA_3" data column | |
| 717 | + self._make_2D(zero, self._hdu_psf, 'SIGMA_3', 'deg') | |
| 711 | 718 | |
| 712 | 719 | # Return |
| 713 | 720 | return |
| 714 | 721 | |
| 715 | - def _root2psf_king(self, file): | |
| 722 | + def _root2psf_king(self, file, irf): | |
| 716 | 723 | """ |
| 717 | - Translate ROOT to CALDB point spread function extension. The following | |
| 718 | - ROOT histograms are used: | |
| 719 | - | |
| 720 | - AngRes_offaxis | |
| 721 | - AngRes80_offaxis | |
| 724 | + Translate ROOT to CALDB point spread function extension | |
| 725 | + | |
| 726 | + The following ROOT histograms are used: | |
| 727 | + - AngRes_offaxis | |
| 728 | + - AngRes80_offaxis | |
| 722 | 729 | |
| 723 | - Parameters: | |
| 724 | - file - ROOT file. | |
| 725 | - Keywords: | |
| 726 | - None | |
| 730 | + Parameters | |
| 731 | + ---------- | |
| 732 | + file : `~ROOT.TFile` | |
| 733 | + ROOT file | |
| 734 | + irf : dict | |
| 735 | + IRF metadata dictionary | |
| 727 | 736 | """ |
| 728 | - # Continue only if point spread function HDU has been opened | |
| 729 | - if self._hdu_psf != None: | |
| 730 | - | |
| 731 | - # Allocate ROOT 2D arrays | |
| 732 | - r68 = TH2F() | |
| 733 | - r80 = TH2F() | |
| 737 | + # Get relevant ROOT histograms | |
| 738 | + r68 = file.Get('AngRes_offaxis') | |
| 739 | + r80 = file.Get('AngRes80_offaxis') | |
| 734 | 740 | |
| 735 | - # Read 68% and 80% containment histograms | |
| 736 | - file.GetObject("AngRes_offaxis", r68) | |
| 737 | - file.GetObject("AngRes80_offaxis", r80) | |
| 738 | - neng = r68.GetXaxis().GetNbins() | |
| 739 | - noffset = r68.GetYaxis().GetNbins() | |
| 741 | + # Extract number of bins in histogram | |
| 742 | + neng = r68.GetXaxis().GetNbins() | |
| 743 | + noffset = r68.GetYaxis().GetNbins() | |
| 740 | 744 | |
| 741 | - # Initialise parameter maps by cloning the r68 2D map | |
| 742 | - gamma2D = r68.Clone() | |
| 743 | - sigma2D = r68.Clone() | |
| 745 | + # Initialise parameter maps by cloning the r68 2D map | |
| 746 | + gamma2D = r68.Clone() | |
| 747 | + sigma2D = r68.Clone() | |
| 744 | 748 | |
| 745 | - # Compute gamma and sigma values | |
| 746 | - for ioff in range(noffset): | |
| 749 | + # Compute gamma and sigma values | |
| 750 | + for ioff in range(noffset): | |
| 747 | 751 | |
| 748 | - # Initialise last results | |
| 749 | - last_gamma = 0.0 | |
| 750 | - last_sigma = 0.0 | |
| 752 | + # Initialise last results | |
| 753 | + last_gamma = 0.0 | |
| 754 | + last_sigma = 0.0 | |
| 751 | 755 | |
| 752 | - for ieng in range(neng): | |
| 756 | + # Loop over all energies | |
| 757 | + for ieng in range(neng): | |
| 753 | 758 | |
| 754 | - # Extract radii | |
| 755 | - r_68 = r68.GetBinContent(ieng+1,ioff+1) | |
| 756 | - r_80 = r80.GetBinContent(ieng+1,ioff+1) | |
| 757 | - | |
| 758 | - # Initialise results | |
| 759 | - gamma = 0.0 | |
| 760 | - sigma = 0.0 | |
| 761 | - | |
| 762 | - # Continue only if both radii are positive | |
| 763 | - if r_68 > 0 and r_80 > 0: | |
| 764 | - | |
| 765 | - # Derive constants for equation to solve | |
| 766 | - a = 1.0 - 0.68 | |
| 767 | - b = 1.0 - 0.80 | |
| 768 | - c = r_68*r_68/(r_80*r_80) | |
| 769 | - | |
| 770 | - # Solve equation (a^x-1)/(b^x-1)=c for x using secant | |
| 771 | - # method. Stop when we are better than 1e-6. | |
| 772 | - x1 = -0.5 | |
| 773 | - x2 = -1.0 | |
| 774 | - f1 = (math.pow(a,x1) - 1.0)/(math.pow(b,x1) - 1.0) - c | |
| 775 | - f2 = (math.pow(a,x2) - 1.0)/(math.pow(b,x2) - 1.0) - c | |
| 776 | - iter = 0 | |
| 777 | - while True: | |
| 778 | - x = x1 - f1 * (x1-x2)/(f1-f2) | |
| 779 | - f = (math.pow(a,x) - 1.0)/(math.pow(b,x) - 1.0) - c | |
| 780 | - iter += 1 | |
| 781 | - if abs(f) < 1.0e-6: | |
| 782 | - break | |
| 783 | - else: | |
| 784 | - f2 = f1 | |
| 785 | - x2 = x1 | |
| 786 | - f1 = f | |
| 787 | - x1 = x | |
| 788 | - | |
| 789 | - # Compute gamma. | |
| 790 | - if x < 0.0: | |
| 791 | - gamma = 1.0 - 1.0/x | |
| 759 | + # Extract radii | |
| 760 | + r_68 = r68.GetBinContent(ieng+1,ioff+1) | |
| 761 | + r_80 = r80.GetBinContent(ieng+1,ioff+1) | |
| 762 | + | |
| 763 | + # Initialise results | |
| 764 | + gamma = 0.0 | |
| 765 | + sigma = 0.0 | |
| 766 | + | |
| 767 | + # Continue only if both radii are positive | |
| 768 | + if r_68 > 0 and r_80 > 0: | |
| 769 | + | |
| 770 | + # Derive constants for equation to solve | |
| 771 | + a = 1.0 - 0.68 | |
| 772 | + b = 1.0 - 0.80 | |
| 773 | + c = r_68*r_68/(r_80*r_80) | |
| 774 | + | |
| 775 | + # Solve equation (a^x-1)/(b^x-1)=c for x using secant | |
| 776 | + # method. Stop when we are better than 1e-6. | |
| 777 | + x1 = -0.5 | |
| 778 | + x2 = -1.0 | |
| 779 | + f1 = (math.pow(a,x1) - 1.0)/(math.pow(b,x1) - 1.0) - c | |
| 780 | + f2 = (math.pow(a,x2) - 1.0)/(math.pow(b,x2) - 1.0) - c | |
| 781 | + iter = 0 | |
| 782 | + while True: | |
| 783 | + x = x1 - f1 * (x1-x2)/(f1-f2) | |
| 784 | + f = (math.pow(a,x) - 1.0)/(math.pow(b,x) - 1.0) - c | |
| 785 | + iter += 1 | |
| 786 | + if abs(f) < 1.0e-6: | |
| 787 | + break | |
| 792 | 788 | else: |
| 793 | - gamma = 1.0 | |
| 789 | + f2 = f1 | |
| 790 | + x2 = x1 | |
| 791 | + f1 = f | |
| 792 | + x1 = x | |
| 793 | + | |
| 794 | + # Compute gamma. | |
| 795 | + if x < 0.0: | |
| 796 | + gamma = 1.0 - 1.0/x | |
| 797 | + else: | |
| 798 | + gamma = 1.0 | |
| 794 | 799 | |
| 795 | - # Compute sigma | |
| 796 | - denominator = 2.0 * gamma * (math.pow(a, x) - 1.0) | |
| 800 | + # Compute sigma | |
| 801 | + denominator = 2.0 * gamma * (math.pow(a, x) - 1.0) | |
| 802 | + if denominator > 0.0: | |
| 803 | + sigma = r_68 * math.sqrt(1.0/denominator) | |
| 804 | + else: | |
| 805 | + denominator = 2.0 * gamma * (math.pow(b, x) - 1.0) | |
| 797 | 806 | if denominator > 0.0: |
| 798 | - sigma = r_68 * math.sqrt(1.0/denominator) | |
| 807 | + sigma = r_80 * math.sqrt(1.0/denominator) | |
| 799 | 808 | else: |
| 800 | - denominator = 2.0 * gamma * (math.pow(b, x) - 1.0) | |
| 801 | - if denominator > 0.0: | |
| 802 | - sigma = r_80 * math.sqrt(1.0/denominator) | |
| 803 | - else: | |
| 804 | - gamma = 0.0 | |
| 805 | - sigma = 0.0 | |
| 806 | - | |
| 807 | - # Handle special case that no results were found. | |
| 808 | - # This takes care of pixels that are ill defined | |
| 809 | - # in the MC file. | |
| 810 | - if gamma == 0.0 and sigma == 0.0: | |
| 811 | - gamma = last_gamma | |
| 812 | - sigma = last_sigma | |
| 813 | - | |
| 814 | - # Store surrent result as last result | |
| 815 | - last_gamma = gamma | |
| 816 | - last_sigma = sigma | |
| 817 | - | |
| 818 | - # Show results on console | |
| 819 | - #print(ioff,ieng,gamma,sigma,x,f,iter) | |
| 820 | - | |
| 821 | - # Set bin contents | |
| 822 | - gamma2D.SetBinContent(ieng+1,ioff+1,gamma) | |
| 823 | - sigma2D.SetBinContent(ieng+1,ioff+1,sigma) | |
| 824 | - | |
| 825 | - # Set boundaries | |
| 826 | - bounds = self._make_2D(r68, self._hdu_psf, None, "deg") | |
| 827 | - for b in bounds: | |
| 828 | - self._psf_bounds.append(b) | |
| 829 | - self._psf_bounds.append("PSF(KING)") | |
| 830 | - self._set_cif_keywords(self._hdu_psf, self._psf_name, \ | |
| 831 | - self._psf_bounds, self._psf_desc) | |
| 832 | - | |
| 833 | - # GAMMA | |
| 834 | - self._make_2D(gamma2D, self._hdu_psf, "GAMMA", "") | |
| 835 | - | |
| 836 | - # SIGMA | |
| 837 | - self._make_2D(sigma2D, self._hdu_psf, "SIGMA", "deg") | |
| 809 | + gamma = 0.0 | |
| 810 | + sigma = 0.0 | |
| 838 | 811 | |
| 839 | - # Return | |
| 840 | - return | |
| 812 | + # Handle special case that no results were found. | |
| 813 | + # This takes care of pixels that are ill defined | |
| 814 | + # in the MC file. | |
| 815 | + if gamma == 0.0 and sigma == 0.0: | |
| 816 | + gamma = last_gamma | |
| 817 | + sigma = last_sigma | |
| 841 | 818 | |
| 842 | - def _root2edisp(self, file): | |
| 843 | - """ | |
| 844 | - Translate ROOT to CALDB energy dispersion extension. The following ROOT | |
| 845 | - histograms are used: | |
| 819 | + # Store surrent result as last result | |
| 820 | + last_gamma = gamma | |
| 821 | + last_sigma = sigma | |
| 846 | 822 | |
| 847 | - EestOverEtrue_offaxis -> MATRIX | |
| 823 | + # Show results on console | |
| 824 | + #print(ioff,ieng,gamma,sigma,x,f,iter) | |
| 848 | 825 | |
| 849 | - Parameters: | |
| 850 | - file - ROOT file. | |
| 851 | - Keywords: | |
| 852 | - None | |
| 853 | - """ | |
| 854 | - # Continue only if energy dispersion HDU has been opened | |
| 855 | - if self._hdu_edisp != None: | |
| 826 | + # Set bin contents | |
| 827 | + gamma2D.SetBinContent(ieng+1,ioff+1,gamma) | |
| 828 | + sigma2D.SetBinContent(ieng+1,ioff+1,sigma) | |
| 856 | 829 | |
| 857 | - # Write header | |
| 858 | - if self._logTerse(): | |
| 859 | - self._log('\n') | |
| 860 | - self._log.header1('Generate energy dispersion extension') | |
| 830 | + # Set boundaries | |
| 831 | + bounds = self._make_2D(r68, self._hdu_psf, None, 'deg') | |
| 832 | + for b in bounds: | |
| 833 | + irf['PSF_BOUNDS'].append(b) | |
| 834 | + irf['PSF_BOUNDS'].append('PSF(KING)') | |
| 861 | 835 | |
| 862 | - # Allocate ROOT 3D array | |
| 863 | - matrix = TH3F() | |
| 864 | - file.GetObject('EestOverEtrue_offaxis', matrix) | |
| 836 | + # Write boundary keywords | |
| 837 | + self._set_cif_keywords(self._hdu_psf, irf['PSF_NAME'], | |
| 838 | + irf['PSF_BOUNDS'], irf['PSF_DESC'], irf) | |
| 865 | 839 | |
| 866 | - # Set boundaries | |
| 867 | - bounds = self._make_3D_migra(matrix, self._hdu_edisp, None, '') | |
| 868 | - for b in bounds: | |
| 869 | - self._edisp_bounds.append(b) | |
| 870 | - self._set_cif_keywords(self._hdu_edisp, self._edisp_name, \ | |
| 871 | - self._edisp_bounds, self._edisp_desc) | |
| 840 | + # Create "GAMMA" data column | |
| 841 | + self._make_2D(gamma2D, self._hdu_psf, 'GAMMA', '') | |
| 872 | 842 | |
| 873 | - # MATRIX | |
| 874 | - self._make_3D_migra(matrix, self._hdu_edisp, 'MATRIX', '') | |
| 843 | + # Create "SIGMA" data column | |
| 844 | + self._make_2D(sigma2D, self._hdu_psf, 'SIGMA', 'deg') | |
| 875 | 845 | |
| 876 | 846 | # Return |
| 877 | 847 | return |
| 878 | 848 | |
| 879 | - def _root2bgd(self, file): | |
| 849 | + def _root2edisp(self, file, irf): | |
| 880 | 850 | """ |
| 881 | - Translate ROOT to CALDB background extension. The following ROOT | |
| 882 | - histograms are used: | |
| 883 | - | |
| 884 | - BGRatePerSqDeg_offaxis -> BGD | |
| 885 | - BGRatePerSqDeg_offaxis -> BGD_RECO | |
| 851 | + Translate ROOT to CALDB energy dispersion extension | |
| 852 | + | |
| 853 | + The following ROOT histograms are used: | |
| 854 | + - EestOverEtrue_offaxis -> MATRIX | |
| 886 | 855 | |
| 887 | - Parameters: | |
| 888 | - file - ROOT file. | |
| 889 | - Keywords: | |
| 890 | - None | |
| 856 | + Parameters | |
| 857 | + ---------- | |
| 858 | + file : `~ROOT.TFile` | |
| 859 | + ROOT file | |
| 860 | + irf : dict | |
| 861 | + IRF metadata dictionary | |
| 891 | 862 | """ |
| 892 | - # Continue only if background HDU has been opened | |
| 893 | - if self._hdu_bgd != None: | |
| 894 | - | |
| 895 | - # Write header | |
| 896 | - if self._logTerse(): | |
| 897 | - self._log('\n') | |
| 898 | - self._log.header1('Generate 2D background extension') | |
| 863 | + # Write header | |
| 864 | + if self._logTerse(): | |
| 865 | + self._log('\n') | |
| 866 | + self._log.header1('Generate energy dispersion extension') | |
| 899 | 867 | |
| 900 | - # Allocate ROOT 2D array | |
| 901 | - array = TH2F() | |
| 902 | - file.GetObject('BGRatePerSqDeg_offaxis', array) | |
| 868 | + # Get relevant ROOT histograms | |
| 869 | + matrix = file.Get('EestOverEtrue_offaxis') | |
| 903 | 870 | |
| 904 | - # Set boundaries | |
| 905 | - bounds = self._make_2D(array, self._hdu_bgd, None, 'deg') | |
| 906 | - for b in bounds: | |
| 907 | - self._bgd_bounds.append(b) | |
| 908 | - self._set_cif_keywords(self._hdu_bgd, self._bgd_name, \ | |
| 909 | - self._bgd_bounds, self._bgd_desc) | |
| 871 | + # Set boundaries | |
| 872 | + bounds = self._make_3D_migra(matrix, self._hdu_edisp, None, '') | |
| 873 | + for b in bounds: | |
| 874 | + irf['EDISP_BOUNDS'].append(b) | |
| 910 | 875 | |
| 911 | - # BGD | |
| 912 | - self._make_2D(array, self._hdu_bgd, 'BGD', '') | |
| 876 | + # Write boundary keywords | |
| 877 | + self._set_cif_keywords(self._hdu_edisp, irf['EDISP_NAME'], | |
| 878 | + irf['EDISP_BOUNDS'], irf['EDISP_DESC'], irf) | |
| 913 | 879 | |
| 914 | - # BGD_RECO | |
| 915 | - self._make_2D(array, self._hdu_bgd, 'BGD_RECO', '') | |
| 880 | + # Create "MATRIX" data column | |
| 881 | + self._make_3D_migra(matrix, self._hdu_edisp, 'MATRIX', '') | |
| 916 | 882 | |
| 917 | 883 | # Return |
| 918 | 884 | return |
| 919 | 885 | |
| 920 | - def _root2bgd3D(self, file): | |
| 886 | + def _root2bgd(self, file, irf): | |
| 921 | 887 | """ |
| 922 | 888 | Translate ROOT to CALDB background extension. |
| 923 | 889 | |
| 924 | 890 | The following ROOT histograms are used: |
| 925 | - BGRatePerSqDeg_offaxis -> BGD | |
| 891 | + - BGRatePerSqDeg_offaxis -> BGD | |
| 926 | 892 | |
| 927 | 893 | Parameters |
| 928 | 894 | ---------- |
| 929 | 895 | file : `~ROOT.TFile` |
| 930 | - ROOT file. | |
| 896 | + ROOT file | |
| 897 | + irf : dict | |
| 898 | + IRF metadata dictionary | |
| 931 | 899 | """ |
| 932 | - # Continue only if background HDU has been opened | |
| 933 | - if self._hdu_bgd != None: | |
| 934 | - | |
| 935 | - # Write header | |
| 936 | - if self._logTerse(): | |
| 937 | - self._log('\n') | |
| 938 | - self._log.header1('Generate 3D background extension') | |
| 900 | + # Write header | |
| 901 | + if self._logTerse(): | |
| 902 | + self._log('\n') | |
| 903 | + self._log.header1('Generate 3D background extension') | |
| 939 | 904 | |
| 940 | - # Get User parameters | |
| 941 | - norm1d = self['norm1d'].boolean() | |
| 942 | - bgdethres = self['bgdethres'].real() | |
| 943 | - bgdinfill = self['bgdinfill'].boolean() | |
| 905 | + # Get relevant ROOT histograms | |
| 906 | + array = file.Get('BGRatePerSqDeg_offaxis') | |
| 944 | 907 | |
| 945 | - # Allocate ROOT 2D array | |
| 946 | - array = TH2F() | |
| 947 | - file.GetObject('BGRatePerSqDeg_offaxis', array) | |
| 908 | + # Replace 2D histogram values by power law extrapolation | |
| 909 | + self._plaw_replace(array, self['bgdethres'].real()) | |
| 948 | 910 | |
| 949 | - # Replace 2D histogram values by power law extrapolation | |
| 950 | - self._plaw_replace(array, bgdethres) | |
| 911 | + # If requested then fill-in empty values in 2D histogram | |
| 912 | + if self['bgdinfill'].boolean(): | |
| 913 | + self._infill_bgd(array) | |
| 951 | 914 | |
| 952 | - # Optionally fill in empty values in 2D histogram | |
| 953 | - if bgdinfill: | |
| 954 | - self._infill_bgd(array) | |
| 915 | + # If requested then normalize the 2D histogram on the on-axis 1D | |
| 916 | + # histogram. This assures that the 2D histogram has the same on-axis | |
| 917 | + # effective area dependence as the 1D histogram. | |
| 918 | + if self['norm1d'].boolean(): | |
| 919 | + array_1D = file.Get('BGRatePerSqDeg') | |
| 920 | + self._renorm_onaxis(array, array_1D) | |
| 955 | 921 | |
| 956 | - # Optionally normalize 2D histogram on on-axis 1D histogram | |
| 957 | - if norm1d: | |
| 958 | - array_1D = TH1F() | |
| 959 | - file.GetObject('BGRatePerSqDeg', array_1D) | |
| 960 | - self._renorm_onaxis(array, array_1D) | |
| 922 | + # Set boundaries | |
| 923 | + bounds = self._make_3D(array, self._hdu_bgd, None, 'deg') | |
| 924 | + for b in bounds: | |
| 925 | + irf['BGD_BOUNDS'].append(b) | |
| 961 | 926 | |
| 962 | - # Set boundaries | |
| 963 | - bounds = self._make_3D(array, self._hdu_bgd, None, 'deg') | |
| 964 | - for b in bounds: | |
| 965 | - self._bgd_bounds.append(b) | |
| 966 | - self._set_cif_keywords(self._hdu_bgd, self._bgd_name, | |
| 967 | - self._bgd_bounds, self._bgd_desc) | |
| 927 | + # Write boundary keywords | |
| 928 | + self._set_cif_keywords(self._hdu_bgd, irf['BGD_NAME'], | |
| 929 | + irf['BGD_BOUNDS'], irf['BGD_DESC'], irf) | |
| 968 | 930 | |
| 969 | - # BGD (reconstructed energy) | |
| 970 | - self._make_3D(array, self._hdu_bgd, 'BGD', '1/s/MeV/sr') | |
| 931 | + # Create "BGD" data column | |
| 932 | + self._make_3D(array, self._hdu_bgd, 'BGD', '1/s/MeV/sr') | |
| 971 | 933 | |
| 972 | 934 | # Return |
| 973 | 935 | return |
| 974 | 936 | |
| 975 | 937 | def _append_column(self, hdu, name, unit, axis, log=False): |
| 976 | 938 | """ |
| 977 | - Append column to HDU. | |
| 939 | + Append column to HDU | |
| 978 | 940 | |
| 979 | - Parameters: | |
| 980 | - hdu: HDU | |
| 981 | - name: Column name | |
| 982 | - unit: Column unit | |
| 983 | - axis: ROOT histogram axis | |
| 984 | - | |
| 985 | - Keywords: | |
| 986 | - log: Logarithmic axis | |
| 941 | + Parameters | |
| 942 | + ---------- | |
| 943 | + hdu : `~gammalib.GFitsHDU` | |
| 944 | + FITS HDU | |
| 945 | + name : str | |
| 946 | + Column name | |
| 947 | + unit : str | |
| 948 | + Column unit | |
| 949 | + axis : `~ROOT.TAxis` | |
| 950 | + ROOT histogram axis | |
| 951 | + log : bool, optional | |
| 952 | + Axis is logarithmic | |
| 987 | 953 | """ |
| 988 | 954 | # Continue only if columns does not yet exist |
| 989 | 955 | if not hdu.contains(name): |
| ... | ... | @@ -1024,9 +990,9 @@ class csroot2caldb(ctools.cscript): |
| 1024 | 990 | Parameters |
| 1025 | 991 | ---------- |
| 1026 | 992 | hist2D : `~ROOT.TH2F` |
| 1027 | - ROOT 2D histogram. | |
| 993 | + ROOT 2D histogram | |
| 1028 | 994 | hist1D : `~ROOT.TH1F` |
| 1029 | - ROOT 1D histogram. | |
| 995 | + ROOT 1D histogram | |
| 1030 | 996 | """ |
| 1031 | 997 | # Get 2D dimensions |
| 1032 | 998 | neng = hist2D.GetXaxis().GetNbins() |
| ... | ... | @@ -1101,9 +1067,9 @@ class csroot2caldb(ctools.cscript): |
| 1101 | 1067 | Parameters |
| 1102 | 1068 | ---------- |
| 1103 | 1069 | hist2D : `~ROOT.TH2F` |
| 1104 | - ROOT 2D histogram. | |
| 1070 | + ROOT 2D histogram | |
| 1105 | 1071 | ethres : float |
| 1106 | - Energy threshold. | |
| 1072 | + Energy threshold | |
| 1107 | 1073 | """ |
| 1108 | 1074 | # Extract energy and offset angle vectors |
| 1109 | 1075 | energies = hist2D.GetXaxis() |
| ... | ... | @@ -1260,7 +1226,7 @@ class csroot2caldb(ctools.cscript): |
| 1260 | 1226 | Parameters |
| 1261 | 1227 | ---------- |
| 1262 | 1228 | hist2D : `~ROOT.TH2F` |
| 1263 | - ROOT 2D histogram. | |
| 1229 | + ROOT 2D histogram | |
| 1264 | 1230 | """ |
| 1265 | 1231 | # Extract energy and offset angle vectors |
| 1266 | 1232 | energies = hist2D.GetXaxis() |
| ... | ... | @@ -1316,19 +1282,24 @@ class csroot2caldb(ctools.cscript): |
| 1316 | 1282 | |
| 1317 | 1283 | def _make_2D(self, array, hdu, name, unit, scale=1.0): |
| 1318 | 1284 | """ |
| 1319 | - Make 2D matrix as function of energy and offset angle from a | |
| 1320 | - ROOT 2D histogram. If the HDU has already the energy and | |
| 1321 | - offset angle columns, this method will simply add another data | |
| 1322 | - column. | |
| 1323 | - If name==None, the method will not append any data column. | |
| 1324 | - | |
| 1325 | - Parameters: | |
| 1326 | - array - ROOT 2D histogram. | |
| 1327 | - hdu - FITS HDU. | |
| 1328 | - name - Data column name. | |
| 1329 | - unit - Data unit. | |
| 1330 | - Keywords: | |
| 1331 | - scale - Scaling factor for histogram values. | |
| 1285 | + Make 2D data column as function of energy and offset angle | |
| 1286 | + | |
| 1287 | + If the HDU has already the energy and offset angle columns, this method | |
| 1288 | + will simply add another data column. If name==None, the method will not | |
| 1289 | + append any data column. | |
| 1290 | + | |
| 1291 | + Parameters | |
| 1292 | + ---------- | |
| 1293 | + array : `~ROOT.TH2F` | |
| 1294 | + ROOT 2D histogram | |
| 1295 | + hdu : `~gammalib.GFitsHDU` | |
| 1296 | + FITS HDU | |
| 1297 | + name : str | |
| 1298 | + Data column name | |
| 1299 | + unit : str | |
| 1300 | + Data unit | |
| 1301 | + scale : float, optional | |
| 1302 | + Scaling factor for histogram values | |
| 1332 | 1303 | """ |
| 1333 | 1304 | # Extract energy and offset angle vectors |
| 1334 | 1305 | energies = array.GetXaxis() |
| ... | ... | @@ -1337,10 +1308,10 @@ class csroot2caldb(ctools.cscript): |
| 1337 | 1308 | noffset = offsets.GetNbins() |
| 1338 | 1309 | |
| 1339 | 1310 | # Append axis columns to HDU |
| 1340 | - self._append_column(hdu, "ENERG_LO", "TeV", energies, log=True) | |
| 1341 | - self._append_column(hdu, "ENERG_HI", "TeV", energies, log=True) | |
| 1342 | - self._append_column(hdu, "THETA_LO", "deg", offsets) | |
| 1343 | - self._append_column(hdu, "THETA_HI", "deg", offsets) | |
| 1311 | + self._append_column(hdu, 'ENERG_LO', 'TeV', energies, log=True) | |
| 1312 | + self._append_column(hdu, 'ENERG_HI', 'TeV', energies, log=True) | |
| 1313 | + self._append_column(hdu, 'THETA_LO', 'deg', offsets) | |
| 1314 | + self._append_column(hdu, 'THETA_HI', 'deg', offsets) | |
| 1344 | 1315 | |
| 1345 | 1316 | # Append array column |
| 1346 | 1317 | if name != None and not hdu.contains(name): |
| ... | ... | @@ -1354,13 +1325,13 @@ class csroot2caldb(ctools.cscript): |
| 1354 | 1325 | hdu[name][0,index] = value * scale |
| 1355 | 1326 | |
| 1356 | 1327 | # Collect boundary information |
| 1357 | - bd_eng = "ENERG(%.4f-%.2f)TeV" % \ | |
| 1328 | + bd_eng = 'ENERG(%.4f-%.2f)TeV' % \ | |
| 1358 | 1329 | (pow(10.0, energies.GetBinLowEdge(1)), \ |
| 1359 | 1330 | pow(10.0, energies.GetBinUpEdge(neng))) |
| 1360 | - bd_off = "THETA(%.2f-%.2f)deg" % \ | |
| 1331 | + bd_off = 'THETA(%.2f-%.2f)deg' % \ | |
| 1361 | 1332 | (offsets.GetBinLowEdge(1), \ |
| 1362 | 1333 | offsets.GetBinUpEdge(noffset)) |
| 1363 | - bd_phi = "PHI(0-360)deg" | |
| 1334 | + bd_phi = 'PHI(0-360)deg' | |
| 1364 | 1335 | bounds = [bd_eng, bd_off, bd_phi] |
| 1365 | 1336 | |
| 1366 | 1337 | # Return boundary information |
| ... | ... | @@ -1368,23 +1339,22 @@ class csroot2caldb(ctools.cscript): |
| 1368 | 1339 | |
| 1369 | 1340 | def _make_3D(self, array, hdu, name, unit): |
| 1370 | 1341 | """ |
| 1371 | - Generate background 3D cube | |
| 1342 | + Make 3D data column as function of DETX, DETY and energy | |
| 1372 | 1343 | |
| 1373 | - Generates 3D cube as function of DETX, DETY and energy from a | |
| 1374 | - ROOT 2D histogram. If the HDU has already the energy and | |
| 1375 | - offset angle columns, this method will simply add another data | |
| 1376 | - column. If name==None, the method will not append any data column. | |
| 1344 | + If the HDU has already the energy and offset angle columns, this method | |
| 1345 | + will simply add another data column. If name==None, the method will not | |
| 1346 | + append any data column. | |
| 1377 | 1347 | |
| 1378 | 1348 | Parameters |
| 1379 | 1349 | ---------- |
| 1380 | 1350 | array : `~ROOT.TH2F` |
| 1381 | - ROOT 2D histogram. | |
| 1351 | + ROOT 2D histogram | |
| 1382 | 1352 | hdu : `~gammalib.GFitsHDU` |
| 1383 | - FITS HDU. | |
| 1353 | + FITS HDU | |
| 1384 | 1354 | name : str |
| 1385 | - Data column name. | |
| 1355 | + Data column name | |
| 1386 | 1356 | unit : str |
| 1387 | - Data unit. | |
| 1357 | + Data unit | |
| 1388 | 1358 | """ |
| 1389 | 1359 | # Get User parameters |
| 1390 | 1360 | scale = self['bgdscale'].real() |
| ... | ... | @@ -1468,21 +1438,6 @@ class csroot2caldb(ctools.cscript): |
| 1468 | 1438 | value = binsq / deg2sr / (ewidth[ieng]) |
| 1469 | 1439 | hdu[name][0,index] = value * scale |
| 1470 | 1440 | |
| 1471 | - # Debugging | |
| 1472 | - if False: | |
| 1473 | - for ieng in range(neng): | |
| 1474 | - sum = 0.0 | |
| 1475 | - for ioff in range(noffset): | |
| 1476 | - index = ieng + ioff * neng | |
| 1477 | - binsq = array.GetBinContent(ieng+1,ioff+1) | |
| 1478 | - value = binsq / deg2sr / ewidth[ieng] | |
| 1479 | - sum += value | |
| 1480 | - if ioff == 0: | |
| 1481 | - peak = value | |
| 1482 | - peaksq = binsq | |
| 1483 | - print(pow(10.0, energies.GetBinLowEdge(ieng+1))+ | |
| 1484 | - pow(10.0, energies.GetBinUpEdge(ieng+1)), sum, peak, peaksq) | |
| 1485 | - | |
| 1486 | 1441 | # Collect boundary information |
| 1487 | 1442 | bd_detx = 'DETX(%.2f-%.2f)deg' % (-det_max, det_max) |
| 1488 | 1443 | bd_dety = 'DETY(%.2f-%.2f)deg' % (-det_max, det_max) |
| ... | ... | @@ -1496,18 +1451,24 @@ class csroot2caldb(ctools.cscript): |
| 1496 | 1451 | |
| 1497 | 1452 | def _make_3D_migra(self, array, hdu, name, unit, scale=1.0): |
| 1498 | 1453 | """ |
| 1499 | - Make 3D cube as function of ETRUE, MIGRA and THETA form ROOT 3D | |
| 1500 | - histogram. If the HDU has already the columns, this method will | |
| 1501 | - simply add another data column. | |
| 1502 | - If name==None, the method will not append any data column. | |
| 1503 | - | |
| 1504 | - Parameters: | |
| 1505 | - array - ROOT 3D histogram. | |
| 1506 | - hdu - FITS HDU. | |
| 1507 | - name - Data column name. | |
| 1508 | - unit - Data unit. | |
| 1509 | - Keywords: | |
| 1510 | - scale - Scaling factor for histogram values. | |
| 1454 | + Make 3D data column as function of ETRUE, MIGRA and THETA | |
| 1455 | + | |
| 1456 | + If the HDU has already the energy and offset angle columns, this method | |
| 1457 | + will simply add another data column. If name==None, the method will not | |
| 1458 | + append any data column. | |
| 1459 | + | |
| 1460 | + Parameters | |
| 1461 | + ---------- | |
| 1462 | + array : `~ROOT.TH3F` | |
| 1463 | + ROOT 2D histogram | |
| 1464 | + hdu : `~gammalib.GFitsHDU` | |
| 1465 | + FITS HDU | |
| 1466 | + name : str | |
| 1467 | + Data column name | |
| 1468 | + unit : str | |
| 1469 | + Data unit | |
| 1470 | + scale : float, optional | |
| 1471 | + Scaling factor for histogram values | |
| 1511 | 1472 | """ |
| 1512 | 1473 | # Extract Etrue, Eobs/Etrue and offset angle vectors |
| 1513 | 1474 | etrue = array.GetXaxis() |
| ... | ... | @@ -1522,12 +1483,12 @@ class csroot2caldb(ctools.cscript): |
| 1522 | 1483 | pow(10.0, etrue.GetBinLowEdge(ieng+1)+6.0)) |
| 1523 | 1484 | |
| 1524 | 1485 | # Append axis columns to HDU |
| 1525 | - self._append_column(hdu, "ETRUE_LO", "TeV", etrue, log=True) | |
| 1526 | - self._append_column(hdu, "ETRUE_HI", "TeV", etrue, log=True) | |
| 1527 | - self._append_column(hdu, "MIGRA_LO", "", migra) | |
| 1528 | - self._append_column(hdu, "MIGRA_HI", "", migra) | |
| 1529 | - self._append_column(hdu, "THETA_LO", "deg", offsets) | |
| 1530 | - self._append_column(hdu, "THETA_HI", "deg", offsets) | |
| 1486 | + self._append_column(hdu, 'ETRUE_LO', 'TeV', etrue, log=True) | |
| 1487 | + self._append_column(hdu, 'ETRUE_HI', 'TeV', etrue, log=True) | |
| 1488 | + self._append_column(hdu, 'MIGRA_LO', '', migra) | |
| 1489 | + self._append_column(hdu, 'MIGRA_HI', '', migra) | |
| 1490 | + self._append_column(hdu, 'THETA_LO', 'deg', offsets) | |
| 1491 | + self._append_column(hdu, 'THETA_HI', 'deg', offsets) | |
| 1531 | 1492 | |
| 1532 | 1493 | # Append migration matrix to HDU |
| 1533 | 1494 | if name != None and not hdu.contains(name): |
| ... | ... | @@ -1542,16 +1503,16 @@ class csroot2caldb(ctools.cscript): |
| 1542 | 1503 | hdu[name][0,index] = value * scale |
| 1543 | 1504 | |
| 1544 | 1505 | # Collect boundary information |
| 1545 | - bd_eng = "ETRUE(%.4f-%.2f)TeV" % \ | |
| 1506 | + bd_eng = 'ETRUE(%.4f-%.2f)TeV' % \ | |
| 1546 | 1507 | (pow(10.0, etrue.GetBinLowEdge(1)), |
| 1547 | 1508 | pow(10.0, etrue.GetBinUpEdge(netrue))) |
| 1548 | - bd_migra = "MIGRA(%.3f-%.3f)" % \ | |
| 1509 | + bd_migra = 'MIGRA(%.3f-%.3f)' % \ | |
| 1549 | 1510 | (migra.GetBinLowEdge(1), |
| 1550 | 1511 | migra.GetBinUpEdge(nmigra)) |
| 1551 | - bd_off = "THETA(%.2f-%.2f)deg" % \ | |
| 1512 | + bd_off = 'THETA(%.2f-%.2f)deg' % \ | |
| 1552 | 1513 | (offsets.GetBinLowEdge(1), |
| 1553 | 1514 | offsets.GetBinUpEdge(noffset)) |
| 1554 | - bd_phi = "PHI(0-360)deg" | |
| 1515 | + bd_phi = 'PHI(0-360)deg' | |
| 1555 | 1516 | bounds = [bd_eng, bd_migra, bd_off, bd_phi] |
| 1556 | 1517 | |
| 1557 | 1518 | # Return boundary information |
| ... | ... | @@ -1561,7 +1522,7 @@ class csroot2caldb(ctools.cscript): |
| 1561 | 1522 | # Public methods |
| 1562 | 1523 | def run(self): |
| 1563 | 1524 | """ |
| 1564 | - Run the script. | |
| 1525 | + Run the script | |
| 1565 | 1526 | """ |
| 1566 | 1527 | # Warn if ROOT module is missing |
| 1567 | 1528 | if not _has_root: |
| ... | ... | @@ -1575,25 +1536,28 @@ class csroot2caldb(ctools.cscript): |
| 1575 | 1536 | # Get parameters |
| 1576 | 1537 | self._get_parameters() |
| 1577 | 1538 | |
| 1578 | - # Initialise IRF | |
| 1579 | - self._initialise() | |
| 1539 | + # Initialise IRF metadata | |
| 1540 | + irf = self._init_metadata() | |
| 1541 | + | |
| 1542 | + # Create directory structure | |
| 1543 | + dir = self._make_dirs('file', irf) | |
| 1580 | 1544 | |
| 1581 | - # Open calibration file | |
| 1582 | - self._open("file") | |
| 1545 | + # Open calibration files | |
| 1546 | + self._open(irf, dir) | |
| 1583 | 1547 | |
| 1584 | 1548 | # Translate ROOT to CALDB information |
| 1585 | 1549 | if _has_root: |
| 1586 | - self._root2caldb() | |
| 1550 | + self._root2caldb(irf) | |
| 1587 | 1551 | |
| 1588 | - # Close calibration file | |
| 1589 | - self._close() | |
| 1552 | + # Close calibration files | |
| 1553 | + self._close(irf, dir) | |
| 1590 | 1554 | |
| 1591 | 1555 | # Return |
| 1592 | 1556 | return |
| 1593 | 1557 | |
| 1594 | 1558 | def execute(self): |
| 1595 | 1559 | """ |
| 1596 | - Execute the script. | |
| 1560 | + Execute the script | |
| 1597 | 1561 | """ |
| 1598 | 1562 | # Open logfile |
| 1599 | 1563 | self.logFileOpen() | ... | ... |