Commit 2c013235982beb1965ae57418469c12c539e5b70

Authored by Michael Mayer
1 parent 4314a78b

Added csobs2caldb cscript and added reference doc

cscripts/Makefile.am
... ... @@ -7,12 +7,12 @@ binscripts = tsmerge.py
7 7 pythonscripts = __init__.py \
8 8 cspull.py cssens.py cstsdist.py cscaldb.py csresmap.py \
9 9 cshessobs.py csobsdef.py csspec.py cslightcrv.py \
10   - csinfo.py \
  10 + csinfo.py csobs2caldb.py \
11 11 obsutils.py
12 12  
13 13 # Scripts for which symbolic links will be created in bindir
14 14 linkscripts = cspull cssens cstsdist cscaldb csresmap \
15   - cshessobs csobsdef csspec cslightcrv \
  15 + cshessobs csobsdef csspec cslightcrv csobs2caldb \
16 16 csinfo
17 17  
18 18 # Distribute scripts
... ...
cscripts/csobs2caldb.py 0 → 100755
  1 +#!/usr/bin/env python
  2 +# ==========================================================================
  3 +# Generation of an caldb entry from general IACT observation.
  4 +#
  5 +# Copyright (C) 2015 Michael Mayer
  6 +#
  7 +# This program is free software: you can redistribute it and/or modify
  8 +# it under the terms of the GNU General Public License as published by
  9 +# the Free Software Foundation, either version 3 of the License, or
  10 +# (at your option) any later version.
  11 +#
  12 +# This program is distributed in the hope that it will be useful,
  13 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15 +# GNU General Public License for more details.
  16 +#
  17 +# You should have received a copy of the GNU General Public License
  18 +# along with this program. If not, see <http://www.gnu.org/licenses/>.
  19 +#
  20 +# ==========================================================================
  21 +import gammalib
  22 +import ctools
  23 +import sys
  24 +import os
  25 +import datetime
  26 +
  27 +
  28 +# =============== #
  29 +# cshessobs class #
  30 +# =============== #
  31 +class csobs2caldb(ctools.cscript):
  32 + """
  33 + This class implements the creation of a caldb entry for a particular observation,
  34 + which might be helpful for running simulations for current IACTs.
  35 + It takes an observation definition file as input and uses the first observation
  36 + to create a caldb entry which can be used for simulations and sensitivity studies later on
  37 + """
  38 + def __init__(self, *argv):
  39 + """
  40 + Constructor.
  41 + """
  42 + # Set name
  43 + self.name = "csobs2caldb"
  44 + self.version = "0.1.0"
  45 +
  46 + # Make sure that parfile exists
  47 + file = self.parfile()
  48 +
  49 + # Initialise application
  50 + if len(argv) == 0:
  51 + ctools.cscript.__init__(self, self.name, self.version)
  52 + elif len(argv) == 1:
  53 + ctools.cscript.__init__(self, self.name, self.version, *argv)
  54 + else:
  55 + raise TypeError("Invalid number of arguments given.")
  56 +
  57 + # Set logger properties
  58 + self.log_header()
  59 + self.log.date(True)
  60 +
  61 + # Return
  62 + return
  63 +
  64 + def __del__(self):
  65 + """
  66 + Destructor.
  67 + """
  68 + # Return
  69 + return
  70 +
  71 + def parfile(self):
  72 + """
  73 + Check if parfile exists. If parfile does not exist then create a
  74 + default parfile. This kluge avoids shipping the cscript with a parfile.
  75 + """
  76 +
  77 + # Set parfile name
  78 + parfile = self.name+".par"
  79 +
  80 + try:
  81 + pars = gammalib.GApplicationPars(parfile)
  82 + except:
  83 + # Signal that parfile was not found
  84 + print("Parfile \""+parfile+"\" not found. Create default parfile.")
  85 +
  86 + # Create default parfile
  87 + pars = gammalib.GApplicationPars()
  88 + pars.append(gammalib.GApplicationPar("inobs","f","a","obs.xml","","","Input observation definition file"))
  89 + pars.append(gammalib.GApplicationPar("rspname","s","a","NONE","","","Response output name (e.g. Zenith50)"))
  90 + pars.append(gammalib.GApplicationPar("outfile","f","h","irf_file.fits","","","Output IRF file name"))
  91 + pars.append(gammalib.GApplicationPar("index","i","h","0","","","Index of observation to be used from XML file"))
  92 + pars.append_standard()
  93 + pars.append(gammalib.GApplicationPar("logfile","f","h","csobs2caldb.log","","","Log filename"))
  94 + pars.save(parfile)
  95 +
  96 + # Return
  97 + return
  98 +
  99 + def get_parameters(self):
  100 + """
  101 + Get parameters from parfile and setup the observation.
  102 + """
  103 + # Get parameters
  104 + self.inobs = self["inobs"].filename()
  105 + self.obs = gammalib.GObservations(self.inobs)
  106 +
  107 + # Get index of observation to be used (0=default)
  108 + inx = self["index"].integer()
  109 +
  110 + # Get observation
  111 + self.observation = self.obs[inx]
  112 +
  113 + # Set instrument mission to cta
  114 + # This is to be compliant with standard gammalib caldb
  115 + self.m_mission = "CTA"
  116 +
  117 + # Get instrument name
  118 + self.m_instrument = self.observation.instrument()
  119 +
  120 + # Get config and file name
  121 + self.m_rspname = self["rspname"].string()
  122 + self.m_outfile = self["outfile"].filename()
  123 +
  124 + # Make sure we have a cta observation
  125 + if not self.observation.classname() == "GCTAObservation":
  126 + raise gammalib.Exception.runtime_error("Input observation not of type \"GCTAObservation\"")
  127 +
  128 + # Make sure we have an irf response
  129 + if not self.observation.response().classname() == "GCTAResponseIrf":
  130 + raise gammalib.Exception.runtime_error("Response of input observation not of type \"GCTAResponseIrf\"")
  131 +
  132 + # Get other parameters
  133 + self.m_clobber = self["clobber"].boolean()
  134 +
  135 + # Return
  136 + return
  137 +
  138 +
  139 + def make_irf_file(self):
  140 +
  141 + # retrieve response component
  142 + rsp = self.observation.response()
  143 +
  144 + # Open FITS files of response components
  145 + fits_aeff = gammalib.GFits(rsp.aeff().filename())
  146 + fits_psf = gammalib.GFits(rsp.psf().filename())
  147 + fits_edisp = gammalib.GFits(rsp.edisp().filename())
  148 + fits_bkg = gammalib.GFits(rsp.background().filename())
  149 +
  150 + # Bundle IRFs into one file
  151 + fits = gammalib.GFits()
  152 + fits.append(fits_aeff["EFFECTIVE AREA"])
  153 + fits.append(fits_psf["POINT SPREAD FUNCTION"])
  154 + fits.append(fits_edisp["ENERGY DISPERSION"])
  155 + fits.append(fits_bkg["BACKGROUND"])
  156 +
  157 + # Return fits file
  158 + return fits
  159 +
  160 +
  161 + def make_caldb_index(self):
  162 +
  163 + # Open calibration database index
  164 + indx_file = self.base_dir+"/caldb.indx"
  165 +
  166 + # Check if indx file exists (create if not existent)
  167 + if os.path.isfile(indx_file):
  168 + cif = gammalib.GFits(indx_file)
  169 + else:
  170 + cif = gammalib.GFits(indx_file, True)
  171 +
  172 + # Retrieve "CIF" table
  173 + if cif.contains("CIF"):
  174 + table = cif.table("CIF")
  175 + else:
  176 + # Create binary table if not available
  177 + bintable = gammalib.GFitsBinTable()
  178 + bintable.extname("CIF")
  179 + bintable.card("CIFVERSN", "1992a", "Version of CIF format")
  180 + cif.append(bintable)
  181 +
  182 + table = cif.table("CIF")
  183 +
  184 + # Copied from cta_root2caldb.py
  185 + # Attach columns. Reference: CAL/GEN/92-008
  186 + table.append(gammalib.GFitsTableStringCol("TELESCOP", 0, 10))
  187 + table.append(gammalib.GFitsTableStringCol("INSTRUME", 0, 10))
  188 + table.append(gammalib.GFitsTableStringCol("DETNAM", 0, 20))
  189 + table.append(gammalib.GFitsTableStringCol("FILTER", 0, 10))
  190 + table.append(gammalib.GFitsTableStringCol("CAL_DEV", 0, 20))
  191 + table.append(gammalib.GFitsTableStringCol("CAL_DIR", 0, 70))
  192 + table.append(gammalib.GFitsTableStringCol("CAL_FILE", 0, 40))
  193 + table.append(gammalib.GFitsTableStringCol("CAL_CLAS", 0, 3))
  194 + table.append(gammalib.GFitsTableStringCol("CAL_DTYP", 0, 4))
  195 + table.append(gammalib.GFitsTableStringCol("CAL_CNAM", 0, 20))
  196 + table.append(gammalib.GFitsTableStringCol("CAL_CBD", 0, 70, 9))
  197 + table.append(gammalib.GFitsTableShortCol("CAL_XNO", 0))
  198 + table.append(gammalib.GFitsTableStringCol("CAL_VSD", 0, 10))
  199 + table.append(gammalib.GFitsTableStringCol("CAL_VST", 0, 8))
  200 + table.append(gammalib.GFitsTableDoubleCol("REF_TIME", 0))
  201 + table.append(gammalib.GFitsTableShortCol("CAL_QUAL", 0))
  202 + table.append(gammalib.GFitsTableStringCol("CAL_DATE", 0, 8))
  203 + table.append(gammalib.GFitsTableStringCol("CAL_DESC", 0, 70))
  204 +
  205 + # Check if output config already exist
  206 + has_config = False
  207 + row_index = -1
  208 + for caldir in table["CAL_DIR"]:
  209 + row_index += 1
  210 + if caldir == self.cal_dir:
  211 + has_config = True
  212 + break
  213 +
  214 + # Create columns if not available
  215 + if not has_config:
  216 + # Append 4 rows to CIF extension
  217 + table.append_rows(4)
  218 + row_index = table.nrows()
  219 + else:
  220 + row_index += 4
  221 +
  222 + # Add generic information for these 4 rows
  223 + for i in range(4):
  224 +
  225 + # Set row number
  226 + row = i + row_index-4
  227 +
  228 + now = str(datetime.datetime.now())
  229 + today, time = now.split()
  230 +
  231 + # Set element
  232 + table["TELESCOP"][row] = self.m_mission
  233 + table["INSTRUME"][row] = self.m_instrument
  234 + table["DETNAM"][row] = "NONE"
  235 + table["FILTER"][row] = "NONE"
  236 + table["CAL_DEV"][row] = "ONLINE"
  237 + table["CAL_CLAS"][row] = "BCF"
  238 + table["CAL_DTYP"][row] = "DATA"
  239 + table["CAL_VSD"][row] = today
  240 + table["CAL_VST"][row] = time.split(".")[0]
  241 + table["REF_TIME"][row] = 51544.0
  242 + table["CAL_QUAL"][row] = 0
  243 + table["CAL_CBD"][row] = "NAME("+self.m_rspname+")"
  244 + table["CAL_DATE"][row] = today.replace("-","/")[2:]
  245 + table["CAL_DIR"][row] = self.cal_dir
  246 + table["CAL_FILE"][row] = self.m_outfile
  247 +
  248 + # Add effective area information
  249 + row = row_index-4
  250 + table["CAL_CNAM"][row] = "EFF_AREA"
  251 + table["CAL_DESC"][row] = self.m_instrument+" effective area"
  252 +
  253 + # Add point spread function information
  254 + row = row_index-3
  255 + table["CAL_CNAM"][row] = "RPSF"
  256 + table["CAL_DESC"][row] = self.m_instrument+" point spread function"
  257 +
  258 + # Add energy dispersion information
  259 + row = row_index-2
  260 + table["CAL_CNAM"][row] = "EDISP"
  261 + table["CAL_DESC"][row] = self.m_instrument+" energy dispersion"
  262 +
  263 + # Add background information
  264 + row = row_index-1
  265 + table["CAL_CNAM"][row] = "BGD"
  266 + table["CAL_DESC"][row] = self.m_instrument+" background"
  267 +
  268 + # Return CIF FITS file
  269 + return cif
  270 +
  271 +
  272 + def make_dirs(self):
  273 +
  274 + # Create gammalib Caldb
  275 + caldb = gammalib.GCaldb()
  276 +
  277 + # Set calibration directory
  278 + self.cal_dir = "data"
  279 + self.cal_dir += "/"+self.m_mission.lower()
  280 + self.cal_dir += "/"+self.m_instrument.lower()
  281 + self.cal_dir += "/bcf/"+self.m_rspname
  282 +
  283 + # Set absolute path
  284 + self.base_dir = caldb.rootdir() +"/data"
  285 + self.base_dir += "/"+self.m_mission.lower()
  286 + self.base_dir += "/"+self.m_instrument.lower()
  287 +
  288 + # Set directory for irf file
  289 + self.rsp_dir = caldb.rootdir() + "/" + self.cal_dir
  290 +
  291 + # Create directories and log information
  292 + if not os.path.isdir(self.rsp_dir):
  293 + if self.logExplicit():
  294 + self.header3("Creating directory \""+self.rsp_dir+"\"")
  295 + os.makedirs(self.rsp_dir)
  296 + else:
  297 + if self.logExplicit():
  298 + self.log("Directory \""+self.rsp_dir+"\" already exists\n")
  299 + self.log("\n")
  300 +
  301 + # Return
  302 + return
  303 +
  304 +
  305 + def run(self):
  306 + """
  307 + Run the script.
  308 + """
  309 + # Switch screen logging on in debug mode
  310 + if self.logDebug():
  311 + self.log.cout(True)
  312 +
  313 + # Get parameters
  314 + self.get_parameters()
  315 +
  316 + # Write input parameters into logger
  317 + if self.logTerse():
  318 + self.log_parameters()
  319 + self.log("\n")
  320 + self.log.header1("Creating directory structure")
  321 + self.log("\n")
  322 +
  323 + # Create directory structure
  324 + self.make_dirs()
  325 +
  326 + # Logging
  327 + if self.logTerse():
  328 + self.log.header1("Updating calibration database")
  329 + self.log("\n")
  330 +
  331 + # Create/update calibration database
  332 + self.caldb_inx = self.make_caldb_index()
  333 +
  334 + # Logging
  335 + if self.logTerse():
  336 + self.log.header1("Creating response file")
  337 + self.log("\n")
  338 +
  339 + # Create IRF file
  340 + self.irf_fits = self.make_irf_file()
  341 +
  342 + # Return
  343 + return
  344 +
  345 + def save(self):
  346 +
  347 + # Save caldb index file
  348 + self.caldb_inx.save(self.m_clobber)
  349 +
  350 + # Save response file
  351 + self.irf_fits.saveto(self.rsp_dir + "/" + self.m_outfile, self.m_clobber)
  352 +
  353 + # Return
  354 + return
  355 +
  356 + def execute(self):
  357 + """
  358 + Execute the script.
  359 + """
  360 + # Run the script
  361 + self.run()
  362 +
  363 + # Save to disk
  364 + self.save()
  365 +
  366 + # Return
  367 + return
  368 +
  369 +# ======================== #
  370 +# Main routine entry point #
  371 +# ======================== #
  372 +if __name__ == '__main__':
  373 + """
  374 + Generates caldb entry.
  375 + """
  376 + # Create instance of application
  377 + app = csobs2caldb(sys.argv)
  378 +
  379 + # Open logfile
  380 + app.logFileOpen()
  381 +
  382 + # Execute application
  383 + app.execute()
... ...
doc/source/reference_manual/csob2caldb.rst 0 → 100644
  1 +.. _csobs2caldb: csobs2caldb ======= Creates an calibration database entry from an input observation definition file. Synopsis -------- This scripts creates a calibration database entry from an input observation container. The caldb entry can be used for simulations later on. The script further takes the name of the respone as input, which allows the user to specify a generic name for this kind of observation. An example could be 'zenith50_azimuth0' referring to the parameter characterising the IRFs. In order to check the available caldb entries, the use of the cscaldb script is recommended afterwards General parameters ------------------ ``inobs [file]`` Input observation definition XML file. ``rspname [string]`` Response output name (e.g. Zenith50) ``(outfile = irf_file.fits) [file]`` Output IRF file name ``(index = 0) [integer]`` Index of observation to be used from XML file Standard parameters ------------------- ``(chatter = 2) [integer]`` Verbosity of the executable: chatter = 0: no information will be logged chatter = 1: only errors will be logged chatter = 2: errors and actions will be logged chatter = 3: report about the task execution chatter = 4: detailed report about the task execution ``(clobber = yes) [boolean]`` Specifies whether an existing output should be overwritten. ``(debug = no) [boolean]`` Enables debug mode. In debug mode the executable will dump any log file output to the console. ``(mode = ql) [string]`` Mode of automatic parameters (default is "ql", i.e. "query and learn"). Related tools ------------- cscaldb
0 2 \ No newline at end of file
... ...