Commit fe0e6e0b359f90a69cf0c561276ffcb86f7e6fce

Authored by Jürgen Knödlseder
2 parents db16ee43 44a68b8f

Merge branch 'integration' into devel

# Conflicts:
#	README
.gitignore
@@ -70,6 +70,8 @@ test/*.trs @@ -70,6 +70,8 @@ test/*.trs
70 test/test_cscripts.sh 70 test/test_cscripts.sh
71 test/reports/*.xml 71 test/reports/*.xml
72 test/butterfly.txt 72 test/butterfly.txt
  73 +test/model.reg
  74 +test/obs.reg
73 examples/*.fits 75 examples/*.fits
74 examples/*.xml 76 examples/*.xml
75 examples/*.dat 77 examples/*.dat
ChangeLog
  1 +2015-11-24 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu>
  2 +
  3 + * Version 1.1.0 released
  4 + ========================
  5 +
  6 + Add csobsinfo, csmodelinfo, csmodelmerge, cstsmapmerge (#1578)
  7 +
  8 +
1 2015-11-19 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu> 9 2015-11-19 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu>
2 10
3 * Version 1.0.0 released 11 * Version 1.0.0 released
1 -New Features and Important Changes in ctools 1.0.0 1 +New Features and Important Changes in ctools 1.1.0
2 2
3 Author(s) : Juergen Knoedlseder 3 Author(s) : Juergen Knoedlseder
4 4
5 -19 November 2015 5 +24 November 2015
6 6
7 7
8 1. Introduction 8 1. Introduction
9 --------------- 9 ---------------
10 This document briefly summarizes executable by executable the most important 10 This document briefly summarizes executable by executable the most important
11 changes made since the last release of ctools. The code complies to GammaLib 11 changes made since the last release of ctools. The code complies to GammaLib
12 -version 1.0.0 or above. 12 +version 1.1.0 or above.
13 13
14 14
15 2. Configuration 15 2. Configuration
@@ -82,8 +82,7 @@ None @@ -82,8 +82,7 @@ None
82 82
83 15. ctcubemask - CTA cube filtering 83 15. ctcubemask - CTA cube filtering
84 ----------------------------------- 84 -----------------------------------
85 -Allow to ignore the spatial filtering by specifying NONE parameters for "ra",  
86 -"dec" or "rad". 85 +None
87 86
88 87
89 16. ctbutterfly - Generate butterfly diagrams 88 16. ctbutterfly - Generate butterfly diagrams
@@ -103,10 +102,11 @@ None @@ -103,10 +102,11 @@ None
103 102
104 19. cscripts 103 19. cscripts
105 ------------ 104 ------------
106 -The csspec script now handled correctly stacked data. Dependent on the  
107 -requested energy binning, it selects for each spectral energy bin the  
108 -relevant energy bins from the counts cube and performs a maximum likelihood  
109 -analysis. 105 +The following scripts have been added:
  106 +- csobsinfo: dump information in observation container
  107 +- csmodelinfo: dump information in model container
  108 +- csmodelmerge: merge model containers into single container
  109 +- cstsmapmerge: merge sliced TS map into single map
110 110
111 111
112 20. Examples 112 20. Examples
1 ctools information 1 ctools information
2 ================== 2 ==================
3 -Version: 1.0.0 (21 November 2015) 3 +Version: 1.1.0 (24 November 2015)
4 Author: Juergen Knodlseder (jurgen.knodlseder@irap.omp.eu) 4 Author: Juergen Knodlseder (jurgen.knodlseder@irap.omp.eu)
5 -GammaLib dependency: 1.0.0 5 +GammaLib dependency: 1.1.0
6 6
7 7
8 License information 8 License information
configure.ac
@@ -29,7 +29,7 @@ @@ -29,7 +29,7 @@
29 ############################################################################# 29 #############################################################################
30 # Initialisation # 30 # Initialisation #
31 ############################################################################# 31 #############################################################################
32 -AC_INIT([ctools], [1.0.0], [jurgen.knodlseder@irap.omp.eu], [ctools]) 32 +AC_INIT([ctools], [1.1.0.dev], [jurgen.knodlseder@irap.omp.eu], [ctools])
33 AC_CONFIG_SRCDIR([src/ctselect/ctselect.cpp]) 33 AC_CONFIG_SRCDIR([src/ctselect/ctselect.cpp])
34 AC_CONFIG_MACRO_DIR([m4]) 34 AC_CONFIG_MACRO_DIR([m4])
35 #AM_INIT_AUTOMAKE([gnu no-dependencies]) 35 #AM_INIT_AUTOMAKE([gnu no-dependencies])
cscripts/Makefile.am
1 ## Process this file with automake to produce Makefile.in 1 ## Process this file with automake to produce Makefile.in
2 2
3 -# Scripts to be distributed in bindir  
4 -binscripts = tsmerge.py  
5 -  
6 # Scripts to be distributed in $(pyexecdir)/cscripts 3 # Scripts to be distributed in $(pyexecdir)/cscripts
7 pythonscripts = __init__.py \ 4 pythonscripts = __init__.py \
8 cspull.py cssens.py cstsdist.py cscaldb.py csresmap.py \ 5 cspull.py cssens.py cstsdist.py cscaldb.py csresmap.py \
9 - cshessobs.py csobsdef.py csspec.py cslightcrv.py \  
10 - csinfo.py \ 6 + cshessobs.py csobsdef.py csspec.py cslightcrv.py csobsinfo.py \
  7 + csinfo.py csmodelinfo.py csmodelmerge.py cstsmapmerge.py \
11 obsutils.py 8 obsutils.py
12 9
13 # Scripts for which symbolic links will be created in bindir 10 # Scripts for which symbolic links will be created in bindir
14 linkscripts = cspull cssens cstsdist cscaldb csresmap \ 11 linkscripts = cspull cssens cstsdist cscaldb csresmap \
15 - cshessobs csobsdef csspec cslightcrv \  
16 - csinfo 12 + cshessobs csobsdef csspec cslightcrv csobsinfo \
  13 + csinfo csmodelinfo csmodelmerge cstsmapmerge
17 14
18 # Distribute scripts 15 # Distribute scripts
19 EXTRA_DIST = $(binscripts) $(pythonscripts) 16 EXTRA_DIST = $(binscripts) $(pythonscripts)
cscripts/csmodelinfo.py 0 → 100755
  1 +#!/usr/bin/env python
  2 +# ==========================================================================
  3 +# Dump information about models into log file
  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 +
  25 +
  26 +# ================= #
  27 +# csmodelinfo class #
  28 +# ================= #
  29 +class csmodelinfo(ctools.cscript):
  30 + """
  31 + This class dumps information about a model container into a logfile or
  32 + on screen. This might be helpful for quick access to the model container,
  33 + showing, e.g., number of sources, background models, free and fixed
  34 + parameters etc. The tool can also dump the models into a region file to
  35 + display e.g. with ds9.
  36 + """
  37 + def __init__(self, *argv):
  38 + """
  39 + Constructor.
  40 + """
  41 + # Set name
  42 + self.name = "csmodelinfo"
  43 + self.version = "1.1.0"
  44 +
  45 + # Make sure that parfile exists
  46 + file = self.parfile()
  47 +
  48 + # Initialise application
  49 + if len(argv) == 0:
  50 + ctools.cscript.__init__(self, self.name, self.version)
  51 + elif len(argv) == 1:
  52 + ctools.cscript.__init__(self, self.name, self.version, *argv)
  53 + else:
  54 + raise TypeError("Invalid number of arguments given.")
  55 +
  56 + # Set logger properties
  57 + self.log_header()
  58 + self.log.date(True)
  59 +
  60 + # Return
  61 + return
  62 +
  63 + def __del__(self):
  64 + """
  65 + Destructor.
  66 + """
  67 + # Return
  68 + return
  69 +
  70 + def parfile(self):
  71 + """
  72 + Check if parfile exists. If parfile does not exist then create a
  73 + default parfile. This kluge avoids shipping the cscript with a
  74 + 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("inmodel","f","a","model.xml","","","Input model XML file"))
  89 + pars.append(gammalib.GApplicationPar("ds9file","f","h","NONE","","","DS9 region file containing models"))
  90 + pars.append(gammalib.GApplicationPar("pnt_type","s","h","cross","circle|box|diamond|cross|x|arrow|boxcircle","","Marker type for point sources"))
  91 + pars.append(gammalib.GApplicationPar("pnt_mark_size","i","h","12","","","Marker size for point sources"))
  92 + pars.append(gammalib.GApplicationPar("show_labels","b","h","yes","yes|no","","Add source labels?"))
  93 + pars.append(gammalib.GApplicationPar("width","i","h","2","","","Line width for regions"))
  94 + pars.append(gammalib.GApplicationPar("font","s","h","helvetica","helvetica|times|courier","","Font for source labels"))
  95 + pars.append(gammalib.GApplicationPar("fontsize","i","h","12","","","Font size for source labels"))
  96 + pars.append(gammalib.GApplicationPar("fonttype","s","h","normal","normal|bold","","Use normal or bold font?"))
  97 + pars.append(gammalib.GApplicationPar("fonttype2","s","h","roman","roman|italic","","Use roman or italic font?"))
  98 + pars.append(gammalib.GApplicationPar("show_ext_type","b","h","yes","yes|no","","Show type of extended model in source name"))
  99 + pars.append(gammalib.GApplicationPar("free_color","s","h","green","","","Color for sources with free parameters (any ds9 color or hex code)"))
  100 + pars.append(gammalib.GApplicationPar("fixed_color","s","h","magenta","","","Color for source without free parameters (any ds9 color or hex code)"))
  101 + pars.append_standard()
  102 + pars.append(gammalib.GApplicationPar("logfile","f","h","csmodelinfo.log","","","Log filename"))
  103 + pars.save(parfile)
  104 +
  105 + # Return
  106 + return
  107 +
  108 + def get_parameters(self):
  109 + """
  110 + Get parameters from parfile and setup the observation.
  111 + """
  112 + # Get models
  113 + self.models = gammalib.GModels(self["inmodel"].filename())
  114 +
  115 + # Get ds9 filename
  116 + self.ds9file = self["ds9file"].filename()
  117 +
  118 + # Get hidden parameters for region file
  119 + self.pnt_type = self["pnt_type"].string()
  120 + self.pnt_mark_size = self["pnt_mark_size"].integer()
  121 + self.show_labels = self["show_labels"].boolean()
  122 + self.width = self["width"].integer()
  123 + self.font = self["font"].string()
  124 + self.fontsize = self["fontsize"].integer()
  125 + self.fonttype = self["fonttype"].string()
  126 + self.fonttype2 = self["fonttype2"].string()
  127 + self.show_ext_type = self["show_ext_type"].boolean()
  128 + self.free_color = self["free_color"].string()
  129 + self.fixed_color = self["fixed_color"].string()
  130 +
  131 + # Return
  132 + return
  133 +
  134 + def run(self):
  135 + """
  136 + Run the script.
  137 + """
  138 + # Switch screen logging on in debug mode
  139 + if self.logDebug():
  140 + self.log.cout(True)
  141 +
  142 + # Get parameters
  143 + self.get_parameters()
  144 +
  145 + # Write input parameters into logger
  146 + if self.logTerse():
  147 + self.log_parameters()
  148 + self.log("\n")
  149 +
  150 + if self.logVerbose():
  151 + self.log("\n")
  152 + self.log.header1("Models in detail")
  153 + self.log("\n")
  154 + self.log(str(self.models))
  155 + self.log("\n")
  156 +
  157 + # Initialise output values
  158 + types = {}
  159 + instruments = {}
  160 + ts = {}
  161 + pars_at_limit = {}
  162 + free_src_pars = {}
  163 + n_par_total = 0
  164 + n_par_free = 0
  165 + n_par_fixed = 0
  166 + n_par_at_limit = 0
  167 + n_par_free_bkg = 0
  168 + n_par_free_src = 0
  169 + n_par_free_spec = 0
  170 + n_par_free_spat = 0
  171 + n_par_free_temp = 0
  172 +
  173 + # Loop over models and initialise dictionaries with model names
  174 + for model in self.models:
  175 + types[model.type()] = 0
  176 + instruments[model.instruments()] = 0
  177 + pars_at_limit[model.name()] = []
  178 +
  179 + # Loop over models again and fill values to be dumped
  180 + for model in self.models:
  181 +
  182 + # Model types
  183 + types[model.type()] += 1
  184 +
  185 + # Model instruments
  186 + instruments[model.instruments()] += 1
  187 +
  188 + # TS
  189 + if model.has_ts():
  190 + ts[model.name()] = model.ts()
  191 +
  192 + # Skymodel?
  193 + skymodel = (model.classname() == "GModelSky")
  194 + if skymodel:
  195 + free_src_pars[model.name()] = []
  196 +
  197 + # Loop over model parameters
  198 + for par in model:
  199 +
  200 + # Increment total parameters
  201 + n_par_total += 1
  202 +
  203 + # Check if parameter is at limit
  204 + if par.has_range():
  205 + if par.value() == par.min() or par.value() == par.max():
  206 + pars_at_limit[model.name()].append(par.name())
  207 + n_par_at_limit += 1
  208 +
  209 + # Check if model parameter is free/fixed and
  210 + # increment respective variable
  211 + if par.is_free():
  212 + n_par_free += 1
  213 + if skymodel:
  214 + free_src_pars[model.name()].append(par)
  215 + n_par_free_src += 1
  216 + else:
  217 + n_par_free_bkg += 1
  218 + else:
  219 + n_par_fixed += 1
  220 +
  221 + # If sky model, divide free parameters into spatial, spectral and temporal
  222 + if skymodel:
  223 + for par in model.spectral():
  224 + if par.is_free():
  225 + n_par_free_spec += 1
  226 + for par in model.spatial():
  227 + if par.is_free():
  228 + n_par_free_spat += 1
  229 + for par in model.temporal():
  230 + if par.is_free():
  231 + n_par_free_temp += 1
  232 +
  233 + # Log summary
  234 + self.log("\n")
  235 + self.log.header1("Summary")
  236 + self.log("\n")
  237 +
  238 + # Log instruments
  239 + self.log.header3("Instrument specific models")
  240 + for inst, n_inst in instruments.iteritems():
  241 + if inst == "":
  242 + inst = "All"
  243 + self.log.parformat(inst)
  244 + self.log(str(n_inst))
  245 + self.log("\n")
  246 +
  247 + # Log model types
  248 + self.log("\n")
  249 + self.log.header3("Model types")
  250 + for modeltype, n_types in types.iteritems():
  251 + self.log.parformat(modeltype)
  252 + self.log(str(n_types))
  253 + self.log("\n")
  254 +
  255 + # Log parameter information
  256 + self.log("\n")
  257 + self.log.header2("Parameter information")
  258 + self.log.parformat("All parameters")
  259 + self.log(str(n_par_total))
  260 + self.log("\n")
  261 + self.log.parformat("Fixed parameters")
  262 + self.log(str(n_par_fixed))
  263 + self.log("\n")
  264 + self.log.parformat("Free parameters (total)")
  265 + self.log(str(n_par_free))
  266 + self.log("\n")
  267 + self.log.parformat("Free background parameters")
  268 + self.log(str(n_par_free_bkg))
  269 + self.log("\n")
  270 + self.log.parformat("Free source parameters")
  271 + self.log(str(n_par_free_src))
  272 + self.log("\n")
  273 + if n_par_free_spec > 0:
  274 + self.log.parformat("Free spectral parameters")
  275 + self.log(str(n_par_free_spec))
  276 + self.log("\n")
  277 + if n_par_free_spat > 0:
  278 + self.log.parformat("Free spatial parameters")
  279 + self.log(str(n_par_free_spat))
  280 + self.log("\n")
  281 + if n_par_free_temp > 0:
  282 + self.log.parformat("Free temporal parameters")
  283 + self.log(str(n_par_free_temp))
  284 + self.log("\n")
  285 + self.log.parformat("Parameters at limit")
  286 + self.log(str(n_par_at_limit))
  287 + self.log("\n")
  288 + self.log("\n")
  289 +
  290 + # Log parameters at limit (if any)
  291 + if n_par_at_limit > 0:
  292 + self.log.header3("Parameters at limit")
  293 + for source, parameter in pars_at_limit.iteritems():
  294 + if len(parameter):
  295 + for par in parameter:
  296 + self.log.parformat(source)
  297 + self.log(par)
  298 + self.log("\n")
  299 +
  300 + # Log free parameters if requested
  301 + if self.logExplicit() and len(free_src_pars):
  302 + self.log("\n")
  303 + self.log.header2("Free source parameters")
  304 + for source, parameter in free_src_pars.iteritems():
  305 + if len(parameter):
  306 + self.log.header3(source)
  307 + for par in parameter:
  308 + self.log(str(par))
  309 + self.log("\n")
  310 + self.log("\n")
  311 +
  312 + # Log TS values if available
  313 + if len(ts):
  314 + self.log.header3("Test statistics")
  315 + for source,tsvalue in ts.iteritems():
  316 + self.log.parformat(source)
  317 + self.log("%.2f"%tsvalue)
  318 + self.log("\n")
  319 +
  320 + # Return
  321 + return
  322 +
  323 + def save(self):
  324 + """
  325 + Save models to ds9 region file if required
  326 + """
  327 +
  328 + # Check if ds9 file is valid
  329 + if not self.ds9file == "NONE":
  330 +
  331 + self.log("\n")
  332 + self.log.header1("Save region file")
  333 + self.log("\n")
  334 +
  335 + # Open file
  336 + f = open(self.ds9file,"w")
  337 +
  338 + # Write coordinate system
  339 + f.write("fk5\n")
  340 +
  341 + # Loop over models
  342 + for model in self.models:
  343 +
  344 + # Continue only if point source or extended source model
  345 + if model.type() == "PointSource" or model.type() == "ExtendedSource":
  346 +
  347 + line = self.model2ds9string(model)
  348 + if len(line):
  349 + f.write(line+"\n")
  350 +
  351 + # Logging for diffuse components
  352 + elif model.type() == "DiffuseSource":
  353 + self.log("Skipping diffuse model "+model.name()+"\n")
  354 +
  355 + # Logging for background components
  356 + else:
  357 + if self.logExplicit():
  358 + self.log("Skipping background model "+model.name()+"\n")
  359 +
  360 + # Close file
  361 + f.close()
  362 +
  363 + # Return
  364 + return
  365 +
  366 + def model2ds9string(self, model):
  367 + """
  368 + Converts model instance to ds9 region string
  369 + """
  370 +
  371 + # Initialise return string
  372 + ds9string = ""
  373 +
  374 + # Determine color
  375 + color = self.fixed_color
  376 + for par in model:
  377 + if par.is_free():
  378 + color = self.free_color
  379 + break
  380 +
  381 + # Initialise flag ot continue
  382 + is_valid = True
  383 +
  384 + # Retrieve model position
  385 + try:
  386 + modelpos = model.spatial().dir()
  387 + except AttributeError:
  388 + self.log("Skipping source "+model.name()+": Could not determine sky position\n")
  389 + is_valid = False
  390 +
  391 + # Continue only if position was found
  392 + if is_valid:
  393 +
  394 + # Retrieve model type and name
  395 + modeltype = model.type()
  396 + modelname = model.name()
  397 +
  398 + # Handle point source
  399 + if modeltype == "PointSource":
  400 +
  401 + ds9string += "point("
  402 + ds9string += str(modelpos.ra_deg())
  403 + ds9string += ","
  404 + ds9string += str(modelpos.dec_deg())
  405 + ds9string += ") # "
  406 + ds9string += "point="+self.pnt_type+" "
  407 + ds9string += str(self.pnt_mark_size)+" "
  408 +
  409 + # Hanlde extended sources
  410 + elif modeltype == "ExtendedSource":
  411 +
  412 + # Retrieve spatial model
  413 + spatial = model.spatial()
  414 + classname = spatial.classname()
  415 +
  416 + # Handle radial sources
  417 + if "Radial" in classname:
  418 +
  419 + # Retrieve short name of model class (e.g. "Gauss" or "Disk)
  420 + shorttype = classname.split("Radial")[-1]
  421 +
  422 + # Handle Disk and Shell model
  423 + if classname == "GModelSpatialRadialDisk" or classname == "GModelSpatialRadialShell":
  424 + size = spatial.radius()
  425 +
  426 + # Handle Gauss Model
  427 + elif classname == "GModelSpatialRadialGauss":
  428 + size = spatial.sigma()
  429 +
  430 + # Skip if source is unknown
  431 + else:
  432 + self.log("Skipping source "+model.name()+": Spatial model \""+classname+"\" unkown\n")
  433 + is_valid = False
  434 +
  435 + # Append radial ds9 string
  436 + if is_valid:
  437 + ds9string += "circle("
  438 + ds9string += str(modelpos.ra_deg())
  439 + ds9string += ","
  440 + ds9string += str(modelpos.dec_deg())
  441 + ds9string += ","
  442 + ds9string += str(size*3600.)+"\") #"
  443 +
  444 + # Handle elliptical sources
  445 + elif "Elliptical" in classname:
  446 +
  447 + # Retrieve short name and source size
  448 + shorttype = classname.split("Elliptical")[-1]
  449 + size1 = spatial.semimajor()
  450 + size2 = spatial.semiminor()
  451 + angle = spatial.posangle()
  452 +
  453 + # Append elliptical ds9 string
  454 + ds9string += "ellipse("
  455 + ds9string += str(modelpos.ra_deg())
  456 + ds9string += ","
  457 + ds9string += str(modelpos.dec_deg())
  458 + ds9string += ","
  459 + ds9string += str(size1*3600.)+"\""
  460 + ds9string += ","
  461 + ds9string += str(size2*3600.)+"\""
  462 + ds9string += ","
  463 + ds9string += str(angle+90.0)+") # "
  464 +
  465 + # Skip if source is neither radial nor elliptical
  466 + else:
  467 + self.log("Skipping source "+model.name()+": Spatial model neither \"Radial\" nor \"Elliptical\"\n")
  468 +
  469 + # Add short name to modelname
  470 + if self.show_ext_type:
  471 + modelname +=" ("+shorttype+")"
  472 +
  473 + # Add user defined attributes
  474 + ds9string += "color="+color+" "
  475 + ds9string += "width="+str(self.width)+" "
  476 + ds9string += "font=\""+self.font+" "+str(self.fontsize)+" "+self.fonttype+" "+self.fonttype2+"\" "
  477 + if self.show_labels:
  478 + ds9string += "text={"+modelname+"}"
  479 +
  480 + # Return string
  481 + return ds9string
  482 +
  483 + def execute(self):
  484 + """
  485 + Execute the script.
  486 + """
  487 + # Run the script
  488 + self.run()
  489 +
  490 + # Save ds9 file if required
  491 + self.save()
  492 +
  493 + # Return
  494 + return
  495 +
  496 +
  497 +# ======================== #
  498 +# Main routine entry point #
  499 +# ======================== #
  500 +if __name__ == '__main__':
  501 + """
  502 + Generates model information output.
  503 + """
  504 + # Create instance of application
  505 + app = csmodelinfo(sys.argv)
  506 +
  507 + # Open logfile
  508 + app.logFileOpen()
  509 +
  510 + # Execute application
  511 + app.execute()
cscripts/csmodelmerge.py 0 → 100755
  1 +#!/usr/bin/env python
  2 +# ==========================================================================
  3 +# Merges model XML files into one file
  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 glob
  25 +
  26 +
  27 +# ================== #
  28 +# csmodelmerge class #
  29 +# ================== #
  30 +class csmodelmerge(ctools.cscript):
  31 + """
  32 + This class merges an arbitray number of model container into one output
  33 + model XML file.
  34 + """
  35 + def __init__(self, *argv):
  36 + """
  37 + Constructor.
  38 + """
  39 + # Set name
  40 + self.name = "csmodelmerge"
  41 + self.version = "1.1.0"
  42 +
  43 + # Make sure that parfile exists
  44 + file = self.parfile()
  45 +
  46 + # Initialise application
  47 + if len(argv) == 0:
  48 + ctools.cscript.__init__(self, self.name, self.version)
  49 + elif len(argv) == 1:
  50 + ctools.cscript.__init__(self, self.name, self.version, *argv)
  51 + else:
  52 + raise TypeError("Invalid number of arguments given.")
  53 +
  54 + # Set logger properties
  55 + self.log_header()
  56 + self.log.date(True)
  57 +
  58 + # Return
  59 + return
  60 +
  61 + def __del__(self):
  62 + """
  63 + Destructor.
  64 + """
  65 + # Return
  66 + return
  67 +
  68 + def parfile(self):
  69 + """
  70 + Check if parfile exists. If parfile does not exist then create a
  71 + default parfile. This kluge avoids shipping the cscript with a
  72 + parfile.
  73 + """
  74 +
  75 + # Set parfile name
  76 + parfile = self.name+".par"
  77 +
  78 + try:
  79 + pars = gammalib.GApplicationPars(parfile)
  80 + except:
  81 + # Signal that parfile was not found
  82 + print("Parfile \""+parfile+"\" not found. Create default parfile.")
  83 +
  84 + # Create default parfile
  85 + pars = gammalib.GApplicationPars()
  86 + pars.append(gammalib.GApplicationPar("inmodels","s","a","model.xml","","","Input model XML files"))
  87 + pars.append(gammalib.GApplicationPar("outmodel","f","a","NONE","","","Output model file"))
  88 + pars.append_standard()
  89 + pars.append(gammalib.GApplicationPar("logfile","f","h","csmodelmerge.log","","","Log filename"))
  90 + pars.save(parfile)
  91 +
  92 + # Return
  93 + return
  94 +
  95 + def get_parameters(self):
  96 + """
  97 + Get parameters from parfile and setup the observation.
  98 + """
  99 + # Get input models
  100 + self.inmodels = self["inmodels"].string()
  101 +
  102 + # Interpet inmodels string
  103 + # Handle ascii files
  104 + if "@" == self.inmodels[0]:
  105 + self.files = open(self.inmodels.replace("@","")).read().splitlines()
  106 +
  107 + # Handle wild card strings
  108 + elif "*" in self.inmodels:
  109 + self.files = glob.glob(self.inmodels)
  110 +
  111 + # Handle space-separated list
  112 + elif " " in self.inmodels:
  113 + self.files = self.inmodels.split(" ")
  114 +
  115 + # Handle comma-separated list
  116 + elif "," in self.inmodels:
  117 + self.files = self.inmodels.split(",")
  118 +
  119 + # Throw exception if input models cannot be decoded
  120 + else:
  121 + msg = "Parameter \"inmodels\" must contain either an @ASCII"+\
  122 + " file, a comma-separated or whitespace-separated list"+\
  123 + " of files or a wildcard string"
  124 + raise gammalib.GException.invalid_argument("csmodelmerge::get_parameters", msg)
  125 +
  126 + # Get output file
  127 + self.outmodel = self["outmodel"].filename()
  128 +
  129 + # Return
  130 + return
  131 +
  132 + def run(self):
  133 + """
  134 + Run the script.
  135 + """
  136 + # Switch screen logging on in debug mode
  137 + if self.logDebug():
  138 + self.log.cout(True)
  139 +
  140 + # Get parameters
  141 + self.get_parameters()
  142 +
  143 + # Write input parameters into logger
  144 + if self.logTerse():
  145 + self.log_parameters()
  146 + self.log("\n")
  147 +
  148 + # Dump header
  149 + if self.logTerse():
  150 + self.log("\n")
  151 + self.log.header1("Merging Models")
  152 + self.log("\n")
  153 +
  154 + # Initialise output model container
  155 + self.models = gammalib.GModels()
  156 +
  157 + # Loop over model files
  158 + for modelfile in self.files:
  159 +
  160 + # Logging
  161 + self.log("Adding "+modelfile)
  162 + self.log("\n")
  163 +
  164 + # Open models
  165 + model_add = gammalib.GModels(modelfile)
  166 +
  167 + # Append models to container
  168 + for model in model_add:
  169 + self.models.append(model)
  170 +
  171 + # Return
  172 + return
  173 +
  174 + def save(self):
  175 + """
  176 + Save pointings to ds9 region file if required
  177 + """
  178 + # Logging
  179 + if self.logExplicit():
  180 + self.log("\n")
  181 + self.log.header1("Saving model file")
  182 + self.log("\n")
  183 +
  184 + # Save models
  185 + self.models.save(self.outmodel)
  186 +
  187 + # Return
  188 + return
  189 +
  190 + def execute(self):
  191 + """
  192 + Execute the script.
  193 + """
  194 + # Run the script
  195 + self.run()
  196 +
  197 + # Save ds9 file if required
  198 + self.save()
  199 +
  200 + # Return
  201 + return
  202 +
  203 +
  204 +# ======================== #
  205 +# Main routine entry point #
  206 +# ======================== #
  207 +if __name__ == '__main__':
  208 + """
  209 + Merges model XML files
  210 + """
  211 + # Create instance of application
  212 + app = csmodelmerge(sys.argv)
  213 +
  214 + # Open logfile
  215 + app.logFileOpen()
  216 +
  217 + # Execute application
  218 + app.execute()
cscripts/csobsinfo.py 0 → 100755
  1 +#!/usr/bin/env python
  2 +# ==========================================================================
  3 +# Dump information about observation into log file
  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 +
  25 +
  26 +# =============== #
  27 +# csobsinfo class #
  28 +# =============== #
  29 +class csobsinfo(ctools.cscript):
  30 + """
  31 + This class dumps information about an observation container into a
  32 + logfile or on screen. This might be helpful for quick access to an
  33 + observation container showing, e.g., total lifetime, energy range etc.
  34 + """
  35 + def __init__(self, *argv):
  36 + """
  37 + Constructor.
  38 + """
  39 + # Set name
  40 + self.name = "csobsinfo"
  41 + self.version = "1.1.0"
  42 +
  43 + # Make sure that parfile exists
  44 + file = self.parfile()
  45 +
  46 + # Initialise application
  47 + if len(argv) == 0:
  48 + ctools.cscript.__init__(self, self.name, self.version)
  49 + elif len(argv) == 1:
  50 + ctools.cscript.__init__(self, self.name, self.version, *argv)
  51 + else:
  52 + raise TypeError("Invalid number of arguments given.")
  53 +
  54 + # Set logger properties
  55 + self.log_header()
  56 + self.log.date(True)
  57 +
  58 + # Return
  59 + return
  60 +
  61 + def __del__(self):
  62 + """
  63 + Destructor.
  64 + """
  65 + # Return
  66 + return
  67 +
  68 + def parfile(self):
  69 + """
  70 + Check if parfile exists. If parfile does not exist then create a
  71 + default parfile. This kluge avoids shipping the cscript with a
  72 + parfile.
  73 + """
  74 +
  75 + # Set parfile name
  76 + parfile = self.name+".par"
  77 +
  78 + try:
  79 + pars = gammalib.GApplicationPars(parfile)
  80 + except:
  81 + # Signal that parfile was not found
  82 + print("Parfile \""+parfile+"\" not found. Create default parfile.")
  83 +
  84 + # Create default parfile
  85 + pars = gammalib.GApplicationPars()
  86 + pars.append(gammalib.GApplicationPar("inobs","f","a","obs.xml","","","Event list, counts cube, or observation definition file"))
  87 + pars.append(gammalib.GApplicationPar("offset","b","h","no","","","Compute offset from target to pointing positions"))
  88 + pars.append(gammalib.GApplicationPar("ra","r","a","0.0","","","Target Right Ascension"))
  89 + pars.append(gammalib.GApplicationPar("dec","r","a","0.0","","","Target Declination"))
  90 + pars.append(gammalib.GApplicationPar("ds9file","f","h","NONE","","","DS9 region file containing pointings"))
  91 + pars.append_standard()
  92 + pars.append(gammalib.GApplicationPar("logfile","f","h","csobsinfo.log","","","Log filename"))
  93 + pars.save(parfile)
  94 +
  95 + # Return
  96 + return
  97 +
  98 + def get_parameters(self):
  99 + """
  100 + Get parameters from parfile and setup the observation.
  101 + """
  102 + # Get parameters
  103 + self.require_inobs("csobsinfo::get_parameters")
  104 + self.obs = self.get_observations(False)
  105 +
  106 + # Initialise object position
  107 + self.obj_dir = gammalib.GSkyDir()
  108 +
  109 + # Get (optional) offset parameters
  110 + self.m_offset = self["offset"].boolean()
  111 + if self.m_offset:
  112 + ra = self["ra"].real()
  113 + dec = self["dec"].real()
  114 + self.obj_dir.radec_deg(ra,dec)
  115 +
  116 + # Get (optional) DS9 filename
  117 + self.ds9file = self["ds9file"].filename()
  118 +
  119 + # Return
  120 + return
  121 +
  122 + def run(self):
  123 + """
  124 + Run the script.
  125 + """
  126 + # Switch screen logging on in debug mode
  127 + if self.logDebug():
  128 + self.log.cout(True)
  129 +
  130 + # Get parameters
  131 + self.get_parameters()
  132 +
  133 + # Write input parameters into logger
  134 + if self.logTerse():
  135 + self.log_parameters()
  136 + self.log("\n")
  137 +
  138 + # Initialise arrays to store certain values for reuse
  139 + # Todo, think about using a python dictionary
  140 + self.offsets = []
  141 + self.zeniths = []
  142 + self.azimuths = []
  143 + self.pnt_ra = []
  144 + self.pnt_dec = []
  145 + obs_names = []
  146 +
  147 + # Initialise output to be filled
  148 + self.ebounds = gammalib.GEbounds()
  149 + self.gti = gammalib.GGti()
  150 + ontime = 0.0
  151 + livetime = 0.0
  152 + n_events = 0
  153 + n_eventbins = 0
  154 + n_obs_binned = 0
  155 + n_obs_unbinned = 0
  156 +
  157 + # Logging
  158 + self.log.header1("Looping over observations")
  159 +
  160 + # Loop over observations
  161 + for obs in self.obs:
  162 +
  163 +
  164 + # Skip non-CTA observations
  165 + if not obs.classname() == "GCTAObservation":
  166 + self.log("Skipping "+obs.instrument()+" observation\n")
  167 + continue
  168 +
  169 + # Use observed object as observation name
  170 + # if name is not given
  171 + obs_name = obs.name()
  172 + if obs_name == "":
  173 + obs_name = obs.object()
  174 +
  175 + # Logging
  176 + if self.logTerse():
  177 + self.log.header2(obs_name)
  178 +
  179 + # Retrieve observation name
  180 + obs_names.append(obs_name)
  181 +
  182 + # Retrieve energy boundaries
  183 + obs_bounds = obs.events().ebounds()
  184 +
  185 + # Retrieve time interval
  186 + obs_gti = obs.events().gti()
  187 +
  188 + # Compute mean time and dead time fraction in percent
  189 + tmean = (obs_gti.tstart() + obs_gti.tstop())
  190 + tmean *= 0.5
  191 + deadfrac = (1.0-obs.deadc(tmean))*100.0
  192 +
  193 + # Retrieve pointing and store Ra,Dec
  194 + pnt_dir = obs.pointing().dir()
  195 + self.pnt_ra.append(pnt_dir.ra_deg())
  196 + self.pnt_dec.append(pnt_dir.dec_deg())
  197 +
  198 + # If avaliable append energy boundaries
  199 + if obs_bounds.size() > 0 :
  200 + self.ebounds.merge(obs_bounds.emin(),obs_bounds.emax())
  201 +
  202 + # Append time interval
  203 + self.gti.merge(obs_gti.tstart(), obs_gti.tstop())
  204 +
  205 + # increment global livetime and ontime
  206 + ontime += obs.ontime()
  207 + livetime += obs.livetime()
  208 +
  209 + # Log the event type (binned or unbinned)
  210 + if self.logTerse():
  211 + self.log.parformat("binned")
  212 +
  213 + if obs.eventtype() == "CountsCube":
  214 + n_eventbins += obs.events().size()
  215 + n_obs_binned += 1
  216 + if self.logTerse():
  217 + self.log("yes")
  218 + self.log("\n")
  219 + self.log.parformat("Number of bins")
  220 + self.log(str(obs.events().size()))
  221 + self.log("\n")
  222 + else:
  223 + n_events += obs.events().size()
  224 + n_obs_unbinned += 1
  225 + if self.logTerse():
  226 + self.log("no")
  227 + self.log("\n")
  228 + self.log.parformat("Number of events")
  229 + self.log(str(obs.events().size()))
  230 + self.log("\n")
  231 +
  232 + # Log option
  233 + if self.logTerse():
  234 +
  235 + # Log the observation energy range (if available)
  236 + self.log.parformat("Energy range")
  237 + if obs_bounds.size() == 0:
  238 + self.log("undefined")
  239 + else:
  240 + self.log(str(obs_bounds.emin())+" - "+str(obs_bounds.emax()))
  241 + self.log("\n")
  242 +
  243 + # Log observation time interval
  244 + self.log.parformat("Time range (MJD)")
  245 + if obs_gti.size() == 0:
  246 + self.log("undefined")
  247 + else:
  248 + self.log(str(obs_gti.tstart().mjd())+" - "+str(obs_gti.tstop().mjd()))
  249 + self.log("\n")
  250 +
  251 + # Log ontime
  252 + self.log.parformat("Ontime [s]")
  253 + self.log(str(obs.ontime()))
  254 + self.log("\n")
  255 +
  256 + # Log livetime
  257 + self.log.parformat("Livetime [s]")
  258 + self.log(str(obs.livetime()))
  259 + self.log("\n")
  260 +
  261 + # Log dead time fraction
  262 + self.log.parformat("Dead-time fraction (%)")
  263 + self.log("%.3f" % (deadfrac))
  264 + self.log("\n")
  265 +
  266 + # Log pointing direction
  267 + self.log.parformat("Pointing")
  268 + self.log(str(pnt_dir))
  269 + self.log("\n")
  270 +
  271 + # Log offset if possible
  272 + if self.m_offset:
  273 + offset = pnt_dir.dist_deg(self.obj_dir)
  274 + self.offsets.append(offset)
  275 + self.log.parformat("Offset")
  276 + self.log("%.2f" % (offset))
  277 + self.log("\n")
  278 + else:
  279 + self.offsets.append(-1.0)
  280 +
  281 + # Retrieve zenith and azimuth and store for later use
  282 + zenith = obs.pointing().zenith()
  283 + azimuth = obs.pointing().azimuth()
  284 + self.zeniths.append(zenith)
  285 + self.azimuths.append(azimuth)
  286 +
  287 + # Log Zenith and Azimuth if required
  288 + if self.logExplicit():
  289 + self.log.parformat("Zenith angle")
  290 + self.log("%.2f" % (zenith))
  291 + self.log("\n")
  292 + self.log.parformat("Azimuth angle")
  293 + self.log("%.2f" % (azimuth))
  294 + self.log("\n\n")
  295 +
  296 + # Log summary
  297 + self.log("\n")
  298 + self.log.header1("Summary")
  299 +
  300 + # Log general summary
  301 + self.log.parformat("Unbinned observations")
  302 + self.log(str(n_obs_unbinned))
  303 + self.log("\n")
  304 + self.log.parformat("Number of events")
  305 + self.log(str(n_events))
  306 + self.log("\n")
  307 + self.log.parformat("Binned observations")
  308 + self.log(str(n_obs_binned))
  309 + self.log("\n")
  310 + self.log.parformat("Number of bins")
  311 + self.log(str(n_eventbins))
  312 + self.log("\n\n")
  313 +
  314 + # Log pointing summary
  315 + self.log.header3("Pointings")
  316 +
  317 + # Log mean offset if possible
  318 + if self.m_offset:
  319 + self.log.parformat("Mean offset angle")
  320 + self.log("%.2f" % (sum(self.offsets)/len(self.offsets)))
  321 + self.log("\n")
  322 +
  323 + # Log mean azimuth and zenith angle
  324 + self.log.parformat("Mean zenith angle")
  325 + self.log("%.2f" % (sum(self.zeniths)/len(self.zeniths)))
  326 + self.log("\n")
  327 + self.log.parformat("Mean azimuth angle")
  328 + self.log("%.2f" % (sum(self.azimuths)/len(self.azimuths)))
  329 + self.log("\n")
  330 +
  331 + # Log name of observations if requested
  332 + if self.logExplicit():
  333 + obs_set = set(obs_names)
  334 + for name in obs_set:
  335 + self.log.parformat("\""+name+"\"")
  336 + self.log(str(obs_names.count(name)))
  337 + self.log("\n")
  338 + self.log("\n")
  339 +
  340 + # Log energy range
  341 + self.log.header3("Energy range")
  342 + self.log.parformat("Emin")
  343 + if self.ebounds.size() == 0:
  344 + self.log("undefined")
  345 + else:
  346 + self.log(str(self.ebounds.emin()))
  347 + self.log("\n")
  348 + self.log.parformat("Emax")
  349 + if self.ebounds.size() == 0:
  350 + self.log("undefined")
  351 + else:
  352 + self.log(str(self.ebounds.emax()))
  353 + self.log("\n\n")
  354 +
  355 + # Log time range
  356 + self.log.header3("Time range")
  357 + self.log.parformat("Start [MJD]")
  358 + self.log(str(self.gti.tstart().mjd()))
  359 + self.log("\n")
  360 + self.log.parformat("Stop [MJD]")
  361 + self.log(str(self.gti.tstop().mjd()))
  362 + self.log("\n")
  363 +
  364 + # Log ontime and livetime in different units
  365 + self.log.parformat("Total ontime")
  366 + self.log("%.2f s = %.2f min = %.2f h" % (ontime, ontime/60., ontime/3600.))
  367 + self.log("\n")
  368 + self.log.parformat("Total livetime")
  369 + self.log("%.2f s = %.2f min = %.2f h" % (livetime, livetime/60.0, livetime/3600.))
  370 + self.log("\n")
  371 +
  372 + # Return
  373 + return
  374 +
  375 + def save(self):
  376 + """
  377 + Save pointings to ds9 region file if required
  378 + """
  379 +
  380 + # Check if ds9 file is valid
  381 + if not self.ds9file == "NONE":
  382 +
  383 + # Open file
  384 + f = open(self.ds9file,"w")
  385 +
  386 + # Write coordinate system
  387 + f.write("fk5\n")
  388 +
  389 + # Loop over pointings
  390 + for i in range(len(self.pnt_ra)):
  391 +
  392 + # Create string
  393 + line = "point("
  394 + line+=str(self.pnt_ra[i])+","+str(self.pnt_dec[i])+")"
  395 + line+=" # point=cross 20 width=3 \n"
  396 +
  397 + # Write to file
  398 + f.write(line)
  399 +
  400 + # Close file
  401 + f.close()
  402 +
  403 + # Return
  404 + return
  405 +
  406 +
  407 + def zeniths(self):
  408 + """
  409 + Return zenith angles
  410 + """
  411 + return self.zeniths
  412 +
  413 + def azimuths(self):
  414 + """
  415 + Return azimuth angles
  416 + """
  417 + return self.azimuths
  418 +
  419 + def offsets(self):
  420 + """
  421 + Return offset angles
  422 + """
  423 + return self.offsets
  424 +
  425 + def ebounds(self):
  426 + """
  427 + Return energy boundaries
  428 + """
  429 + return self.ebounds
  430 +
  431 + def gti(self):
  432 + """
  433 + Return good time intervals
  434 + """
  435 + return self.gti
  436 +
  437 + def execute(self):
  438 + """
  439 + Execute the script.
  440 + """
  441 + # Run the script
  442 + self.run()
  443 +
  444 + # Save ds9 file if required
  445 + self.save()
  446 +
  447 + # Return
  448 + return
  449 +
  450 +
  451 +# ======================== #
  452 +# Main routine entry point #
  453 +# ======================== #
  454 +if __name__ == '__main__':
  455 + """
  456 + Generates information about an observation container.
  457 + """
  458 + # Create instance of application
  459 + app = csobsinfo(sys.argv)
  460 +
  461 + # Open logfile
  462 + app.logFileOpen()
  463 +
  464 + # Execute application
  465 + app.execute()
cscripts/cstsmapmerge.py 0 → 100755
  1 +#!/usr/bin/env python
  2 +# ==========================================================================
  3 +# Merges sliced TS map files into one map
  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 glob
  25 +import os
  26 +
  27 +
  28 +# ================== #
  29 +# cstsmapmerge class #
  30 +# ================== #
  31 +class cstsmapmerge(ctools.cscript):
  32 + """
  33 + This class merges TS map files into one TS map
  34 + """
  35 + def __init__(self, *argv):
  36 + """
  37 + Constructor.
  38 + """
  39 + # Set name
  40 + self.name = "cstsmapmerge"
  41 + self.version = "1.1.0"
  42 +
  43 + # Make sure that parfile exists
  44 + file = self.parfile()
  45 +
  46 + # Initialise application
  47 + if len(argv) == 0:
  48 + ctools.cscript.__init__(self, self.name, self.version)
  49 + elif len(argv) == 1:
  50 + ctools.cscript.__init__(self, self.name, self.version, *argv)
  51 + else:
  52 + raise TypeError("Invalid number of arguments given.")
  53 +
  54 + # Set logger properties
  55 + self.log_header()
  56 + self.log.date(True)
  57 +
  58 + # Return
  59 + return
  60 +
  61 + def __del__(self):
  62 + """
  63 + Destructor.
  64 + """
  65 + # Return
  66 + return
  67 +
  68 + def parfile(self):
  69 + """
  70 + Check if parfile exists. If parfile does not exist then create a
  71 + default parfile. This kluge avoids shipping the cscript with a
  72 + parfile.
  73 + """
  74 +
  75 + # Set parfile name
  76 + parfile = self.name+".par"
  77 +
  78 + try:
  79 + pars = gammalib.GApplicationPars(parfile)
  80 + except:
  81 + # Signal that parfile was not found
  82 + print("Parfile \""+parfile+"\" not found. Create default parfile.")
  83 +
  84 + # Create default parfile
  85 + pars = gammalib.GApplicationPars()
  86 + pars.append(gammalib.GApplicationPar("inmaps","s","a","tsmap.fits","","","Input TS map FITS files"))
  87 + pars.append(gammalib.GApplicationPar("outmap","f","a","NONE","","","Output TS map FITS file"))
  88 + pars.append(gammalib.GApplicationPar("overwrite","b","h","yes","","","Overwrite previously filled bins?"))
  89 + pars.append(gammalib.GApplicationPar("delete","b","h","no","","","Delete merged files?"))
  90 + pars.append_standard()
  91 + pars.append(gammalib.GApplicationPar("logfile","f","h","cstsmapmerge.log","","","Log filename"))
  92 + pars.save(parfile)
  93 +
  94 + # Return
  95 + return
  96 +
  97 + def get_parameters(self):
  98 + """
  99 + Get parameters from parfile and setup the observation.
  100 + """
  101 + # Get input models
  102 + self.inmodels = self["inmaps"].string()
  103 +
  104 + # Interpet inmodels string
  105 + # Handle ascii files
  106 + if "@" == self.inmodels[0]:
  107 + self.files = open(self.inmodels.replace("@","")).read().splitlines()
  108 +
  109 + # Handle wild card strings
  110 + elif "*" in self.inmodels:
  111 + self.files = glob.glob(self.inmodels)
  112 +
  113 + # Handle space-separated list
  114 + elif " " in self.inmodels:
  115 + self.files = self.inmodels.split(" ")
  116 +
  117 + # Handle comma-separated list
  118 + elif "," in self.inmodels:
  119 + self.files = self.inmodels.split(",")
  120 +
  121 + # Throw exception if input models cannot be decoded
  122 + else:
  123 + msg = "Parameter \"inmmaps\" must contain either an @ASCII file,"+\
  124 + " a comma-separated or whitespace-separated list of files"+\
  125 + " or a wildcard string"
  126 + raise gammalib.GException.invalid_argument("cstsmapmerge::get_parameters", msg)
  127 +
  128 + # Check number of files. We need at least two files.
  129 + if len(self.files) <= 1:
  130 + msg = "Need at least two files to start merging, "+\
  131 + str(len(self.files))+" files given."
  132 + raise gammalib.GException.invalid_argument("cstsmapmerge::get_parameters", msg)
  133 +
  134 + # Get output file
  135 + self.outmap = self["outmap"].filename()
  136 +
  137 + # Get other parameters
  138 + self.overwrite = self["overwrite"].boolean()
  139 + self.delete = self["delete"].boolean()
  140 +
  141 + # Return
  142 + return
  143 +
  144 + def init_map(self, fitsfile):
  145 + """
  146 + """
  147 + # Set filename
  148 + self.in_filename = fitsfile
  149 +
  150 + # Open FITS file
  151 + fits = gammalib.GFits(fitsfile)
  152 + self.tsmap = gammalib.GSkyMap()
  153 + self.tsmap.read(fits[0])
  154 + self.statusmap = gammalib.GSkyMap()
  155 + self.statusmap.read(fits["STATUS MAP"])
  156 +
  157 + # Get other maps
  158 + self.maps = []
  159 + self.mapnames = []
  160 +
  161 + # Loop over extensions
  162 + for hdu in fits:
  163 +
  164 + # Leave out primary and status extension
  165 + if hdu.extname() != "IMAGE" and hdu.extname() != "STATUS MAP":
  166 +
  167 + # Add present maps
  168 + skymap = gammalib.GSkyMap()
  169 + skymap.read(hdu)
  170 + self.maps.append(skymap)
  171 + self.mapnames.append(hdu.extname())
  172 +
  173 + # Close FITS file
  174 + fits.close()
  175 +
  176 + # Return
  177 + return
  178 +
  179 + # Add map instances to each other. In this way the TS maps get merged
  180 + def add(self, fitsfile):
  181 +
  182 + # open FITS file
  183 + fits = gammalib.GFits(fitsfile)
  184 + add_tsmap = gammalib.GSkyMap()
  185 + add_tsmap.read(fits[0])
  186 + add_statusmap = gammalib.GSkyMap()
  187 + add_statusmap.read(fits["STATUS MAP"])
  188 +
  189 + # Get other maps
  190 + add_maps = []
  191 +
  192 + # Loop over extensions
  193 + for hdu in fits:
  194 +
  195 + # Leave out primary and status extension
  196 + if hdu.extname() != "IMAGE" and hdu.extname() != "STATUS MAP":
  197 +
  198 + # Add present maps
  199 + skymap = gammalib.GSkyMap()
  200 + skymap.read(hdu)
  201 + add_maps.append(skymap)
  202 +
  203 + # Close FITS file
  204 + fits.close()
  205 +
  206 + # Compare size of other maps
  207 + if not len(add_maps) == len(self.maps):
  208 + self.error("Maps cannot be added: Maps from \""+self.in_filename+"\" do not match from \""+fitsfile+"\"")
  209 +
  210 + # Loop over bins
  211 + for i in range(self.tsmap.npix()):
  212 + if add_statusmap[i] > 0.5:
  213 +
  214 + # Throw exception if this bin has already been computed
  215 + if self.statusmap[i] > 0.5 and not self.overwrite:
  216 + msg = "Attempt to merge bin which apparently has already"+\
  217 + " been merged. File \""+fitsfile+"\" contains"+\
  218 + " already merged bins. Set hidden parameter"+\
  219 + " overwrite=yes to avoid this error."
  220 + raise gammalib.GException.invalid_value("cstsmapmerge::add", msg)
  221 +
  222 + # Copy TS values
  223 + self.tsmap[i] = add_tsmap[i]
  224 +
  225 + # Copy status
  226 + self.statusmap[i] = add_statusmap[i]
  227 +
  228 + # Loop over maps and copy entries
  229 + for j in range(len(self.maps)):
  230 + self.maps[j][i] = add_maps[j][i]
  231 +
  232 + # Return
  233 + return
  234 +
  235 + def run(self):
  236 + """
  237 + Run the script.
  238 + """
  239 + # Switch screen logging on in debug mode
  240 + if self.logDebug():
  241 + self.log.cout(True)
  242 +
  243 + # Get parameters
  244 + self.get_parameters()
  245 +
  246 + # Write input parameters into logger
  247 + if self.logTerse():
  248 + self.log_parameters()
  249 + self.log("\n")
  250 +
  251 + if self.logTerse():
  252 + self.log("\n")
  253 + self.log.header1("Merging sliced TS map files")
  254 + self.log("\n")
  255 +
  256 + # Initialise file to start with
  257 + file0 = ""
  258 +
  259 + self.added_files = []
  260 +
  261 + # Test files for the entry status map
  262 + # use the first one to appear useful
  263 + for fitsfile in self.files:
  264 + if not gammalib.is_fits(fitsfile):
  265 + self.log("Skipping file \""+fitsfile+" (not a FITS file)\n")
  266 + fits = gammalib.GFits(fitsfile)
  267 +
  268 + if fits.contains("STATUS MAP"):
  269 + self.log("Using file \""+fitsfile+"\" as initialising map\n")
  270 + file0 = fitsfile
  271 + break
  272 + else:
  273 + if self.logExplicit():
  274 + self.log("File \""+fitsfile+"\" has not \"STATUS MAP\" extension\n")
  275 +
  276 + # Print an error message if no suitable file was provided
  277 + if file0 == "":
  278 + if self.logTerse():
  279 + self.log("None of the provided file seems to be a sliced ts map file (no \"STATUS MAP\" extension)\n")
  280 +
  281 + # Otherwise merge files
  282 + else:
  283 +
  284 + # copy file list
  285 + workfiles = self.files
  286 +
  287 + # Remove entry which will be used to initalise the map
  288 + workfiles.remove(file0)
  289 +
  290 + # Initialise map from first file
  291 + self.init_map(file0)
  292 +
  293 + # Append to added files
  294 + self.added_files.append(file0)
  295 +
  296 + # Loop over files
  297 + for fitsfile in workfiles:
  298 +
  299 + # Skip if file is not FITS
  300 + if not gammalib.is_fits(fitsfile):
  301 + if self.logTerse():
  302 + self.log("Skipping file \""+fitsfile+" (not a FITS file)\n")
  303 + continue
  304 +
  305 + # Skip if file does not contain status map
  306 + fits = gammalib.GFits(fitsfile)
  307 + if not fits.contains("STATUS MAP"):
  308 + if self.logTerse():
  309 + self.log("Skipping file \""+fitsfile+" (not a FITS file)\n")
  310 + continue
  311 +
  312 + # Logging
  313 + if self.logTerse():
  314 + self.log("Adding TS map slice \""+fitsfile+"\"\n")
  315 +
  316 + # Add file
  317 + self.add(fitsfile)
  318 +
  319 + # Append to added files
  320 + self.added_files.append(fitsfile)
  321 +
  322 + # Return
  323 + return
  324 +
  325 + def save(self):
  326 + """
  327 + Save merged tsmap file and remove slices if requested
  328 + """
  329 +
  330 + # Logging
  331 + if self.logExplicit():
  332 + self.log("\n")
  333 + self.log.header1("Saving merged TS map")
  334 + self.log("\n")
  335 +
  336 + # Create FITS file
  337 + fits = gammalib.GFits()
  338 +
  339 + # Write TS map into primary
  340 + self.tsmap.write(fits)
  341 +
  342 + # Loop over maps and write them to fits
  343 + for i in range(len(self.maps)):
  344 + self.maps[i].write(fits)
  345 +
  346 + # Set map names as extensions
  347 + for i in range(len(self.mapnames)):
  348 + fits[i+1].extname(self.mapnames[i])
  349 +
  350 + # Check if map is fully done
  351 + done = True
  352 + for pix in self.statusmap:
  353 + if pix < 0.5:
  354 + done = False
  355 + break
  356 +
  357 + # Write Status map if we are not done yet
  358 + if not done:
  359 + self.statusmap.write(fits)
  360 + fits[fits.size()-1].extname("STATUS MAP")
  361 +
  362 + # Save FITS file
  363 + fits.saveto(self.outmap, self.clobber())
  364 + if self.logExplicit():
  365 + self.log("Saved output map to \""+self.outmap+"\"\n")
  366 + if self.delete:
  367 + if self.logTerse():
  368 + self.log("\n")
  369 + self.log.header1("Deleting slices")
  370 + self.log("\n")
  371 + for filename in self.added_files:
  372 + if self.logExplicit():
  373 + self.log("Deleting file \""+filename+"\"\n")
  374 + os.remove(filename)
  375 +
  376 + # Return
  377 + return
  378 +
  379 + def execute(self):
  380 + """
  381 + Execute the script.
  382 + """
  383 + # Run the script
  384 + self.run()
  385 +
  386 + # Save ds9 file if required
  387 + self.save()
  388 +
  389 + # Return
  390 + return
  391 +
  392 +
  393 +# ======================== #
  394 +# Main routine entry point #
  395 +# ======================== #
  396 +if __name__ == '__main__':
  397 + """
  398 + Merges ts map slices.
  399 + """
  400 + # Create instance of application
  401 + app = cstsmapmerge(sys.argv)
  402 +
  403 + # Open logfile
  404 + app.logFileOpen()
  405 +
  406 + # Execute application
  407 + app.execute()
cscripts/tsmerge.py deleted
1 -#!/usr/bin/env python  
2 -  
3 -import gammalib  
4 -import sys  
5 -import os  
6 -import glob  
7 -import json  
8 -  
9 -def print_help():  
10 - print("")  
11 - print("tsmerge.py expects two keyword argumens: use via command line as follows")  
12 - print("tsmerge.py files=<list of files> outfile=<desired outfile name>")  
13 - print("-------------------------------------------------------------------------")  
14 - print("*** \"outfile\" should be a path to a fits file")  
15 - print("*** \"files\" should be either be:")  
16 - print(" - an ascii-file listing the files your want to merge")  
17 - print(" OR - a wildcard string describing the files for merging")  
18 - print("-------------------------------------------------------------------------")  
19 - print("")  
20 - print("Example: python tsmerge,py files=tsmap*.fits outfile=tsmap.fits")  
21 - print("")  
22 - sys.exit(-1)  
23 -  
24 -  
25 -# Maps class holding the different sky maps  
26 -# created by cttsmap  
27 -class maps:  
28 -  
29 - # Constructor  
30 - def __init__(self,fitsfile):  
31 -  
32 - self.filename = fitsfile  
33 - if not os.path.isfile(fitsfile):  
34 - self.error("Maps instance cannot be constructed: File \""+self.filename+"\" does not exist")  
35 -  
36 - # open FITS file  
37 - fits = gammalib.GFits(fitsfile)  
38 -  
39 - # get TS map  
40 - self.tsmap = gammalib.GSkyMap()  
41 - self.tsmap.read(fits[0])  
42 -  
43 - # Get status map  
44 - if not fits.contains("STATUS MAP"):  
45 - self.error("No extension \"STATUS MAP\" found in \""+self.filename+"\"")  
46 - self.statusmap = gammalib.GSkyMap()  
47 - self.statusmap.read(fits["STATUS MAP"])  
48 -  
49 - # Get other maps  
50 - self.maps = []  
51 - self.mapnames = []  
52 - for hdu in fits:  
53 - if hdu.extname() != "IMAGE" and hdu.extname() != "STATUS MAP":  
54 - skymap = gammalib.GSkyMap()  
55 - skymap.read(hdu)  
56 - self.maps.append(skymap)  
57 - self.mapnames.append(hdu.extname())  
58 -  
59 - # len operator  
60 - def __len__(self):  
61 - return len(self.maps)  
62 -  
63 - # operator []  
64 - def __getitem__(self,index):  
65 - return self.maps[index]  
66 -  
67 - # Check the status map for completeness  
68 - def check_status(self):  
69 - check = True  
70 - for pix in self.statusmap:  
71 - if pix < 0.5:  
72 - check = False  
73 - break  
74 - return check  
75 -  
76 - # Save maps to outfile  
77 - def save(self,outfile):  
78 -  
79 - fits = gammalib.GFits()  
80 - self.tsmap.write(fits)  
81 -  
82 - for i in range(len(self.maps)):  
83 - self.maps[i].write(fits)  
84 -  
85 - for i in range(len(self.mapnames)):  
86 - fits[i+1].extname(self.mapnames[i])  
87 -  
88 - if not self.check_status():  
89 - self.statusmap.write(fits)  
90 - fits[fits.size()-1].extname("STATUS MAP")  
91 - fits.saveto(outfile,True)  
92 -  
93 - # Add map instances to each other  
94 - # in this way the TS maps get merged  
95 - def add(self,addmaps):  
96 - if not len(addmaps) == len(self.maps):  
97 - self.error("Maps cannot be added: Maps from \""+self.filename+"\" do not match from \""+addmaps.filename+"\"")  
98 -  
99 - # Loop over bins  
100 - for i in range(self.tsmap.npix()):  
101 - if addmaps.statusmap[i] > 0.5:  
102 - self.tsmap[i] = addmaps.tsmap[i]  
103 - self.statusmap[i] = addmaps.statusmap[i]  
104 - for j in range(len(self.maps)):  
105 - self.maps[j][i] = addmaps[j][i]  
106 - # Unify error messages  
107 - def error(self,message):  
108 - print("*** ERROR ***: "+message)  
109 - sys.exit(-1)  
110 -  
111 -  
112 -def pars_from_argv(argv):  
113 -  
114 - if argv is None:  
115 - argv = sys.argv  
116 -  
117 - args = []  
118 - kwargs = {}  
119 - for s in argv[1:]:  
120 - if s.count('=') == 1:  
121 - key, value = s.split('=', 1)  
122 - else:  
123 - key, value = None, s  
124 - try:  
125 - value = json.loads(value)  
126 - except ValueError:  
127 - pass  
128 - if key:  
129 - kwargs[key] = value  
130 - else:  
131 - args.append(value)  
132 - return args, kwargs  
133 -  
134 -  
135 -def get_kwargs(argv):  
136 - kwargs = {}  
137 -  
138 - for s in argv:  
139 - if s.count('=') == 1:  
140 - key, value = s.split('=', 1)  
141 - kwargs[key] = value  
142 -  
143 - else:  
144 - print_help()  
145 -  
146 - return kwargs  
147 -  
148 -if __name__ == "__main__":  
149 - # Initialise list of files  
150 -  
151 - kwargs = get_kwargs(sys.argv[1:])  
152 - if "outfile" not in kwargs or "files" not in kwargs:  
153 - print_help()  
154 - outfile = kwargs["outfile"]  
155 - files = kwargs["files"]  
156 - allfiles = []  
157 - if os.path.isfile(files):  
158 - allfiles = open(files).read().splitlines()  
159 - else:  
160 - allfiles = glob.glob(files)  
161 -  
162 - # Initialise files to be merged  
163 - mergefiles = []  
164 -  
165 - # Test files for the entry status map  
166 - # and add them to the file list  
167 - for fitsfile in allfiles:  
168 - fits = gammalib.GFits(fitsfile)  
169 - if fits.contains("STATUS MAP"):  
170 - mergefiles.append(fitsfile)  
171 - fits.close()  
172 -  
173 - # create a maps instance from the first file  
174 - finalmaps = maps(mergefiles[0])  
175 -  
176 - # add other files to the maps instance  
177 - for fitsfile in mergefiles[1:]:  
178 - finalmaps.add(maps(fitsfile))  
179 -  
180 - # save the filled maps to file  
181 - finalmaps.save(outfile=outfile)  
ctools.pc.in
@@ -6,9 +6,9 @@ includedir=${prefix}/include @@ -6,9 +6,9 @@ includedir=${prefix}/include
6 Name: ctools 6 Name: ctools
7 Description: CTA science analysis tools 7 Description: CTA science analysis tools
8 URL: http://cta.irap.omp.eu/ctools 8 URL: http://cta.irap.omp.eu/ctools
9 -Version: 1.0.0 9 +Version: 1.1.0
10 Requires: 10 Requires:
11 -Requires.private: gammalib >= 1.0.0 11 +Requires.private: gammalib >= 1.1.0
12 Conflicts: 12 Conflicts:
13 Cflags: -I${includedir}/ctools @OPENMP_CXXFLAGS@ 13 Cflags: -I${includedir}/ctools @OPENMP_CXXFLAGS@
14 Libs: -L${libdir} -lctools 14 Libs: -L${libdir} -lctools
doc/Doxyfile
@@ -32,7 +32,7 @@ PROJECT_NAME = ctools @@ -32,7 +32,7 @@ PROJECT_NAME = ctools
32 # This could be handy for archiving the generated documentation or 32 # This could be handy for archiving the generated documentation or
33 # if some version control system is used. 33 # if some version control system is used.
34 34
35 -PROJECT_NUMBER = 1.0.0 35 +PROJECT_NUMBER = 1.1.0.dev
36 36
37 # Using the PROJECT_BRIEF tag one can provide an optional one line description 37 # Using the PROJECT_BRIEF tag one can provide an optional one line description
38 # for a project that appears at the top of each page and should give viewer 38 # for a project that appears at the top of each page and should give viewer
doc/source/conf.py
@@ -66,10 +66,10 @@ copyright = u&#39;2014-2015, ctools developers&#39; @@ -66,10 +66,10 @@ copyright = u&#39;2014-2015, ctools developers&#39;
66 # built documents. 66 # built documents.
67 # 67 #
68 # The short X.Y version. 68 # The short X.Y version.
69 -version = '1.0' 69 +version = '1.1'
70 70
71 # The full version, including alpha/beta/rc tags. 71 # The full version, including alpha/beta/rc tags.
72 -release = '1.0.0' 72 +release = '1.1.0.dev'
73 73
74 # The language for content autogenerated by Sphinx. Refer to documentation 74 # The language for content autogenerated by Sphinx. Refer to documentation
75 # for a list of supported languages. 75 # for a list of supported languages.
doc/source/reference_manual/cscaldb.rst
1 -.. _cscaldb: cscaldb ======= Dumps all available instrument response functions into log fil. Synopsis -------- This scripts dumps all instrument response functions that are available in the calibration database into the log file. If you want the information on the screen, add the ``debug=yes`` parameter. General parameters ------------------ None 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 counts cube 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 ------------- None  
2 \ No newline at end of file 1 \ No newline at end of file
  2 +.. _cscaldb: cscaldb ======= Dumps all available instrument response functions into log file. Synopsis -------- This scripts dumps all instrument response functions that are available in the calibration database into the log file. If you want the information on the screen, add the ``debug=yes`` parameter. General parameters ------------------ None 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 counts cube 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 ------------- None
3 \ No newline at end of file 3 \ No newline at end of file
doc/source/reference_manual/csmodelinfo.rst 0 → 100644
  1 +.. _csmodelinfo:
  2 +
  3 +csmodelinfo
  4 +===========
  5 +
  6 +Dumps information about a model container into log file or on screen.
  7 +
  8 +
  9 +Synopsis
  10 +--------
  11 +
  12 +This script provides detailled information about a given model container.
  13 +It presents the number of parameters, the number of free parameters (sub-
  14 +divided by spectral, spatial and temporal type). The tool further creates
  15 +information about any parameter that is stuck at the parameter boundaries.
  16 +This might be quite useful for debugging a fit. Finally the tool also list
  17 +the TS values of each source that was fitted, in order have a quick overview
  18 +on these quantities on the screen.
  19 +
  20 +In addition the tool is also capable of exporting the input model XML container
  21 +to a region file which is compatible to be read with ds9 or other displying
  22 +tools. To create a region file, the hidden parameter "ds9file" needs to be
  23 +specified. There are quite a few further hidden parameters to steer e.g.
  24 +color, font, etc of the region file output.
  25 +
  26 +
  27 +General parameters
  28 +------------------
  29 +
  30 +``inmodel [file]``
  31 + Event list, counts cube, or observation definition file
  32 +
  33 +``(ds9file = NONE) [file]``
  34 + Output DS9 region file containing models
  35 +
  36 +``(pnt_type=cross) <circle|box|diamond|cross|x|arrow|boxcircle> [string]``
  37 + Marker type for point sources
  38 +
  39 +``pnt_mark_size [integer]``
  40 + Marker size for point sources
  41 +
  42 +``(show_labels=yes) [boolean]``
  43 + Add source labels?
  44 +
  45 +``(width=2) [integer]``
  46 + Line width for regions
  47 +
  48 + ``(font=helvetica) <helvetica|times|courier> [string]``
  49 + Font for source labels
  50 +
  51 +``(fontsize=12) [integer]``
  52 + Font size for source labels
  53 +
  54 +``(fonttype=normal) <normal|bold> [string]``
  55 + Use normal or bold font?
  56 +
  57 +``(fonttype2=roman) <roman|italic> [string]``
  58 + Use roman or italic font?
  59 +
  60 +``(show_ext_type=yes) [boolean]``
  61 + Show type of extended model in source name?
  62 +
  63 +``(free_color=green) [string]``
  64 + Color for sources with free parameters (any ds9 color or hex code)
  65 +
  66 +``(fixed_color=magenta) [string]``
  67 + Color for sources without free parameters (any ds9 color or hex code)
  68 +
  69 +
  70 +Standard parameters
  71 +-------------------
  72 +
  73 +``(chatter = 2) [integer]``
  74 + Verbosity of the executable:
  75 + chatter = 0: no information will be logged
  76 +
  77 + chatter = 1: only errors will be logged
  78 +
  79 + chatter = 2: errors and actions will be logged
  80 +
  81 + chatter = 3: report about the task execution
  82 +
  83 + chatter = 4: detailed report about the task execution
  84 +
  85 +``(clobber = yes) [boolean]``
  86 + Specifies whether an existing output counts cube should be overwritten.
  87 +
  88 +``(debug = no) [boolean]``
  89 + Enables debug mode. In debug mode the executable will dump any log file output to the console.
  90 +
  91 +``(mode = ql) [string]``
  92 + Mode of automatic parameters (default is "ql", i.e. "query and learn").
  93 +
  94 +``(logfile = csmodelinfo.log) [filename]``
  95 + Log filename.
  96 +
  97 +
  98 +Related tools or scripts
  99 +------------------------
  100 +
  101 +None
0 \ No newline at end of file 102 \ No newline at end of file
doc/source/reference_manual/csmodelmerge.rst 0 → 100644
  1 +.. _csmodelmerge:
  2 +
  3 +csmodelmerge
  4 +============
  5 +
  6 +Merges an arbitrary number of model XML files into a single file.
  7 +
  8 +
  9 +Synopsis
  10 +--------
  11 +
  12 +This script merges several model XML file into a single model XML file. The
  13 +files are passed via the ``inmodels`` parameter. There are 4 options to specify
  14 +a list of files that should be merged:
  15 +- a space-separated list of file names (e.g. model1.xml model2.xml)
  16 +- a comma-separated list of file names (e.g. model1.xml,model2.xml)
  17 +- a wildcard string (e.g. mymodel*.xml)
  18 +- an ASCII file containing the file names, one file per line (e.g. @mymodels.txt)
  19 +
  20 +Note that the "@" needs to be specified in case of an ASCII file name. It is
  21 +also important to note that models with the same name cannot be appended. The
  22 +tool will throw and exception if the provided file contain models with the same
  23 +name.
  24 +
  25 +
  26 +General parameters
  27 +------------------
  28 +
  29 +``inmodels [string]``
  30 + Input model XML files
  31 +
  32 +``outmodel [file]``
  33 + Output model file
  34 +
  35 +
  36 +Standard parameters
  37 +-------------------
  38 +
  39 +``(chatter = 2) [integer]``
  40 + Verbosity of the executable:
  41 + chatter = 0: no information will be logged
  42 +
  43 + chatter = 1: only errors will be logged
  44 +
  45 + chatter = 2: errors and actions will be logged
  46 +
  47 + chatter = 3: report about the task execution
  48 +
  49 + chatter = 4: detailed report about the task execution
  50 +
  51 +``(clobber = yes) [boolean]``
  52 + Specifies whether an existing output counts cube should be overwritten.
  53 +
  54 +``(debug = no) [boolean]``
  55 + Enables debug mode. In debug mode the executable will dump any log file output to the console.
  56 +
  57 +``(mode = ql) [string]``
  58 + Mode of automatic parameters (default is "ql", i.e. "query and learn").
  59 +
  60 +``(logfile = csmodelmerge.log) [filename]``
  61 + Log filename.
  62 +
  63 +
  64 +Related tools or scripts
  65 +------------------------
  66 +
  67 +None
0 \ No newline at end of file 68 \ No newline at end of file
doc/source/reference_manual/csobsinfo.rst 0 → 100644
  1 +.. _csobsinfo:
  2 +
  3 +csobsinfo
  4 +=========
  5 +
  6 +Dumps information about an observation container into log file or on
  7 +screen.
  8 +
  9 +
  10 +Synopsis
  11 +--------
  12 +
  13 +This script provides detailed information about a given observation container.
  14 +For IACT observations usually several observations with different configurations
  15 +are combined. The script computes e.g. the overall energy range which could be
  16 +an important input for :doc:`ctbin` to create a suitable energy range. In
  17 +addition the script prints the pointing attributes like the average
  18 +zenith/azimuth angle. If the hidden boolean parameter "offset" is specified to
  19 +"yes", the script queries for the target position and computes the run-by-run
  20 +offset as well as its average. In the observation summary, the time range of
  21 +the observations including total ontime and (dead-time corrected) livetime is
  22 +shown.
  23 +
  24 +The script further contains the hidden parameter "ds9file". If specified with
  25 +a file name, the tool writes out a ds9 region file including a cross for each
  26 +pointing position in the sky.
  27 +
  28 +When executed from within python, the script provides methods to return arrays
  29 +containing observation-wise parameters. This might be useful for graphical
  30 +display within a script. The following methods are implemented:
  31 +- zeniths (returning all zenith angles)
  32 +- azimuths (returning all azimuth angles)
  33 +- offsets (returning all offset angles, provided the hidden parameter offset=yes)
  34 +- ebounds (returning energy boundaries)
  35 +- gtis (returning good time intervals)
  36 +
  37 +
  38 +General parameters
  39 +------------------
  40 +
  41 +``inobs [file]``
  42 + Event list, counts cube, or observation definition file
  43 +
  44 +``(offset = no) [file]``
  45 + Compute offset from target to pointing positions
  46 +
  47 +``ra [real]``
  48 + Target right ascension for offset computation (only queried if offset=yes)
  49 +
  50 +``dec [real]``
  51 + Target declination for offset computation (only queried if offset=yes)
  52 +
  53 +``(ds9file = NONE) [file]``
  54 + DS9 region file containing pointings
  55 +
  56 +
  57 +Standard parameters
  58 +-------------------
  59 +
  60 +``(chatter = 2) [integer]``
  61 + Verbosity of the executable:
  62 + chatter = 0: no information will be logged
  63 +
  64 + chatter = 1: only errors will be logged
  65 +
  66 + chatter = 2: errors and actions will be logged
  67 +
  68 + chatter = 3: report about the task execution
  69 +
  70 + chatter = 4: detailed report about the task execution
  71 +
  72 +``(clobber = yes) [boolean]``
  73 + Specifies whether an existing output counts cube should be overwritten.
  74 +
  75 +``(debug = no) [boolean]``
  76 + Enables debug mode. In debug mode the executable will dump any log file output to the console.
  77 +
  78 +``(mode = ql) [string]``
  79 + Mode of automatic parameters (default is "ql", i.e. "query and learn").
  80 +
  81 +``(logfile = csobsinfo.log) [filename]``
  82 + Log filename.
  83 +
  84 +
  85 +Related tools or scripts
  86 +------------------------
  87 +
  88 +None
0 \ No newline at end of file 89 \ No newline at end of file
doc/source/reference_manual/cstsmapmerge.rst 0 → 100644
  1 +.. _cstsmapmerge:
  2 +
  3 +cstsmapmerge
  4 +============
  5 +
  6 +Merges slices of splitted tsmap computations.
  7 +
  8 +
  9 +Synopsis
  10 +--------
  11 +
  12 +In case a TS map has been computed using the option to split the calculations
  13 +into several jobs, this tool is required to merge the output into one final
  14 +map again. Running :doc:`cttsmap` with the hidden parameters ``binmin`` and
  15 +``binmax`` specified will result in several sliced TS maps. This script merges
  16 +them into one FITS file. The input slices can be passed via the ``inmaps``
  17 +parameter. There are 4 options to specify a list of files that should be merged:
  18 +- a space-separated list of file names (e.g. tsmap1.fits tsmap2.fits)
  19 +- a comma-separated list of file names (e.g. tsmap1.fits,tsmap2.fits)
  20 +- a wildcard string (e.g. tsmap*.xml)
  21 +- an ASCII file containing the file names, one file per line (e.g. @mymaps.txt)
  22 +
  23 +Note that the "@" needs to be specified in case of an ASCII file name.
  24 +
  25 +General parameters
  26 +------------------
  27 +
  28 +``inmaps [string]``
  29 + Input TS map FITS files
  30 +
  31 +``outmap [file]``
  32 + Output TS map FITS file
  33 +
  34 +``(overwrite=yes) [boolean]``
  35 + Overwrite previously filled bins?
  36 +
  37 +``(delete=no) [boolean]``
  38 + Delete merged files?
  39 +
  40 +
  41 +Standard parameters
  42 +-------------------
  43 +
  44 +``(chatter = 2) [integer]``
  45 + Verbosity of the executable:
  46 + chatter = 0: no information will be logged
  47 +
  48 + chatter = 1: only errors will be logged
  49 +
  50 + chatter = 2: errors and actions will be logged
  51 +
  52 + chatter = 3: report about the task execution
  53 +
  54 + chatter = 4: detailed report about the task execution
  55 +
  56 +``(clobber = yes) [boolean]``
  57 + Specifies whether an existing output counts cube should be overwritten.
  58 +
  59 +``(debug = no) [boolean]``
  60 + Enables debug mode. In debug mode the executable will dump any log file output to the console.
  61 +
  62 +``(mode = ql) [string]``
  63 + Mode of automatic parameters (default is "ql", i.e. "query and learn").
  64 +
  65 +``(logfile = cstsmapmerge.log) [filename]``
  66 + Log filename.
  67 +
  68 +
  69 +Related tools or scripts
  70 +------------------------
  71 +
  72 +:ref:`cstsmap`
doc/source/reference_manual/cttsmap.rst
@@ -108,7 +108,8 @@ Standard parameters @@ -108,7 +108,8 @@ Standard parameters
108 Name of log file. 108 Name of log file.
109 109
110 110
111 -Related tools  
112 -------------- 111 +Related tools or scripts
  112 +------------------------
  113 +
  114 +:ref:`cstsmapmerge`
113 115
114 -None  
doc/source/reference_manual/index.rst
@@ -45,3 +45,7 @@ cscripts @@ -45,3 +45,7 @@ cscripts
45 csspec --- Computes spectral points <csspec> 45 csspec --- Computes spectral points <csspec>
46 csresmap --- Generates residual map <csresmap> 46 csresmap --- Generates residual map <csresmap>
47 cstsdist --- Generates TS distribution <cstsdist> 47 cstsdist --- Generates TS distribution <cstsdist>
  48 + csobsinfo --- Shows observation container content <csobsinfo>
  49 + csmodelinfo --- Shows model container content <csmodelinfo>
  50 + csmodelmerge --- Merges several model containers into one file <csmodelmerge>
  51 + cstsmapmerge --- Merges slices from ts map computations <cstsmapmerge>
test/data/model_cube_background2.xml 0 → 100644
  1 +<?xml version="1.0" standalone="no"?>
  2 +<source_library title="source library">
  3 + <source name="CTABackgroundModel2" type="CTACubeBackground" instrument="CTA">
  4 + <spectrum type="PowerLaw">
  5 + <parameter name="Prefactor" scale="1.0" value="1.0" min="1e-3" max="1e+3" free="1"/>
  6 + <parameter name="Index" scale="1.0" value="0.0" min="-5.0" max="+5.0" free="1"/>
  7 + <parameter name="Scale" scale="1e6" value="1.0" min="0.01" max="1000.0" free="0"/>
  8 + </spectrum>
  9 + </source>
  10 +</source_library>
test/data/tsmap_0.fits 0 → 100644
No preview for this file type
test/data/tsmap_1.fits 0 → 100644
No preview for this file type
test/test_cscripts.sh.in
@@ -36,7 +36,7 @@ $ECHO &quot;*****************&quot; @@ -36,7 +36,7 @@ $ECHO &quot;*****************&quot;
36 # 36 #
37 # Remove any existing result files 37 # Remove any existing result files
38 # ================================ 38 # ================================
39 -rm -rf *.fits *.xml *.dat 39 +rm -rf *.fits *.xml *.dat *.reg
40 40
41 41
42 # 42 #
@@ -74,6 +74,203 @@ $ECHO &quot; ok&quot; @@ -74,6 +74,203 @@ $ECHO &quot; ok&quot;
74 74
75 75
76 # 76 #
  77 +# Test csobsinfo
  78 +# ==============
  79 +$ECHO -n "Test csobsinfo: "
  80 +chmod +x @abs_top_srcdir@/cscripts/csobsinfo.py
  81 +@abs_top_srcdir@/cscripts/csobsinfo.py \
  82 + inobs="obs.xml" \
  83 + ds9file="obs.reg" \
  84 + offset=yes \
  85 + ra="83.6331" \
  86 + dec="22.01" > csobsinfo.log
  87 +$ECHO -n "."
  88 +if [ -s "obs.reg" ]
  89 +then
  90 + $ECHO -n "."
  91 +else
  92 + $ECHO " obs.reg file is not valid"
  93 + exit 1
  94 +fi
  95 +$ECHO " ok"
  96 +
  97 +
  98 +#
  99 +# Test csmodelinfo
  100 +# ================
  101 +$ECHO -n "Test csmodelinfo: "
  102 +chmod +x @abs_top_srcdir@/cscripts/csmodelinfo.py
  103 +@abs_top_srcdir@/cscripts/csmodelinfo.py \
  104 + inmodel="data/crab.xml" \
  105 + ds9file="model.reg" > csmodelinfo.log
  106 +$ECHO -n "."
  107 +if [ -s "model.reg" ]
  108 +then
  109 + $ECHO -n "."
  110 +else
  111 + $ECHO " model.reg file is not valid"
  112 + exit 1
  113 +fi
  114 +$ECHO " ok"
  115 +
  116 +
  117 +#
  118 +# Test csmodelmerge (space-separated)
  119 +# ===================================
  120 +$ECHO -n "Test csmodelmerge (space-separated): "
  121 +chmod +x @abs_top_srcdir@/cscripts/csmodelmerge.py
  122 +@abs_top_srcdir@/cscripts/csmodelmerge.py \
  123 + inmodels="data/crab.xml data/source1.xml" \
  124 + outmodel="merged_models.xml" > csmodelmerge.log
  125 +$ECHO -n "."
  126 +if [ -s "merged_models.xml" ]
  127 +then
  128 + $ECHO -n "."
  129 +else
  130 + $ECHO " merged_models.xml file is not valid"
  131 + exit 1
  132 +fi
  133 +$ECHO " ok"
  134 +
  135 +
  136 +#
  137 +# Test csmodelmerge (comma-separated)
  138 +# ===================================
  139 +$ECHO -n "Test csmodelmerge (comma-separated): "
  140 +chmod +x @abs_top_srcdir@/cscripts/csmodelmerge.py
  141 +@abs_top_srcdir@/cscripts/csmodelmerge.py \
  142 + inmodels="data/crab.xml,data/source1.xml" \
  143 + outmodel="merged_models2.xml" > csmodelmerge.log
  144 +$ECHO -n "."
  145 +if [ -s "merged_models2.xml" ]
  146 +then
  147 + $ECHO -n "."
  148 +else
  149 + $ECHO " merged_models2.xml file is not valid"
  150 + exit 1
  151 +fi
  152 +$ECHO " ok"
  153 +
  154 +
  155 +#
  156 +# Test csmodelmerge (wildcard string)
  157 +# ===================================
  158 +$ECHO -n "Test csmodelmerge (wildcard string): "
  159 +chmod +x @abs_top_srcdir@/cscripts/csmodelmerge.py
  160 +@abs_top_srcdir@/cscripts/csmodelmerge.py \
  161 + inmodels="data/model_cube_background*.xml" \
  162 + outmodel="merged_models3.xml" > csmodelmerge.log
  163 +$ECHO -n "."
  164 +if [ -s "merged_models3.xml" ]
  165 +then
  166 + $ECHO -n "."
  167 +else
  168 + $ECHO " merged_models3.xml file is not valid"
  169 + exit 1
  170 +fi
  171 +$ECHO " ok"
  172 +
  173 +
  174 +#
  175 +# Test csmodelmerge (ascii-file)
  176 +# ==============================
  177 +ls data/model_cube_background* > models.txt
  178 +$ECHO -n "Test csmodelmerge (ascii-file): "
  179 +chmod +x @abs_top_srcdir@/cscripts/csmodelmerge.py
  180 +@abs_top_srcdir@/cscripts/csmodelmerge.py \
  181 + inmodels="@models.txt" \
  182 + outmodel="merged_models4.xml" > csmodelmerge.log
  183 +$ECHO -n "."
  184 +if [ -s "merged_models4.xml" ]
  185 +then
  186 + $ECHO -n "."
  187 +else
  188 + $ECHO " merged_models4.xml file is not valid"
  189 + exit 1
  190 +fi
  191 +$ECHO " ok"
  192 +rm models.txt
  193 +
  194 +
  195 +#
  196 +# Test cstsmapmerge (comma-separated)
  197 +# ===================================
  198 +$ECHO -n "Test cstsmapmerge (comma-separated): "
  199 +chmod +x @abs_top_srcdir@/cscripts/cstsmapmerge.py
  200 +@abs_top_srcdir@/cscripts/cstsmapmerge.py \
  201 + inmaps="data/tsmap_0.fits,data/tsmap_1.fits" \
  202 + outmap="merged_tsmap1.fits" > cstsmapmerge.log
  203 +$ECHO -n "."
  204 +if [ -s "merged_tsmap1.fits" ]
  205 +then
  206 + $ECHO -n "."
  207 +else
  208 + $ECHO " merged_tsmap1.fits file is not valid"
  209 + exit 1
  210 +fi
  211 +$ECHO " ok"
  212 +
  213 +
  214 +#
  215 +# Test cstsmapmerge (space-separated)
  216 +# ===================================
  217 +$ECHO -n "Test cstsmapmerge (space-separated): "
  218 +chmod +x @abs_top_srcdir@/cscripts/cstsmapmerge.py
  219 +@abs_top_srcdir@/cscripts/cstsmapmerge.py \
  220 + inmaps="data/tsmap_0.fits data/tsmap_1.fits" \
  221 + outmap="merged_tsmap2.fits" > cstsmapmerge.log
  222 +$ECHO -n "."
  223 +if [ -s "merged_tsmap2.fits" ]
  224 +then
  225 + $ECHO -n "."
  226 +else
  227 + $ECHO " merged_tsmap2.fits file is not valid"
  228 + exit 1
  229 +fi
  230 +$ECHO " ok"
  231 +
  232 +
  233 +#
  234 +# Test cstsmapmerge (wildcard string)
  235 +# ===================================
  236 +$ECHO -n "Test cstsmapmerge (wildcard string): "
  237 +chmod +x @abs_top_srcdir@/cscripts/cstsmapmerge.py
  238 +@abs_top_srcdir@/cscripts/cstsmapmerge.py \
  239 + inmaps="data/tsmap_*.fits" \
  240 + outmap="merged_tsmap3.fits" > cstsmapmerge.log
  241 +$ECHO -n "."
  242 +if [ -s "merged_tsmap3.fits" ]
  243 +then
  244 + $ECHO -n "."
  245 +else
  246 + $ECHO " merged_tsmap3.fits file is not valid"
  247 + exit 1
  248 +fi
  249 +$ECHO " ok"
  250 +
  251 +
  252 +#
  253 +# Test cstsmapmerge (ascii-file)
  254 +# ==============================
  255 +ls data/tsmap_*.fits > tsmaps.txt
  256 +$ECHO -n "Test cstsmapmerge (ascii-file): "
  257 +chmod +x @abs_top_srcdir@/cscripts/cstsmapmerge.py
  258 +@abs_top_srcdir@/cscripts/cstsmapmerge.py \
  259 + inmaps="@tsmaps.txt" \
  260 + outmap="merged_tsmap4.fits" > cstsmapmerge.log
  261 +$ECHO -n "."
  262 +if [ -s "merged_tsmap4.fits" ]
  263 +then
  264 + $ECHO -n "."
  265 +else
  266 + $ECHO " merged_tsmap4.fits file is not valid"
  267 + exit 1
  268 +fi
  269 +$ECHO " ok"
  270 +rm tsmaps.txt
  271 +
  272 +
  273 +#
77 # Test cspull 274 # Test cspull
78 # =========== 275 # ===========
79 $ECHO -n "Test cspull: " 276 $ECHO -n "Test cspull: "