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,7 +5,7 @@ | ||
| 5 | # ------------------------------------------------------------------------- # | 5 | # ------------------------------------------------------------------------- # |
| 6 | # # | 6 | # # |
| 7 | # File: csroot2caldb.par # | 7 | # File: csroot2caldb.par # |
| 8 | -# Version: 1.0.0 # | 8 | +# Version: 1.2.0 # |
| 9 | # # | 9 | # # |
| 10 | # Author: Juergen Knoedlseder # | 10 | # Author: Juergen Knoedlseder # |
| 11 | # Jurgen.Knodlseder@irap.omp.eu # | 11 | # Jurgen.Knodlseder@irap.omp.eu # |
| @@ -24,6 +24,7 @@ id, s, a, South_50h,,, "Instrument Response Function identifier" | @@ -24,6 +24,7 @@ id, s, a, South_50h,,, "Instrument Response Function identifier" | ||
| 24 | version, s, a, prod3,,, "Instrument Response Function version" | 24 | version, s, a, prod3,,, "Instrument Response Function version" |
| 25 | analysis, s, a, DESY,,, "Instrument Response Function analysis" | 25 | analysis, s, a, DESY,,, "Instrument Response Function analysis" |
| 26 | psftype, s, h, Gauss,Gauss|King,, "Point spread function type" | 26 | psftype, s, h, Gauss,Gauss|King,, "Point spread function type" |
| 27 | +split, b, h, no,,, "Split IRF components into different files" | ||
| 27 | norm1d, b, h, no,,, "Normalize on 1D histograms" | 28 | norm1d, b, h, no,,, "Normalize on 1D histograms" |
| 28 | rebin, b, h, no,,, "Rebin" | 29 | rebin, b, h, no,,, "Rebin" |
| 29 | eascale, r, h, 1.0,,, "Scaling factor for effective areas" | 30 | eascale, r, h, 1.0,,, "Scaling factor for effective areas" |
cscripts/csroot2caldb.py
| @@ -39,7 +39,7 @@ except: | @@ -39,7 +39,7 @@ except: | ||
| 39 | # ================== # | 39 | # ================== # |
| 40 | class csroot2caldb(ctools.cscript): | 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 | # Constructor | 45 | # Constructor |
| @@ -51,9 +51,8 @@ class csroot2caldb(ctools.cscript): | @@ -51,9 +51,8 @@ class csroot2caldb(ctools.cscript): | ||
| 51 | self._name = 'csroot2caldb' | 51 | self._name = 'csroot2caldb' |
| 52 | self._version = '1.2.0' | 52 | self._version = '1.2.0' |
| 53 | 53 | ||
| 54 | - # Initialise some members | 54 | + # Initialise file members |
| 55 | self._cif = None | 55 | self._cif = None |
| 56 | - self._irf = None | ||
| 57 | self._ea = None | 56 | self._ea = None |
| 58 | self._psf = None | 57 | self._psf = None |
| 59 | self._edisp = None | 58 | self._edisp = None |
| @@ -80,6 +79,7 @@ class csroot2caldb(ctools.cscript): | @@ -80,6 +79,7 @@ class csroot2caldb(ctools.cscript): | ||
| 80 | self['analysis'].string() | 79 | self['analysis'].string() |
| 81 | self['version'].string() | 80 | self['version'].string() |
| 82 | self['psftype'].string() | 81 | self['psftype'].string() |
| 82 | + self['split'].boolean() | ||
| 83 | self['norm1d'].boolean() | 83 | self['norm1d'].boolean() |
| 84 | self['rebin'].boolean() | 84 | self['rebin'].boolean() |
| 85 | self['eascale'].real() | 85 | self['eascale'].real() |
| @@ -90,64 +90,66 @@ class csroot2caldb(ctools.cscript): | @@ -90,64 +90,66 @@ class csroot2caldb(ctools.cscript): | ||
| 90 | # Write input parameters into logger | 90 | # Write input parameters into logger |
| 91 | if self._logTerse(): | 91 | if self._logTerse(): |
| 92 | self._log_parameters() | 92 | self._log_parameters() |
| 93 | - self._log("\n") | 93 | + self._log('\n') |
| 94 | 94 | ||
| 95 | # Return | 95 | # Return |
| 96 | return | 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 | The structure is given by | 153 | The structure is given by |
| 152 | 154 | ||
| 153 | data/<tel>/<inst>/bcf/<obsid> | 155 | data/<tel>/<inst>/bcf/<obsid> |
| @@ -155,172 +157,193 @@ class csroot2caldb(ctools.cscript): | @@ -155,172 +157,193 @@ class csroot2caldb(ctools.cscript): | ||
| 155 | where <tel> is "cta" and <inst> is the instrument specified in the | 157 | where <tel> is "cta" and <inst> is the instrument specified in the |
| 156 | CALDB constructor (the instrument may be used for different array | 158 | CALDB constructor (the instrument may be used for different array |
| 157 | configurations). | 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 | # Set base directory | 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 | # Set directory names | 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 | if len(outdir) > 0: | 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 | else: | 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 | # Create directory structure | 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 | # Open calibration database index | 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 | # If file has no CIF extension than create it now | 249 | # If file has no CIF extension than create it now |
| 228 | try: | 250 | try: |
| 229 | - self._hdu_cif = self._cif.table("CIF") | 251 | + self._hdu_cif = self._cif.table('CIF') |
| 230 | except: | 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 | self._ea = gammalib.GFits(ea_filename, True) | 264 | self._ea = gammalib.GFits(ea_filename, True) |
| 243 | self._psf = gammalib.GFits(psf_filename, True) | 265 | self._psf = gammalib.GFits(psf_filename, True) |
| 244 | self._edisp = gammalib.GFits(edisp_filename, True) | 266 | self._edisp = gammalib.GFits(edisp_filename, True) |
| 245 | self._bgd = gammalib.GFits(bgd_filename, True) | 267 | self._bgd = gammalib.GFits(bgd_filename, True) |
| 246 | else: | 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 | # Open HDUs | 274 | # Open HDUs |
| 254 | self._hdu_ea = self._open_hdu(self._ea, "EFFECTIVE AREA", | 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 | self._hdu_psf = self._open_hdu(self._psf, "POINT SPREAD FUNCTION", | 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 | self._hdu_edisp = self._open_hdu(self._edisp, "ENERGY DISPERSION", | 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 | self._hdu_bgd = self._open_hdu(self._bgd, "BACKGROUND", | 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 | # Return | 284 | # Return |
| 264 | return | 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 | # Return | 320 | # Return |
| 308 | return | 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 | Open HDU | 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 | # Create table if it does not yet exist | 348 | # Create table if it does not yet exist |
| 326 | if not fits.contains(extname): | 349 | if not fits.contains(extname): |
| @@ -332,7 +355,7 @@ class csroot2caldb(ctools.cscript): | @@ -332,7 +355,7 @@ class csroot2caldb(ctools.cscript): | ||
| 332 | table.extname(extname) | 355 | table.extname(extname) |
| 333 | 356 | ||
| 334 | # Set OGIP keywords | 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 | # Append table to FITS file | 360 | # Append table to FITS file |
| 338 | fits.append(table) | 361 | fits.append(table) |
| @@ -340,650 +363,593 @@ class csroot2caldb(ctools.cscript): | @@ -340,650 +363,593 @@ class csroot2caldb(ctools.cscript): | ||
| 340 | # Return FITS table | 363 | # Return FITS table |
| 341 | return fits.table(extname) | 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 | # Set UTC date of file creation | 381 | # Set UTC date of file creation |
| 353 | utc = datetime.utcnow().isoformat()[:19] | 382 | utc = datetime.utcnow().isoformat()[:19] |
| 354 | 383 | ||
| 355 | # Set keywords | 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 | for i, item in enumerate(hduclas): | 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 | # Return | 397 | # Return |
| 369 | return | 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 | # Return | 459 | # Return |
| 468 | return | 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 | # Set standard CIF keywords | 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 | # Set boundary keywords | 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 | else: | 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 | # Set validity keywords | 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 | # Return | 501 | # Return |
| 495 | return | 502 | return |
| 496 | 503 | ||
| 497 | 504 | ||
| 498 | # ROOT specific private members | 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 | # Open ROOT performance file | 515 | # Open ROOT performance file |
| 507 | - file = TFile(self["infile"].filename().url()) | 516 | + file = TFile(self['infile'].filename().url()) |
| 508 | 517 | ||
| 509 | # Create effective area | 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 | # Create point spread function | 521 | # Create point spread function |
| 514 | - self._root2psf(file, self["psftype"].string()) | 522 | + self._root2psf(file, irf) |
| 515 | 523 | ||
| 516 | # Create energy dispersion | 524 | # Create energy dispersion |
| 517 | - self._root2edisp(file) | 525 | + self._root2edisp(file, irf) |
| 518 | 526 | ||
| 519 | # Create background | 527 | # Create background |
| 520 | - #self._root2bgd(file) | ||
| 521 | - self._root2bgd3D(file) | 528 | + self._root2bgd(file, irf) |
| 522 | 529 | ||
| 523 | # Return | 530 | # Return |
| 524 | return | 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 | # Return | 611 | # Return |
| 606 | return | 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 | # Return | 638 | # Return |
| 632 | return | 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 | # Return | 719 | # Return |
| 713 | return | 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 | else: | 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 | if denominator > 0.0: | 806 | if denominator > 0.0: |
| 798 | - sigma = r_68 * math.sqrt(1.0/denominator) | 807 | + sigma = r_80 * math.sqrt(1.0/denominator) |
| 799 | else: | 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 | # Return | 846 | # Return |
| 877 | return | 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 | # Return | 883 | # Return |
| 918 | return | 884 | return |
| 919 | 885 | ||
| 920 | - def _root2bgd3D(self, file): | 886 | + def _root2bgd(self, file, irf): |
| 921 | """ | 887 | """ |
| 922 | Translate ROOT to CALDB background extension. | 888 | Translate ROOT to CALDB background extension. |
| 923 | 889 | ||
| 924 | The following ROOT histograms are used: | 890 | The following ROOT histograms are used: |
| 925 | - BGRatePerSqDeg_offaxis -> BGD | 891 | + - BGRatePerSqDeg_offaxis -> BGD |
| 926 | 892 | ||
| 927 | Parameters | 893 | Parameters |
| 928 | ---------- | 894 | ---------- |
| 929 | file : `~ROOT.TFile` | 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 | # Return | 934 | # Return |
| 973 | return | 935 | return |
| 974 | 936 | ||
| 975 | def _append_column(self, hdu, name, unit, axis, log=False): | 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 | # Continue only if columns does not yet exist | 954 | # Continue only if columns does not yet exist |
| 989 | if not hdu.contains(name): | 955 | if not hdu.contains(name): |
| @@ -1024,9 +990,9 @@ class csroot2caldb(ctools.cscript): | @@ -1024,9 +990,9 @@ class csroot2caldb(ctools.cscript): | ||
| 1024 | Parameters | 990 | Parameters |
| 1025 | ---------- | 991 | ---------- |
| 1026 | hist2D : `~ROOT.TH2F` | 992 | hist2D : `~ROOT.TH2F` |
| 1027 | - ROOT 2D histogram. | 993 | + ROOT 2D histogram |
| 1028 | hist1D : `~ROOT.TH1F` | 994 | hist1D : `~ROOT.TH1F` |
| 1029 | - ROOT 1D histogram. | 995 | + ROOT 1D histogram |
| 1030 | """ | 996 | """ |
| 1031 | # Get 2D dimensions | 997 | # Get 2D dimensions |
| 1032 | neng = hist2D.GetXaxis().GetNbins() | 998 | neng = hist2D.GetXaxis().GetNbins() |
| @@ -1101,9 +1067,9 @@ class csroot2caldb(ctools.cscript): | @@ -1101,9 +1067,9 @@ class csroot2caldb(ctools.cscript): | ||
| 1101 | Parameters | 1067 | Parameters |
| 1102 | ---------- | 1068 | ---------- |
| 1103 | hist2D : `~ROOT.TH2F` | 1069 | hist2D : `~ROOT.TH2F` |
| 1104 | - ROOT 2D histogram. | 1070 | + ROOT 2D histogram |
| 1105 | ethres : float | 1071 | ethres : float |
| 1106 | - Energy threshold. | 1072 | + Energy threshold |
| 1107 | """ | 1073 | """ |
| 1108 | # Extract energy and offset angle vectors | 1074 | # Extract energy and offset angle vectors |
| 1109 | energies = hist2D.GetXaxis() | 1075 | energies = hist2D.GetXaxis() |
| @@ -1260,7 +1226,7 @@ class csroot2caldb(ctools.cscript): | @@ -1260,7 +1226,7 @@ class csroot2caldb(ctools.cscript): | ||
| 1260 | Parameters | 1226 | Parameters |
| 1261 | ---------- | 1227 | ---------- |
| 1262 | hist2D : `~ROOT.TH2F` | 1228 | hist2D : `~ROOT.TH2F` |
| 1263 | - ROOT 2D histogram. | 1229 | + ROOT 2D histogram |
| 1264 | """ | 1230 | """ |
| 1265 | # Extract energy and offset angle vectors | 1231 | # Extract energy and offset angle vectors |
| 1266 | energies = hist2D.GetXaxis() | 1232 | energies = hist2D.GetXaxis() |
| @@ -1316,19 +1282,24 @@ class csroot2caldb(ctools.cscript): | @@ -1316,19 +1282,24 @@ class csroot2caldb(ctools.cscript): | ||
| 1316 | 1282 | ||
| 1317 | def _make_2D(self, array, hdu, name, unit, scale=1.0): | 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 | # Extract energy and offset angle vectors | 1304 | # Extract energy and offset angle vectors |
| 1334 | energies = array.GetXaxis() | 1305 | energies = array.GetXaxis() |
| @@ -1337,10 +1308,10 @@ class csroot2caldb(ctools.cscript): | @@ -1337,10 +1308,10 @@ class csroot2caldb(ctools.cscript): | ||
| 1337 | noffset = offsets.GetNbins() | 1308 | noffset = offsets.GetNbins() |
| 1338 | 1309 | ||
| 1339 | # Append axis columns to HDU | 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 | # Append array column | 1316 | # Append array column |
| 1346 | if name != None and not hdu.contains(name): | 1317 | if name != None and not hdu.contains(name): |
| @@ -1354,13 +1325,13 @@ class csroot2caldb(ctools.cscript): | @@ -1354,13 +1325,13 @@ class csroot2caldb(ctools.cscript): | ||
| 1354 | hdu[name][0,index] = value * scale | 1325 | hdu[name][0,index] = value * scale |
| 1355 | 1326 | ||
| 1356 | # Collect boundary information | 1327 | # Collect boundary information |
| 1357 | - bd_eng = "ENERG(%.4f-%.2f)TeV" % \ | 1328 | + bd_eng = 'ENERG(%.4f-%.2f)TeV' % \ |
| 1358 | (pow(10.0, energies.GetBinLowEdge(1)), \ | 1329 | (pow(10.0, energies.GetBinLowEdge(1)), \ |
| 1359 | pow(10.0, energies.GetBinUpEdge(neng))) | 1330 | pow(10.0, energies.GetBinUpEdge(neng))) |
| 1360 | - bd_off = "THETA(%.2f-%.2f)deg" % \ | 1331 | + bd_off = 'THETA(%.2f-%.2f)deg' % \ |
| 1361 | (offsets.GetBinLowEdge(1), \ | 1332 | (offsets.GetBinLowEdge(1), \ |
| 1362 | offsets.GetBinUpEdge(noffset)) | 1333 | offsets.GetBinUpEdge(noffset)) |
| 1363 | - bd_phi = "PHI(0-360)deg" | 1334 | + bd_phi = 'PHI(0-360)deg' |
| 1364 | bounds = [bd_eng, bd_off, bd_phi] | 1335 | bounds = [bd_eng, bd_off, bd_phi] |
| 1365 | 1336 | ||
| 1366 | # Return boundary information | 1337 | # Return boundary information |
| @@ -1368,23 +1339,22 @@ class csroot2caldb(ctools.cscript): | @@ -1368,23 +1339,22 @@ class csroot2caldb(ctools.cscript): | ||
| 1368 | 1339 | ||
| 1369 | def _make_3D(self, array, hdu, name, unit): | 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 | Parameters | 1348 | Parameters |
| 1379 | ---------- | 1349 | ---------- |
| 1380 | array : `~ROOT.TH2F` | 1350 | array : `~ROOT.TH2F` |
| 1381 | - ROOT 2D histogram. | 1351 | + ROOT 2D histogram |
| 1382 | hdu : `~gammalib.GFitsHDU` | 1352 | hdu : `~gammalib.GFitsHDU` |
| 1383 | - FITS HDU. | 1353 | + FITS HDU |
| 1384 | name : str | 1354 | name : str |
| 1385 | - Data column name. | 1355 | + Data column name |
| 1386 | unit : str | 1356 | unit : str |
| 1387 | - Data unit. | 1357 | + Data unit |
| 1388 | """ | 1358 | """ |
| 1389 | # Get User parameters | 1359 | # Get User parameters |
| 1390 | scale = self['bgdscale'].real() | 1360 | scale = self['bgdscale'].real() |
| @@ -1468,21 +1438,6 @@ class csroot2caldb(ctools.cscript): | @@ -1468,21 +1438,6 @@ class csroot2caldb(ctools.cscript): | ||
| 1468 | value = binsq / deg2sr / (ewidth[ieng]) | 1438 | value = binsq / deg2sr / (ewidth[ieng]) |
| 1469 | hdu[name][0,index] = value * scale | 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 | # Collect boundary information | 1441 | # Collect boundary information |
| 1487 | bd_detx = 'DETX(%.2f-%.2f)deg' % (-det_max, det_max) | 1442 | bd_detx = 'DETX(%.2f-%.2f)deg' % (-det_max, det_max) |
| 1488 | bd_dety = 'DETY(%.2f-%.2f)deg' % (-det_max, det_max) | 1443 | bd_dety = 'DETY(%.2f-%.2f)deg' % (-det_max, det_max) |
| @@ -1496,18 +1451,24 @@ class csroot2caldb(ctools.cscript): | @@ -1496,18 +1451,24 @@ class csroot2caldb(ctools.cscript): | ||
| 1496 | 1451 | ||
| 1497 | def _make_3D_migra(self, array, hdu, name, unit, scale=1.0): | 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 | # Extract Etrue, Eobs/Etrue and offset angle vectors | 1473 | # Extract Etrue, Eobs/Etrue and offset angle vectors |
| 1513 | etrue = array.GetXaxis() | 1474 | etrue = array.GetXaxis() |
| @@ -1522,12 +1483,12 @@ class csroot2caldb(ctools.cscript): | @@ -1522,12 +1483,12 @@ class csroot2caldb(ctools.cscript): | ||
| 1522 | pow(10.0, etrue.GetBinLowEdge(ieng+1)+6.0)) | 1483 | pow(10.0, etrue.GetBinLowEdge(ieng+1)+6.0)) |
| 1523 | 1484 | ||
| 1524 | # Append axis columns to HDU | 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 | # Append migration matrix to HDU | 1493 | # Append migration matrix to HDU |
| 1533 | if name != None and not hdu.contains(name): | 1494 | if name != None and not hdu.contains(name): |
| @@ -1542,16 +1503,16 @@ class csroot2caldb(ctools.cscript): | @@ -1542,16 +1503,16 @@ class csroot2caldb(ctools.cscript): | ||
| 1542 | hdu[name][0,index] = value * scale | 1503 | hdu[name][0,index] = value * scale |
| 1543 | 1504 | ||
| 1544 | # Collect boundary information | 1505 | # Collect boundary information |
| 1545 | - bd_eng = "ETRUE(%.4f-%.2f)TeV" % \ | 1506 | + bd_eng = 'ETRUE(%.4f-%.2f)TeV' % \ |
| 1546 | (pow(10.0, etrue.GetBinLowEdge(1)), | 1507 | (pow(10.0, etrue.GetBinLowEdge(1)), |
| 1547 | pow(10.0, etrue.GetBinUpEdge(netrue))) | 1508 | pow(10.0, etrue.GetBinUpEdge(netrue))) |
| 1548 | - bd_migra = "MIGRA(%.3f-%.3f)" % \ | 1509 | + bd_migra = 'MIGRA(%.3f-%.3f)' % \ |
| 1549 | (migra.GetBinLowEdge(1), | 1510 | (migra.GetBinLowEdge(1), |
| 1550 | migra.GetBinUpEdge(nmigra)) | 1511 | migra.GetBinUpEdge(nmigra)) |
| 1551 | - bd_off = "THETA(%.2f-%.2f)deg" % \ | 1512 | + bd_off = 'THETA(%.2f-%.2f)deg' % \ |
| 1552 | (offsets.GetBinLowEdge(1), | 1513 | (offsets.GetBinLowEdge(1), |
| 1553 | offsets.GetBinUpEdge(noffset)) | 1514 | offsets.GetBinUpEdge(noffset)) |
| 1554 | - bd_phi = "PHI(0-360)deg" | 1515 | + bd_phi = 'PHI(0-360)deg' |
| 1555 | bounds = [bd_eng, bd_migra, bd_off, bd_phi] | 1516 | bounds = [bd_eng, bd_migra, bd_off, bd_phi] |
| 1556 | 1517 | ||
| 1557 | # Return boundary information | 1518 | # Return boundary information |
| @@ -1561,7 +1522,7 @@ class csroot2caldb(ctools.cscript): | @@ -1561,7 +1522,7 @@ class csroot2caldb(ctools.cscript): | ||
| 1561 | # Public methods | 1522 | # Public methods |
| 1562 | def run(self): | 1523 | def run(self): |
| 1563 | """ | 1524 | """ |
| 1564 | - Run the script. | 1525 | + Run the script |
| 1565 | """ | 1526 | """ |
| 1566 | # Warn if ROOT module is missing | 1527 | # Warn if ROOT module is missing |
| 1567 | if not _has_root: | 1528 | if not _has_root: |
| @@ -1575,25 +1536,28 @@ class csroot2caldb(ctools.cscript): | @@ -1575,25 +1536,28 @@ class csroot2caldb(ctools.cscript): | ||
| 1575 | # Get parameters | 1536 | # Get parameters |
| 1576 | self._get_parameters() | 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 | # Translate ROOT to CALDB information | 1548 | # Translate ROOT to CALDB information |
| 1585 | if _has_root: | 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 | # Return | 1555 | # Return |
| 1592 | return | 1556 | return |
| 1593 | 1557 | ||
| 1594 | def execute(self): | 1558 | def execute(self): |
| 1595 | """ | 1559 | """ |
| 1596 | - Execute the script. | 1560 | + Execute the script |
| 1597 | """ | 1561 | """ |
| 1598 | # Open logfile | 1562 | # Open logfile |
| 1599 | self.logFileOpen() | 1563 | self.logFileOpen() |