Commit d5049a1a6fae633f25f4cfd19fdf6903e6831c0b

Authored by Jürgen Knödlseder
1 parent 5ce18429

Update to conform with agreed response format.

Showing 1 changed file with 456 additions and 89 deletions
scripts/cta_root2caldb.py
... ... @@ -2,11 +2,9 @@
2 2 # ==========================================================================
3 3 # This script generates IRFs in the CALDB format of HEASARC using ROOT 2D
4 4 # performance files.
5   -#
6   -# Requirements:
7   -# - pyroot
8   -#
9   -# Copyright (C) 2011 Jurgen Knodlseder
  5 +# -------------------------------------------------------------------------
  6 +# Copyright (C) 2011-2012 Juergen Knoedlseder
  7 +# -------------------------------------------------------------------------
10 8 #
11 9 # This program is free software: you can redistribute it and/or modify
12 10 # it under the terms of the GNU General Public License as published by
... ... @@ -21,6 +19,10 @@
21 19 # You should have received a copy of the GNU General Public License
22 20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
23 21 #
  22 +# -------------------------------------------------------------------------
  23 +# Requirements:
  24 +# - gammalib
  25 +# - pyroot
24 26 # ==========================================================================
25 27 from ROOT import TFile, TH1F, TH2F
26 28 from gammalib import *
... ... @@ -37,18 +39,27 @@ import os
37 39 class caldb():
38 40 """
39 41 """
40   - def __init__(self, conf, path=""):
  42 + def __init__(self, inst, obsid, path=""):
41 43 """
42   - Constructor.
  44 + CALDB constructor. The constructor will create one CALDB entry for
  45 + an observation.
  46 +
  47 + Parameters:
  48 + inst - Instrument string.
  49 + obsid - Observation ID string.
  50 + Keywords:
  51 + path - CALDB Root path.
43 52 """
44 53 # Store root path
45 54 self.path = path
46 55  
47 56 # Initialise some members
48 57 self.cif = None
  58 + self.irf = None
49 59 self.ea = None
50 60 self.psf = None
51 61 self.edisp = None
  62 + self.bgd = None
52 63 self.hdu_cif = None
53 64  
54 65 # Store UTC date of job execution
... ... @@ -56,7 +67,8 @@ class caldb():
56 67  
57 68 # Set CALDB information
58 69 self.cal_tel = "CTA"
59   - self.cal_inst = conf.upper()
  70 + self.cal_inst = inst.upper()
  71 + self.cal_obsid = obsid
60 72 self.cal_det = "NONE"
61 73 self.cal_flt = "NONE"
62 74 self.cal_class = "BCF"
... ... @@ -84,6 +96,11 @@ class caldb():
84 96 self.edisp_doc = "???"
85 97 self.edisp_bounds = [self.cal_version, self.cal_cut, self.cal_analysis]
86 98 self.edisp_desc = "CTA energy dispersion"
  99 + #
  100 + self.bgd_name = "BGD"
  101 + self.bgd_doc = "???"
  102 + self.bgd_bounds = [self.cal_version, self.cal_cut, self.cal_analysis]
  103 + self.bgd_desc = "CTA background"
87 104  
88 105 # Create directory structure
89 106 self.make_dirs()
... ... @@ -93,6 +110,7 @@ class caldb():
93 110  
94 111 def __del__(self):
95 112 """
  113 + Destructor. Close all FITS files.
96 114 """
97 115 # Close calibration
98 116 self.close()
... ... @@ -102,32 +120,50 @@ class caldb():
102 120  
103 121 def make_dirs(self):
104 122 """
  123 + Generate CALDB directory structure for one observation identifier.
  124 + The structure is given by
  125 +
  126 + data/<tel>/<inst>/bcf/<obsid>
  127 +
  128 + where <tel> is "cta" and <inst> is the instrument specified in the
  129 + CALDB constructor (the instrument may be used for different array
  130 + configurations).
  131 +
  132 + Parameters:
  133 + None
  134 + Keywords:
  135 + None
105 136 """
106 137 # Set base path
107 138 self.base_dir = "data"
108 139 self.base_dir += "/"+self.cal_tel.lower()
109 140 self.base_dir += "/"+self.cal_inst.lower()
110 141  
111   -
112 142 # Set directory names
113 143 self.bcf_dir = self.base_dir+"/bcf"
114   - self.ea_dir = self.bcf_dir+"/ea"
115   - self.psf_dir = self.bcf_dir+"/psf"
116   - self.edisp_dir = self.bcf_dir+"/edisp"
  144 + self.obs_dir = self.bcf_dir+"/"+self.cal_obsid
  145 + self.ea_dir = self.obs_dir
  146 + self.psf_dir = self.obs_dir
  147 + self.edisp_dir = self.obs_dir
  148 + self.bgd_dir = self.obs_dir
117 149  
118   - # Add path (if required)
  150 + # Optionally prefix path
119 151 if len(self.path) > 0:
120 152 self.base_path = self.path+"/"+self.base_dir
121 153 self.bcf_path = self.path+"/"+self.bcf_dir
  154 + self.obs_path = self.path+"/"+self.obs_dir
122 155 self.ea_path = self.path+"/"+self.ea_dir
123 156 self.psf_path = self.path+"/"+self.psf_dir
124 157 self.edisp_path = self.path+"/"+self.edisp_dir
  158 + self.bgd_path = self.path+"/"+self.bgd_dir
125 159 else:
126 160 self.base_path = self.base_dir
127 161 self.bcf_path = self.bcf_dir
  162 + self.obs_path = self.obs_dir
128 163 self.ea_path = self.ea_dir
129 164 self.psf_path = self.psf_dir
130 165 self.edisp_path = self.edisp_dir
  166 + self.bgd_path = self.bgd_dir
131 167  
132 168 # Create directory structure
133 169 if not os.path.isdir(self.ea_path):
... ... @@ -136,18 +172,36 @@ class caldb():
136 172 os.makedirs(self.psf_path)
137 173 if not os.path.isdir(self.edisp_path):
138 174 os.makedirs(self.edisp_path)
  175 + if not os.path.isdir(self.bgd_path):
  176 + os.makedirs(self.bgd_path)
139 177  
140 178 # Return
141 179 return
142 180  
143   - def open(self, name, clobber=True):
  181 + def open(self, version, split=False, clobber=True):
144 182 """
145   - Open existing or create new calibration.
  183 + Open existing or create new calibration. The actual version will put
  184 + all calibrations in the same file, although each part of the response
  185 + function will have its own logical name. We can thus easily modify
  186 + the script to put each calibration information in a separate file.
  187 +
  188 + Parameters:
  189 + version - Filename version
  190 + Keywords:
  191 + split - Split IRF over several files?
  192 + clobber - Overwrite existing files?
146 193 """
147 194 # Set calibrate file names
148   - self.ea_file = "ea_"+name+".fits"
149   - self.psf_file = "psf_"+name+".fits"
150   - self.edisp_file = "edisp_"+name+".fits"
  195 + if split:
  196 + self.ea_file = "ea_"+version+".fits"
  197 + self.psf_file = "psf_"+version+".fits"
  198 + self.edisp_file = "edisp_"+version+".fits"
  199 + self.bgd_file = "bgd_"+version+".fits"
  200 + else:
  201 + self.ea_file = "irf_"+version+".fits"
  202 + self.psf_file = "irf_"+version+".fits"
  203 + self.edisp_file = "irf_"+version+".fits"
  204 + self.bgd_file = "irf_"+version+".fits"
151 205  
152 206 # Open calibration database index
153 207 self.cif = GFits(self.base_path+"/caldb.indx", True)
... ... @@ -159,17 +213,42 @@ class caldb():
159 213 self.create_cif()
160 214 self.hdu_cif = self.cif.table("CIF")
161 215  
162   - # Open calibration files
163   - self.open_ea(self.ea_path+"/"+self.ea_file)
164   - self.open_psf(self.psf_path+"/"+self.psf_file)
165   - self.open_edisp(self.edisp_path+"/"+self.edisp_file)
  216 + # Set filenames
  217 + ea_filename = self.ea_path+"/"+self.ea_file
  218 + psf_filename = self.psf_path+"/"+self.psf_file
  219 + edisp_filename = self.edisp_path+"/"+self.edisp_file
  220 + bgd_filename = self.bgd_path+"/"+self.bgd_file
  221 +
  222 + # Open files
  223 + if split:
  224 + self.ea = GFits(ea_filename, True)
  225 + self.psf = GFits(psf_filename, True)
  226 + self.edisp = GFits(edisp_filename, True)
  227 + self.bgd = GFits(bgd_filename, True)
  228 + else:
  229 + self.irf = GFits(ea_filename, True)
  230 + self.ea = self.irf
  231 + self.psf = self.irf
  232 + self.edisp = self.irf
  233 + self.bgd = self.irf
  234 +
  235 + # Open HDUs
  236 + self.open_ea()
  237 + self.open_psf()
  238 + self.open_edisp()
  239 + self.open_bgd()
166 240  
167 241 # Return
168 242 return
169 243  
170 244 def close(self):
171 245 """
172   - Close calibration.
  246 + Close calibration FITS files.
  247 +
  248 + Parameters:
  249 + None
  250 + Keywords:
  251 + None
173 252 """
174 253 # Add information to CIF. We do this now as before we did not
175 254 # necessarily have all the information at hand (in particular
... ... @@ -181,31 +260,57 @@ class caldb():
181 260 self.cif.save(True)
182 261 self.cif.close()
183 262 self.cif = None
184   -
185   - # Close effective area
186   - if self.ea != None:
187   - self.ea.save(True)
188   - self.ea.close()
189   - self.ea = None
190   -
191   - # Close point spread function
192   - if self.psf != None:
193   - self.psf.save(True)
194   - self.psf.close()
195   - self.psf = None
196   -
197   - # Close energy dispersion
198   - if self.edisp != None:
199   - self.edisp.save(True)
200   - self.edisp.close()
  263 +
  264 + # If IRF file exists then close it now. All file pointers will
  265 + # be set to None
  266 + if self.irf != None:
  267 + self.irf.save(True)
  268 + self.irf.close()
  269 + self.irf = None
  270 + self.ea = None
  271 + self.psf = None
201 272 self.edisp = None
  273 + self.bgd = None
  274 +
  275 + # ... otherwise we have split files, so we have to close them
  276 + # all
  277 + else:
  278 +
  279 + # Close effective area file
  280 + if self.ea != None:
  281 + self.ea.save(True)
  282 + self.ea.close()
  283 + self.ea = None
  284 +
  285 + # Close point spread function file
  286 + if self.psf != None:
  287 + self.psf.save(True)
  288 + self.psf.close()
  289 + self.psf = None
  290 +
  291 + # Close energy dispersion file
  292 + if self.edisp != None:
  293 + self.edisp.save(True)
  294 + self.edisp.close()
  295 + self.edisp = None
  296 +
  297 + # Close background file
  298 + if self.bgd != None:
  299 + self.bgd.save(True)
  300 + self.bgd.close()
  301 + self.bgd = None
202 302  
203 303 # Return
204 304 return
205 305  
206 306 def create_cif(self):
207 307 """
208   - Create CIF extension in FITS file.
  308 + Create Calibration Index File (CIF) extension in CIF FITS file.
  309 +
  310 + Parameters:
  311 + None
  312 + Keywords:
  313 + None
209 314 """
210 315 # Create binary table
211 316 table = GFitsBinTable()
... ... @@ -248,6 +353,11 @@ class caldb():
248 353 def add_cif_info(self):
249 354 """
250 355 Add information to CIF extension.
  356 +
  357 + Parameters:
  358 + None
  359 + Keywords:
  360 + None
251 361 """
252 362 # Append 3 rows to CIF extension
253 363 self.hdu_cif.append_rows(3)
... ... @@ -310,20 +420,35 @@ class caldb():
310 420 self.hdu_cif["CAL_CBD"][row, n] = "NONE"
311 421 else:
312 422 self.hdu_cif["CAL_CBD"][row, n] = self.edisp_bounds[n]
  423 +
  424 + # Add background information
  425 + row = self.hdu_cif.nrows()-1
  426 + self.hdu_cif["CAL_DIR"][row] = self.bgd_dir
  427 + self.hdu_cif["CAL_FILE"][row] = self.bgd_file
  428 + self.hdu_cif["CAL_CNAM"][row] = self.bgd_name
  429 + self.hdu_cif["CAL_DESC"][row] = self.bgd_desc
  430 + self.hdu_cif["CAL_XNO"][row] = 1
  431 + for n in range(9):
  432 + if n >= len(self.bgd_bounds):
  433 + self.hdu_cif["CAL_CBD"][row, n] = "NONE"
  434 + else:
  435 + self.hdu_cif["CAL_CBD"][row, n] = self.bgd_bounds[n]
313 436  
314 437 # Return
315 438 return
316 439  
317   - def open_ea(self, filename):
  440 + def open_ea(self):
318 441 """
319 442 Open effective area extension. If no extension was found
320 443 then create one. We do not yet set any data as we don't
321 444 know the dimensions of the table yet.
322   - """
323   - # Open FITS file
324   - self.ea = GFits(filename, True)
325 445  
326   - # Get extensions. If they do not exist then create them now
  446 + Parameters:
  447 + None
  448 + Keywords:
  449 + None
  450 + """
  451 + # Get extension. If it does not exist then create it now.
327 452 try:
328 453 self.hdu_ea = self.ea.table("EFFECTIVE AREA")
329 454 except:
... ... @@ -346,16 +471,18 @@ class caldb():
346 471 # Return
347 472 return
348 473  
349   - def open_psf(self, filename):
  474 + def open_psf(self):
350 475 """
351 476 Open point spread function extension. If no extension was
352 477 found then create one. We do not yet set any data as we don't
353 478 know the dimensions of the table yet.
354   - """
355   - # Open FITS file
356   - self.psf = GFits(filename, True)
357 479  
358   - # Get extensions. If they do not exist then create them now
  480 + Parameters:
  481 + None
  482 + Keywords:
  483 + None
  484 + """
  485 + # Get extension. If it does not exist then create it now.
359 486 try:
360 487 self.hdu_psf = self.psf.table("POINT SPREAD FUNCTION")
361 488 except:
... ... @@ -378,16 +505,18 @@ class caldb():
378 505 # Return
379 506 return
380 507  
381   - def open_edisp(self, filename):
  508 + def open_edisp(self):
382 509 """
383 510 Open energy dispersion extension. If no extension was found
384 511 then create one. We do not yet set any data as we don't
385 512 know the dimensions of the table yet.
386   - """
387   - # Open FITS file
388   - self.edisp = GFits(filename, True)
389 513  
390   - # Get extensions. If they do not exist then create them now
  514 + Parameters:
  515 + None
  516 + Keywords:
  517 + None
  518 + """
  519 + # Get extension. If it does not exist then create it now.
391 520 try:
392 521 self.hdu_edisp = self.edisp.table("ENERGY DISPERSION")
393 522 except:
... ... @@ -410,9 +539,50 @@ class caldb():
410 539 # Return
411 540 return
412 541  
  542 + def open_bgd(self):
  543 + """
  544 + Open background extension. If no extension was found
  545 + then create one. We do not yet set any data as we don't
  546 + know the dimensions of the table yet.
  547 +
  548 + Parameters:
  549 + None
  550 + Keywords:
  551 + None
  552 + """
  553 + # Get extension. If it does not exist then create it now.
  554 + try:
  555 + self.hdu_bgd = self.bgd.table("BACKGROUND")
  556 + except:
  557 + # Create binary table
  558 + table = GFitsBinTable()
  559 +
  560 + # Set extension name
  561 + table.extname("BACKGROUND")
  562 +
  563 + # Set OGIP keywords
  564 + self.set_ogip_keywords(table, self.bgd_doc, \
  565 + ["RESPONSE", self.bgd_name])
  566 +
  567 + # Append table
  568 + self.bgd.append(table)
  569 +
  570 + # Get extension
  571 + self.hdu_bgd = self.bgd.table("BACKGROUND")
  572 +
  573 + # Return
  574 + return
  575 +
413 576 def set_ogip_keywords(self, hdu, hdudoc, hduclas):
414 577 """
415 578 Set standard OGIP keywords for extension.
  579 +
  580 + Parameters:
  581 + hdu - Header Data Unit.
  582 + hdudoc - Documentation reference string
  583 + hduclas - Array of HDUCLAS fields
  584 + Keywords:
  585 + None
416 586 """
417 587 # Set keywords
418 588 hdu.card("ORIGIN", "IRAP", "Name of organization making this file")
... ... @@ -433,12 +603,17 @@ class caldb():
433 603 def make_2D(self, array, hdu, name, unit, scale=1.0):
434 604 """
435 605 Make 2D matrix as function of energy and offset angle from a
436   - ROOT 2D histogram.
  606 + ROOT 2D histogram. If the HDU has already the energy and
  607 + offset angle columns, this method will simply add another data
  608 + column.
  609 + If name==None, the method will not append any data column.
437 610  
438 611 Parameters:
439   - array - ROOT 2D histgram.
  612 + array - ROOT 2D histogram.
440 613 hdu - FITS HDU.
441   - Keyword:
  614 + name - Data column name.
  615 + unit - Data unit.
  616 + Keywords:
442 617 scale - Scaling factor for histogram values.
443 618 """
444 619 # Extract energy and offset angle vectors
... ... @@ -485,7 +660,7 @@ class caldb():
485 660 hdu["THETA_HI"][0,ioff] = o_hi
486 661 #
487 662 # "NAME"
488   - if not hdu.hascolumn(name):
  663 + if name != None and not hdu.hascolumn(name):
489 664 hdu.append_column(GFitsTableFloatCol(name, 1, neng*noffset))
490 665 hdu[name].unit(unit)
491 666 hdu[name].dim([neng, noffset])
... ... @@ -515,44 +690,217 @@ class caldb():
515 690 Parameters:
516 691 filename - ROOT 2D performance filename.
517 692 """
518   - # Open performance file
  693 + # Open ROOT performance file
519 694 file = TFile(filename)
520 695  
521   - # Allocate ROOT 2D array
522   - array = TH2F()
  696 + # Create effective area
  697 + self.root2ea(file)
  698 +
  699 + # Create point spread function
  700 + self.root2psf(file)
  701 +
  702 + # Create energy dispersion
  703 + self.root2edisp(file)
  704 +
  705 + # Create background
  706 + self.root2bgd(file)
  707 +
  708 + # Return
  709 + return
523 710  
524   - # Make 2D effective 80% area
  711 + def root2ea(self, file):
  712 + """
  713 + Translate ROOT to CALDB effective area extension. The following ROOT
  714 + histograms are used:
  715 +
  716 + EffectiveAreaEtrue_offaxis -> EFFAREA
  717 + EffectiveArea_offaxis -> EFFAREA_RECO
  718 +
  719 + Parameters:
  720 + file - ROOT file.
  721 + Keywords:
  722 + None
  723 + """
  724 + # Continue only if effective area HDU has been opened
525 725 if self.hdu_ea != None:
526   - file.GetObject("EffectiveArea80_offaxis", array)
527   - bounds = self.make_2D(array, self.hdu_ea, "EFFAREA", "m2", scale=1.0/0.8)
  726 +
  727 + # Allocate ROOT 2D arrays
  728 + etrue = TH2F()
  729 + ereco = TH2F()
  730 + file.GetObject("EffectiveAreaEtrue_offaxis", etrue)
  731 + file.GetObject("EffectiveArea_offaxis", ereco)
  732 + #print etrue.GetXaxis().GetBinLowEdge(1), etrue.GetXaxis().GetBinUpEdge(etrue.GetXaxis().GetNbins())
  733 + #print ereco.GetXaxis().GetBinLowEdge(1), ereco.GetXaxis().GetBinUpEdge(ereco.GetXaxis().GetNbins())
  734 +
  735 + # Rebin etrue histogram
  736 + etrue.RebinX(10)
  737 + neng = etrue.GetXaxis().GetNbins()
  738 + noffset = etrue.GetYaxis().GetNbins()
  739 + for ioff in range(noffset):
  740 + for ieng in range(neng):
  741 + value = etrue.GetBinContent(ieng+1,ioff+1) / 10.0
  742 + etrue.SetBinContent(ieng+1,ioff+1,value)
  743 +
  744 + # Write boundaries (use Ereco boundaries)
  745 + bounds = self.make_2D(ereco, self.hdu_ea, None, "m2")
528 746 for b in bounds:
529 747 self.ea_bounds.append(b)
530 748 self.set_cif_keywords(self.hdu_ea, self.ea_name, \
531 749 self.ea_bounds, self.ea_desc)
532 750  
533   - # Make 2D 68% point spread function
  751 + # EFFAREA
  752 + self.make_2D(etrue, self.hdu_ea, "EFFAREA", "m2")
  753 +
  754 + # EFFAREA_RECO
  755 + self.make_2D(ereco, self.hdu_ea, "EFFAREA_RECO", "m2")
  756 +
  757 + # Return
  758 + return
  759 +
  760 + def root2psf(self, file):
  761 + """
  762 + Translate ROOT to CALDB point spread function extension. The following
  763 + ROOT histograms are used:
  764 +
  765 + 1/(2*pi*SIGMA_1) -> SCALE
  766 + AngRes_offaxis -> SIGMA_1 (scaling: 1/0.8)
  767 + 0.0 -> AMPL_2
  768 + 0.0 -> SIGMA_2
  769 + 0.0 -> AMPL_3
  770 + 0.0 -> SIGMA_3
  771 +
  772 + Parameters:
  773 + file - ROOT file.
  774 + Keywords:
  775 + None
  776 + """
  777 + # Continue only if point spread function HDU has been opened
534 778 if self.hdu_psf != None:
535   - file.GetObject("AngRes_offaxis", array)
536   - bounds = self.make_2D(array, self.hdu_psf, "R68", "deg")
  779 +
  780 + # Allocate ROOT 2D array
  781 + r68 = TH2F()
  782 +
  783 + # Read 68% containment histogram
  784 + file.GetObject("AngRes_offaxis", r68)
  785 + neng = r68.GetXaxis().GetNbins()
  786 + noffset = r68.GetYaxis().GetNbins()
  787 +
  788 + # Compute scale histogram
  789 + scale = r68.Clone()
  790 + for ioff in range(noffset):
  791 + for ieng in range(neng):
  792 + integral = 2.0 * math.pi * r68.GetBinContent(ieng+1,ioff+1)
  793 + if integral > 0.0:
  794 + value = 1.0 / integral
  795 + else:
  796 + value = 0.0
  797 + scale.SetBinContent(ieng+1,ioff+1,value)
  798 +
  799 + # Set zero histogram
  800 + zero = r68.Clone()
  801 + for ioff in range(noffset):
  802 + for ieng in range(neng):
  803 + zero.SetBinContent(ieng+1,ioff+1,0.0)
  804 +
  805 + # Set boundaries
  806 + bounds = self.make_2D(r68, self.hdu_psf, None, "deg")
537 807 for b in bounds:
538 808 self.psf_bounds.append(b)
539 809 self.set_cif_keywords(self.hdu_psf, self.psf_name, \
540 810 self.psf_bounds, self.psf_desc)
541 811  
542   - # Make 2D 80% point spread function
543   - if self.hdu_psf != None:
544   - file.GetObject("AngRes80_offaxis", array)
545   - self.make_2D(array, self.hdu_psf, "R80", "deg")
  812 + # SCALE
  813 + self.make_2D(scale, self.hdu_psf, "SCALE", "")
  814 +
  815 + # SIGMA_1
  816 + self.make_2D(r68, self.hdu_psf, "SIGMA_1", "deg")
546 817  
547   - # Make 2D energy resolution
  818 + # AMPL_2
  819 + self.make_2D(zero, self.hdu_psf, "AMPL_2", "")
  820 +
  821 + # SIGMA_2
  822 + self.make_2D(zero, self.hdu_psf, "SIGMA_2", "deg")
  823 +
  824 + # AMPL_3
  825 + self.make_2D(zero, self.hdu_psf, "AMPL_3", "")
  826 +
  827 + # SIGMA_3
  828 + self.make_2D(zero, self.hdu_psf, "SIGMA_3", "deg")
  829 +
  830 + # Return
  831 + return
  832 +
  833 + def root2edisp(self, file):
  834 + """
  835 + Translate ROOT to CALDB energy dispersion extension. The following ROOT
  836 + histograms are used:
  837 +
  838 + ERes_offaxis -> ERES
  839 + Ebias_offaxis -> EBIAS
  840 +
  841 + Parameters:
  842 + file - ROOT file.
  843 + Keywords:
  844 + None
  845 + """
  846 + # Continue only if energy dispersion HDU has been opened
548 847 if self.hdu_edisp != None:
549   - file.GetObject("ERes", array)
550   - bounds = self.make_2D(array, self.hdu_edisp, "ERES68", "")
  848 +
  849 + # Allocate ROOT 2D array
  850 + eres = TH2F()
  851 + ebias = TH2F()
  852 + file.GetObject("ERes_offaxis", eres)
  853 + file.GetObject("Ebias_offaxis", ebias)
  854 +
  855 + # Set boundaries
  856 + bounds = self.make_2D(eres, self.hdu_edisp, None, "deg")
551 857 for b in bounds:
552 858 self.edisp_bounds.append(b)
553 859 self.set_cif_keywords(self.hdu_edisp, self.edisp_name, \
554 860 self.edisp_bounds, self.edisp_desc)
555   -
  861 +
  862 + # ERES
  863 + self.make_2D(eres, self.hdu_edisp, "ERES", "Ereco/Etrue")
  864 +
  865 + # EBIAS
  866 + self.make_2D(ebias, self.hdu_edisp, "EBIAS", "Ereco/Etrue")
  867 +
  868 + # Return
  869 + return
  870 +
  871 + def root2bgd(self, file):
  872 + """
  873 + Translate ROOT to CALDB background extension. The following ROOT
  874 + histograms are used:
  875 +
  876 + BGRatePerSqDeg_offaxis -> BGD
  877 + BGRatePerSqDeg_offaxis -> BGD_RECO
  878 +
  879 + Parameters:
  880 + file - ROOT file.
  881 + Keywords:
  882 + None
  883 + """
  884 + # Continue only if background HDU has been opened
  885 + if self.hdu_bgd != None:
  886 +
  887 + # Allocate ROOT 2D array
  888 + array = TH2F()
  889 + file.GetObject("BGRatePerSqDeg_offaxis", array)
  890 +
  891 + # Set boundaries
  892 + bounds = self.make_2D(array, self.hdu_bgd, None, "deg")
  893 + for b in bounds:
  894 + self.bgd_bounds.append(b)
  895 + self.set_cif_keywords(self.hdu_bgd, self.bgd_name, \
  896 + self.bgd_bounds, self.bgd_desc)
  897 +
  898 + # BGD
  899 + self.make_2D(array, self.hdu_bgd, "BGD", "")
  900 +
  901 + # BGD_RECO
  902 + self.make_2D(array, self.hdu_bgd, "BGD_RECO", "")
  903 +
556 904 # Return
557 905 return
558 906  
... ... @@ -589,22 +937,41 @@ class caldb():
589 937 #==========================#
590 938 if __name__ == '__main__':
591 939 """
592   - This script translates a ROOT 2D performance file in a CALDB compliant
593   - CTA response.
  940 + This script translates a CTA ROOT 2D performance files in a CALDB compliant
  941 + CTA response. The script will create the response for 3 observations to
  942 + illustrate the run-wise file structure.
  943 +
  944 + The CTA ROOT 2D performance files contain the following histograms:
  945 + - DiffSens_offaxis (2D) - Differential sensitivity
  946 + - EffectiveArea_offaxis (2D) - Effective area (full containment?, reco energy?)
  947 + - EffectiveArea80_offaxis (2D) - Effective area for 80% source containment
  948 + - AngRes_offaxis (2D) - Angular resolution 68% containment
  949 + - AngRes80_offaxis (2D) - Angular resolution 80% containment
  950 + - BGRatePerSqDeg_offaxis (2D) - Background rate per square degree
  951 + - BGRate_offaxis (2D) - Background rate
  952 + - EffectiveAreaEtrue_offaxis (2D) - Effective area in true energy (finer bins)
  953 + - MigMatrix_offaxis (3D)
  954 + - EestOverEtrue_offaxis (3D)
  955 + - ERes_offaxis (2D) - Energy Resolution
  956 + - Ebias_offaxis (2D) - Energy bias
594 957 """
595 958 # Set ROOT filename
596   - #path = "/Users/jurgen/Documents/Travail/Projects/CTA/WP-MC/root/IFAEOffaxis"
597   - #irf = "SubarrayE_offaxis.root"
598   - path = "/Users/jurgen/Documents/Travail/Projects/CTA/WP-MC/root/IFAEOffaxisPerformanceBEI_Nov2011"
599   - irf = "SubarrayE_IFAE_50hours_20111121_offaxis.root"
  959 + path = "/Users/jurgen/Documents/Travail/Projects/CTA/WP-MC/root/IFAEOffaxisPerformanceBEI_May2012"
  960 + irf = "SubarrayE_IFAE_50hours_20120510_offaxis.root"
600 961 filename = path+"/"+irf
601 962  
602   - # Allocate caldb
603   - db = caldb("E")
  963 + # Set observation identifiers
  964 + obsids = ["000001", "000002", "000003"]
  965 +
  966 + # Generate CALDB entries, one for each observation (or run)
  967 + for obsid in obsids:
  968 +
  969 + # Allocate caldb
  970 + db = caldb("E", obsid)
604 971  
605   - # Open calibration
606   - db.open("test")
  972 + # Open calibration
  973 + db.open("test")
607 974  
608   - # Translate ROOT to CALDB information
609   - db.root2caldb(filename)
  975 + # Translate ROOT to CALDB information
  976 + db.root2caldb(filename)
610 977  
611 978 \ No newline at end of file
... ...