Commit 71926bca0d6d34123337bc34d5579de99dcf78bc

Authored by Jürgen Knödlseder
1 parent 2cbd1b20

Add csmodelselect script (#1879)

ChangeLog
1 -2016-11-21 1 +2016-11-22
2 2
3 * Version 1.2.0 released 3 * Version 1.2.0 released
4 ======================== 4 ========================
5 5
  6 + Add csmodelselect script (#1879)
6 Add startindex parameter to ctobssim (#1878) 7 Add startindex parameter to ctobssim (#1878)
7 Fix energy boundary handline in cssens (#1873) 8 Fix energy boundary handline in cssens (#1873)
8 Add outcovmat parameter to ctlike (#1863) 9 Add outcovmat parameter to ctlike (#1863)
1 New Features and Important Changes in ctools 1.2.0 1 New Features and Important Changes in ctools 1.2.0
2 2
3 -21 November 2016 3 +22 November 2016
4 4
5 5
6 Introduction 6 Introduction
@@ -219,6 +219,9 @@ results on a VO hub (#1871). @@ -219,6 +219,9 @@ results on a VO hub (#1871).
219 Fix energy boundary handling in cssens that has been corrupted during code 219 Fix energy boundary handling in cssens that has been corrupted during code
220 refactoring (#1873). 220 refactoring (#1873).
221 221
  222 +Added csmodelselect script that allows selecting models from a model definition
  223 +XML file (#1879).
  224 +
222 225
223 Examples 226 Examples
224 -------- 227 --------
cscripts/Makefile.am
@@ -26,6 +26,7 @@ pythonscripts = $(builddir)/__init__.py \ @@ -26,6 +26,7 @@ pythonscripts = $(builddir)/__init__.py \
26 $(srcdir)/cslightcrv.py \ 26 $(srcdir)/cslightcrv.py \
27 $(srcdir)/csmodelinfo.py \ 27 $(srcdir)/csmodelinfo.py \
28 $(srcdir)/csmodelmerge.py \ 28 $(srcdir)/csmodelmerge.py \
  29 + $(srcdir)/csmodelselect.py \
29 $(srcdir)/csobs2caldb.py \ 30 $(srcdir)/csobs2caldb.py \
30 $(srcdir)/csobsdef.py \ 31 $(srcdir)/csobsdef.py \
31 $(srcdir)/csobsinfo.py \ 32 $(srcdir)/csobsinfo.py \
@@ -53,6 +54,7 @@ parfiles = $(srcdir)/cscaldb.par \ @@ -53,6 +54,7 @@ parfiles = $(srcdir)/cscaldb.par \
53 $(srcdir)/cslightcrv.par \ 54 $(srcdir)/cslightcrv.par \
54 $(srcdir)/csmodelinfo.par \ 55 $(srcdir)/csmodelinfo.par \
55 $(srcdir)/csmodelmerge.par \ 56 $(srcdir)/csmodelmerge.par \
  57 + $(srcdir)/csmodelselect.par \
56 $(srcdir)/csobs2caldb.par \ 58 $(srcdir)/csobs2caldb.par \
57 $(srcdir)/csobsdef.par \ 59 $(srcdir)/csobsdef.par \
58 $(srcdir)/csobsinfo.par \ 60 $(srcdir)/csobsinfo.par \
@@ -77,6 +79,7 @@ linkscripts = cscaldb \ @@ -77,6 +79,7 @@ linkscripts = cscaldb \
77 cslightcrv \ 79 cslightcrv \
78 csmodelinfo \ 80 csmodelinfo \
79 csmodelmerge \ 81 csmodelmerge \
  82 + csmodelselect \
80 csobs2caldb \ 83 csobs2caldb \
81 csobsdef \ 84 csobsdef \
82 csobsinfo \ 85 csobsinfo \
@@ -102,6 +105,7 @@ testscripts = $(srcdir)/tests/__init__.py \ @@ -102,6 +105,7 @@ testscripts = $(srcdir)/tests/__init__.py \
102 $(top_srcdir)/test/test_cscaldb.py \ 105 $(top_srcdir)/test/test_cscaldb.py \
103 $(top_srcdir)/test/test_csmodelinfo.py \ 106 $(top_srcdir)/test/test_csmodelinfo.py \
104 $(top_srcdir)/test/test_csmodelmerge.py \ 107 $(top_srcdir)/test/test_csmodelmerge.py \
  108 + $(top_srcdir)/test/test_csmodelselect.py \
105 $(top_srcdir)/test/test_csobs2caldb.py \ 109 $(top_srcdir)/test/test_csobs2caldb.py \
106 $(top_srcdir)/test/test_csobsdef.py \ 110 $(top_srcdir)/test/test_csobsdef.py \
107 $(top_srcdir)/test/test_csobsinfo.py \ 111 $(top_srcdir)/test/test_csobsinfo.py \
cscripts/__init__.py.in
@@ -29,6 +29,7 @@ __all__ = [ @@ -29,6 +29,7 @@ __all__ = [
29 "cslightcrv", 29 "cslightcrv",
30 "csmodelinfo", 30 "csmodelinfo",
31 "csmodelmerge", 31 "csmodelmerge",
  32 + "csmodelselect",
32 "csobs2caldb", 33 "csobs2caldb",
33 "csobsdef", 34 "csobsdef",
34 "csobsinfo", 35 "csobsinfo",
@@ -54,28 +55,29 @@ if cur_version > req_version: @@ -54,28 +55,29 @@ if cur_version > req_version:
54 "csiactobs"]) 55 "csiactobs"])
55 56
56 # Import 57 # Import
57 -from cscripts.cscaldb import cscaldb  
58 -from cscripts.csinfo import csinfo  
59 -from cscripts.cslightcrv import cslightcrv  
60 -from cscripts.csmodelinfo import csmodelinfo  
61 -from cscripts.csmodelmerge import csmodelmerge  
62 -from cscripts.csobs2caldb import csobs2caldb  
63 -from cscripts.csobsdef import csobsdef  
64 -from cscripts.csobsinfo import csobsinfo  
65 -from cscripts.cspull import cspull  
66 -from cscripts.csresmap import csresmap  
67 -from cscripts.csroot2caldb import csroot2caldb  
68 -from cscripts.cssens import cssens  
69 -from cscripts.csspec import csspec  
70 -from cscripts.cstsdist import cstsdist  
71 -from cscripts.cstsmapmerge import cstsmapmerge  
72 -from cscripts.cstsmapsplit import cstsmapsplit  
73 -from cscripts.csviscube import csviscube  
74 -from cscripts.csworkflow import csworkflow  
75 -from cscripts import obsutils  
76 -from cscripts import modutils  
77 -from cscripts import calutils  
78 -from cscripts import ioutils 58 +from cscripts.cscaldb import cscaldb
  59 +from cscripts.csinfo import csinfo
  60 +from cscripts.cslightcrv import cslightcrv
  61 +from cscripts.csmodelinfo import csmodelinfo
  62 +from cscripts.csmodelmerge import csmodelmerge
  63 +from cscripts.csmodelselect import csmodelselect
  64 +from cscripts.csobs2caldb import csobs2caldb
  65 +from cscripts.csobsdef import csobsdef
  66 +from cscripts.csobsinfo import csobsinfo
  67 +from cscripts.cspull import cspull
  68 +from cscripts.csresmap import csresmap
  69 +from cscripts.csroot2caldb import csroot2caldb
  70 +from cscripts.cssens import cssens
  71 +from cscripts.csspec import csspec
  72 +from cscripts.cstsdist import cstsdist
  73 +from cscripts.cstsmapmerge import cstsmapmerge
  74 +from cscripts.cstsmapsplit import cstsmapsplit
  75 +from cscripts.csviscube import csviscube
  76 +from cscripts.csworkflow import csworkflow
  77 +from cscripts import obsutils
  78 +from cscripts import modutils
  79 +from cscripts import calutils
  80 +from cscripts import ioutils
79 if cur_version > req_version: 81 if cur_version > req_version:
80 from cscripts.csfindobs import csfindobs 82 from cscripts.csfindobs import csfindobs
81 from cscripts.csiactcopy import csiactcopy 83 from cscripts.csiactcopy import csiactcopy
cscripts/csmodelselect.par 0 → 100644
  1 +#############################################################################
  2 +# #
  3 +# CTA Science Analysis Tools #
  4 +# #
  5 +# ------------------------------------------------------------------------- #
  6 +# #
  7 +# File: csmodelselect.par #
  8 +# #
  9 +# Author: Juergen Knoedlseder #
  10 +# jknodlseder@irap.omp.eu #
  11 +# IRAP, Toulouse, France #
  12 +# #
  13 +# Purpose: Parameter file for the csmodelselect script #
  14 +# #
  15 +#############################################################################
  16 +#
  17 +# Input and output parameters
  18 +#============================
  19 +inobs, f, a, obs.xml,,, "Input event list or observation definition XML file"
  20 +inmodel, f, a, inmodel.xml,,, "Input model definition XML file"
  21 +outmodel, f, a, outmodel.xml,,, "Output model definition XML file"
  22 +
  23 +#
  24 +# Script parameters
  25 +#==================
  26 +roilimit, r, h, 4.5,,, "Maximum RoI radius (deg)"
  27 +roimargin, r, h, 0.1,,, "Radial margin to be added to RoIs (deg)"
  28 +ethres, r, h, 0.1,,, "Energy threshold for source flux selection (TeV)"
  29 +fluxlimit, r, h, 1.0e-12,,, "Minimum source flux for selection (ph/cm2/s)"
  30 +tslimit, r, h, 10.0,,, "Minimum Test Statistic for selection"
  31 +fit_pos, b, h, yes,,, "Fit source positions?"
  32 +fit_shape, b, h, no,,, "Fit source shapes?"
  33 +
  34 +#
  35 +# Standard parameters
  36 +#====================
  37 +chatter, i, h, 2,0,4, "Chattiness of output"
  38 +clobber, b, h, yes,,, "Overwrite existing output files with new output files?"
  39 +debug, b, h, no,,, "Debugging mode activated"
  40 +mode, s, h, ql,,, "Mode of automatic parameters"
  41 +logfile, f, h, csmodelselect.log,,, "Log filename"
cscripts/csmodelselect.py 0 → 100755
  1 +#!/usr/bin/env python
  2 +# ==========================================================================
  3 +# Selects model from a model definition XML file
  4 +#
  5 +# Copyright (C) 2016 Juergen Knoedlseder
  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 sys
  22 +import gammalib
  23 +import ctools
  24 +
  25 +
  26 +# =================== #
  27 +# csmodelselect class #
  28 +# =================== #
  29 +class csmodelselect(ctools.cscript):
  30 + """
  31 + Selects model from a model container
  32 + """
  33 +
  34 + # Constructor
  35 + def __init__(self, *argv):
  36 + """
  37 + Constructor
  38 + """
  39 + # Set name
  40 + self._name = 'csmodelselect'
  41 + self._version = '1.2.0'
  42 +
  43 + # Initialise observation container from constructor arguments
  44 + self._obs, argv = self._set_input_obs(argv)
  45 +
  46 + # Initialise class members
  47 + self._models = gammalib.GModels()
  48 +
  49 + # Initialise application by calling the appropriate class constructor
  50 + self._init_cscript(argv)
  51 +
  52 + # Return
  53 + return
  54 +
  55 +
  56 + # Private methods
  57 + def _get_parameters(self):
  58 + """
  59 + Get parameters from parfile and setup the observation
  60 + """
  61 + # Query input parameters
  62 + self['inobs'].filename()
  63 + self['inmodel'].filename()
  64 +
  65 + # Query hidden parameters
  66 + self['roilimit'].real()
  67 + self['roimargin'].real()
  68 + self['ethres'].real()
  69 + self['fluxlimit'].real()
  70 + self['tslimit'].real()
  71 + self['fit_pos'].boolean()
  72 + self['fit_shape'].boolean()
  73 +
  74 + # Query ahead output model filename
  75 + if self._read_ahead():
  76 + self['outmodel'].filename()
  77 +
  78 + # If there are no observations in container then get them from the
  79 + # parameter file
  80 + if self._obs.size() == 0:
  81 + self._obs = self._get_observations(False)
  82 +
  83 + # Get models
  84 + self._models = gammalib.GModels(self['inmodel'].filename())
  85 +
  86 + # Write input parameters into logger
  87 + self._log_parameters(gammalib.TERSE)
  88 +
  89 + # Return
  90 + return
  91 +
  92 + def _select_model(self, model, obs):
  93 + """
  94 + Select model
  95 +
  96 + Parameters
  97 + ----------
  98 + model : `~gammalib.GModel`
  99 + Model
  100 + obs : `~gammalib.GObservation`
  101 + Observation container
  102 +
  103 + Returns
  104 + -------
  105 + select : bool
  106 + Model selection flag
  107 + """
  108 + # Get selection parameters
  109 + roilimit = self['roilimit'].real()
  110 + roimargin = self['roimargin'].real()
  111 + ethres = self['ethres'].real()
  112 + fluxlimit = self['fluxlimit'].real()
  113 + tslimit = self['tslimit'].real()
  114 +
  115 + # Initialise selection flag to True
  116 + select = True
  117 + msg = 'Select by default'
  118 +
  119 + # If the model has a spatial component then check of overlap
  120 + if hasattr(model, 'spatial'):
  121 +
  122 + # Determine the model bounding box
  123 + model_bounds = model.spatial().region()
  124 +
  125 + # Initialise with an unselect model
  126 + select = False
  127 + msg = 'Exclude since outside any RoI'
  128 +
  129 + # Loop over all observations and check whether the model falls
  130 + # into one of them
  131 + for o in obs:
  132 +
  133 + # Get RoI centre and radius. The RoI radius is limited by
  134 + # roilimit. A margin given by roimargin is added to the RoI
  135 + # radius.
  136 + obs_centre = o.roi().centre().dir()
  137 + obs_radius = o.roi().radius()
  138 + if obs_radius > roilimit:
  139 + obs_radius = roilimit
  140 + obs_radius += roimargin
  141 +
  142 + # Set circular sky region
  143 + obs_bounds = gammalib.GSkyRegionCircle(obs_centre, obs_radius)
  144 +
  145 + # If model overlaps with RoI then signal overlap
  146 + if obs_bounds.overlaps(model_bounds):
  147 + select = True
  148 + msg = 'Select due to overlap with at least one RoI'
  149 + break
  150 +
  151 + # If model is selected and if model has a TS value then apply TS
  152 + # selection
  153 + if select and model.has_ts():
  154 + if model.ts() < tslimit:
  155 + select = False
  156 + msg = 'Exclude since below TS limit (TS=%.3f)' % model.ts()
  157 +
  158 +
  159 + # If model is selected and if model is a sky model then apply flux
  160 + # limit selection
  161 + if select and model.classname() == 'GModelSky':
  162 + emin = gammalib.GEnergy(ethres, 'TeV')
  163 + emax = gammalib.GEnergy(1000.0, 'TeV')
  164 + flux = model.spectral().flux(emin, emax)
  165 + if flux < fluxlimit:
  166 + select = False
  167 + msg = 'Exclude since below flux limit (Flux=%.3e ph/cm2/s)' % flux
  168 +
  169 + # Log model selection
  170 + self._log_value(gammalib.NORMAL, model.name(), msg)
  171 +
  172 + # Return selection flag
  173 + return select
  174 +
  175 + def _set_model_parameters(self, model):
  176 + """
  177 + Set model parameters
  178 +
  179 + Parameters
  180 + ----------
  181 + model : `~gammalib.GModel`
  182 + Model
  183 +
  184 + Returns
  185 + -------
  186 + model : `~gammalib.GModel`
  187 + Model with parameter set
  188 + """
  189 + # Get selection parameters
  190 + fit_pos = self['fit_pos'].boolean()
  191 + fit_shape = self['fit_shape'].boolean()
  192 +
  193 + # If the model has a spatial component then set the spatial parameters
  194 + if hasattr(model, 'spatial'):
  195 +
  196 + # Loop over all parameters
  197 + for par in model:
  198 +
  199 + # Handle position parameters
  200 + if par.name() == 'RA' or par.name() == 'DEC':
  201 + if fit_pos:
  202 + par.free()
  203 + else:
  204 + par.fix()
  205 +
  206 + # Handle shape parameters
  207 + elif par.name() == 'Radius' or \
  208 + par.name() == 'Sigma' or \
  209 + par.name() == 'Width' or \
  210 + par.name() == 'PA' or \
  211 + par.name() == 'MajorRadius' or \
  212 + par.name() == 'MinorRadius':
  213 + if fit_shape:
  214 + par.free()
  215 + else:
  216 + par.fix()
  217 +
  218 + # Return model
  219 + return model
  220 +
  221 +
  222 + # Public methods
  223 + def run(self):
  224 + """
  225 + Run the script
  226 + """
  227 + # Switch screen logging on in debug mode
  228 + if self._logDebug():
  229 + self._log.cout(True)
  230 +
  231 + # Get parameters
  232 + self._get_parameters()
  233 +
  234 + # Initialise empty model container for selected models
  235 + models = gammalib.GModels()
  236 +
  237 + # Write input observation container into logger
  238 + self._log_observations(gammalib.NORMAL, self._obs, 'Input observation');
  239 +
  240 + # Write input models into logger
  241 + self._log_models(gammalib.VERBOSE, self._models, 'Input model')
  242 +
  243 + # Write header
  244 + self._log_header1(gammalib.NORMAL, 'Model selection')
  245 +
  246 + # Loop over model components
  247 + for model in self._models:
  248 +
  249 + # If model should be selected then set model parameters and append
  250 + # model to the output container
  251 + if self._select_model(model, self._obs):
  252 +
  253 + # Set model parameters
  254 + model = self._set_model_parameters(model)
  255 +
  256 + # Append model
  257 + models.append(model)
  258 +
  259 + # Copy selected model into selected models
  260 + self._models = models
  261 +
  262 + # Write selected models into logger
  263 + self._log_models(gammalib.VERBOSE, self._models, 'Selected model')
  264 +
  265 + # Return
  266 + return
  267 +
  268 + def save(self):
  269 + """
  270 + Save model definition XML file
  271 + """
  272 + # Write header
  273 + self._log_header1(gammalib.TERSE, 'Save models')
  274 +
  275 + # Get output filename in case it was not read ahead
  276 + outmodel = self['outmodel'].filename()
  277 +
  278 + # If file exists and clobber flag is false then raise an exception
  279 + if outmodel.exists() and not self._clobber:
  280 + msg = ('Cannot save "'+outmodel.url()+'": File already exists. '
  281 + 'Use parameter clobber=yes to allow overwriting of files.')
  282 + raise RuntimeError(msg)
  283 +
  284 + # Otherwise log filename and save file
  285 + else:
  286 + # Log filename
  287 + self._log_value(gammalib.NORMAL, 'Model definition XML file',
  288 + outmodel.url())
  289 +
  290 + # Save models
  291 + self._models.save(outmodel)
  292 +
  293 + # Return
  294 + return
  295 +
  296 + def execute(self):
  297 + """
  298 + Execute the script
  299 + """
  300 + # Open logfile
  301 + self.logFileOpen()
  302 +
  303 + # Read ahead output parameters
  304 + self._read_ahead(True)
  305 +
  306 + # Run the script
  307 + self.run()
  308 +
  309 + # Save model file if required
  310 + self.save()
  311 +
  312 + # Return
  313 + return
  314 +
  315 +
  316 +# ======================== #
  317 +# Main routine entry point #
  318 +# ======================== #
  319 +if __name__ == '__main__':
  320 +
  321 + # Create instance of application
  322 + app = csmodelselect(sys.argv)
  323 +
  324 + # Execute application
  325 + app.execute()
doc/source/users/reference_manual/csmodelselect.rst 0 → 100644
  1 +.. _csmodelselect:
  2 +
  3 +csmodelselect
  4 +=============
  5 +
  6 +Selects models from a model definition XML file.
  7 +
  8 +
  9 +Synopsis
  10 +--------
  11 +
  12 +This script selects all models from a model definiton XML file that spatially
  13 +overlap with the Region of Interests (RoIs) of a list of observations and writes
  14 +these models into a new model definition XML file. In addition to the spatial
  15 +selection, the tool allows selecting only models with a photon flux and/or a
  16 +Test Statistic value above a given limit. The script also allows to specify
  17 +whether the source positions and/or source shapes should be fit.
  18 +
  19 +
  20 +General parameters
  21 +------------------
  22 +
  23 +``inobs [file]``
  24 + Input event list or observation definition XML file
  25 +
  26 +``inmodel [file]``
  27 + Input model definition XML file
  28 +
  29 +``outmodel [file]``
  30 + Output model definition XML file
  31 +
  32 +``(roilimit = 4.5) [real]``
  33 + Maximum RoI radius (deg)
  34 +
  35 +``(roimargin = 0.1) [real]``
  36 + Radial margin to be added to RoIs (deg)
  37 +
  38 +``(ethres = 0.1) [real]``
  39 + Energy threshold for source flux selection (TeV)
  40 +
  41 +``(fluxlimit = 1.0e-12) [real]``
  42 + Minimum source flux for selection (ph/cm2/s)
  43 +
  44 +``(tslimit = 10.0) [real]``
  45 + Minimum Test Statistic for selection
  46 +
  47 +``(fit_pos = yes) [boolean]``
  48 + Fit source positions?
  49 +
  50 +``(fit_shape = no) [boolean]``
  51 + Fit source shapes?
  52 +
  53 +
  54 +Standard parameters
  55 +-------------------
  56 +
  57 +``(chatter = 2) [integer]``
  58 + Verbosity of the executable:
  59 + chatter = 0: no information will be logged
  60 +
  61 + chatter = 1: only errors will be logged
  62 +
  63 + chatter = 2: errors and actions will be logged
  64 +
  65 + chatter = 3: report about the task execution
  66 +
  67 + chatter = 4: detailed report about the task execution
  68 +
  69 +``(clobber = yes) [boolean]``
  70 + Specifies whether an existing output model file should be overwritten.
  71 +
  72 +``(debug = no) [boolean]``
  73 + Enables debug mode. In debug mode the executable will dump any log file
  74 + output to the console.
  75 +
  76 +``(mode = ql) [string]``
  77 + Mode of automatic parameters (default is "ql", i.e. "query and learn").
  78 +
  79 +``(logfile = csmodelselect.log) [filename]``
  80 + Log filename.
  81 +
  82 +
  83 +Related tools or scripts
  84 +------------------------
  85 +
  86 +None
doc/source/users/reference_manual/cspull.rst
@@ -124,7 +124,8 @@ Standard parameters @@ -124,7 +124,8 @@ Standard parameters
124 Specifies whether an existing output file should be overwritten. 124 Specifies whether an existing output file should be overwritten.
125 125
126 ``(debug = no) [boolean]`` 126 ``(debug = no) [boolean]``
127 - Enables debug mode. In debug mode the executable will dump any log file output to the console. 127 + Enables debug mode. In debug mode the executable will dump any log file
  128 + output to the console.
128 129
129 ``(mode = ql) [string]`` 130 ``(mode = ql) [string]``
130 Mode of automatic parameters (default is "ql", i.e. "query and learn"). 131 Mode of automatic parameters (default is "ql", i.e. "query and learn").
doc/source/users/reference_manual/index.rst
@@ -44,6 +44,7 @@ cscripts @@ -44,6 +44,7 @@ cscripts
44 cslightcrv --- Computes lightcurve <cslightcrv> 44 cslightcrv --- Computes lightcurve <cslightcrv>
45 csmodelinfo --- Shows model container content <csmodelinfo> 45 csmodelinfo --- Shows model container content <csmodelinfo>
46 csmodelmerge --- Merges several model containers into one file <csmodelmerge> 46 csmodelmerge --- Merges several model containers into one file <csmodelmerge>
  47 + csmodelselect --- Select models from model definition file <csmodelselect>
47 csobsdef --- Generates observation definition file <csobsdef> 48 csobsdef --- Generates observation definition file <csobsdef>
48 csobsinfo --- Shows observation container content <csobsinfo> 49 csobsinfo --- Shows observation container content <csobsinfo>
49 cspull --- Generates pull distribution <cspull> 50 cspull --- Generates pull distribution <cspull>
test/test_csmodelselect.py 0 → 100755
  1 +#! /usr/bin/env python
  2 +# ==========================================================================
  3 +# This scripts performs unit tests for the csmodelselect script
  4 +#
  5 +# Copyright (C) 2016 Juergen Knoedlseder
  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 os
  22 +import gammalib
  23 +import cscripts
  24 +from testing import test
  25 +
  26 +
  27 +# =================================== #
  28 +# Test class for csmodelselect script #
  29 +# =================================== #
  30 +class Test(test):
  31 + """
  32 + Test class for csmodelselect script
  33 +
  34 + This test class makes unit tests for the csmodelselect script by using it
  35 + from the command line and from Python.
  36 + """
  37 +
  38 + # Constructor
  39 + def __init__(self):
  40 + """
  41 + Constructor.
  42 + """
  43 + # Call base class constructor
  44 + test.__init__(self)
  45 +
  46 + # Return
  47 + return
  48 +
  49 + # Set test functions
  50 + def set(self):
  51 + """
  52 + Set all test functions.
  53 + """
  54 + # Set test name
  55 + self.name('csmodelselect')
  56 +
  57 + # Append tests
  58 + self.append(self._test_cmd, 'Test csmodelselect on command line')
  59 + self.append(self._test_python, 'Test csmodelselect from Python')
  60 +
  61 + # Return
  62 + return
  63 +
  64 + # Test csmodelselect on command line
  65 + def _test_cmd(self):
  66 + """
  67 + Test csmodelselect on the command line
  68 + """
  69 + # Set script name
  70 + csmodelselect = self._script('csmodelselect')
  71 +
  72 + # Setup csmodelselect command
  73 + cmd = csmodelselect+' inobs="'+self._events+'"'+ \
  74 + ' inmodel="'+self._model+'"'+ \
  75 + ' outmodel="csmodelselect_cmd1.xml"'+ \
  76 + ' logfile="csmodelselect_cmd1.log" chatter=1'
  77 +
  78 + # Check if execution of wrong command fails
  79 + self.test_assert(self._execute('command_that_does_not_exist') != 0,
  80 + 'Self test of test script')
  81 +
  82 + # Check if execution was successful
  83 + self.test_assert(self._execute(cmd) == 0,
  84 + 'Check successful execution from command line')
  85 +
  86 + # Check model file
  87 + self._check_model_file('csmodelselect_cmd1.xml', 2)
  88 +
  89 + # Setup csmodelselect command
  90 + cmd = csmodelselect+' inobs="'+self._events+'"'+ \
  91 + ' inmodel="model_that_does_not_exist.xml"'+ \
  92 + ' outmodel="csmodelselect_cmd2.xml"'+ \
  93 + ' logfile="csmodelselect_cmd2.log"'
  94 +
  95 + # Check if execution failed
  96 + self.test_assert(self._execute(cmd) != 0,
  97 + 'Check invalid input file when executed from command line')
  98 +
  99 + # Return
  100 + return
  101 +
  102 + # Test csmodelselect from Python
  103 + def _test_python(self):
  104 + """
  105 + Test csmodelselect from Python
  106 + """
  107 + # Allocate empty csmodelselect script
  108 + modelselect = cscripts.csmodelselect()
  109 +
  110 + # Check that saving does not nothing
  111 + modelselect['outmodel'] = 'csmodelselect_py0.xml'
  112 + modelselect['logfile'] = 'csmodelselect_py0.log'
  113 + modelselect.logFileOpen()
  114 + modelselect.save()
  115 +
  116 + # Check than an empty model definition file has been created
  117 + self._check_model_file('csmodelselect_py0.xml', 0)
  118 +
  119 + # Check that clearing does not lead to an exception or segfault
  120 + modelselect.clear()
  121 +
  122 + # Now set csmodelselect parameters
  123 + modelselect['inobs'] = self._events
  124 + modelselect['inmodel'] = self._model
  125 + modelselect['outmodel'] = 'csmodelselect_py1.xml'
  126 + modelselect['logfile'] = 'csmodelselect_py1.log'
  127 + modelselect['chatter'] = 2
  128 +
  129 + # Run csmodelselect script and save models
  130 + modelselect.logFileOpen() # Make sure we get a log file
  131 + modelselect.run()
  132 + modelselect.save()
  133 +
  134 + # Check model file
  135 + self._check_model_file('csmodelselect_py1.xml', 2)
  136 +
  137 + # Execute csmodelselect script again, now with a higher chatter level
  138 + # than before
  139 + modelselect['outmodel'] = 'csmodelselect_py2.xml'
  140 + modelselect['logfile'] = 'csmodelselect_py2.log'
  141 + modelselect['chatter'] = 3
  142 + modelselect.logFileOpen() # Needed to get a new log file
  143 + modelselect.execute()
  144 +
  145 + # Check model file
  146 + self._check_model_file('csmodelselect_py2.xml', 2)
  147 +
  148 + # Return
  149 + return
  150 +
  151 + # Check model file
  152 + def _check_model_file(self, filename, number):
  153 + """
  154 + Check model file
  155 + """
  156 + # Open models
  157 + models = gammalib.GModels(filename)
  158 +
  159 + # Check number of models
  160 + self.test_value(models.size(), number, 'Check for '+str(number)+
  161 + ' models in XML file')
  162 +
  163 + # Return
  164 + return
test/test_python_cscripts.py
@@ -30,6 +30,7 @@ import test_csinfo @@ -30,6 +30,7 @@ import test_csinfo
30 import test_cslightcrv 30 import test_cslightcrv
31 import test_csmodelinfo 31 import test_csmodelinfo
32 import test_csmodelmerge 32 import test_csmodelmerge
  33 +import test_csmodelselect
33 import test_csobs2caldb 34 import test_csobs2caldb
34 import test_csobsdef 35 import test_csobsdef
35 import test_csobsinfo 36 import test_csobsinfo
@@ -114,6 +115,7 @@ def test(installed=False, debug=False): @@ -114,6 +115,7 @@ def test(installed=False, debug=False):
114 test_cslightcrv.Test(), 115 test_cslightcrv.Test(),
115 test_csmodelinfo.Test(), 116 test_csmodelinfo.Test(),
116 test_csmodelmerge.Test(), 117 test_csmodelmerge.Test(),
  118 + test_csmodelselect.Test(),
117 test_csobs2caldb.Test(), 119 test_csobs2caldb.Test(),
118 test_csobsdef.Test(), 120 test_csobsdef.Test(),
119 test_csobsinfo.Test(), 121 test_csobsinfo.Test(),