Commit 25a6a46b78a0f2a94fe8860a7160881863551302
1 parent
85273f2e
Adapt to new GApplication interface with private methods and add par file.
Showing
25 changed files
with
3055 additions
and
2542 deletions
cscripts/Makefile.am
| ... | ... | @@ -10,7 +10,10 @@ pythonscripts = __init__.py \ |
| 10 | 10 | obsutils.py |
| 11 | 11 | |
| 12 | 12 | # Parfiles to be distributed in $(prefix)/syspfiles |
| 13 | -parfiles = cscaldb.par | |
| 13 | +parfiles = cspull.par cssens.par cstsdist.par cscaldb.par csresmap.par \ | |
| 14 | + csobsdef.par csspec.par csobsinfo.par \ | |
| 15 | + csmodelinfo.par csmodelmerge.par cstsmapmerge.par \ | |
| 16 | + csobs2caldb.par | |
| 14 | 17 | |
| 15 | 18 | # Scripts for which symbolic links will be created in bindir |
| 16 | 19 | linkscripts = cspull cssens cstsdist cscaldb csresmap \ | ... | ... |
cscripts/cscaldb.par
| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | # File: cscaldb.par # |
| 8 | 8 | # Version: 1.1.0 # |
| 9 | 9 | # # |
| 10 | -# Author: Jurgen Knodlseder # | |
| 10 | +# Author: Juergen Knoedlseder # | |
| 11 | 11 | # Jurgen.Knodlseder@irap.omp.eu # |
| 12 | 12 | # IRAP # |
| 13 | 13 | # # |
| ... | ... | @@ -20,5 +20,5 @@ |
| 20 | 20 | chatter, i, h, 2,0,4, "Chattiness of output" |
| 21 | 21 | clobber, b, h, yes,,, "Overwrite existing output files with new output files?" |
| 22 | 22 | debug, b, h, no,,, "Debugging mode activated" |
| 23 | -mode, s, h, "ql",,, "Mode of automatic parameters" | |
| 24 | -logfile, f, h, "cscaldb.log",,, "Log filename" | |
| 23 | +mode, s, h, ql,,, "Mode of automatic parameters" | |
| 24 | +logfile, f, h, cscaldb.log,,, "Log filename" | ... | ... |
cscripts/csmodelinfo.par
0 → 100644
| 1 | +############################################################################# | |
| 2 | +# # | |
| 3 | +# CTA Science Analysis Tools # | |
| 4 | +# # | |
| 5 | +# ------------------------------------------------------------------------- # | |
| 6 | +# # | |
| 7 | +# File: csmodelinfo.par # | |
| 8 | +# Version: 1.1.0 # | |
| 9 | +# # | |
| 10 | +# Author: Juergen Knoedlseder # | |
| 11 | +# Jurgen.Knodlseder@irap.omp.eu # | |
| 12 | +# IRAP # | |
| 13 | +# # | |
| 14 | +# Purpose: Parameter file for the csmodelinfo script # | |
| 15 | +# # | |
| 16 | +############################################################################# | |
| 17 | +# | |
| 18 | +# Input and output parameters | |
| 19 | +#============================ | |
| 20 | +inmodel, f, a, model.xml,,, "Input model XML file" | |
| 21 | +ds9file, f, h, NONE,,, "Output DS9 region file containing models" | |
| 22 | + | |
| 23 | +# | |
| 24 | +# Script parameters | |
| 25 | +#================== | |
| 26 | +pnt_type, s, h, cross,circle|box|diamond|cross|x|arrow|boxcircle,, "Marker type for point sources" | |
| 27 | +pnt_mark_size, i, h, 12,,, "Marker size for point sources" | |
| 28 | +show_labels, b, h, yes,yes|no,, "Add source labels?" | |
| 29 | +width, i, h, 2,,, "Line width for regions" | |
| 30 | +fontfamily, s, h, helvetica,helvetica|times|courier,, "Font family for source labels" | |
| 31 | +fontsize, i, h, 12,,, "Font size for source labels" | |
| 32 | +fontweight, s, h, normal,normal|bold,, "Font weight for source labels" | |
| 33 | +fontslant, s, h, roman,roman|italic,, "Font slant for source labels" | |
| 34 | +show_ext_type, b, h, yes,,, "Show type of extended model in source name?" | |
| 35 | +free_color, s, h, green,,, "Color for sources with free parameters (any DS9 color or hex code)" | |
| 36 | +fixed_color, s, h, magenta,,, "Color for source without free parameters (any DS9 color or hex code)" | |
| 37 | + | |
| 38 | +# | |
| 39 | +# Standard parameters | |
| 40 | +#==================== | |
| 41 | +chatter, i, h, 2,0,4, "Chattiness of output" | |
| 42 | +clobber, b, h, yes,,, "Overwrite existing output files with new output files?" | |
| 43 | +debug, b, h, no,,, "Debugging mode activated" | |
| 44 | +mode, s, h, ql,,, "Mode of automatic parameters" | |
| 45 | +logfile, f, h, csmodelinfo.log,,, "Log filename" | ... | ... |
cscripts/csmodelinfo.py
| 1 | 1 | #!/usr/bin/env python |
| 2 | 2 | # ========================================================================== |
| 3 | -# Dump information about models into log file | |
| 3 | +# Shows the content of a model container | |
| 4 | 4 | # |
| 5 | 5 | # Copyright (C) 2015-2016 Michael Mayer |
| 6 | 6 | # |
| ... | ... | @@ -28,34 +28,50 @@ import sys |
| 28 | 28 | # ================= # |
| 29 | 29 | class csmodelinfo(ctools.cscript): |
| 30 | 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. | |
| 31 | + Shows the content of a model container. | |
| 32 | + | |
| 33 | + The script is useful to show, e.g., the number of sources in a model | |
| 34 | + container, the background models, free and fixed parameters etc. | |
| 35 | + The script can also dump the models into a region file to for display | |
| 36 | + with DS9. | |
| 36 | 37 | """ |
| 38 | + | |
| 39 | + # Constructors and destructors | |
| 37 | 40 | def __init__(self, *argv): |
| 38 | 41 | """ |
| 39 | 42 | Constructor. |
| 40 | 43 | """ |
| 41 | 44 | # Set name |
| 42 | - self.name = "csmodelinfo" | |
| 43 | - self.version = "1.1.0" | |
| 45 | + self._name = "csmodelinfo" | |
| 46 | + self._version = "1.1.0" | |
| 44 | 47 | |
| 45 | - # Make sure that parfile exists | |
| 46 | - file = self.parfile() | |
| 48 | + # Initialise class members | |
| 49 | + self._models = gammalib.GModels() | |
| 50 | + self._ds9file = "NONE" | |
| 51 | + self._pnt_type = "" | |
| 52 | + self._pnt_mark_size = 12 | |
| 53 | + self._show_labels = True | |
| 54 | + self._width = 2 | |
| 55 | + self._fontfamily = "helvetica" | |
| 56 | + self._fontsize = 12 | |
| 57 | + self._fontweight = "normal" | |
| 58 | + self._fontslant = "roman" | |
| 59 | + self._show_ext_type = True | |
| 60 | + self._free_color = "green" | |
| 61 | + self._fixed_color = "magenta" | |
| 62 | + self._read_ahead = False | |
| 47 | 63 | |
| 48 | 64 | # Initialise application |
| 49 | 65 | if len(argv) == 0: |
| 50 | - ctools.cscript.__init__(self, self.name, self.version) | |
| 66 | + ctools.cscript.__init__(self, self._name, self._version) | |
| 51 | 67 | elif len(argv) == 1: |
| 52 | - ctools.cscript.__init__(self, self.name, self.version, *argv) | |
| 68 | + ctools.cscript.__init__(self, self._name, self._version, *argv) | |
| 53 | 69 | else: |
| 54 | 70 | raise TypeError("Invalid number of arguments given.") |
| 55 | 71 | |
| 56 | 72 | # Set logger properties |
| 57 | - self.log_header() | |
| 58 | - self.log.date(True) | |
| 73 | + self._log_header() | |
| 74 | + self._log.date(True) | |
| 59 | 75 | |
| 60 | 76 | # Return |
| 61 | 77 | return |
| ... | ... | @@ -67,92 +83,197 @@ class csmodelinfo(ctools.cscript): |
| 67 | 83 | # Return |
| 68 | 84 | return |
| 69 | 85 | |
| 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 | 86 | |
| 105 | - # Return | |
| 106 | - return | |
| 107 | - | |
| 108 | - def get_parameters(self): | |
| 87 | + # Private methods | |
| 88 | + def _get_parameters(self): | |
| 109 | 89 | """ |
| 110 | 90 | Get parameters from parfile and setup the observation. |
| 111 | 91 | """ |
| 112 | 92 | # Get models |
| 113 | - self.models = gammalib.GModels(self["inmodel"].filename()) | |
| 114 | - | |
| 115 | - # Get ds9 filename | |
| 116 | - self.ds9file = self["ds9file"].filename() | |
| 93 | + self._models = gammalib.GModels(self["inmodel"].filename()) | |
| 117 | 94 | |
| 118 | 95 | # 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() | |
| 96 | + self._pnt_type = self["pnt_type"].string() | |
| 97 | + self._pnt_mark_size = self["pnt_mark_size"].integer() | |
| 98 | + self._show_labels = self["show_labels"].boolean() | |
| 99 | + self._width = self["width"].integer() | |
| 100 | + self._fontfamily = self["fontfamily"].string() | |
| 101 | + self._fontsize = self["fontsize"].integer() | |
| 102 | + self._fontweight = self["fontweight"].string() | |
| 103 | + self._fontslant = self["fontslant"].string() | |
| 104 | + self._show_ext_type = self["show_ext_type"].boolean() | |
| 105 | + self._free_color = self["free_color"].string() | |
| 106 | + self._fixed_color = self["fixed_color"].string() | |
| 107 | + | |
| 108 | + # Read ahead DS9 filename | |
| 109 | + if self._read_ahead: | |
| 110 | + self._ds9file = self["ds9file"].filename() | |
| 111 | + | |
| 112 | + # Write input parameters into logger | |
| 113 | + if self._logTerse(): | |
| 114 | + self._log_parameters() | |
| 115 | + self._log("\n") | |
| 130 | 116 | |
| 131 | 117 | # Return |
| 132 | 118 | return |
| 119 | + | |
| 120 | + def _model2ds9string(self, model): | |
| 121 | + """ | |
| 122 | + Converts model into a DS9 region string. | |
| 123 | + | |
| 124 | + Args: | |
| 125 | + model: Model. | |
| 126 | + | |
| 127 | + Returns: | |
| 128 | + DS9 region string. | |
| 129 | + """ | |
| 130 | + # Initialise DS9 region string | |
| 131 | + ds9string = "" | |
| 132 | + | |
| 133 | + # Determine region color. The color will change between a model | |
| 134 | + # where all parameters are fixed and a model with at least one | |
| 135 | + # free parameter. | |
| 136 | + color = self._fixed_color | |
| 137 | + for par in model: | |
| 138 | + if par.is_free(): | |
| 139 | + color = self._free_color | |
| 140 | + break | |
| 141 | + | |
| 142 | + # Retrieve model sky direction. The model is skipped in case that | |
| 143 | + # it does not provide a sky direction. | |
| 144 | + is_valid = True | |
| 145 | + try: | |
| 146 | + modelpos = model.spatial().dir() | |
| 147 | + except AttributeError: | |
| 148 | + self._log("Skip source \""+model.name()+"\" since no " | |
| 149 | + "sky direction is associated with that model.\n") | |
| 150 | + is_valid = False | |
| 151 | + | |
| 152 | + # Continue only if sky direction was found | |
| 153 | + if is_valid: | |
| 154 | + | |
| 155 | + # Retrieve model type and name | |
| 156 | + modeltype = model.type() | |
| 157 | + modelname = model.name() | |
| 158 | + | |
| 159 | + # Handle point source | |
| 160 | + if modeltype == "PointSource": | |
| 161 | + | |
| 162 | + # Append point to DS9 string | |
| 163 | + ds9string += "point(" | |
| 164 | + ds9string += str(modelpos.ra_deg()) | |
| 165 | + ds9string += "," | |
| 166 | + ds9string += str(modelpos.dec_deg()) | |
| 167 | + ds9string += ") # " | |
| 168 | + ds9string += "point="+self._pnt_type+" " | |
| 169 | + ds9string += str(self._pnt_mark_size)+" " | |
| 170 | + | |
| 171 | + # Handle extended sources | |
| 172 | + elif modeltype == "ExtendedSource": | |
| 173 | + | |
| 174 | + # Retrieve spatial model | |
| 175 | + spatial = model.spatial() | |
| 176 | + classname = spatial.classname() | |
| 177 | + | |
| 178 | + # Handle radial sources | |
| 179 | + if "Radial" in classname: | |
| 180 | + | |
| 181 | + # Retrieve short name of model class (e.g. "Gauss" | |
| 182 | + # or "Disk) | |
| 183 | + shorttype = classname.split("Radial")[-1] | |
| 184 | + | |
| 185 | + # Handle Disk and Shell model | |
| 186 | + if (classname == "GModelSpatialRadialDisk" or | |
| 187 | + classname == "GModelSpatialRadialShell"): | |
| 188 | + size = spatial.radius() | |
| 189 | + | |
| 190 | + # Handle Gauss Model | |
| 191 | + elif classname == "GModelSpatialRadialGauss": | |
| 192 | + size = spatial.sigma() | |
| 193 | + | |
| 194 | + # Skip if source is unknown | |
| 195 | + else: | |
| 196 | + self._log("Skip source \""+model.name()+"\"" | |
| 197 | + " since the radial model \""+classname+ | |
| 198 | + "\" is unkown.\n") | |
| 199 | + is_valid = False | |
| 200 | + | |
| 201 | + # Append circle to DS9 string | |
| 202 | + if is_valid: | |
| 203 | + ds9string += "circle(" | |
| 204 | + ds9string += str(modelpos.ra_deg()) | |
| 205 | + ds9string += "," | |
| 206 | + ds9string += str(modelpos.dec_deg()) | |
| 207 | + ds9string += "," | |
| 208 | + ds9string += str(size*3600.)+"\") # " | |
| 209 | + | |
| 210 | + # Handle elliptical sources | |
| 211 | + elif "Elliptical" in classname: | |
| 212 | + | |
| 213 | + # Retrieve short name and source size | |
| 214 | + shorttype = classname.split("Elliptical")[-1] | |
| 215 | + size1 = spatial.semimajor() | |
| 216 | + size2 = spatial.semiminor() | |
| 217 | + angle = spatial.posangle() | |
| 218 | + | |
| 219 | + # Append ellipse to DS9 string | |
| 220 | + ds9string += "ellipse(" | |
| 221 | + ds9string += str(modelpos.ra_deg()) | |
| 222 | + ds9string += "," | |
| 223 | + ds9string += str(modelpos.dec_deg()) | |
| 224 | + ds9string += "," | |
| 225 | + ds9string += str(size1*3600.)+"\"" | |
| 226 | + ds9string += "," | |
| 227 | + ds9string += str(size2*3600.)+"\"" | |
| 228 | + ds9string += "," | |
| 229 | + ds9string += str(angle+90.0)+") # " | |
| 230 | + | |
| 231 | + # Skip if source is neither radial nor elliptical | |
| 232 | + else: | |
| 233 | + self._log("Skip source \""+model.name()+"\" " | |
| 234 | + "since the model \""+classname+"\" is " | |
| 235 | + "neither a point source, a radial source, " | |
| 236 | + "nor a elliptical source.\n") | |
| 237 | + is_valid = False | |
| 238 | + | |
| 239 | + # Add short model type to modelname | |
| 240 | + if self._show_ext_type: | |
| 241 | + modelname +=" ("+shorttype+")" | |
| 242 | + | |
| 243 | + # Add DS9 attributes | |
| 244 | + if is_valid: | |
| 245 | + ds9string += "color="+color+" " | |
| 246 | + ds9string += "width="+str(self._width)+" " | |
| 247 | + ds9string += "font=\""+self._fontfamily+" " | |
| 248 | + ds9string += str(self._fontsize)+" " | |
| 249 | + ds9string += self._fontweight+" " | |
| 250 | + ds9string += self._fontslant+"\"" | |
| 251 | + if self._show_labels: | |
| 252 | + ds9string += " text={"+modelname+"}" | |
| 253 | + | |
| 254 | + # Return string | |
| 255 | + return ds9string | |
| 133 | 256 | |
| 257 | + | |
| 258 | + # Public methods | |
| 134 | 259 | def run(self): |
| 135 | 260 | """ |
| 136 | 261 | Run the script. |
| 137 | 262 | """ |
| 138 | 263 | # Switch screen logging on in debug mode |
| 139 | - if self.logDebug(): | |
| 140 | - self.log.cout(True) | |
| 264 | + if self._logDebug(): | |
| 265 | + self._log.cout(True) | |
| 141 | 266 | |
| 142 | 267 | # Get parameters |
| 143 | - self.get_parameters() | |
| 268 | + self._get_parameters() | |
| 144 | 269 | |
| 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") | |
| 270 | + # Optionally log models | |
| 271 | + if self._logVerbose(): | |
| 272 | + self._log("\n") | |
| 273 | + self._log.header1("Models") | |
| 274 | + self._log("\n") | |
| 275 | + self._log(str(self._models)) | |
| 276 | + self._log("\n") | |
| 156 | 277 | |
| 157 | 278 | # Initialise output values |
| 158 | 279 | types = {} |
| ... | ... | @@ -171,13 +292,13 @@ class csmodelinfo(ctools.cscript): |
| 171 | 292 | n_par_free_temp = 0 |
| 172 | 293 | |
| 173 | 294 | # Loop over models and initialise dictionaries with model names |
| 174 | - for model in self.models: | |
| 295 | + for model in self._models: | |
| 175 | 296 | types[model.type()] = 0 |
| 176 | 297 | instruments[model.instruments()] = 0 |
| 177 | 298 | pars_at_limit[model.name()] = [] |
| 178 | 299 | |
| 179 | 300 | # Loop over models again and fill values to be dumped |
| 180 | - for model in self.models: | |
| 301 | + for model in self._models: | |
| 181 | 302 | |
| 182 | 303 | # Model types |
| 183 | 304 | types[model.type()] += 1 |
| ... | ... | @@ -218,7 +339,8 @@ class csmodelinfo(ctools.cscript): |
| 218 | 339 | else: |
| 219 | 340 | n_par_fixed += 1 |
| 220 | 341 | |
| 221 | - # If sky model, divide free parameters into spatial, spectral and temporal | |
| 342 | + # If sky model, divide free parameters into spatial, spectral | |
| 343 | + # and temporal | |
| 222 | 344 | if skymodel: |
| 223 | 345 | for par in model.spectral(): |
| 224 | 346 | if par.is_free(): |
| ... | ... | @@ -229,90 +351,93 @@ class csmodelinfo(ctools.cscript): |
| 229 | 351 | for par in model.temporal(): |
| 230 | 352 | if par.is_free(): |
| 231 | 353 | n_par_free_temp += 1 |
| 354 | + | |
| 355 | + # Optionally log model information | |
| 356 | + if self._logTerse(): | |
| 232 | 357 | |
| 233 | - # Log summary | |
| 234 | - self.log("\n") | |
| 235 | - self.log.header1("Summary") | |
| 358 | + # Log summary | |
| 359 | + self._log("\n") | |
| 360 | + self._log.header1("Summary") | |
| 236 | 361 | |
| 237 | - # Log instruments | |
| 238 | - self.log.header3("Instrument specific models") | |
| 239 | - for inst, n_inst in instruments.items(): | |
| 240 | - if inst == "": | |
| 241 | - inst = "All" | |
| 242 | - self.log.parformat(inst) | |
| 243 | - self.log(str(n_inst)) | |
| 244 | - self.log("\n") | |
| 362 | + # Log instruments | |
| 363 | + self._log.header3("Instrument specific models") | |
| 364 | + for inst, n_inst in instruments.items(): | |
| 365 | + if inst == "": | |
| 366 | + inst = "All" | |
| 367 | + self._log.parformat(inst) | |
| 368 | + self._log(str(n_inst)) | |
| 369 | + self._log("\n") | |
| 245 | 370 | |
| 246 | - # Log model types | |
| 247 | - self.log.header3("Model types") | |
| 248 | - for modeltype, n_types in types.items(): | |
| 249 | - self.log.parformat(modeltype) | |
| 250 | - self.log(str(n_types)) | |
| 251 | - self.log("\n") | |
| 371 | + # Log model types | |
| 372 | + self._log.header3("Model types") | |
| 373 | + for modeltype, n_types in types.items(): | |
| 374 | + self._log.parformat(modeltype) | |
| 375 | + self._log(str(n_types)) | |
| 376 | + self._log("\n") | |
| 252 | 377 | |
| 253 | - # Log parameter information | |
| 254 | - self.log("\n") | |
| 255 | - self.log.header1("Parameter information") | |
| 256 | - self.log.parformat("All parameters") | |
| 257 | - self.log(str(n_par_total)) | |
| 258 | - self.log("\n") | |
| 259 | - self.log.parformat("Fixed parameters") | |
| 260 | - self.log(str(n_par_fixed)) | |
| 261 | - self.log("\n") | |
| 262 | - self.log.parformat("Free parameters (total)") | |
| 263 | - self.log(str(n_par_free)) | |
| 264 | - self.log("\n") | |
| 265 | - self.log.parformat("Free background parameters") | |
| 266 | - self.log(str(n_par_free_bkg)) | |
| 267 | - self.log("\n") | |
| 268 | - self.log.parformat("Free source parameters") | |
| 269 | - self.log(str(n_par_free_src)) | |
| 270 | - self.log("\n") | |
| 271 | - if n_par_free_spec > 0: | |
| 272 | - self.log.parformat("Free spectral parameters") | |
| 273 | - self.log(str(n_par_free_spec)) | |
| 274 | - self.log("\n") | |
| 275 | - if n_par_free_spat > 0: | |
| 276 | - self.log.parformat("Free spatial parameters") | |
| 277 | - self.log(str(n_par_free_spat)) | |
| 278 | - self.log("\n") | |
| 279 | - if n_par_free_temp > 0: | |
| 280 | - self.log.parformat("Free temporal parameters") | |
| 281 | - self.log(str(n_par_free_temp)) | |
| 282 | - self.log("\n") | |
| 283 | - self.log.parformat("Parameters at limit") | |
| 284 | - self.log(str(n_par_at_limit)) | |
| 285 | - self.log("\n") | |
| 378 | + # Log model parameter information | |
| 379 | + self._log("\n") | |
| 380 | + self._log.header1("Parameter information") | |
| 381 | + self._log.parformat("All parameters") | |
| 382 | + self._log(str(n_par_total)) | |
| 383 | + self._log("\n") | |
| 384 | + self._log.parformat("Fixed parameters") | |
| 385 | + self._log(str(n_par_fixed)) | |
| 386 | + self._log("\n") | |
| 387 | + self._log.parformat("Free parameters (total)") | |
| 388 | + self._log(str(n_par_free)) | |
| 389 | + self._log("\n") | |
| 390 | + self._log.parformat("Free background parameters") | |
| 391 | + self._log(str(n_par_free_bkg)) | |
| 392 | + self._log("\n") | |
| 393 | + self._log.parformat("Free source parameters") | |
| 394 | + self._log(str(n_par_free_src)) | |
| 395 | + self._log("\n") | |
| 396 | + if n_par_free_spec > 0: | |
| 397 | + self._log.parformat("Free spectral parameters") | |
| 398 | + self._log(str(n_par_free_spec)) | |
| 399 | + self._log("\n") | |
| 400 | + if n_par_free_spat > 0: | |
| 401 | + self._log.parformat("Free spatial parameters") | |
| 402 | + self._log(str(n_par_free_spat)) | |
| 403 | + self._log("\n") | |
| 404 | + if n_par_free_temp > 0: | |
| 405 | + self._log.parformat("Free temporal parameters") | |
| 406 | + self._log(str(n_par_free_temp)) | |
| 407 | + self._log("\n") | |
| 408 | + self._log.parformat("Parameters at limit") | |
| 409 | + self._log(str(n_par_at_limit)) | |
| 410 | + self._log("\n") | |
| 286 | 411 | |
| 287 | - # Log parameters at limit (if any) | |
| 288 | - if n_par_at_limit > 0: | |
| 289 | - self.log.header3("Parameters at limit") | |
| 290 | - for source, parameter in pars_at_limit.items(): | |
| 291 | - if len(parameter): | |
| 292 | - for par in parameter: | |
| 293 | - self.log.parformat(source) | |
| 294 | - self.log(par) | |
| 295 | - self.log("\n") | |
| 412 | + # Log parameters at limit (if any) | |
| 413 | + if n_par_at_limit > 0: | |
| 414 | + self._log.header3("Parameters at limit") | |
| 415 | + for source, parameter in pars_at_limit.items(): | |
| 416 | + if len(parameter): | |
| 417 | + for par in parameter: | |
| 418 | + self._log.parformat(source) | |
| 419 | + self._log(par) | |
| 420 | + self._log("\n") | |
| 296 | 421 | |
| 297 | - # Log free parameters if requested | |
| 298 | - if self.logExplicit() and len(free_src_pars): | |
| 299 | - self.log("\n") | |
| 300 | - self.log.header2("Free source parameters") | |
| 301 | - for source, parameter in free_src_pars.items(): | |
| 302 | - if len(parameter): | |
| 303 | - self.log.header3(source) | |
| 304 | - for par in parameter: | |
| 305 | - self.log(str(par)) | |
| 306 | - self.log("\n") | |
| 307 | - self.log("\n") | |
| 422 | + # Optionally log free parameters | |
| 423 | + if self._logExplicit() and len(free_src_pars): | |
| 424 | + self._log("\n") | |
| 425 | + self._log.header2("Free source parameters") | |
| 426 | + for source, parameter in free_src_pars.items(): | |
| 427 | + if len(parameter): | |
| 428 | + self._log.header3(source) | |
| 429 | + for par in parameter: | |
| 430 | + self._log(str(par)) | |
| 431 | + self._log("\n") | |
| 432 | + self._log("\n") | |
| 308 | 433 | |
| 309 | - # Log TS values if available | |
| 310 | - if len(ts): | |
| 311 | - self.log.header3("Test statistics") | |
| 312 | - for source,tsvalue in ts.items(): | |
| 313 | - self.log.parformat(source) | |
| 314 | - self.log("%.2f"%tsvalue) | |
| 315 | - self.log("\n") | |
| 434 | + # Log TS values if available | |
| 435 | + if len(ts): | |
| 436 | + self._log.header3("Test statistics") | |
| 437 | + for source,tsvalue in ts.items(): | |
| 438 | + self._log.parformat(source) | |
| 439 | + self._log("%.2f"%tsvalue) | |
| 440 | + self._log("\n") | |
| 316 | 441 | |
| 317 | 442 | # Return |
| 318 | 443 | return |
| ... | ... | @@ -321,37 +446,49 @@ class csmodelinfo(ctools.cscript): |
| 321 | 446 | """ |
| 322 | 447 | Save models to ds9 region file if required |
| 323 | 448 | """ |
| 324 | - | |
| 325 | - # Check if ds9 file is valid | |
| 326 | - if not self.ds9file == "NONE": | |
| 449 | + # Write header | |
| 450 | + if self._logTerse(): | |
| 451 | + self._log("\n") | |
| 452 | + self._log.header1("Save models in DS9 file") | |
| 453 | + | |
| 454 | + # Get output filename in case it was not read ahead | |
| 455 | + self._ds9file = self["ds9file"].filename() | |
| 456 | + | |
| 457 | + # Check if DS9 file is valid | |
| 458 | + if self._ds9file != "NONE": | |
| 327 | 459 | |
| 328 | - self.log("\n") | |
| 329 | - self.log.header1("Save region file") | |
| 460 | + # Log filename | |
| 461 | + if self._logTerse(): | |
| 462 | + self._log(gammalib.parformat("DS9 filename")) | |
| 463 | + self._log(self._ds9file.url()) | |
| 464 | + self._log("\n") | |
| 330 | 465 | |
| 331 | 466 | # Open file |
| 332 | - f = open(self.ds9file.url(),"w") | |
| 467 | + f = open(self._ds9file.url(),"w") | |
| 333 | 468 | |
| 334 | 469 | # Write coordinate system |
| 335 | 470 | f.write("fk5\n") |
| 336 | 471 | |
| 337 | 472 | # Loop over models |
| 338 | - for model in self.models: | |
| 473 | + for model in self._models: | |
| 339 | 474 | |
| 340 | 475 | # Continue only if point source or extended source model |
| 341 | - if model.type() == "PointSource" or model.type() == "ExtendedSource": | |
| 342 | - | |
| 343 | - line = self.model2ds9string(model) | |
| 476 | + if (model.type() == "PointSource" or | |
| 477 | + model.type() == "ExtendedSource"): | |
| 478 | + line = self._model2ds9string(model) | |
| 344 | 479 | if len(line): |
| 345 | 480 | f.write(line+"\n") |
| 346 | 481 | |
| 347 | 482 | # Logging for diffuse components |
| 348 | 483 | elif model.type() == "DiffuseSource": |
| 349 | - self.log("Skipping diffuse model "+model.name()+"\n") | |
| 484 | + self._log("Skipping diffuse model \""+model.name()+ | |
| 485 | + "\"\n") | |
| 350 | 486 | |
| 351 | 487 | # Logging for background components |
| 352 | 488 | else: |
| 353 | - if self.logExplicit(): | |
| 354 | - self.log("Skipping background model "+model.name()+"\n") | |
| 489 | + if self._logExplicit(): | |
| 490 | + self._log("Skipping background model \""+ | |
| 491 | + model.name()+"\"\n") | |
| 355 | 492 | |
| 356 | 493 | # Close file |
| 357 | 494 | f.close() |
| ... | ... | @@ -359,127 +496,13 @@ class csmodelinfo(ctools.cscript): |
| 359 | 496 | # Return |
| 360 | 497 | return |
| 361 | 498 | |
| 362 | - def model2ds9string(self, model): | |
| 363 | - """ | |
| 364 | - Converts model instance to ds9 region string | |
| 365 | - """ | |
| 366 | - | |
| 367 | - # Initialise return string | |
| 368 | - ds9string = "" | |
| 369 | - | |
| 370 | - # Determine color | |
| 371 | - color = self.fixed_color | |
| 372 | - for par in model: | |
| 373 | - if par.is_free(): | |
| 374 | - color = self.free_color | |
| 375 | - break | |
| 376 | - | |
| 377 | - # Initialise flag ot continue | |
| 378 | - is_valid = True | |
| 379 | - | |
| 380 | - # Retrieve model position | |
| 381 | - try: | |
| 382 | - modelpos = model.spatial().dir() | |
| 383 | - except AttributeError: | |
| 384 | - self.log("Skipping source "+model.name()+": Could not determine sky position\n") | |
| 385 | - is_valid = False | |
| 386 | - | |
| 387 | - # Continue only if position was found | |
| 388 | - if is_valid: | |
| 389 | - | |
| 390 | - # Retrieve model type and name | |
| 391 | - modeltype = model.type() | |
| 392 | - modelname = model.name() | |
| 393 | - | |
| 394 | - # Handle point source | |
| 395 | - if modeltype == "PointSource": | |
| 396 | - | |
| 397 | - ds9string += "point(" | |
| 398 | - ds9string += str(modelpos.ra_deg()) | |
| 399 | - ds9string += "," | |
| 400 | - ds9string += str(modelpos.dec_deg()) | |
| 401 | - ds9string += ") # " | |
| 402 | - ds9string += "point="+self.pnt_type+" " | |
| 403 | - ds9string += str(self.pnt_mark_size)+" " | |
| 404 | - | |
| 405 | - # Hanlde extended sources | |
| 406 | - elif modeltype == "ExtendedSource": | |
| 407 | - | |
| 408 | - # Retrieve spatial model | |
| 409 | - spatial = model.spatial() | |
| 410 | - classname = spatial.classname() | |
| 411 | - | |
| 412 | - # Handle radial sources | |
| 413 | - if "Radial" in classname: | |
| 414 | - | |
| 415 | - # Retrieve short name of model class (e.g. "Gauss" or "Disk) | |
| 416 | - shorttype = classname.split("Radial")[-1] | |
| 417 | - | |
| 418 | - # Handle Disk and Shell model | |
| 419 | - if classname == "GModelSpatialRadialDisk" or classname == "GModelSpatialRadialShell": | |
| 420 | - size = spatial.radius() | |
| 421 | - | |
| 422 | - # Handle Gauss Model | |
| 423 | - elif classname == "GModelSpatialRadialGauss": | |
| 424 | - size = spatial.sigma() | |
| 425 | - | |
| 426 | - # Skip if source is unknown | |
| 427 | - else: | |
| 428 | - self.log("Skipping source "+model.name()+": Spatial model \""+classname+"\" unkown\n") | |
| 429 | - is_valid = False | |
| 430 | - | |
| 431 | - # Append radial ds9 string | |
| 432 | - if is_valid: | |
| 433 | - ds9string += "circle(" | |
| 434 | - ds9string += str(modelpos.ra_deg()) | |
| 435 | - ds9string += "," | |
| 436 | - ds9string += str(modelpos.dec_deg()) | |
| 437 | - ds9string += "," | |
| 438 | - ds9string += str(size*3600.)+"\") #" | |
| 439 | - | |
| 440 | - # Handle elliptical sources | |
| 441 | - elif "Elliptical" in classname: | |
| 442 | - | |
| 443 | - # Retrieve short name and source size | |
| 444 | - shorttype = classname.split("Elliptical")[-1] | |
| 445 | - size1 = spatial.semimajor() | |
| 446 | - size2 = spatial.semiminor() | |
| 447 | - angle = spatial.posangle() | |
| 448 | - | |
| 449 | - # Append elliptical ds9 string | |
| 450 | - ds9string += "ellipse(" | |
| 451 | - ds9string += str(modelpos.ra_deg()) | |
| 452 | - ds9string += "," | |
| 453 | - ds9string += str(modelpos.dec_deg()) | |
| 454 | - ds9string += "," | |
| 455 | - ds9string += str(size1*3600.)+"\"" | |
| 456 | - ds9string += "," | |
| 457 | - ds9string += str(size2*3600.)+"\"" | |
| 458 | - ds9string += "," | |
| 459 | - ds9string += str(angle+90.0)+") # " | |
| 460 | - | |
| 461 | - # Skip if source is neither radial nor elliptical | |
| 462 | - else: | |
| 463 | - self.log("Skipping source "+model.name()+": Spatial model neither \"Radial\" nor \"Elliptical\"\n") | |
| 464 | - | |
| 465 | - # Add short name to modelname | |
| 466 | - if self.show_ext_type: | |
| 467 | - modelname +=" ("+shorttype+")" | |
| 468 | - | |
| 469 | - # Add user defined attributes | |
| 470 | - ds9string += "color="+color+" " | |
| 471 | - ds9string += "width="+str(self.width)+" " | |
| 472 | - ds9string += "font=\""+self.font+" "+str(self.fontsize)+" "+self.fonttype+" "+self.fonttype2+"\" " | |
| 473 | - if self.show_labels: | |
| 474 | - ds9string += "text={"+modelname+"}" | |
| 475 | - | |
| 476 | - # Return string | |
| 477 | - return ds9string | |
| 478 | - | |
| 479 | 499 | def execute(self): |
| 480 | 500 | """ |
| 481 | 501 | Execute the script. |
| 482 | 502 | """ |
| 503 | + # Set read ahead flag | |
| 504 | + self._read_ahead = True | |
| 505 | + | |
| 483 | 506 | # Run the script |
| 484 | 507 | self.run() |
| 485 | 508 | |
| ... | ... | @@ -494,14 +517,12 @@ class csmodelinfo(ctools.cscript): |
| 494 | 517 | # Main routine entry point # |
| 495 | 518 | # ======================== # |
| 496 | 519 | if __name__ == '__main__': |
| 497 | - """ | |
| 498 | - Generates model information output. | |
| 499 | - """ | |
| 520 | + | |
| 500 | 521 | # Create instance of application |
| 501 | 522 | app = csmodelinfo(sys.argv) |
| 502 | 523 | |
| 503 | 524 | # Open logfile |
| 504 | - app.logFileOpen() | |
| 525 | + app._logFileOpen() | |
| 505 | 526 | |
| 506 | 527 | # Execute application |
| 507 | 528 | app.execute() | ... | ... |
cscripts/csmodelmerge.par
0 → 100644
| 1 | +############################################################################# | |
| 2 | +# # | |
| 3 | +# CTA Science Analysis Tools # | |
| 4 | +# # | |
| 5 | +# ------------------------------------------------------------------------- # | |
| 6 | +# # | |
| 7 | +# File: csmodelmerge.par # | |
| 8 | +# Version: 1.1.0 # | |
| 9 | +# # | |
| 10 | +# Author: Juergen Knoedlseder # | |
| 11 | +# Jurgen.Knodlseder@irap.omp.eu # | |
| 12 | +# IRAP # | |
| 13 | +# # | |
| 14 | +# Purpose: Parameter file for the csmodelmerge script # | |
| 15 | +# # | |
| 16 | +############################################################################# | |
| 17 | +# | |
| 18 | +# Input and output parameters | |
| 19 | +#============================ | |
| 20 | +inmodels, s, a, model.xml,,, "Input model definition XML files" | |
| 21 | +outmodel, f, a, NONE,,, "Output model definition XML file" | |
| 22 | + | |
| 23 | +# | |
| 24 | +# Standard parameters | |
| 25 | +#==================== | |
| 26 | +chatter, i, h, 2,0,4, "Chattiness of output" | |
| 27 | +clobber, b, h, yes,,, "Overwrite existing output files with new output files?" | |
| 28 | +debug, b, h, no,,, "Debugging mode activated" | |
| 29 | +mode, s, h, ql,,, "Mode of automatic parameters" | |
| 30 | +logfile, f, h, csmodelmerge.log,,, "Log filename" | ... | ... |
cscripts/csmodelmerge.py
| 1 | 1 | #!/usr/bin/env python |
| 2 | 2 | # ========================================================================== |
| 3 | -# Merges model XML files into one file | |
| 3 | +# Merge model definition XML files | |
| 4 | 4 | # |
| 5 | -# Copyright (C) 2015 Michael Mayer | |
| 5 | +# Copyright (C) 2015-2016 Michael Mayer | |
| 6 | 6 | # |
| 7 | 7 | # This program is free software: you can redistribute it and/or modify |
| 8 | 8 | # it under the terms of the GNU General Public License as published by |
| ... | ... | @@ -29,31 +29,38 @@ import glob |
| 29 | 29 | # ================== # |
| 30 | 30 | class csmodelmerge(ctools.cscript): |
| 31 | 31 | """ |
| 32 | - This class merges an arbitray number of model container into one output | |
| 33 | - model XML file. | |
| 32 | + Merge model definition XML files. | |
| 33 | + | |
| 34 | + An arbitrary number of model definition XML files will be merged into | |
| 35 | + a single model definition XML file. | |
| 34 | 36 | """ |
| 37 | + | |
| 38 | + # Constructors and destructors | |
| 35 | 39 | def __init__(self, *argv): |
| 36 | 40 | """ |
| 37 | 41 | Constructor. |
| 38 | 42 | """ |
| 39 | 43 | # Set name |
| 40 | - self.name = "csmodelmerge" | |
| 41 | - self.version = "1.1.0" | |
| 44 | + self._name = "csmodelmerge" | |
| 45 | + self._version = "1.1.0" | |
| 42 | 46 | |
| 43 | - # Make sure that parfile exists | |
| 44 | - file = self.parfile() | |
| 47 | + # Initialise class members | |
| 48 | + self._files = None | |
| 49 | + self._models = gammalib.GModels() | |
| 50 | + self._outmodel = "NONE" | |
| 51 | + self._read_ahead = False | |
| 45 | 52 | |
| 46 | 53 | # Initialise application |
| 47 | 54 | if len(argv) == 0: |
| 48 | - ctools.cscript.__init__(self, self.name, self.version) | |
| 55 | + ctools.cscript.__init__(self, self._name, self._version) | |
| 49 | 56 | elif len(argv) == 1: |
| 50 | - ctools.cscript.__init__(self, self.name, self.version, *argv) | |
| 57 | + ctools.cscript.__init__(self, self._name, self._version, *argv) | |
| 51 | 58 | else: |
| 52 | 59 | raise TypeError("Invalid number of arguments given.") |
| 53 | 60 | |
| 54 | 61 | # Set logger properties |
| 55 | - self.log_header() | |
| 56 | - self.log.date(True) | |
| 62 | + self._log_header() | |
| 63 | + self._log.date(True) | |
| 57 | 64 | |
| 58 | 65 | # Return |
| 59 | 66 | return |
| ... | ... | @@ -65,124 +72,122 @@ class csmodelmerge(ctools.cscript): |
| 65 | 72 | # Return |
| 66 | 73 | return |
| 67 | 74 | |
| 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 | 75 | |
| 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): | |
| 76 | + # Private methods | |
| 77 | + def _get_parameters(self): | |
| 96 | 78 | """ |
| 97 | - Get parameters from parfile and setup the observation. | |
| 79 | + Get parameters from parfile. | |
| 98 | 80 | """ |
| 99 | - # Get input models | |
| 100 | - self.inmodels = self["inmodels"].string() | |
| 81 | + # Get input models string | |
| 82 | + inmodels = self["inmodels"].string() | |
| 101 | 83 | |
| 102 | - # Interpet inmodels string | |
| 103 | 84 | # Handle ascii files |
| 104 | - if "@" == self.inmodels[0]: | |
| 105 | - self.files = open(self.inmodels.replace("@","")).read().splitlines() | |
| 85 | + if "@" == inmodels[0]: | |
| 86 | + self._files = open(inmodels.replace("@","")).read().splitlines() | |
| 106 | 87 | |
| 107 | 88 | # Handle wild card strings |
| 108 | - elif "*" in self.inmodels: | |
| 109 | - self.files = glob.glob(self.inmodels) | |
| 89 | + elif "*" in inmodels: | |
| 90 | + self._files = glob.glob(inmodels) | |
| 110 | 91 | |
| 111 | - # Handle space-separated list | |
| 112 | - elif " " in self.inmodels: | |
| 113 | - self.files = self.inmodels.split(" ") | |
| 92 | + # Handle space separated list | |
| 93 | + elif " " in inmodels: | |
| 94 | + self._files = inmodels.split(" ") | |
| 114 | 95 | |
| 115 | - # Handle comma-separated list | |
| 116 | - elif "," in self.inmodels: | |
| 117 | - self.files = self.inmodels.split(",") | |
| 96 | + # Handle semi-colon separated list | |
| 97 | + elif ";" in inmodels: | |
| 98 | + self._files = inmodels.split(";") | |
| 118 | 99 | |
| 119 | 100 | # Throw exception if input models cannot be decoded |
| 120 | 101 | 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" | |
| 102 | + msg = "Parameter \"inmodels\" must contain either an @ASCII "\ | |
| 103 | + "file, a semi-colon-separated or whitespace-separated "\ | |
| 104 | + "list of files or a wildcard string." | |
| 124 | 105 | raise RuntimeError(msg) |
| 125 | 106 | |
| 126 | - # Get output file | |
| 127 | - self.outmodel = self["outmodel"].filename() | |
| 107 | + # Read ahead output filename | |
| 108 | + if self._read_ahead: | |
| 109 | + self.outmodel = self["outmodel"].filename() | |
| 110 | + | |
| 111 | + # Write input parameters into logger | |
| 112 | + if self._logTerse(): | |
| 113 | + self._log_parameters() | |
| 114 | + self._log("\n") | |
| 128 | 115 | |
| 129 | 116 | # Return |
| 130 | 117 | return |
| 131 | 118 | |
| 119 | + | |
| 120 | + # Public methods | |
| 132 | 121 | def run(self): |
| 133 | 122 | """ |
| 134 | 123 | Run the script. |
| 135 | 124 | """ |
| 136 | 125 | # Switch screen logging on in debug mode |
| 137 | - if self.logDebug(): | |
| 138 | - self.log.cout(True) | |
| 126 | + if self._logDebug(): | |
| 127 | + self._log.cout(True) | |
| 139 | 128 | |
| 140 | 129 | # Get parameters |
| 141 | - self.get_parameters() | |
| 130 | + self._get_parameters() | |
| 142 | 131 | |
| 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() | |
| 132 | + # Write header | |
| 133 | + if self._logTerse(): | |
| 134 | + self._log("\n") | |
| 135 | + self._log.header1("Merge models") | |
| 136 | + | |
| 137 | + # Initialise model container | |
| 138 | + self._models = gammalib.GModels() | |
| 156 | 139 | |
| 157 | 140 | # Loop over model files |
| 158 | - for modelfile in self.files: | |
| 159 | - | |
| 160 | - # Logging | |
| 161 | - self.log("Adding "+modelfile) | |
| 162 | - self.log("\n") | |
| 141 | + for file in self._files: | |
| 142 | + | |
| 143 | + # Construct container from XML file | |
| 144 | + models = gammalib.GModels(file) | |
| 163 | 145 | |
| 164 | - # Open models | |
| 165 | - model_add = gammalib.GModels(modelfile) | |
| 146 | + # Log number of models to add | |
| 147 | + if self._logTerse(): | |
| 148 | + nmodels = models.size() | |
| 149 | + if nmodels == 0: | |
| 150 | + self._log(gammalib.parformat("Add no model from file")) | |
| 151 | + elif nmodels == 1: | |
| 152 | + self._log(gammalib.parformat("Add 1 model from file")) | |
| 153 | + else: | |
| 154 | + self._log(gammalib.parformat("Add %d models from file" % | |
| 155 | + nmodels)) | |
| 156 | + self._log(file) | |
| 157 | + self._log("\n") | |
| 166 | 158 | |
| 167 | - # Append models to container | |
| 168 | - for model in model_add: | |
| 169 | - self.models.append(model) | |
| 159 | + # Extend model container by adding all models in the model file | |
| 160 | + self._models.extend(models) | |
| 170 | 161 | |
| 162 | + # Log total number of models | |
| 163 | + if self._logTerse(): | |
| 164 | + self._log(gammalib.parformat("Models after merging")) | |
| 165 | + self._log(self._models.size()) | |
| 166 | + self._log("\n") | |
| 167 | + | |
| 171 | 168 | # Return |
| 172 | 169 | return |
| 173 | 170 | |
| 174 | 171 | def save(self): |
| 175 | 172 | """ |
| 176 | - Save pointings to ds9 region file if required | |
| 173 | + Save model definition XML file | |
| 177 | 174 | """ |
| 178 | - # Logging | |
| 179 | - if self.logExplicit(): | |
| 180 | - self.log("\n") | |
| 181 | - self.log.header1("Saving model file") | |
| 182 | - self.log("\n") | |
| 175 | + # Write header | |
| 176 | + if self._logTerse(): | |
| 177 | + self._log("\n") | |
| 178 | + self._log.header1("Save models") | |
| 179 | + | |
| 180 | + # Get output filename in case it was not read ahead | |
| 181 | + self._outmodel = self["outmodel"].filename() | |
| 183 | 182 | |
| 183 | + # Log filename | |
| 184 | + if self._logTerse(): | |
| 185 | + self._log(gammalib.parformat("Model definition XML file")) | |
| 186 | + self._log(self._outmodel.url()) | |
| 187 | + self._log("\n") | |
| 188 | + | |
| 184 | 189 | # Save models |
| 185 | - self.models.save(self.outmodel) | |
| 190 | + self._models.save(self._outmodel) | |
| 186 | 191 | |
| 187 | 192 | # Return |
| 188 | 193 | return |
| ... | ... | @@ -191,6 +196,9 @@ class csmodelmerge(ctools.cscript): |
| 191 | 196 | """ |
| 192 | 197 | Execute the script. |
| 193 | 198 | """ |
| 199 | + # Set read ahead flag | |
| 200 | + self._read_ahead = True | |
| 201 | + | |
| 194 | 202 | # Run the script |
| 195 | 203 | self.run() |
| 196 | 204 | |
| ... | ... | @@ -205,14 +213,12 @@ class csmodelmerge(ctools.cscript): |
| 205 | 213 | # Main routine entry point # |
| 206 | 214 | # ======================== # |
| 207 | 215 | if __name__ == '__main__': |
| 208 | - """ | |
| 209 | - Merges model XML files | |
| 210 | - """ | |
| 216 | + | |
| 211 | 217 | # Create instance of application |
| 212 | 218 | app = csmodelmerge(sys.argv) |
| 213 | 219 | |
| 214 | 220 | # Open logfile |
| 215 | - app.logFileOpen() | |
| 221 | + app._logFileOpen() | |
| 216 | 222 | |
| 217 | 223 | # Execute application |
| 218 | 224 | app.execute() | ... | ... |
cscripts/csobs2caldb.par
0 → 100644
| 1 | +############################################################################# | |
| 2 | +# # | |
| 3 | +# CTA Science Analysis Tools # | |
| 4 | +# # | |
| 5 | +# ------------------------------------------------------------------------- # | |
| 6 | +# # | |
| 7 | +# File: csobs2caldb.par # | |
| 8 | +# Version: 1.1.0 # | |
| 9 | +# # | |
| 10 | +# Author: Juergen Knoedlseder # | |
| 11 | +# Jurgen.Knodlseder@irap.omp.eu # | |
| 12 | +# IRAP # | |
| 13 | +# # | |
| 14 | +# Purpose: Parameter file for the csobs2caldb script # | |
| 15 | +# # | |
| 16 | +############################################################################# | |
| 17 | +# | |
| 18 | +# General parameters | |
| 19 | +#=================== | |
| 20 | +inobs, f, a, obs.xml,,, "Observation definition XML file" | |
| 21 | +rspname, s, a, NONE,,, "Response output name (e.g. Zenith50)" | |
| 22 | +outirfs, f, h, irf_file.fits,,, "Output IRF file name" | |
| 23 | +index, i, h, 0,,, "Index of observation to be used from XML file" | |
| 24 | + | |
| 25 | +# | |
| 26 | +# Standard parameters | |
| 27 | +#==================== | |
| 28 | +chatter, i, h, 2,0,4, "Chattiness of output" | |
| 29 | +clobber, b, h, yes,,, "Overwrite existing output files with new output files?" | |
| 30 | +debug, b, h, no,,, "Debugging mode activated" | |
| 31 | +mode, s, h, ql,,, "Mode of automatic parameters" | |
| 32 | +logfile, f, h, csobs2caldb.log,,, "Log filename" | ... | ... |
cscripts/csobs2caldb.py
| ... | ... | @@ -30,34 +30,46 @@ import datetime |
| 30 | 30 | # ================= # |
| 31 | 31 | class csobs2caldb(ctools.cscript): |
| 32 | 32 | """ |
| 33 | - This class implements the creation of a caldb entry for a particular | |
| 34 | - observation, which might be helpful for running simulations for current | |
| 35 | - IACTs. It takes an observation definition file as input and uses the | |
| 36 | - first observation to create a caldb entry which can be used for | |
| 37 | - simulations and sensitivity studies later on. | |
| 33 | + Creates a calibration database entry for an observation. | |
| 34 | + | |
| 35 | + The creation of a calibration database entry is useful for performing | |
| 36 | + simulations for current Imaging Air Cherenkov Telescopes (IACTs). | |
| 37 | + The class takes an observation definition XML file as input and uses | |
| 38 | + one observation to create a calibration database entry. By default | |
| 39 | + the first observation will be used, but the user can specify the | |
| 40 | + index of any observation using the hidden "index" parameter. | |
| 38 | 41 | """ |
| 42 | + | |
| 43 | + # Constructors and destructors | |
| 39 | 44 | def __init__(self, *argv): |
| 40 | 45 | """ |
| 41 | 46 | Constructor. |
| 42 | 47 | """ |
| 43 | - # Set name | |
| 44 | - self.name = "csobs2caldb" | |
| 45 | - self.version = "1.1.0" | |
| 46 | - | |
| 47 | - # Make sure that parfile exists | |
| 48 | - file = self.parfile() | |
| 49 | - | |
| 48 | + # Set name and version | |
| 49 | + self._name = "csobs2caldb" | |
| 50 | + self._version = "1.1.0" | |
| 51 | + | |
| 52 | + # Initialise members | |
| 53 | + self._obs = [] # Observation container | |
| 54 | + self._observation = None | |
| 55 | + self._mission = "CTA" | |
| 56 | + self._instrument = "" | |
| 57 | + self._rspname = "" | |
| 58 | + self._outfile = "" | |
| 59 | + self._base_dir = "" | |
| 60 | + self._cal_dir = "" | |
| 61 | + | |
| 50 | 62 | # Initialise application |
| 51 | 63 | if len(argv) == 0: |
| 52 | - ctools.cscript.__init__(self, self.name, self.version) | |
| 64 | + ctools.cscript.__init__(self, self._name, self._version) | |
| 53 | 65 | elif len(argv) == 1: |
| 54 | - ctools.cscript.__init__(self, self.name, self.version, *argv) | |
| 66 | + ctools.cscript.__init__(self, self._name, self._version, *argv) | |
| 55 | 67 | else: |
| 56 | 68 | raise TypeError("Invalid number of arguments given.") |
| 57 | 69 | |
| 58 | 70 | # Set logger properties |
| 59 | - self.log_header() | |
| 60 | - self.log.date(True) | |
| 71 | + self._log_header() | |
| 72 | + self._log.date(True) | |
| 61 | 73 | |
| 62 | 74 | # Return |
| 63 | 75 | return |
| ... | ... | @@ -69,87 +81,76 @@ class csobs2caldb(ctools.cscript): |
| 69 | 81 | # Return |
| 70 | 82 | return |
| 71 | 83 | |
| 72 | - def parfile(self): | |
| 73 | - """ | |
| 74 | - Check if parfile exists. If parfile does not exist then create a | |
| 75 | - default parfile. This kluge avoids shipping the cscript with a | |
| 76 | - parfile. | |
| 77 | - """ | |
| 78 | - | |
| 79 | - # Set parfile name | |
| 80 | - parfile = self.name+".par" | |
| 81 | - | |
| 82 | - try: | |
| 83 | - pars = gammalib.GApplicationPars(parfile) | |
| 84 | - except: | |
| 85 | - # Signal that parfile was not found | |
| 86 | - print("Parfile \""+parfile+"\" not found. Create default parfile.") | |
| 87 | - | |
| 88 | - # Create default parfile | |
| 89 | - pars = gammalib.GApplicationPars() | |
| 90 | - pars.append(gammalib.GApplicationPar("inobs","f","a","obs.xml","","","Input observation definition file")) | |
| 91 | - pars.append(gammalib.GApplicationPar("rspname","s","a","NONE","","","Response output name (e.g. Zenith50)")) | |
| 92 | - pars.append(gammalib.GApplicationPar("outirfs","f","h","irf_file.fits","","","Output IRF file name")) | |
| 93 | - pars.append(gammalib.GApplicationPar("index","i","h","0","","","Index of observation to be used from XML file")) | |
| 94 | - pars.append_standard() | |
| 95 | - pars.append(gammalib.GApplicationPar("logfile","f","h","csobs2caldb.log","","","Log filename")) | |
| 96 | - pars.save(parfile) | |
| 97 | - | |
| 98 | - # Return | |
| 99 | - return | |
| 100 | 84 | |
| 101 | - def get_parameters(self): | |
| 85 | + # Private methods | |
| 86 | + def _get_parameters(self): | |
| 102 | 87 | """ |
| 103 | 88 | Get parameters from parfile and setup the observation. |
| 104 | 89 | """ |
| 105 | - # Get parameters | |
| 106 | - self.inobs = self["inobs"].filename() | |
| 107 | - self.obs = gammalib.GObservations(self.inobs) | |
| 90 | + # Load observation container | |
| 91 | + self._obs = gammalib.GObservations(self["inobs"].filename()) | |
| 108 | 92 | |
| 109 | 93 | # Get index of observation to be used (0=default) |
| 110 | 94 | inx = self["index"].integer() |
| 111 | 95 | |
| 112 | 96 | # Get observation |
| 113 | - self.observation = self.obs[inx] | |
| 114 | - | |
| 115 | - # Set instrument mission to cta | |
| 116 | - # This is to be compliant with standard gammalib caldb | |
| 117 | - self.m_mission = "CTA" | |
| 97 | + self._observation = self._obs[inx] | |
| 118 | 98 | |
| 119 | 99 | # Get instrument name |
| 120 | - self.m_instrument = self.observation.instrument() | |
| 100 | + self._instrument = self._observation.instrument() | |
| 121 | 101 | |
| 122 | 102 | # Get config and file name |
| 123 | - self.m_rspname = self["rspname"].string() | |
| 124 | - self.m_outfile = self["outirfs"].filename() | |
| 103 | + self._rspname = self["rspname"].string() | |
| 104 | + self._outfile = self["outirfs"].filename() | |
| 125 | 105 | |
| 126 | 106 | # Make sure we have a cta observation |
| 127 | - if not self.observation.classname() == "GCTAObservation": | |
| 128 | - raise gammalib.Exception.runtime_error("Input observation not of type \"GCTAObservation\"") | |
| 107 | + if not self._observation.classname() == "GCTAObservation": | |
| 108 | + raise RuntimeError("Input observation not of type "+ | |
| 109 | + "\"GCTAObservation\".") | |
| 129 | 110 | |
| 130 | 111 | # Make sure we have an irf response |
| 131 | - if not self.observation.response().classname() == "GCTAResponseIrf": | |
| 132 | - raise gammalib.Exception.runtime_error("Response of input observation not of type \"GCTAResponseIrf\"") | |
| 112 | + if not self._observation.response().classname() == "GCTAResponseIrf": | |
| 113 | + raise RuntimeError("Response of input observation not of "+ | |
| 114 | + "type \"GCTAResponseIrf\".") | |
| 133 | 115 | |
| 134 | 116 | # Get other parameters |
| 135 | - self.m_clobber = self["clobber"].boolean() | |
| 117 | + self._clobber = self["clobber"].boolean() | |
| 136 | 118 | |
| 137 | 119 | # Return |
| 138 | 120 | return |
| 139 | 121 | |
| 140 | - def make_irf_file(self): | |
| 141 | - | |
| 142 | - # retrieve response component | |
| 143 | - rsp = self.observation.response() | |
| 144 | - | |
| 145 | - # Initialise FITS file | |
| 146 | - fits = gammalib.GFits() | |
| 122 | + def _make_irf_file(self): | |
| 123 | + """ | |
| 124 | + Creates an IRF FITS file. | |
| 125 | + """ | |
| 126 | + # Write header into logger | |
| 127 | + if self._logTerse(): | |
| 128 | + self._log("\n") | |
| 129 | + self._log.header2("Creating IRF file") | |
| 130 | + | |
| 131 | + # Get response for the observation | |
| 132 | + rsp = self._observation.response() | |
| 147 | 133 | |
| 148 | - # Create GFilename instances | |
| 149 | - fname_aeff = gammalib.GFilename(rsp.aeff().filename()) | |
| 150 | - fname_psf = gammalib.GFilename(rsp.psf().filename()) | |
| 151 | - fname_edisp = gammalib.GFilename(rsp.edisp().filename()) | |
| 152 | - fname_bkg = gammalib.GFilename(rsp.background().filename()) | |
| 134 | + # Extract response file names | |
| 135 | + fname_aeff = rsp.aeff().filename() | |
| 136 | + fname_psf = rsp.psf().filename() | |
| 137 | + fname_edisp = rsp.edisp().filename() | |
| 138 | + fname_bkg = rsp.background().filename() | |
| 139 | + | |
| 140 | + # Log filename instances | |
| 141 | + if self._logTerse(): | |
| 142 | + self._log(gammalib.parformat("Effective area")) | |
| 143 | + self._log(repr(fname_aeff)) | |
| 144 | + self._log("\n") | |
| 145 | + self._log(gammalib.parformat("Point spread function")) | |
| 146 | + self._log(fname_psf.url()) | |
| 147 | + self._log("\n") | |
| 148 | + self._log(gammalib.parformat("Energy dispersion")) | |
| 149 | + self._log(fname_edisp.url()) | |
| 150 | + self._log("\n") | |
| 151 | + self._log(gammalib.parformat("Background rate")) | |
| 152 | + self._log(fname_bkg.url()) | |
| 153 | + self._log("\n") | |
| 153 | 154 | |
| 154 | 155 | # Open FITS files of response components |
| 155 | 156 | fits_aeff = gammalib.GFits(fname_aeff) |
| ... | ... | @@ -157,7 +158,10 @@ class csobs2caldb(ctools.cscript): |
| 157 | 158 | fits_edisp = gammalib.GFits(fname_edisp) |
| 158 | 159 | fits_bkg = gammalib.GFits(fname_bkg) |
| 159 | 160 | |
| 160 | - # Bundle IRFs into one file | |
| 161 | + # Create empty FITS file | |
| 162 | + fits = gammalib.GFits() | |
| 163 | + | |
| 164 | + # Append IRF component to FITS file | |
| 161 | 165 | fits.append(fits_aeff[fname_aeff.extname("EFFECTIVE AREA")]) |
| 162 | 166 | fits.append(fits_psf[fname_psf.extname("POINT SPREAD FUNCTION")]) |
| 163 | 167 | fits.append(fits_edisp[fname_edisp.extname("ENERGY DISPERSION")]) |
| ... | ... | @@ -166,30 +170,37 @@ class csobs2caldb(ctools.cscript): |
| 166 | 170 | # Return fits file |
| 167 | 171 | return fits |
| 168 | 172 | |
| 169 | - def make_caldb_index(self): | |
| 170 | - | |
| 173 | + def _make_caldb_index(self): | |
| 174 | + """ | |
| 175 | + Creates an IRF index FITS file. | |
| 176 | + """ | |
| 177 | + # Write header into logger | |
| 178 | + if self._logTerse(): | |
| 179 | + self._log("\n") | |
| 180 | + self._log.header2("Creating database index file") | |
| 181 | + | |
| 171 | 182 | # Open calibration database index |
| 172 | - indx_file = self.base_dir+"/caldb.indx" | |
| 183 | + indx_file = self._base_dir+"/caldb.indx" | |
| 173 | 184 | |
| 174 | - # Check if indx file exists (create if not existent) | |
| 175 | - if os.path.isfile(indx_file): | |
| 176 | - cif = gammalib.GFits(indx_file) | |
| 177 | - else: | |
| 178 | - cif = gammalib.GFits(indx_file, True) | |
| 185 | + # Open index file (or create one if it does not exist) | |
| 186 | + cif = gammalib.GFits(indx_file, True) | |
| 179 | 187 | |
| 180 | 188 | # Retrieve "CIF" table |
| 181 | 189 | if cif.contains("CIF"): |
| 182 | 190 | table = cif.table("CIF") |
| 191 | + | |
| 192 | + # ... or create binary table if no "CIF" table exists yet | |
| 183 | 193 | else: |
| 184 | - # Create binary table if not available | |
| 194 | + | |
| 195 | + # Create empty binary table | |
| 185 | 196 | bintable = gammalib.GFitsBinTable() |
| 186 | 197 | bintable.extname("CIF") |
| 187 | 198 | bintable.card("CIFVERSN", "1992a", "Version of CIF format") |
| 188 | - cif.append(bintable) | |
| 189 | - | |
| 190 | - table = cif.table("CIF") | |
| 199 | + | |
| 200 | + # Append table to FITS file and recover a reference to the | |
| 201 | + # appended table | |
| 202 | + table = cif.append(bintable) | |
| 191 | 203 | |
| 192 | - # Copied from cta_root2caldb.py | |
| 193 | 204 | # Attach columns. Reference: CAL/GEN/92-008 |
| 194 | 205 | table.append(gammalib.GFitsTableStringCol("TELESCOP", 0, 10)) |
| 195 | 206 | table.append(gammalib.GFitsTableStringCol("INSTRUME", 0, 10)) |
| ... | ... | @@ -215,7 +226,7 @@ class csobs2caldb(ctools.cscript): |
| 215 | 226 | row_index = -1 |
| 216 | 227 | for caldir in table["CAL_DIR"]: |
| 217 | 228 | row_index += 1 |
| 218 | - if caldir == self.cal_dir: | |
| 229 | + if caldir == self._cal_dir: | |
| 219 | 230 | has_config = True |
| 220 | 231 | break |
| 221 | 232 | |
| ... | ... | @@ -238,8 +249,8 @@ class csobs2caldb(ctools.cscript): |
| 238 | 249 | today, time = now.split() |
| 239 | 250 | |
| 240 | 251 | # Set element |
| 241 | - table["TELESCOP"][row] = self.m_mission | |
| 242 | - table["INSTRUME"][row] = self.m_instrument | |
| 252 | + table["TELESCOP"][row] = self._mission | |
| 253 | + table["INSTRUME"][row] = self._instrument | |
| 243 | 254 | table["DETNAM"][row] = "NONE" |
| 244 | 255 | table["FILTER"][row] = "NONE" |
| 245 | 256 | table["CAL_DEV"][row] = "ONLINE" |
| ... | ... | @@ -249,115 +260,133 @@ class csobs2caldb(ctools.cscript): |
| 249 | 260 | table["CAL_VST"][row] = time.split(".")[0] |
| 250 | 261 | table["REF_TIME"][row] = 51544.0 |
| 251 | 262 | table["CAL_QUAL"][row] = 0 |
| 252 | - table["CAL_CBD"][row] = "NAME("+self.m_rspname+")" | |
| 263 | + table["CAL_CBD"][row] = "NAME("+self._rspname+")" | |
| 253 | 264 | table["CAL_DATE"][row] = today.replace("-","/")[2:] |
| 254 | - table["CAL_DIR"][row] = self.cal_dir | |
| 255 | - table["CAL_FILE"][row] = self.m_outfile | |
| 265 | + table["CAL_DIR"][row] = self._cal_dir | |
| 266 | + table["CAL_FILE"][row] = self._outfile | |
| 256 | 267 | |
| 257 | 268 | # Add effective area information |
| 258 | 269 | row = row_index-4 |
| 259 | - table["CAL_CNAM"][row] = "EFF_AREA" | |
| 260 | - table["CAL_DESC"][row] = self.m_instrument+" effective area" | |
| 270 | + table["CAL_CNAM"][row] = "EFF_AREA" | |
| 271 | + table["CAL_DESC"][row] = self._instrument+" effective area" | |
| 261 | 272 | |
| 262 | 273 | # Add point spread function information |
| 263 | 274 | row = row_index-3 |
| 264 | - table["CAL_CNAM"][row] = "RPSF" | |
| 265 | - table["CAL_DESC"][row] = self.m_instrument+" point spread function" | |
| 275 | + table["CAL_CNAM"][row] = "RPSF" | |
| 276 | + table["CAL_DESC"][row] = self._instrument+" point spread function" | |
| 266 | 277 | |
| 267 | 278 | # Add energy dispersion information |
| 268 | 279 | row = row_index-2 |
| 269 | - table["CAL_CNAM"][row] = "EDISP" | |
| 270 | - table["CAL_DESC"][row] = self.m_instrument+" energy dispersion" | |
| 280 | + table["CAL_CNAM"][row] = "EDISP" | |
| 281 | + table["CAL_DESC"][row] = self._instrument+" energy dispersion" | |
| 271 | 282 | |
| 272 | 283 | # Add background information |
| 273 | 284 | row = row_index-1 |
| 274 | - table["CAL_CNAM"][row] = "BGD" | |
| 275 | - table["CAL_DESC"][row] = self.m_instrument+" background" | |
| 285 | + table["CAL_CNAM"][row] = "BGD" | |
| 286 | + table["CAL_DESC"][row] = self._instrument+" background" | |
| 276 | 287 | |
| 277 | 288 | # Return CIF FITS file |
| 278 | 289 | return cif |
| 279 | 290 | |
| 280 | - def make_dirs(self): | |
| 291 | + def _make_dirs(self): | |
| 292 | + """ | |
| 293 | + Make CALDB directories. | |
| 294 | + """ | |
| 295 | + # Write header into logger | |
| 296 | + if self._logTerse(): | |
| 297 | + self._log("\n") | |
| 298 | + self._log.header2("Creating directory structure") | |
| 281 | 299 | |
| 282 | - # Create gammalib Caldb | |
| 300 | + # Create calibration database | |
| 283 | 301 | caldb = gammalib.GCaldb() |
| 284 | 302 | |
| 285 | 303 | # Set calibration directory |
| 286 | - self.cal_dir = "data" | |
| 287 | - self.cal_dir += "/"+self.m_mission.lower() | |
| 288 | - self.cal_dir += "/"+self.m_instrument.lower() | |
| 289 | - self.cal_dir += "/bcf/"+self.m_rspname | |
| 304 | + self._cal_dir = "data" | |
| 305 | + self._cal_dir += "/"+self._mission.lower() | |
| 306 | + self._cal_dir += "/"+self._instrument.lower() | |
| 307 | + self._cal_dir += "/bcf/"+self._rspname | |
| 290 | 308 | |
| 291 | 309 | # Set absolute path |
| 292 | - self.base_dir = caldb.rootdir() +"/data" | |
| 293 | - self.base_dir += "/"+self.m_mission.lower() | |
| 294 | - self.base_dir += "/"+self.m_instrument.lower() | |
| 310 | + self._base_dir = caldb.rootdir() +"/data" | |
| 311 | + self._base_dir += "/"+self._mission.lower() | |
| 312 | + self._base_dir += "/"+self._instrument.lower() | |
| 295 | 313 | |
| 296 | 314 | # Set directory for irf file |
| 297 | - self.rsp_dir = caldb.rootdir() + "/" + self.cal_dir | |
| 315 | + self._rsp_dir = caldb.rootdir() + "/" + self._cal_dir | |
| 298 | 316 | |
| 299 | 317 | # Create directories and log information |
| 300 | - if not os.path.isdir(self.rsp_dir): | |
| 301 | - if self.logExplicit(): | |
| 302 | - self.log(gammalib.parformat("Directory")) | |
| 303 | - self.log(self.rsp_dir) | |
| 304 | - self.log("\n") | |
| 305 | - os.makedirs(self.rsp_dir) | |
| 318 | + if not os.path.isdir(self._rsp_dir): | |
| 319 | + if self._logExplicit(): | |
| 320 | + self._log(gammalib.parformat("Directory")) | |
| 321 | + self._log(self._rsp_dir) | |
| 322 | + self._log("\n") | |
| 323 | + os.makedirs(self._rsp_dir) | |
| 306 | 324 | else: |
| 307 | - if self.logExplicit(): | |
| 308 | - self.log(gammalib.parformat("Directory (existing)")) | |
| 309 | - self.log(self.rsp_dir) | |
| 310 | - self.log("\n") | |
| 325 | + if self._logExplicit(): | |
| 326 | + self._log(gammalib.parformat("Directory (existing)")) | |
| 327 | + self._log(self._rsp_dir) | |
| 328 | + self._log("\n") | |
| 311 | 329 | |
| 312 | 330 | # Return |
| 313 | 331 | return |
| 314 | 332 | |
| 333 | + | |
| 334 | + # Public methods | |
| 315 | 335 | def run(self): |
| 316 | 336 | """ |
| 317 | 337 | Run the script. |
| 318 | 338 | """ |
| 319 | 339 | # Switch screen logging on in debug mode |
| 320 | - if self.logDebug(): | |
| 321 | - self.log.cout(True) | |
| 340 | + if self._logDebug(): | |
| 341 | + self._log.cout(True) | |
| 322 | 342 | |
| 323 | 343 | # Get parameters |
| 324 | - self.get_parameters() | |
| 344 | + self._get_parameters() | |
| 325 | 345 | |
| 326 | - # Write input parameters into logger | |
| 327 | - if self.logTerse(): | |
| 328 | - self.log_parameters() | |
| 329 | - self.log("\n\n") | |
| 330 | - self.log.header1("Creating directory structure") | |
| 346 | + # Write input parameters and header into logger | |
| 347 | + if self._logTerse(): | |
| 348 | + self._log_parameters() | |
| 349 | + self._log("\n\n") | |
| 350 | + self._log.header1("Creating CALDB entry") | |
| 331 | 351 | |
| 332 | 352 | # Create directory structure |
| 333 | - self.make_dirs() | |
| 334 | - | |
| 335 | - # Logging | |
| 336 | - if self.logTerse(): | |
| 337 | - self.log("\n") | |
| 338 | - self.log.header1("Updating calibration database") | |
| 353 | + self._make_dirs() | |
| 339 | 354 | |
| 340 | 355 | # Create/update calibration database |
| 341 | - self.caldb_inx = self.make_caldb_index() | |
| 356 | + self._caldb_inx = self._make_caldb_index() | |
| 342 | 357 | |
| 343 | - # Logging | |
| 344 | - if self.logTerse(): | |
| 345 | - self.log("\n") | |
| 346 | - self.log.header1("Creating response file") | |
| 347 | - | |
| 348 | - # Create IRF file | |
| 349 | - self.irf_fits = self.make_irf_file() | |
| 358 | + # Create response file | |
| 359 | + self._irf_fits = self._make_irf_file() | |
| 350 | 360 | |
| 351 | 361 | # Return |
| 352 | 362 | return |
| 353 | 363 | |
| 354 | 364 | def save(self): |
| 365 | + """ | |
| 366 | + Save calibration database FITS file. | |
| 367 | + """ | |
| 368 | + # Write header into logger | |
| 369 | + if self._logTerse(): | |
| 370 | + self._log("\n") | |
| 371 | + self._log.header1("Save calibration database") | |
| 372 | + | |
| 373 | + # Set response filename | |
| 374 | + filename = self._rsp_dir + "/" + self._outfile | |
| 375 | + | |
| 376 | + # Write filenames into logger | |
| 377 | + if self._logTerse(): | |
| 378 | + self._log(gammalib.parformat("CALDB index file")) | |
| 379 | + self._log(self._caldb_inx.filename().url()) | |
| 380 | + self._log("\n") | |
| 381 | + self._log(gammalib.parformat("Response file")) | |
| 382 | + self._log(filename) | |
| 383 | + self._log("\n") | |
| 355 | 384 | |
| 356 | 385 | # Save caldb index file |
| 357 | - self.caldb_inx.save(self.m_clobber) | |
| 386 | + self._caldb_inx.save(self._clobber) | |
| 358 | 387 | |
| 359 | 388 | # Save response file |
| 360 | - self.irf_fits.saveto(self.rsp_dir + "/" + self.m_outfile, self.m_clobber) | |
| 389 | + self._irf_fits.saveto(filename, self._clobber) | |
| 361 | 390 | |
| 362 | 391 | # Return |
| 363 | 392 | return |
| ... | ... | @@ -380,14 +409,12 @@ class csobs2caldb(ctools.cscript): |
| 380 | 409 | # Main routine entry point # |
| 381 | 410 | # ======================== # |
| 382 | 411 | if __name__ == '__main__': |
| 383 | - """ | |
| 384 | - Generates caldb entry. | |
| 385 | - """ | |
| 412 | + | |
| 386 | 413 | # Create instance of application |
| 387 | 414 | app = csobs2caldb(sys.argv) |
| 388 | 415 | |
| 389 | 416 | # Open logfile |
| 390 | - app.logFileOpen() | |
| 417 | + app._logFileOpen() | |
| 391 | 418 | |
| 392 | 419 | # Execute application |
| 393 | 420 | app.execute() | ... | ... |
cscripts/csobsdef.par
0 → 100644
| 1 | +############################################################################# | |
| 2 | +# # | |
| 3 | +# CTA Science Analysis Tools # | |
| 4 | +# # | |
| 5 | +# ------------------------------------------------------------------------- # | |
| 6 | +# # | |
| 7 | +# File: csobsdef.par # | |
| 8 | +# Version: 1.1.0 # | |
| 9 | +# # | |
| 10 | +# Author: Juergen Knoedlseder # | |
| 11 | +# Jurgen.Knodlseder@irap.omp.eu # | |
| 12 | +# IRAP # | |
| 13 | +# # | |
| 14 | +# Purpose: Parameter file for the csobsdef script # | |
| 15 | +# # | |
| 16 | +############################################################################# | |
| 17 | +# | |
| 18 | +# General parameters | |
| 19 | +#=================== | |
| 20 | +inpnt, f, a, NONE,,, "Input pointing definition ASCII file" | |
| 21 | +outobs, f, a, obs.xml,,, "Output observation definition XML file" | |
| 22 | + | |
| 23 | +# | |
| 24 | +# Common pointing parameter values | |
| 25 | +#================================= | |
| 26 | +duration, r, a, 1800.0,,, "Pointing duration (seconds)" | |
| 27 | +caldb, s, h, ,,, "Calibration database" | |
| 28 | +irf, s, h, ,,, "Instrument response function" | |
| 29 | +emin, r, h, UNDEF,,, "Lower energy limit (TeV)" | |
| 30 | +emax, r, h, UNDEF,,, "Upper energy limit (TeV)" | |
| 31 | +rad, r, h, UNDEF,,, "Radius of ROI (degrees)" | |
| 32 | +deadc, r, h, 0.95,,, "Deadtime correction factor" | |
| 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, csobsdef.log,,, "Log filename" | ... | ... |
cscripts/csobsdef.py
| ... | ... | @@ -28,11 +28,12 @@ import sys |
| 28 | 28 | # ============== # |
| 29 | 29 | class csobsdef(ctools.cscript): |
| 30 | 30 | """ |
| 31 | - The csobsdef class generates an observation definition file from a | |
| 32 | - pointing list. The pointing list is a comma-separated value ASCII | |
| 33 | - file with header keywords in the first row followed by a list of | |
| 34 | - pointings (one pointing per row). The following header keywords | |
| 35 | - are supported (case sensitive, column order irrelevant): | |
| 31 | + Creates an observation definition file from a pointing list. | |
| 32 | + | |
| 33 | + The pointing list is a comma-separated value ASCII file with header | |
| 34 | + keywords in the first row followed by a list of pointings (one | |
| 35 | + pointing per row). The following header keywords are supported (case | |
| 36 | + sensitive, column order irrelevant): | |
| 36 | 37 | |
| 37 | 38 | name - Observation name string |
| 38 | 39 | id - Unique observation identifier string |
| ... | ... | @@ -53,53 +54,54 @@ class csobsdef(ctools.cscript): |
| 53 | 54 | csobsdef as user parameters. The only exception is the "duration" |
| 54 | 55 | keyword that will automatically be queried. |
| 55 | 56 | |
| 56 | - Here some usage examples: | |
| 57 | + Examples: | |
| 57 | 58 | |
| 58 | - csobsdef | |
| 59 | - Creates minimal observation definition file. | |
| 59 | + ./csobsdef | |
| 60 | + Creates minimal observation definition file. | |
| 60 | 61 | |
| 61 | - csobsdef emin=0.1 emax=100.0 | |
| 62 | - Creates observation definition file with an energy range 100 GeV - 100 TeV. | |
| 62 | + ./csobsdef emin=0.1 emax=100.0 | |
| 63 | + Creates observation definition file with an energy range | |
| 64 | + 100 GeV - 100 TeV. | |
| 63 | 65 | |
| 64 | - csobsdef rad=5 | |
| 65 | - Creates observation definition file with a ROI radius of 5 deg. | |
| 66 | + ./csobsdef rad=5 | |
| 67 | + Creates observation definition file with a ROI radius of | |
| 68 | + 5 degrees. | |
| 66 | 69 | |
| 67 | - csobsdef caldb=dummy irf=cta_dummy_irf | |
| 68 | - Creates observation definition file using the "cta_dummy_irf" IRF in the | |
| 69 | - "dummy" calibration database. | |
| 70 | + ./csobsdef caldb=dummy irf=cta_dummy_irf | |
| 71 | + Creates observation definition file using the "cta_dummy_irf" | |
| 72 | + IRF in the "dummy" calibration database. | |
| 70 | 73 | """ |
| 74 | + | |
| 75 | + # Constructors and destructors | |
| 71 | 76 | def __init__(self, *argv): |
| 72 | 77 | """ |
| 73 | 78 | Constructor. |
| 74 | 79 | """ |
| 75 | 80 | # Set name and version |
| 76 | - self.name = "csobsdef" | |
| 77 | - self.version = "1.0.0" | |
| 81 | + self._name = "csobsdef" | |
| 82 | + self._version = "1.1.0" | |
| 78 | 83 | |
| 79 | 84 | # Initialise class members |
| 80 | - self.obs = gammalib.GObservations() | |
| 81 | - self.inpnt = "" | |
| 82 | - self.tmin = 0.0 | |
| 83 | - self.outfile = "" | |
| 84 | - self.chatter = 2 | |
| 85 | - self.clobber = True | |
| 86 | - self.debug = False | |
| 87 | - self.read_ahead = False | |
| 88 | - | |
| 89 | - # Make sure that parfile exists | |
| 90 | - file = self.parfile() | |
| 85 | + self._obs = gammalib.GObservations() | |
| 86 | + self._inpnt = "" | |
| 87 | + self._tmin = 0.0 | |
| 88 | + self._outobs = "NONE" | |
| 89 | + self._chatter = 2 | |
| 90 | + self._clobber = True | |
| 91 | + self._debug = False | |
| 92 | + self._read_ahead = False | |
| 91 | 93 | |
| 92 | 94 | # Initialise application |
| 93 | 95 | if len(argv) == 0: |
| 94 | - ctools.cscript.__init__(self, self.name, self.version) | |
| 96 | + ctools.cscript.__init__(self, self._name, self._version) | |
| 95 | 97 | elif len(argv) ==1: |
| 96 | - ctools.cscript.__init__(self, self.name, self.version, *argv) | |
| 98 | + ctools.cscript.__init__(self, self._name, self._version, *argv) | |
| 97 | 99 | else: |
| 98 | 100 | raise TypeError("Invalid number of arguments given.") |
| 99 | 101 | |
| 100 | 102 | # Set logger properties |
| 101 | - self.log_header() | |
| 102 | - self.log.date(True) | |
| 103 | + self._log_header() | |
| 104 | + self._log.date(True) | |
| 103 | 105 | |
| 104 | 106 | # Return |
| 105 | 107 | return |
| ... | ... | @@ -111,92 +113,78 @@ class csobsdef(ctools.cscript): |
| 111 | 113 | # Return |
| 112 | 114 | return |
| 113 | 115 | |
| 114 | - def parfile(self): | |
| 115 | - """ | |
| 116 | - Check if parfile exists. If parfile does not exist then create a | |
| 117 | - default parfile. This kluge avoids shipping the cscript with a parfile. | |
| 118 | - """ | |
| 119 | - # Set parfile name | |
| 120 | - parfile = self.name+".par" | |
| 121 | - | |
| 122 | - # Test parfile existence, and create parfile if it does not exist | |
| 123 | - try: | |
| 124 | - pars = gammalib.GApplicationPars(parfile) | |
| 125 | - except: | |
| 126 | - # Signal that parfile was not found | |
| 127 | - print("Parfile \""+parfile+"\" not found. Create default parfile.") | |
| 128 | - | |
| 129 | - # Create default parfile | |
| 130 | - pars = gammalib.GApplicationPars() | |
| 131 | - pars.append(gammalib.GApplicationPar("inpnt","f","a","NONE","","","Input pointing definition file")) | |
| 132 | - pars.append(gammalib.GApplicationPar("outobs","f","a","obs.xml","","","Output observation definition XML file")) | |
| 133 | - pars.append(gammalib.GApplicationPar("duration","r","a","1800.0","","","Pointing duration (seconds)")) | |
| 134 | - pars.append(gammalib.GApplicationPar("caldb","s","h","","","","Calibration database")) | |
| 135 | - pars.append(gammalib.GApplicationPar("irf","s","h","","","","Instrument response function")) | |
| 136 | - pars.append(gammalib.GApplicationPar("emin","r","h","UNDEF","","","Lower energy limit (TeV)")) | |
| 137 | - pars.append(gammalib.GApplicationPar("emax","r","h","UNDEF","","","Upper energy limit (TeV)")) | |
| 138 | - pars.append(gammalib.GApplicationPar("rad","r","h","UNDEF","","","Radius of ROI (degrees)")) | |
| 139 | - pars.append(gammalib.GApplicationPar("deadc","r","h","0.95","","","Deadtime correction factor")) | |
| 140 | - pars.append_standard() | |
| 141 | - pars.append(gammalib.GApplicationPar("logfile","f","h","csobsdef.log","","","Log filename")) | |
| 142 | - pars.save(parfile) | |
| 143 | - | |
| 144 | - # Return | |
| 145 | - return | |
| 146 | 116 | |
| 147 | - def get_parameters(self): | |
| 117 | + # Private methods | |
| 118 | + def _get_parameters(self): | |
| 148 | 119 | """ |
| 149 | 120 | Get parameters from parfile. |
| 150 | 121 | """ |
| 151 | 122 | # Read parameters |
| 152 | - self.inpnt = self["inpnt"].filename() | |
| 123 | + self._inpnt = self["inpnt"].filename() | |
| 153 | 124 | |
| 154 | 125 | # Read ahead parameters |
| 155 | - if self.read_ahead: | |
| 156 | - self.outfile = self["outobs"].filename() | |
| 126 | + if self._read_ahead: | |
| 127 | + self._outobs = self["outobs"].filename() | |
| 157 | 128 | |
| 158 | 129 | # Set some fixed parameters |
| 159 | - self.chatter = self["chatter"].integer() | |
| 160 | - self.clobber = self["clobber"].boolean() | |
| 161 | - self.debug = self["debug"].boolean() | |
| 130 | + self._chatter = self["chatter"].integer() | |
| 131 | + self._clobber = self["clobber"].boolean() | |
| 132 | + self._debug = self["debug"].boolean() | |
| 133 | + | |
| 134 | + # Write input parameters into logger | |
| 135 | + if self._logTerse(): | |
| 136 | + self._log_parameters() | |
| 137 | + self._log("\n") | |
| 162 | 138 | |
| 163 | 139 | # Return |
| 164 | 140 | return |
| 165 | 141 | |
| 166 | - def execute(self): | |
| 142 | + def _set_response(self, obs, caldb, irf): | |
| 167 | 143 | """ |
| 168 | - Execute the script. | |
| 144 | + Set response for an observation. | |
| 145 | + | |
| 146 | + The method creates an XML element so that that the response XML | |
| 147 | + writer will write the database and response name into the | |
| 148 | + observation definition file. | |
| 169 | 149 | """ |
| 170 | - # Set read ahead flag | |
| 171 | - self.read_ahead = True | |
| 150 | + # Create XML element | |
| 151 | + xml = gammalib.GXmlElement() | |
| 172 | 152 | |
| 173 | - # Run the script | |
| 174 | - self.run() | |
| 153 | + # Append parameter | |
| 154 | + parameter = "parameter name=\"Calibration\" database=\""+\ | |
| 155 | + caldb+"\" response=\""+irf+"\"" | |
| 156 | + xml.append(gammalib.GXmlElement(parameter)) | |
| 175 | 157 | |
| 176 | - # Save observation definition file | |
| 177 | - self.obs.save(self.outfile) | |
| 158 | + # Create CTA response | |
| 159 | + response = gammalib.GCTAResponseIrf() | |
| 160 | + response.read(xml) | |
| 178 | 161 | |
| 179 | - # Return | |
| 180 | - return | |
| 162 | + # Attach response to observation | |
| 163 | + obs.response(response) | |
| 164 | + | |
| 165 | + # Return observation | |
| 166 | + return obs | |
| 181 | 167 | |
| 168 | + | |
| 169 | + # Public methods | |
| 182 | 170 | def run(self): |
| 183 | 171 | """ |
| 184 | 172 | Run the script. |
| 185 | 173 | """ |
| 186 | 174 | # Switch screen logging on in debug mode |
| 187 | - if self.logDebug(): | |
| 188 | - self.log.cout(True) | |
| 175 | + if self._logDebug(): | |
| 176 | + self._log.cout(True) | |
| 189 | 177 | |
| 190 | 178 | # Get parameters |
| 191 | - self.get_parameters() | |
| 179 | + self._get_parameters() | |
| 192 | 180 | |
| 193 | - # Write input parameters into logger | |
| 194 | - if self.logTerse(): | |
| 195 | - self.log_parameters() | |
| 196 | - self.log("\n") | |
| 181 | + # Write header into logger | |
| 182 | + if self._logTerse(): | |
| 183 | + self._log("\n") | |
| 184 | + self._log.header1("Creating observation definition XML file") | |
| 197 | 185 | |
| 198 | 186 | # Load pointing definition file |
| 199 | - pntdef = gammalib.GCsv(self.inpnt, ",") | |
| 187 | + pntdef = gammalib.GCsv(self._inpnt, ",") | |
| 200 | 188 | ncols = pntdef.ncols() |
| 201 | 189 | npnt = pntdef.nrows()-1 |
| 202 | 190 | |
| ... | ... | @@ -205,8 +193,8 @@ class csobsdef(ctools.cscript): |
| 205 | 193 | raise RuntimeError("No header found in pointing definition file.") |
| 206 | 194 | |
| 207 | 195 | # Clear observation container |
| 208 | - self.obs.clear() | |
| 209 | - self.id = 1 | |
| 196 | + self._obs.clear() | |
| 197 | + self._id = 1 | |
| 210 | 198 | |
| 211 | 199 | # Extract header from pointing definition file |
| 212 | 200 | header = [] |
| ... | ... | @@ -233,8 +221,8 @@ class csobsdef(ctools.cscript): |
| 233 | 221 | if "id" in header: |
| 234 | 222 | id = pntdef[row, header.index("id")] |
| 235 | 223 | else: |
| 236 | - id = "%6.6d" % self.id | |
| 237 | - self.id += 1 | |
| 224 | + id = "%6.6d" % self._id | |
| 225 | + self._id += 1 | |
| 238 | 226 | obs.id(id) |
| 239 | 227 | |
| 240 | 228 | # Set pointing |
| ... | ... | @@ -249,8 +237,8 @@ class csobsdef(ctools.cscript): |
| 249 | 237 | pntdir = gammalib.GSkyDir() |
| 250 | 238 | pntdir.lb_deg(lon,lat) |
| 251 | 239 | else: |
| 252 | - raise RuntimeError("No (ra,dec) or (lon,lat) columns found in pointing" | |
| 253 | - " definition file.") | |
| 240 | + raise RuntimeError("No (ra,dec) or (lon,lat) columns " | |
| 241 | + "found in pointing definition file.") | |
| 254 | 242 | obs.pointing(gammalib.GCTAPointing(pntdir)) |
| 255 | 243 | |
| 256 | 244 | # Set response function |
| ... | ... | @@ -263,7 +251,7 @@ class csobsdef(ctools.cscript): |
| 263 | 251 | else: |
| 264 | 252 | irf = self["irf"].string() |
| 265 | 253 | if caldb != "" and irf != "": |
| 266 | - obs = self.__set_response(obs, caldb, irf) | |
| 254 | + obs = self._set_response(obs, caldb, irf) | |
| 267 | 255 | |
| 268 | 256 | # Set deadtime correction factor |
| 269 | 257 | if "deadc" in header: |
| ... | ... | @@ -277,12 +265,12 @@ class csobsdef(ctools.cscript): |
| 277 | 265 | duration = float(pntdef[row, header.index("duration")]) |
| 278 | 266 | else: |
| 279 | 267 | duration = self["duration"].real() |
| 280 | - tmin = self.tmin | |
| 281 | - tmax = self.tmin + duration | |
| 282 | - gti = gammalib.GGti(self._time_reference()) | |
| 283 | - tstart = gammalib.GTime(tmin, self._time_reference()) | |
| 284 | - tstop = gammalib.GTime(tmax, self._time_reference()) | |
| 285 | - self.tmin = tmax | |
| 268 | + tmin = self._tmin | |
| 269 | + tmax = self._tmin + duration | |
| 270 | + gti = gammalib.GGti(self._time_reference()) | |
| 271 | + tstart = gammalib.GTime(tmin, self._time_reference()) | |
| 272 | + tstop = gammalib.GTime(tmax, self._time_reference()) | |
| 273 | + self._tmin = tmax | |
| 286 | 274 | gti.append(tstart, tstop) |
| 287 | 275 | obs.ontime(gti.ontime()) |
| 288 | 276 | obs.livetime(gti.ontime()*deadc) |
| ... | ... | @@ -334,49 +322,75 @@ class csobsdef(ctools.cscript): |
| 334 | 322 | # Attach event list to CTA observation |
| 335 | 323 | obs.events(list) |
| 336 | 324 | |
| 325 | + # Write observation into logger | |
| 326 | + if self._logExplicit(): | |
| 327 | + self._log(str(obs)) | |
| 328 | + self._log("\n") | |
| 329 | + elif self._logTerse(): | |
| 330 | + self._log(gammalib.parformat(obs.instrument()+" observation")) | |
| 331 | + self._log("Name=\""+obs.name()+"\" ") | |
| 332 | + self._log("ID=\""+obs.id()+"\"\n") | |
| 333 | + | |
| 337 | 334 | # Append observation |
| 338 | - self.obs.append(obs) | |
| 335 | + self._obs.append(obs) | |
| 339 | 336 | |
| 340 | 337 | # Return |
| 341 | 338 | return |
| 342 | 339 | |
| 343 | - def __set_response(self, obs, caldb, irf): | |
| 340 | + def save(self): | |
| 344 | 341 | """ |
| 345 | - Set response for an observation. We create an XML element for that | |
| 346 | - so that the response XML writer will write the database and response | |
| 347 | - name into the observation definition file. | |
| 342 | + Save observation definition XML file. | |
| 348 | 343 | """ |
| 349 | - # Create XML element | |
| 350 | - xml = gammalib.GXmlElement() | |
| 344 | + # Write header and filename into logger | |
| 345 | + if self._logTerse(): | |
| 346 | + self._log("\n") | |
| 347 | + self._log.header1("Save observation definition XML file") | |
| 348 | + | |
| 349 | + # Get output filename in case it was not read ahead | |
| 350 | + self._outobs = self["outobs"].filename() | |
| 351 | + | |
| 352 | + # Check if observation definition XML file is valid | |
| 353 | + if self._outobs != "NONE": | |
| 354 | + | |
| 355 | + # Log filename | |
| 356 | + if self._logTerse(): | |
| 357 | + self._log(gammalib.parformat("Observation XML file")) | |
| 358 | + self._log(self._outobs.url()) | |
| 359 | + self._log("\n") | |
| 360 | + | |
| 361 | + # Save observation definition XML file | |
| 362 | + self._obs.save(self._outobs) | |
| 363 | + | |
| 364 | + # Return | |
| 365 | + return | |
| 351 | 366 | |
| 352 | - # Append parameter | |
| 353 | - parameter = "parameter name=\"Calibration\" database=\""+\ | |
| 354 | - caldb+"\" response=\""+irf+"\"" | |
| 355 | - xml.append(gammalib.GXmlElement(parameter)) | |
| 367 | + def execute(self): | |
| 368 | + """ | |
| 369 | + Execute the script. | |
| 370 | + """ | |
| 371 | + # Set read ahead flag | |
| 372 | + self._read_ahead = True | |
| 356 | 373 | |
| 357 | - # Create CTA response | |
| 358 | - response = gammalib.GCTAResponseIrf() | |
| 359 | - response.read(xml) | |
| 374 | + # Run the script | |
| 375 | + self.run() | |
| 360 | 376 | |
| 361 | - # Attach response to observation | |
| 362 | - obs.response(response) | |
| 377 | + # Save observation definition file | |
| 378 | + self.save() | |
| 363 | 379 | |
| 364 | - # Return observation | |
| 365 | - return obs | |
| 380 | + # Return | |
| 381 | + return | |
| 366 | 382 | |
| 367 | 383 | |
| 368 | 384 | # ======================== # |
| 369 | 385 | # Main routine entry point # |
| 370 | 386 | # ======================== # |
| 371 | 387 | if __name__ == '__main__': |
| 372 | - """ | |
| 373 | - Generates observation definition file. | |
| 374 | - """ | |
| 388 | + | |
| 375 | 389 | # Create instance of application |
| 376 | 390 | app = csobsdef(sys.argv) |
| 377 | 391 | |
| 378 | 392 | # Open logfile |
| 379 | - app.logFileOpen() | |
| 393 | + app._logFileOpen() | |
| 380 | 394 | |
| 381 | 395 | # Execute application |
| 382 | 396 | app.execute() | ... | ... |
cscripts/csobsinfo.par
0 → 100644
| 1 | +############################################################################# | |
| 2 | +# # | |
| 3 | +# CTA Science Analysis Tools # | |
| 4 | +# # | |
| 5 | +# ------------------------------------------------------------------------- # | |
| 6 | +# # | |
| 7 | +# File: csobsinfo.par # | |
| 8 | +# Version: 1.1.0 # | |
| 9 | +# # | |
| 10 | +# Author: Juergen Knoedlseder # | |
| 11 | +# Jurgen.Knodlseder@irap.omp.eu # | |
| 12 | +# IRAP # | |
| 13 | +# # | |
| 14 | +# Purpose: Parameter file for the csobsinfo script # | |
| 15 | +# # | |
| 16 | +############################################################################# | |
| 17 | +# | |
| 18 | +# Input and output parameters | |
| 19 | +#============================ | |
| 20 | +inobs, f, a, obs.xml,,, "Input event list, counts cube, or observation definition XML file" | |
| 21 | +ds9file, f, h, NONE,,, "Output DS9 region file containing pointings" | |
| 22 | + | |
| 23 | +# | |
| 24 | +# Script parameters | |
| 25 | +#================== | |
| 26 | +offset, b, h, no,,, "Compute offset from target to pointing positions?" | |
| 27 | +ra, r, a, 0.0,,, "Target Right Ascension (deg)" | |
| 28 | +dec, r, a, 0.0,,, "Target Declination (deg)") | |
| 29 | + | |
| 30 | +# | |
| 31 | +# Standard parameters | |
| 32 | +#==================== | |
| 33 | +chatter, i, h, 2,0,4, "Chattiness of output" | |
| 34 | +clobber, b, h, yes,,, "Overwrite existing output files with new output files?" | |
| 35 | +debug, b, h, no,,, "Debugging mode activated" | |
| 36 | +mode, s, h, ql,,, "Mode of automatic parameters" | |
| 37 | +logfile, f, h, csobsinfo.log,,, "Log filename" | ... | ... |
cscripts/csobsinfo.py
| ... | ... | @@ -28,40 +28,48 @@ import sys |
| 28 | 28 | # =============== # |
| 29 | 29 | class csobsinfo(ctools.cscript): |
| 30 | 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. | |
| 31 | + Shows the content of an observation container. | |
| 34 | 32 | """ |
| 33 | + | |
| 34 | + # Constructors and destructors | |
| 35 | 35 | def __init__(self, *argv): |
| 36 | 36 | """ |
| 37 | 37 | Constructor. |
| 38 | 38 | """ |
| 39 | 39 | # Set name |
| 40 | - self.name = "csobsinfo" | |
| 41 | - self.version = "1.1.0" | |
| 40 | + self._name = "csobsinfo" | |
| 41 | + self._version = "1.1.0" | |
| 42 | 42 | |
| 43 | - # Initialise some members | |
| 43 | + # Initialise class members | |
| 44 | + self._obj_dir = None | |
| 45 | + self._compute_offset = False | |
| 46 | + self._ds9file = "" | |
| 47 | + self._offsets = [] | |
| 48 | + self._zeniths = [] | |
| 49 | + self._azimuths = [] | |
| 50 | + self._pnt_ra = [] | |
| 51 | + self._pnt_dec = [] | |
| 52 | + self._ebounds = gammalib.GEbounds() | |
| 53 | + self._gti = gammalib.GGti() | |
| 54 | + self._read_ahead = False | |
| 44 | 55 | if len(argv) > 0 and isinstance(argv[0],gammalib.GObservations): |
| 45 | - self.obs = argv[0] | |
| 46 | - argv = argv[1:] | |
| 56 | + self._obs = argv[0] | |
| 57 | + argv = argv[1:] | |
| 47 | 58 | else: |
| 48 | - self.obs = gammalib.GObservations() | |
| 49 | - self.obs.clear() | |
| 50 | - | |
| 51 | - # Make sure that parfile exists | |
| 52 | - file = self.parfile() | |
| 59 | + self._obs = gammalib.GObservations() | |
| 60 | + self._obs.clear() | |
| 53 | 61 | |
| 54 | 62 | # Initialise application |
| 55 | 63 | if len(argv) == 0: |
| 56 | - ctools.cscript.__init__(self, self.name, self.version) | |
| 64 | + ctools.cscript.__init__(self, self._name, self._version) | |
| 57 | 65 | elif len(argv) == 1: |
| 58 | - ctools.cscript.__init__(self, self.name, self.version, *argv) | |
| 66 | + ctools.cscript.__init__(self, self._name, self._version, *argv) | |
| 59 | 67 | else: |
| 60 | 68 | raise TypeError("Invalid number of arguments given.") |
| 61 | 69 | |
| 62 | 70 | # Set logger properties |
| 63 | - self.log_header() | |
| 64 | - self.log.date(True) | |
| 71 | + self._log_header() | |
| 72 | + self._log.date(True) | |
| 65 | 73 | |
| 66 | 74 | # Return |
| 67 | 75 | return |
| ... | ... | @@ -73,89 +81,64 @@ class csobsinfo(ctools.cscript): |
| 73 | 81 | # Return |
| 74 | 82 | return |
| 75 | 83 | |
| 76 | - def parfile(self): | |
| 77 | - """ | |
| 78 | - Check if parfile exists. If parfile does not exist then create a | |
| 79 | - default parfile. This kluge avoids shipping the cscript with a | |
| 80 | - parfile. | |
| 81 | - """ | |
| 82 | - | |
| 83 | - # Set parfile name | |
| 84 | - parfile = self.name+".par" | |
| 85 | - | |
| 86 | - try: | |
| 87 | - pars = gammalib.GApplicationPars(parfile) | |
| 88 | - except: | |
| 89 | - # Signal that parfile was not found | |
| 90 | - print("Parfile \""+parfile+"\" not found. Create default parfile.") | |
| 91 | - | |
| 92 | - # Create default parfile | |
| 93 | - pars = gammalib.GApplicationPars() | |
| 94 | - pars.append(gammalib.GApplicationPar("inobs","f","a","obs.xml","","","Event list, counts cube, or observation definition file")) | |
| 95 | - pars.append(gammalib.GApplicationPar("offset","b","h","no","","","Compute offset from target to pointing positions")) | |
| 96 | - pars.append(gammalib.GApplicationPar("ra","r","a","0.0","","","Target Right Ascension")) | |
| 97 | - pars.append(gammalib.GApplicationPar("dec","r","a","0.0","","","Target Declination")) | |
| 98 | - pars.append(gammalib.GApplicationPar("ds9file","f","h","NONE","","","DS9 region file containing pointings")) | |
| 99 | - pars.append_standard() | |
| 100 | - pars.append(gammalib.GApplicationPar("logfile","f","h","csobsinfo.log","","","Log filename")) | |
| 101 | - pars.save(parfile) | |
| 102 | 84 | |
| 103 | - # Return | |
| 104 | - return | |
| 105 | - | |
| 106 | - def get_parameters(self): | |
| 85 | + # Private methods | |
| 86 | + def _get_parameters(self): | |
| 107 | 87 | """ |
| 108 | 88 | Get parameters from parfile and setup the observation. |
| 109 | 89 | """ |
| 110 | 90 | # Get parameters |
| 111 | - if self.obs.size() == 0: | |
| 91 | + if self._obs.size() == 0: | |
| 112 | 92 | self._require_inobs("csobsinfo::get_parameters") |
| 113 | - self.obs = self._get_observations(False) | |
| 93 | + self._obs = self._get_observations(False) | |
| 114 | 94 | |
| 115 | 95 | # Initialise object position |
| 116 | - self.obj_dir = gammalib.GSkyDir() | |
| 96 | + self._obj_dir = gammalib.GSkyDir() | |
| 117 | 97 | |
| 118 | 98 | # Get (optional) offset parameters |
| 119 | - self.m_offset = self["offset"].boolean() | |
| 120 | - if self.m_offset: | |
| 99 | + self._compute_offset = self["offset"].boolean() | |
| 100 | + if self._compute_offset: | |
| 121 | 101 | ra = self["ra"].real() |
| 122 | 102 | dec = self["dec"].real() |
| 123 | - self.obj_dir.radec_deg(ra,dec) | |
| 103 | + self._obj_dir.radec_deg(ra,dec) | |
| 104 | + | |
| 105 | + # Read ahead DS9 filename | |
| 106 | + if self._read_ahead: | |
| 107 | + self._ds9file = self["ds9file"].filename() | |
| 124 | 108 | |
| 125 | - # Get (optional) DS9 filename | |
| 126 | - self.ds9file = self["ds9file"].filename() | |
| 109 | + # Write input parameters into logger | |
| 110 | + if self._logTerse(): | |
| 111 | + self._log_parameters() | |
| 112 | + self._log("\n") | |
| 127 | 113 | |
| 128 | 114 | # Return |
| 129 | 115 | return |
| 130 | 116 | |
| 117 | + | |
| 118 | + # Public methods | |
| 131 | 119 | def run(self): |
| 132 | 120 | """ |
| 133 | 121 | Run the script. |
| 134 | 122 | """ |
| 135 | 123 | # Switch screen logging on in debug mode |
| 136 | - if self.logDebug(): | |
| 137 | - self.log.cout(True) | |
| 124 | + if self._logDebug(): | |
| 125 | + self._log.cout(True) | |
| 138 | 126 | |
| 139 | 127 | # Get parameters |
| 140 | - self.get_parameters() | |
| 141 | - | |
| 142 | - # Write input parameters into logger | |
| 143 | - if self.logTerse(): | |
| 144 | - self.log_parameters() | |
| 145 | - self.log("\n") | |
| 128 | + self._get_parameters() | |
| 146 | 129 | |
| 147 | 130 | # Initialise arrays to store certain values for reuse |
| 148 | 131 | # Todo, think about using a python dictionary |
| 149 | - self.m_offsets = [] | |
| 150 | - self.m_zeniths = [] | |
| 151 | - self.m_azimuths = [] | |
| 152 | - self.pnt_ra = [] | |
| 153 | - self.pnt_dec = [] | |
| 154 | - obs_names = [] | |
| 132 | + self._offsets = [] | |
| 133 | + self._zeniths = [] | |
| 134 | + self._azimuths = [] | |
| 135 | + self._pnt_ra = [] | |
| 136 | + self._pnt_dec = [] | |
| 137 | + self._ebounds = gammalib.GEbounds() | |
| 138 | + self._gti = gammalib.GGti() | |
| 139 | + obs_names = [] | |
| 155 | 140 | |
| 156 | 141 | # Initialise output to be filled |
| 157 | - self.m_ebounds = gammalib.GEbounds() | |
| 158 | - self.m_gti = gammalib.GGti() | |
| 159 | 142 | ontime = 0.0 |
| 160 | 143 | livetime = 0.0 |
| 161 | 144 | n_events = 0 |
| ... | ... | @@ -163,27 +146,30 @@ class csobsinfo(ctools.cscript): |
| 163 | 146 | n_obs_binned = 0 |
| 164 | 147 | n_obs_unbinned = 0 |
| 165 | 148 | |
| 166 | - # Logging | |
| 167 | - self.log.header1("Looping over observations") | |
| 149 | + # Write header | |
| 150 | + if self._logTerse(): | |
| 151 | + self._log("\n") | |
| 152 | + if self._obs.size() > 1: | |
| 153 | + self._log.header1("Observations") | |
| 154 | + else: | |
| 155 | + self._log.header1("Observation") | |
| 168 | 156 | |
| 169 | 157 | # Loop over observations |
| 170 | - for obs in self.obs: | |
| 171 | - | |
| 158 | + for obs in self._obs: | |
| 172 | 159 | |
| 173 | 160 | # Skip non-CTA observations |
| 174 | 161 | if not obs.classname() == "GCTAObservation": |
| 175 | - self.log("Skipping "+obs.instrument()+" observation\n") | |
| 162 | + self._log("Skipping "+obs.instrument()+" observation\n") | |
| 176 | 163 | continue |
| 177 | 164 | |
| 178 | - # Use observed object as observation name | |
| 179 | - # if name is not given | |
| 165 | + # Use observed object as observation name if name is not given | |
| 180 | 166 | obs_name = obs.name() |
| 181 | 167 | if obs_name == "": |
| 182 | 168 | obs_name = obs.object() |
| 183 | 169 | |
| 184 | 170 | # Logging |
| 185 | - if self.logTerse(): | |
| 186 | - self.log.header2(obs_name) | |
| 171 | + if self._logTerse(): | |
| 172 | + self._log.header2(obs_name) | |
| 187 | 173 | |
| 188 | 174 | # Retrieve observation name |
| 189 | 175 | obs_names.append(obs_name) |
| ... | ... | @@ -199,206 +185,231 @@ class csobsinfo(ctools.cscript): |
| 199 | 185 | |
| 200 | 186 | # Retrieve pointing and store Ra,Dec |
| 201 | 187 | pnt_dir = obs.pointing().dir() |
| 202 | - self.pnt_ra.append(pnt_dir.ra_deg()) | |
| 203 | - self.pnt_dec.append(pnt_dir.dec_deg()) | |
| 188 | + self._pnt_ra.append(pnt_dir.ra_deg()) | |
| 189 | + self._pnt_dec.append(pnt_dir.dec_deg()) | |
| 204 | 190 | |
| 205 | 191 | # If avaliable append energy boundaries |
| 206 | 192 | if obs_bounds.size() > 0 : |
| 207 | - self.m_ebounds.append(obs_bounds.emin(),obs_bounds.emax()) | |
| 193 | + self._ebounds.append(obs_bounds.emin(),obs_bounds.emax()) | |
| 208 | 194 | |
| 209 | 195 | # Append time interval |
| 210 | - self.m_gti.append(obs_gti.tstart(), obs_gti.tstop()) | |
| 196 | + self._gti.append(obs_gti.tstart(), obs_gti.tstop()) | |
| 211 | 197 | |
| 212 | 198 | # Increment global livetime and ontime |
| 213 | 199 | ontime += obs.ontime() |
| 214 | 200 | livetime += obs.livetime() |
| 215 | 201 | |
| 216 | - # Log the event type (binned or unbinned) | |
| 217 | - if self.logTerse(): | |
| 218 | - self.log.parformat("binned") | |
| 219 | - | |
| 202 | + # Bookkeeping | |
| 220 | 203 | if obs.eventtype() == "CountsCube": |
| 221 | 204 | n_eventbins += obs.events().size() |
| 222 | 205 | n_obs_binned += 1 |
| 223 | - if self.logTerse(): | |
| 224 | - self.log("yes") | |
| 225 | - self.log("\n") | |
| 226 | - self.log.parformat("Number of bins") | |
| 227 | - self.log(str(obs.events().size())) | |
| 228 | - self.log("\n") | |
| 206 | + if self._logTerse(): | |
| 207 | + self._log.parformat("Binned") | |
| 208 | + self._log("yes\n") | |
| 209 | + self._log.parformat("Number of bins") | |
| 210 | + self._log(str(obs.events().size())) | |
| 211 | + self._log("\n") | |
| 229 | 212 | else: |
| 230 | 213 | n_events += obs.events().size() |
| 231 | 214 | n_obs_unbinned += 1 |
| 232 | - if self.logTerse(): | |
| 233 | - self.log("no") | |
| 234 | - self.log("\n") | |
| 235 | - self.log.parformat("Number of events") | |
| 236 | - self.log(str(obs.events().size())) | |
| 237 | - self.log("\n") | |
| 215 | + if self._logTerse(): | |
| 216 | + self._log.parformat("Binned") | |
| 217 | + self._log("no\n") | |
| 218 | + self._log.parformat("Number of events") | |
| 219 | + self._log(str(obs.events().size())) | |
| 220 | + self._log("\n") | |
| 221 | + | |
| 222 | + # Retrieve zenith and azimuth and store for later use | |
| 223 | + zenith = obs.pointing().zenith() | |
| 224 | + azimuth = obs.pointing().azimuth() | |
| 225 | + self._zeniths.append(zenith) | |
| 226 | + self._azimuths.append(azimuth) | |
| 227 | + | |
| 228 | + # Optionally compute offset with respect to target direction | |
| 229 | + if self._compute_offset: | |
| 230 | + offset = pnt_dir.dist_deg(self._obj_dir) | |
| 231 | + self._offsets.append(offset) | |
| 232 | + else: | |
| 233 | + self._offsets.append(-1.0) | |
| 238 | 234 | |
| 239 | - # Log option | |
| 240 | - if self.logTerse(): | |
| 235 | + # Optionally log details | |
| 236 | + if self._logTerse(): | |
| 241 | 237 | |
| 242 | 238 | # Log the observation energy range (if available) |
| 243 | - self.log.parformat("Energy range") | |
| 239 | + self._log.parformat("Energy range") | |
| 244 | 240 | if obs_bounds.size() == 0: |
| 245 | - self.log("undefined") | |
| 241 | + self._log("undefined") | |
| 246 | 242 | else: |
| 247 | - self.log(str(obs_bounds.emin())+" - "+str(obs_bounds.emax())) | |
| 248 | - self.log("\n") | |
| 243 | + self._log(str(obs_bounds.emin())) | |
| 244 | + self._log(" - ") | |
| 245 | + self._log(str(obs_bounds.emax())) | |
| 246 | + self._log("\n") | |
| 249 | 247 | |
| 250 | 248 | # Log observation time interval |
| 251 | - self.log.parformat("Time range (MJD)") | |
| 249 | + self._log.parformat("Time range (MJD)") | |
| 252 | 250 | if obs_gti.size() == 0: |
| 253 | - self.log("undefined") | |
| 251 | + self._log("undefined") | |
| 254 | 252 | else: |
| 255 | - self.log(str(obs_gti.tstart().mjd())+" - "+str(obs_gti.tstop().mjd())) | |
| 256 | - self.log("\n") | |
| 253 | + self._log(str(obs_gti.tstart().mjd())) | |
| 254 | + self._log(" - ") | |
| 255 | + self._log(str(obs_gti.tstop().mjd())) | |
| 256 | + self._log("\n") | |
| 257 | 257 | |
| 258 | 258 | # Log ontime |
| 259 | - self.log.parformat("Ontime [s]") | |
| 260 | - self.log(str(obs.ontime())) | |
| 261 | - self.log("\n") | |
| 259 | + self._log.parformat("Ontime") | |
| 260 | + self._log(str(obs.ontime())) | |
| 261 | + self._log(" s\n") | |
| 262 | 262 | |
| 263 | 263 | # Log livetime |
| 264 | - self.log.parformat("Livetime [s]") | |
| 265 | - self.log(str(obs.livetime())) | |
| 266 | - self.log("\n") | |
| 264 | + self._log.parformat("Livetime") | |
| 265 | + self._log(str(obs.livetime())) | |
| 266 | + self._log(" s\n") | |
| 267 | 267 | |
| 268 | 268 | # Log dead time fraction |
| 269 | - self.log.parformat("Dead-time fraction (%)") | |
| 270 | - self.log("%.3f" % (deadfrac)) | |
| 271 | - self.log("\n") | |
| 269 | + self._log.parformat("Deadtime fraction (%)") | |
| 270 | + self._log("%.3f" % (deadfrac)) | |
| 271 | + self._log("\n") | |
| 272 | 272 | |
| 273 | 273 | # Log pointing direction |
| 274 | - self.log.parformat("Pointing") | |
| 275 | - self.log(str(pnt_dir)) | |
| 276 | - self.log("\n") | |
| 274 | + self._log.parformat("Pointing") | |
| 275 | + self._log(str(pnt_dir)) | |
| 276 | + self._log("\n") | |
| 277 | 277 | |
| 278 | - # Log offset if possible | |
| 279 | - if self.m_offset: | |
| 280 | - offset = pnt_dir.dist_deg(self.obj_dir) | |
| 281 | - self.m_offsets.append(offset) | |
| 282 | - self.log.parformat("Offset") | |
| 283 | - self.log("%.2f" % (offset)) | |
| 284 | - self.log("\n") | |
| 285 | - else: | |
| 286 | - self.m_offsets.append(-1.0) | |
| 278 | + # Optionally log offset with respect to target direction | |
| 279 | + if self._compute_offset: | |
| 280 | + self._log.parformat("Offset from target") | |
| 281 | + self._log("%.2f" % (offset)) | |
| 282 | + self._log(" deg\n") | |
| 287 | 283 | |
| 288 | - # Retrieve zenith and azimuth and store for later use | |
| 289 | - zenith = obs.pointing().zenith() | |
| 290 | - azimuth = obs.pointing().azimuth() | |
| 291 | - self.m_zeniths.append(zenith) | |
| 292 | - self.m_azimuths.append(azimuth) | |
| 293 | - | |
| 294 | 284 | # Log Zenith and Azimuth if required |
| 295 | - if self.logExplicit(): | |
| 296 | - self.log.parformat("Zenith angle") | |
| 297 | - self.log("%.2f" % (zenith)) | |
| 298 | - self.log("\n") | |
| 299 | - self.log.parformat("Azimuth angle") | |
| 300 | - self.log("%.2f" % (azimuth)) | |
| 301 | - self.log("\n\n") | |
| 285 | + self._log.parformat("Zenith angle") | |
| 286 | + self._log("%.2f" % (zenith)) | |
| 287 | + self._log(" deg\n") | |
| 288 | + self._log.parformat("Azimuth angle") | |
| 289 | + self._log("%.2f" % (azimuth)) | |
| 290 | + self._log(" deg\n") | |
| 302 | 291 | |
| 303 | 292 | # Log summary |
| 304 | - self.log("\n") | |
| 305 | - self.log.header1("Summary") | |
| 293 | + if self._logTerse(): | |
| 294 | + | |
| 295 | + # Write header | |
| 296 | + self._log("\n") | |
| 297 | + self._log.header1("Summary") | |
| 306 | 298 | |
| 307 | - # Log general summary | |
| 308 | - self.log.parformat("Unbinned observations") | |
| 309 | - self.log(str(n_obs_unbinned)) | |
| 310 | - self.log("\n") | |
| 311 | - self.log.parformat("Number of events") | |
| 312 | - self.log(str(n_events)) | |
| 313 | - self.log("\n") | |
| 314 | - self.log.parformat("Binned observations") | |
| 315 | - self.log(str(n_obs_binned)) | |
| 316 | - self.log("\n") | |
| 317 | - self.log.parformat("Number of bins") | |
| 318 | - self.log(str(n_eventbins)) | |
| 319 | - self.log("\n\n") | |
| 299 | + # Log general summary | |
| 300 | + self._log.header3("Observations") | |
| 301 | + self._log.parformat("Unbinned observations") | |
| 302 | + self._log(str(n_obs_unbinned)) | |
| 303 | + self._log("\n") | |
| 304 | + self._log.parformat("Binned observations") | |
| 305 | + self._log(str(n_obs_binned)) | |
| 306 | + self._log("\n") | |
| 307 | + self._log.header3("Events") | |
| 308 | + self._log.parformat("Number of events") | |
| 309 | + self._log(str(n_events)) | |
| 310 | + self._log("\n") | |
| 311 | + self._log.parformat("Number of bins") | |
| 312 | + self._log(str(n_eventbins)) | |
| 313 | + self._log("\n") | |
| 320 | 314 | |
| 321 | - # Log pointing summary | |
| 322 | - self.log.header3("Pointings") | |
| 315 | + # Log pointing summary | |
| 316 | + self._log.header3("Pointings") | |
| 323 | 317 | |
| 324 | - # Log mean offset if possible | |
| 325 | - if self.m_offset: | |
| 326 | - self.log.parformat("Mean offset angle") | |
| 327 | - self.log("%.2f" % (sum(self.m_offsets)/len(self.m_offsets))) | |
| 328 | - self.log("\n") | |
| 318 | + # Log mean offset if possible | |
| 319 | + if self._compute_offset: | |
| 320 | + self._log.parformat("Mean offset angle") | |
| 321 | + self._log("%.2f" % (sum(self._offsets)/len(self._offsets))) | |
| 322 | + self._log(" deg\n") | |
| 329 | 323 | |
| 330 | - # Log mean azimuth and zenith angle | |
| 331 | - self.log.parformat("Mean zenith angle") | |
| 332 | - self.log("%.2f" % (sum(self.m_zeniths)/len(self.m_zeniths))) | |
| 333 | - self.log("\n") | |
| 334 | - self.log.parformat("Mean azimuth angle") | |
| 335 | - self.log("%.2f" % (sum(self.m_azimuths)/len(self.m_azimuths))) | |
| 336 | - self.log("\n") | |
| 324 | + # Log mean azimuth and zenith angle | |
| 325 | + self._log.parformat("Mean zenith angle") | |
| 326 | + self._log("%.2f" % (sum(self._zeniths)/len(self._zeniths))) | |
| 327 | + self._log(" deg\n") | |
| 328 | + self._log.parformat("Mean azimuth angle") | |
| 329 | + self._log("%.2f" % (sum(self._azimuths)/len(self._azimuths))) | |
| 330 | + self._log(" deg\n") | |
| 337 | 331 | |
| 338 | - # Log name of observations if requested | |
| 339 | - if self.logExplicit(): | |
| 340 | - obs_set = set(obs_names) | |
| 341 | - for name in obs_set: | |
| 342 | - self.log.parformat("\""+name+"\"") | |
| 343 | - self.log(str(obs_names.count(name))) | |
| 344 | - self.log("\n") | |
| 345 | - self.log("\n") | |
| 332 | + # Optionally log name of observations | |
| 333 | + if self._logExplicit(): | |
| 334 | + obs_set = set(obs_names) | |
| 335 | + for name in obs_set: | |
| 336 | + self._log.parformat("\""+name+"\"") | |
| 337 | + self._log(str(obs_names.count(name))) | |
| 338 | + self._log("\n") | |
| 339 | + self._log("\n") | |
| 346 | 340 | |
| 347 | - # Log energy range | |
| 348 | - self.log.header3("Energy range") | |
| 349 | - self.log.parformat("Emin") | |
| 350 | - if self.m_ebounds.size() == 0: | |
| 351 | - self.log("undefined") | |
| 352 | - else: | |
| 353 | - self.log(str(self.m_ebounds.emin())) | |
| 354 | - self.log("\n") | |
| 355 | - self.log.parformat("Emax") | |
| 356 | - if self.m_ebounds.size() == 0: | |
| 357 | - self.log("undefined") | |
| 358 | - else: | |
| 359 | - self.log(str(self.m_ebounds.emax())) | |
| 360 | - self.log("\n\n") | |
| 341 | + # Log energy range | |
| 342 | + self._log.header3("Energy range") | |
| 343 | + self._log.parformat("Minimum energy") | |
| 344 | + if self._ebounds.size() == 0: | |
| 345 | + self._log("undefined") | |
| 346 | + else: | |
| 347 | + self._log(str(self._ebounds.emin())) | |
| 348 | + self._log("\n") | |
| 349 | + self._log.parformat("Maximum energy") | |
| 350 | + if self._ebounds.size() == 0: | |
| 351 | + self._log("undefined") | |
| 352 | + else: | |
| 353 | + self._log(str(self._ebounds.emax())) | |
| 354 | + self._log("\n") | |
| 361 | 355 | |
| 362 | - # Log time range | |
| 363 | - self.log.header3("Time range") | |
| 364 | - self.log.parformat("Start [MJD]") | |
| 365 | - self.log(str(self.m_gti.tstart().mjd())) | |
| 366 | - self.log("\n") | |
| 367 | - self.log.parformat("Stop [MJD]") | |
| 368 | - self.log(str(self.m_gti.tstop().mjd())) | |
| 369 | - self.log("\n") | |
| 356 | + # Log time range | |
| 357 | + self._log.header3("Time range") | |
| 358 | + self._log.parformat("Start (MJD)") | |
| 359 | + self._log(str(self._gti.tstart().mjd())) | |
| 360 | + self._log("\n") | |
| 361 | + self._log.parformat("Stop (MJD)") | |
| 362 | + self._log(str(self._gti.tstop().mjd())) | |
| 363 | + self._log("\n") | |
| 370 | 364 | |
| 371 | - # Log ontime and livetime in different units | |
| 372 | - self.log.parformat("Total ontime") | |
| 373 | - self.log("%.2f s = %.2f min = %.2f h" % (ontime, ontime/60., ontime/3600.)) | |
| 374 | - self.log("\n") | |
| 375 | - self.log.parformat("Total livetime") | |
| 376 | - self.log("%.2f s = %.2f min = %.2f h" % (livetime, livetime/60.0, livetime/3600.)) | |
| 377 | - self.log("\n") | |
| 365 | + # Log ontime and livetime in different units | |
| 366 | + self._log.parformat("Total ontime") | |
| 367 | + self._log("%.2f s = %.2f min = %.2f h" % (ontime, ontime/60., ontime/3600.)) | |
| 368 | + self._log("\n") | |
| 369 | + self._log.parformat("Total livetime") | |
| 370 | + self._log("%.2f s = %.2f min = %.2f h" % (livetime, livetime/60.0, livetime/3600.)) | |
| 371 | + self._log("\n") | |
| 378 | 372 | |
| 379 | 373 | # Return |
| 380 | 374 | return |
| 381 | 375 | |
| 382 | 376 | def save(self): |
| 383 | 377 | """ |
| 384 | - Save pointings to ds9 region file if required | |
| 378 | + Save pointings into DS9 region file. | |
| 379 | + | |
| 380 | + This method saves all pointing directions that are found in the | |
| 381 | + observation container into a DS9 region file. If "NONE" is | |
| 382 | + specified for the "ds9file" parameter the method does nothing. | |
| 385 | 383 | """ |
| 386 | - | |
| 387 | - # Check if ds9 file is valid | |
| 388 | - if not self.ds9file == "NONE": | |
| 384 | + # Write header | |
| 385 | + if self._logTerse(): | |
| 386 | + self._log("\n") | |
| 387 | + self._log.header1("Save pointings in DS9 file") | |
| 388 | + | |
| 389 | + # Get output filename in case it was not read ahead | |
| 390 | + self._ds9file = self["ds9file"].filename() | |
| 391 | + | |
| 392 | + # Check if DS9 file is valid | |
| 393 | + if self._ds9file != "NONE": | |
| 394 | + | |
| 395 | + # Log filename | |
| 396 | + if self._logTerse(): | |
| 397 | + self._log(gammalib.parformat("DS9 filename")) | |
| 398 | + self._log(self._ds9file.url()) | |
| 399 | + self._log("\n") | |
| 389 | 400 | |
| 390 | 401 | # Open file |
| 391 | - f = open(self.ds9file.url(),"w") | |
| 402 | + f = open(self._ds9file.url(),"w") | |
| 392 | 403 | |
| 393 | 404 | # Write coordinate system |
| 394 | 405 | f.write("fk5\n") |
| 395 | 406 | |
| 396 | 407 | # Loop over pointings |
| 397 | - for i in range(len(self.pnt_ra)): | |
| 408 | + for i in range(len(self._pnt_ra)): | |
| 398 | 409 | |
| 399 | 410 | # Create string |
| 400 | 411 | line = "point(" |
| 401 | - line+=str(self.pnt_ra[i])+","+str(self.pnt_dec[i])+")" | |
| 412 | + line+=str(self._pnt_ra[i])+","+str(self._pnt_dec[i])+")" | |
| 402 | 413 | line+=" # point=cross 20 width=3 \n" |
| 403 | 414 | |
| 404 | 415 | # Write to file |
| ... | ... | @@ -410,41 +421,43 @@ class csobsinfo(ctools.cscript): |
| 410 | 421 | # Return |
| 411 | 422 | return |
| 412 | 423 | |
| 413 | - | |
| 414 | 424 | def zeniths(self): |
| 415 | 425 | """ |
| 416 | 426 | Return zenith angles |
| 417 | 427 | """ |
| 418 | - return self.m_zeniths | |
| 428 | + return self._zeniths | |
| 419 | 429 | |
| 420 | 430 | def azimuths(self): |
| 421 | 431 | """ |
| 422 | 432 | Return azimuth angles |
| 423 | 433 | """ |
| 424 | - return self.m_azimuths | |
| 434 | + return self._azimuths | |
| 425 | 435 | |
| 426 | 436 | def offsets(self): |
| 427 | 437 | """ |
| 428 | 438 | Return offset angles |
| 429 | 439 | """ |
| 430 | - return self.m_offsets | |
| 440 | + return self._offsets | |
| 431 | 441 | |
| 432 | 442 | def ebounds(self): |
| 433 | 443 | """ |
| 434 | 444 | Return energy boundaries |
| 435 | 445 | """ |
| 436 | - return self.m_ebounds | |
| 446 | + return self._ebounds | |
| 437 | 447 | |
| 438 | 448 | def gti(self): |
| 439 | 449 | """ |
| 440 | 450 | Return good time intervals |
| 441 | 451 | """ |
| 442 | - return self.m_gti | |
| 452 | + return self._gti | |
| 443 | 453 | |
| 444 | 454 | def execute(self): |
| 445 | 455 | """ |
| 446 | 456 | Execute the script. |
| 447 | 457 | """ |
| 458 | + # Set read ahead flag | |
| 459 | + self._read_ahead = True | |
| 460 | + | |
| 448 | 461 | # Run the script |
| 449 | 462 | self.run() |
| 450 | 463 | |
| ... | ... | @@ -459,14 +472,12 @@ class csobsinfo(ctools.cscript): |
| 459 | 472 | # Main routine entry point # |
| 460 | 473 | # ======================== # |
| 461 | 474 | if __name__ == '__main__': |
| 462 | - """ | |
| 463 | - Generates information about an observation container. | |
| 464 | - """ | |
| 475 | + | |
| 465 | 476 | # Create instance of application |
| 466 | 477 | app = csobsinfo(sys.argv) |
| 467 | 478 | |
| 468 | 479 | # Open logfile |
| 469 | - app.logFileOpen() | |
| 480 | + app._logFileOpen() | |
| 470 | 481 | |
| 471 | 482 | # Execute application |
| 472 | 483 | app.execute() | ... | ... |
cscripts/cspull.par
0 → 100644
| 1 | +############################################################################# | |
| 2 | +# # | |
| 3 | +# CTA Science Analysis Tools # | |
| 4 | +# # | |
| 5 | +# ------------------------------------------------------------------------- # | |
| 6 | +# # | |
| 7 | +# File: cspull.par # | |
| 8 | +# Version: 1.1.0 # | |
| 9 | +# # | |
| 10 | +# Author: Juergen Knoedlseder # | |
| 11 | +# Jurgen.Knodlseder@irap.omp.eu # | |
| 12 | +# IRAP # | |
| 13 | +# # | |
| 14 | +# Purpose: Parameter file for the cspull script # | |
| 15 | +# # | |
| 16 | +############################################################################# | |
| 17 | +# | |
| 18 | +# Input and output parameters | |
| 19 | +#============================ | |
| 20 | +inobs, f, h, NONE,,, "Input event list, counts cube, or observation definition XML file" | |
| 21 | +inmodel, f, a, $CTOOLS/share/models/crab.xml,,, "Input model XML file" | |
| 22 | +caldb, s, a, prod2,,, "Calibration database" | |
| 23 | +irf, s, a, South_0.5h,,, "Instrument response function" | |
| 24 | +edisp, b, h, no,,, "Apply energy dispersion?" | |
| 25 | +deadc, r, h, 0.95,0,1, "Deadtime correction factor" | |
| 26 | +outfile, f, a, pull.dat,,, "Output pull distribution file" | |
| 27 | + | |
| 28 | +# | |
| 29 | +# Script parameters | |
| 30 | +#================== | |
| 31 | +ntrials, i, a, 10,,, "Number of trials" | |
| 32 | +ra, r, a, 83.6331,0,360, "RA of pointing (deg)" | |
| 33 | +dec, r, a, 22.0145,-90,90, "Dec of pointing (deg)" | |
| 34 | +coordsys, s, a, CEL,CEL|GAL,, "Coordinate system (CEL - celestial, GAL - galactic)" | |
| 35 | +proj, s, a, TAN,AIT|AZP|CAR|MER|MOL|STG|TAN,, "Projection method" | |
| 36 | +emin, r, a, 0.1,,, "Lower energy limit (TeV)" | |
| 37 | +emax, r, a, 100.0,,, "Upper energy limit (TeV)" | |
| 38 | +enumbins, i, a, 0,,, "Number of energy bins (0=unbinned)" | |
| 39 | +tmin, r, h, 0.0,,, "Start time (MET in s)" | |
| 40 | +tmax, r, a, 1800.0,,, "Duration (s)" | |
| 41 | +npix, i, a, 200,,, "Number of pixels for binned" | |
| 42 | +binsz, r, a, 0.05,,, "Pixel size for binned (deg/pixel)" | |
| 43 | +rad, r, h, 5.0,0,180, "Radius of ROI (deg)" | |
| 44 | +pattern, s, h, single,single|four,, "Observation pattern" | |
| 45 | +offset, r, h, 1.5,,, "Observation pattern offset (deg)" | |
| 46 | +profile, b, h, no,,, "Use likelihood profile method for errors?" | |
| 47 | + | |
| 48 | +# | |
| 49 | +# Standard parameters | |
| 50 | +#==================== | |
| 51 | +chatter, i, h, 2,0,4, "Chattiness of output" | |
| 52 | +clobber, b, h, yes,,, "Overwrite existing output files with new output files?" | |
| 53 | +debug, b, h, no,,, "Debugging mode activated" | |
| 54 | +mode, s, h, ql,,, "Mode of automatic parameters" | |
| 55 | +logfile, f, h, cspull.log,,, "Log filename" | ... | ... |
cscripts/cspull.py
| ... | ... | @@ -30,47 +30,49 @@ import csv |
| 30 | 30 | # ============ # |
| 31 | 31 | class cspull(ctools.cscript): |
| 32 | 32 | """ |
| 33 | + Generates pull distributions for a model. | |
| 34 | + | |
| 33 | 35 | This class implements the pull distribution generation script. It derives |
| 34 | 36 | from the ctools.cscript class which provides support for parameter |
| 35 | 37 | files, command line arguments, and logging. In that way the Python |
| 36 | 38 | script behaves just as a regular ctool. |
| 37 | 39 | """ |
| 40 | + | |
| 41 | + # Constructors and destructors | |
| 38 | 42 | def __init__(self, *argv): |
| 39 | 43 | """ |
| 40 | 44 | Constructor. |
| 41 | 45 | """ |
| 42 | 46 | # Set name |
| 43 | - self.name = "cspull" | |
| 44 | - self.version = "1.0.0" | |
| 47 | + self._name = "cspull" | |
| 48 | + self._version = "1.1.0" | |
| 45 | 49 | |
| 46 | 50 | # Initialise some members |
| 47 | - self.obs = None | |
| 48 | - self.model = None | |
| 49 | - self.m_inmodel = None | |
| 50 | - self.m_edisp = False | |
| 51 | - self.m_profile = False | |
| 52 | - self.m_exposure = None | |
| 53 | - self.m_psfcube = None | |
| 54 | - self.m_bckcube = None | |
| 55 | - self.m_edispcube = None | |
| 56 | - self.m_stackmodels = None | |
| 57 | - self.m_coordsys = "CEL" | |
| 58 | - self.m_proj = "TAN" | |
| 59 | - | |
| 60 | - # Make sure that parfile exists | |
| 61 | - file = self.parfile() | |
| 51 | + self._obs = None | |
| 52 | + self._model = None | |
| 53 | + self._inmodel = None | |
| 54 | + self._edisp = False | |
| 55 | + self._profile = False | |
| 56 | + self._exposure = None | |
| 57 | + self._psfcube = None | |
| 58 | + self._bckcube = None | |
| 59 | + self._edispcube = None | |
| 60 | + self._stackmodels = None | |
| 61 | + self._coordsys = "CEL" | |
| 62 | + self._proj = "TAN" | |
| 63 | + self._log_clients = False | |
| 62 | 64 | |
| 63 | 65 | # Initialise application |
| 64 | 66 | if len(argv) == 0: |
| 65 | - ctools.cscript.__init__(self, self.name, self.version) | |
| 67 | + ctools.cscript.__init__(self, self._name, self._version) | |
| 66 | 68 | elif len(argv) ==1: |
| 67 | - ctools.cscript.__init__(self, self.name, self.version, *argv) | |
| 69 | + ctools.cscript.__init__(self, self._name, self._version, *argv) | |
| 68 | 70 | else: |
| 69 | 71 | raise TypeError("Invalid number of arguments given.") |
| 70 | 72 | |
| 71 | 73 | # Set logger properties |
| 72 | - self.log_header() | |
| 73 | - self.log.date(True) | |
| 74 | + self._log_header() | |
| 75 | + self._log.date(True) | |
| 74 | 76 | |
| 75 | 77 | # Return |
| 76 | 78 | return |
| ... | ... | @@ -79,348 +81,220 @@ class cspull(ctools.cscript): |
| 79 | 81 | """ |
| 80 | 82 | Destructor. |
| 81 | 83 | """ |
| 82 | - # Write separator into logger | |
| 83 | - if self.logTerse(): | |
| 84 | - self.log("\n") | |
| 85 | - | |
| 86 | 84 | # Return |
| 87 | 85 | return |
| 88 | 86 | |
| 89 | - def parfile(self): | |
| 90 | - """ | |
| 91 | - Check if parfile exists. If parfile does not exist then create a | |
| 92 | - default parfile. This kluge avoids shipping the cscript with a parfile. | |
| 93 | - """ | |
| 94 | - # Set parfile name | |
| 95 | - parfile = self.name+".par" | |
| 96 | - | |
| 97 | - try: | |
| 98 | - pars = gammalib.GApplicationPars(parfile) | |
| 99 | - except: | |
| 100 | - # Signal if parfile was not found | |
| 101 | - print("Parfile "+parfile+" not found. Create default parfile.") | |
| 102 | - | |
| 103 | - # Create default parfile | |
| 104 | - pars = gammalib.GApplicationPars() | |
| 105 | - pars.append(gammalib.GApplicationPar("inobs","f","h","NONE","","","Input event list, counts cube, or observation definition XML file")) | |
| 106 | - pars.append(gammalib.GApplicationPar("inmodel","f","a","$CTOOLS/share/models/crab.xml","","","Input model XML file")) | |
| 107 | - pars.append(gammalib.GApplicationPar("caldb","s","a","prod2","","","Calibration database")) | |
| 108 | - pars.append(gammalib.GApplicationPar("irf","s","a","South_0.5h","","","Instrument response function")) | |
| 109 | - pars.append(gammalib.GApplicationPar("edisp","b","h","no","","","Apply energy dispersion?")) | |
| 110 | - pars.append(gammalib.GApplicationPar("deadc","r","h","0.95","0","1","Deadtime correction factor")) | |
| 111 | - pars.append(gammalib.GApplicationPar("outfile","f","a","pull.dat","","","Output pull distribution file")) | |
| 112 | - pars.append(gammalib.GApplicationPar("profile","b","h","no","","","Use likelihood profile method for errors?")) | |
| 113 | - pars.append(gammalib.GApplicationPar("ntrials","i","a","10","","","Number of trials")) | |
| 114 | - pars.append(gammalib.GApplicationPar("ra","r","a","83.6331","0","360","RA of pointing (deg)")) | |
| 115 | - pars.append(gammalib.GApplicationPar("dec","r","a","22.0145","-90","90","Dec of pointing (deg)")) | |
| 116 | - pars.append(gammalib.GApplicationPar("coordsys","s","a","CEL","CEL|GAL","","Coordinate system (CEL - celestial, GAL - galactic)")) | |
| 117 | - pars.append(gammalib.GApplicationPar("proj","s","a","TAN","AIT|AZP|CAR|MER|MOL|STG|TAN","","Projection method")) | |
| 118 | - pars.append(gammalib.GApplicationPar("emin","r","a","0.1","","","Lower energy limit (TeV)")) | |
| 119 | - pars.append(gammalib.GApplicationPar("emax","r","a","100.0","","","Upper energy limit (TeV)")) | |
| 120 | - pars.append(gammalib.GApplicationPar("enumbins","i","a","0","","","Number of energy bins (0=unbinned)")) | |
| 121 | - pars.append(gammalib.GApplicationPar("tmin","r","h","0.0","","","Start time (MET in s)")) | |
| 122 | - pars.append(gammalib.GApplicationPar("tmax","r","a","1800.0","","","Duration (in s)")) | |
| 123 | - pars.append(gammalib.GApplicationPar("npix","i","a","200","","","Number of pixels for binned")) | |
| 124 | - pars.append(gammalib.GApplicationPar("binsz","r","a","0.05","","","Pixel size for binned (deg/pixel)")) | |
| 125 | - pars.append(gammalib.GApplicationPar("rad","r","h","5.0","0","180","Radius of ROI (deg)")) | |
| 126 | - pars.append(gammalib.GApplicationPar("pattern","s","h","single","","","Observation pattern (single/four)")) | |
| 127 | - pars.append(gammalib.GApplicationPar("offset","r","h","1.5","","","Observation pattern offset (deg)")) | |
| 128 | - pars.append_standard() | |
| 129 | - pars.append(gammalib.GApplicationPar("logfile","f","h","cspull.log","","","Log filename")) | |
| 130 | - pars.save(parfile) | |
| 131 | - | |
| 132 | - # Return | |
| 133 | - return | |
| 134 | 87 | |
| 135 | - def get_parameters(self): | |
| 88 | + # Private methods | |
| 89 | + def _get_parameters(self): | |
| 136 | 90 | """ |
| 137 | - Get parameters from parfile and setup the observation. | |
| 91 | + Get parameters from parfile. | |
| 138 | 92 | """ |
| 139 | 93 | # Get parameters |
| 140 | 94 | |
| 141 | 95 | # Set observation if not done before |
| 142 | - if self.obs == None or self.obs.size() == 0: | |
| 143 | - self.obs = self._get_observations() | |
| 96 | + if self._obs == None or self._obs.size() == 0: | |
| 97 | + self._obs = self._get_observations() | |
| 144 | 98 | |
| 145 | 99 | # Check for requested pattern and use above |
| 146 | 100 | # observation parameters to set wobble pattern |
| 147 | - self.m_pattern = self["pattern"].string() | |
| 148 | - if self.m_pattern == "four": | |
| 149 | - self.obs = self.set_obs() | |
| 101 | + self._pattern = self["pattern"].string() | |
| 102 | + if self._pattern == "four": | |
| 103 | + self._obs = self._set_obs() | |
| 150 | 104 | |
| 151 | 105 | # Get number of energy bins |
| 152 | - self.m_enumbins = self["enumbins"].integer() | |
| 106 | + self._enumbins = self["enumbins"].integer() | |
| 153 | 107 | |
| 154 | 108 | # Read parameters for binned if requested |
| 155 | - if not self.m_enumbins == 0: | |
| 156 | - self.m_npix = self["npix"].integer() | |
| 157 | - self.m_binsz = self["binsz"].real() | |
| 158 | - self.m_coordsys = self["coordsys"].string() | |
| 159 | - self.m_proj = self["proj"].string() | |
| 109 | + if not self._enumbins == 0: | |
| 110 | + self._npix = self["npix"].integer() | |
| 111 | + self._binsz = self["binsz"].real() | |
| 112 | + self._coordsys = self["coordsys"].string() | |
| 113 | + self._proj = self["proj"].string() | |
| 160 | 114 | else: |
| 161 | 115 | # Set dummy values (required by obsutils) |
| 162 | - self.m_npix = 0 | |
| 163 | - self.m_binsz = 0.0 | |
| 116 | + self._npix = 0 | |
| 117 | + self._binsz = 0.0 | |
| 164 | 118 | |
| 165 | 119 | # Set models if we have none |
| 166 | - if self.obs.models().size() == 0: | |
| 167 | - self.obs.models(self["inmodel"].filename()) | |
| 120 | + if self._obs.models().size() == 0: | |
| 121 | + self._obs.models(self["inmodel"].filename()) | |
| 168 | 122 | |
| 169 | 123 | # Read other parameters |
| 170 | - self.m_outfile = self["outfile"].filename() | |
| 171 | - self.m_ntrials = self["ntrials"].integer() | |
| 172 | - self.m_edisp = self["edisp"].boolean() | |
| 173 | - self.m_offset = self["offset"].real() | |
| 174 | - self.m_profile = self["profile"].boolean() | |
| 124 | + self._outfile = self["outfile"].filename() | |
| 125 | + self._ntrials = self["ntrials"].integer() | |
| 126 | + self._edisp = self["edisp"].boolean() | |
| 127 | + self._offset = self["offset"].real() | |
| 128 | + self._profile = self["profile"].boolean() | |
| 129 | + self._chatter = self["chatter"].integer() | |
| 130 | + self._debug = self["debug"].boolean() | |
| 175 | 131 | |
| 176 | - # Set some fixed parameters | |
| 177 | - self.m_log = False # Logging in client tools | |
| 178 | - self.m_chatter = self["chatter"].integer() # Chatter level | |
| 179 | - self.m_debug = self["debug"].boolean() # Debugging in client tools | |
| 132 | + # Write input parameters into logger | |
| 133 | + if self._logTerse(): | |
| 134 | + self._log_parameters() | |
| 135 | + self._log("\n") | |
| 180 | 136 | |
| 181 | 137 | # Return |
| 182 | 138 | return |
| 183 | 139 | |
| 184 | - | |
| 185 | - def models(self, models): | |
| 140 | + def _set_obs(self): | |
| 186 | 141 | """ |
| 187 | - Set model. | |
| 188 | - """ | |
| 189 | - # Copy models | |
| 190 | - self.obs.models(models.copy()) | |
| 191 | - | |
| 192 | - # Return | |
| 193 | - return | |
| 194 | - | |
| 142 | + Set CTA observation(s). | |
| 195 | 143 | |
| 196 | - def execute(self): | |
| 197 | - """ | |
| 198 | - Execute the script. | |
| 144 | + Returns: | |
| 145 | + An observation container. | |
| 199 | 146 | """ |
| 200 | - # Run the script | |
| 201 | - self.run() | |
| 147 | + # Setup observation definition list | |
| 148 | + obsdeflist = obsutils.set_obs_patterns(self._pattern, | |
| 149 | + ra=self["ra"].real(), | |
| 150 | + dec=self["dec"].real(), | |
| 151 | + offset=self["offset"].real()) | |
| 202 | 152 | |
| 203 | - # Return | |
| 204 | - return | |
| 153 | + # Create list of observations | |
| 154 | + obs = obsutils.set_obs_list(obsdeflist, | |
| 155 | + tstart=self["tmin"].real(), | |
| 156 | + duration=self["tmax"].real()-self["tmin"].real(), | |
| 157 | + deadc=self["deadc"].real(), | |
| 158 | + emin=self["emin"].real(), | |
| 159 | + emax=self["emax"].real(), | |
| 160 | + rad=self["rad"].real(), | |
| 161 | + irf=self["irf"].string(), | |
| 162 | + caldb=self["caldb"].string()) | |
| 205 | 163 | |
| 164 | + # Return observation container | |
| 165 | + return obs | |
| 206 | 166 | |
| 207 | - def set_stacked_irf(self): | |
| 167 | + def _set_stacked_irf(self): | |
| 208 | 168 | """ |
| 209 | 169 | For stacked analysis prepare stacked irfs |
| 210 | 170 | """ |
| 211 | 171 | # Write header into logger |
| 212 | - if self.logTerse(): | |
| 213 | - self.log("\n") | |
| 214 | - self.log.header1("Compute stacked response") | |
| 172 | + if self._logTerse(): | |
| 173 | + self._log("\n") | |
| 174 | + self._log.header1("Compute stacked response") | |
| 215 | 175 | |
| 216 | 176 | # Get stacked exposure |
| 217 | - expcube = ctools.ctexpcube(self.obs) | |
| 177 | + expcube = ctools.ctexpcube(self._obs) | |
| 218 | 178 | expcube["incube"] = "NONE" |
| 219 | 179 | expcube["usepnt"] = True |
| 220 | 180 | expcube["ebinalg"] = "LOG" |
| 221 | - expcube["binsz"] = self.m_binsz | |
| 222 | - expcube["nxpix"] = self.m_npix | |
| 223 | - expcube["nypix"] = self.m_npix | |
| 224 | - expcube["enumbins"] = self.m_enumbins | |
| 181 | + expcube["binsz"] = self._binsz | |
| 182 | + expcube["nxpix"] = self._npix | |
| 183 | + expcube["nypix"] = self._npix | |
| 184 | + expcube["enumbins"] = self._enumbins | |
| 225 | 185 | expcube["emin"] = self["emin"].real() |
| 226 | 186 | expcube["emax"] = self["emax"].real() |
| 227 | - expcube["coordsys"] = self.m_coordsys | |
| 228 | - expcube["proj"] = self.m_proj | |
| 187 | + expcube["coordsys"] = self._coordsys | |
| 188 | + expcube["proj"] = self._proj | |
| 229 | 189 | expcube.run() |
| 230 | 190 | |
| 231 | 191 | # Notify exposure computation |
| 232 | - if self.logTerse(): | |
| 233 | - self.log("Computed exposure cube\n") | |
| 192 | + if self._logTerse(): | |
| 193 | + self._log("Computed exposure cube\n") | |
| 234 | 194 | |
| 235 | 195 | # Get stacked Psf |
| 236 | - psfcube = ctools.ctpsfcube(self.obs) | |
| 196 | + psfcube = ctools.ctpsfcube(self._obs) | |
| 237 | 197 | psfcube["incube"] = "NONE" |
| 238 | 198 | psfcube["usepnt"] = True |
| 239 | 199 | psfcube["ebinalg"] = "LOG" |
| 240 | - psfcube["binsz"] = self.m_binsz*10.0 | |
| 241 | - psfcube["nxpix"] = self.m_npix/10 | |
| 242 | - psfcube["nypix"] = self.m_npix/10 | |
| 243 | - psfcube["enumbins"] = self.m_enumbins | |
| 200 | + psfcube["binsz"] = self._binsz*10.0 | |
| 201 | + psfcube["nxpix"] = self._npix/10 | |
| 202 | + psfcube["nypix"] = self._npix/10 | |
| 203 | + psfcube["enumbins"] = self._enumbins | |
| 244 | 204 | psfcube["emin"] = self["emin"].real() |
| 245 | 205 | psfcube["emax"] = self["emax"].real() |
| 246 | - psfcube["coordsys"] = self.m_coordsys | |
| 247 | - psfcube["proj"] = self.m_proj | |
| 206 | + psfcube["coordsys"] = self._coordsys | |
| 207 | + psfcube["proj"] = self._proj | |
| 248 | 208 | psfcube.run() |
| 249 | 209 | |
| 250 | 210 | # Notify Psf computation |
| 251 | - if self.logTerse(): | |
| 252 | - self.log("Computed Psf cube\n") | |
| 211 | + if self._logTerse(): | |
| 212 | + self._log("Computed point spread function cube\n") | |
| 253 | 213 | |
| 254 | 214 | # Optionally get stacked Edisp |
| 255 | - if self.m_edisp: | |
| 256 | - edispcube = ctools.edispcube(self.obs) | |
| 215 | + if self._edisp: | |
| 216 | + edispcube = ctools.edispcube(self._obs) | |
| 257 | 217 | edispcube["incube"] = "NONE" |
| 258 | 218 | edispcube["usepnt"] = True |
| 259 | 219 | edispcube["ebinalg"] = "LOG" |
| 260 | - edispcube["binsz"] = self.m_binsz*10.0 | |
| 261 | - edispcube["nxpix"] = self.m_npix/10 | |
| 262 | - edispcube["nypix"] = self.m_npix/10 | |
| 263 | - edispcube["enumbins"] = self.m_enumbins | |
| 220 | + edispcube["binsz"] = self._binsz*10.0 | |
| 221 | + edispcube["nxpix"] = self._npix/10 | |
| 222 | + edispcube["nypix"] = self._npix/10 | |
| 223 | + edispcube["enumbins"] = self._enumbins | |
| 264 | 224 | edispcube["emin"] = self["emin"].real() |
| 265 | 225 | edispcube["emax"] = self["emax"].real() |
| 266 | - edispcube["coordsys"] = self.m_coordsys | |
| 267 | - edispcube["proj"] = self.m_proj | |
| 226 | + edispcube["coordsys"] = self._coordsys | |
| 227 | + edispcube["proj"] = self._proj | |
| 268 | 228 | edispcube.run() |
| 269 | 229 | |
| 270 | 230 | # Store result |
| 271 | - self.m_edispcube = edispcube.edispcube().copy() | |
| 231 | + self._edispcube = edispcube.edispcube().copy() | |
| 272 | 232 | |
| 273 | 233 | # Logging |
| 274 | - if self.logTerse(): | |
| 275 | - self.log("Computed energy dispersion cube\n") | |
| 234 | + if self._logTerse(): | |
| 235 | + self._log("Computed energy dispersion cube\n") | |
| 276 | 236 | |
| 277 | 237 | # Get stacked background |
| 278 | - bkgcube = ctools.ctbkgcube(self.obs) | |
| 238 | + bkgcube = ctools.ctbkgcube(self._obs) | |
| 279 | 239 | bkgcube["incube"] = "NONE" |
| 280 | 240 | bkgcube["usepnt"] = True |
| 281 | 241 | bkgcube["ebinalg"] = "LOG" |
| 282 | - bkgcube["binsz"] = self.m_binsz | |
| 283 | - bkgcube["nxpix"] = self.m_npix | |
| 284 | - bkgcube["nypix"] = self.m_npix | |
| 285 | - bkgcube["enumbins"] = self.m_enumbins | |
| 242 | + bkgcube["binsz"] = self._binsz | |
| 243 | + bkgcube["nxpix"] = self._npix | |
| 244 | + bkgcube["nypix"] = self._npix | |
| 245 | + bkgcube["enumbins"] = self._enumbins | |
| 286 | 246 | bkgcube["emin"] = self["emin"].real() |
| 287 | 247 | bkgcube["emax"] = self["emax"].real() |
| 288 | - bkgcube["coordsys"] = self.m_coordsys | |
| 289 | - bkgcube["proj"] = self.m_proj | |
| 248 | + bkgcube["coordsys"] = self._coordsys | |
| 249 | + bkgcube["proj"] = self._proj | |
| 290 | 250 | bkgcube.run() |
| 291 | 251 | |
| 292 | 252 | # Notify background cube computation |
| 293 | - if self.logTerse(): | |
| 294 | - self.log("Computed background cube\n") | |
| 253 | + if self._logTerse(): | |
| 254 | + self._log("Computed background cube\n") | |
| 295 | 255 | |
| 296 | 256 | # Store results |
| 297 | - self.m_exposure = expcube.expcube().copy() | |
| 298 | - self.m_psfcube = psfcube.psfcube().copy() | |
| 299 | - self.m_bckcube = bkgcube.bkgcube().copy() | |
| 300 | - self.m_stackmodels = bkgcube.models().copy() | |
| 301 | - | |
| 302 | - # Return | |
| 303 | - return | |
| 304 | - | |
| 305 | - | |
| 306 | - def run(self): | |
| 307 | - """ | |
| 308 | - Run the script. | |
| 309 | - """ | |
| 310 | - # Switch screen logging on in debug mode | |
| 311 | - if self.logDebug(): | |
| 312 | - self.log.cout(True) | |
| 313 | - | |
| 314 | - # Get parameters | |
| 315 | - self.get_parameters() | |
| 316 | - | |
| 317 | - # Write input parameters into logger | |
| 318 | - if self.logTerse(): | |
| 319 | - self.log_parameters() | |
| 320 | - self.log("\n") | |
| 321 | - | |
| 322 | - # Write observation into logger | |
| 323 | - if self.logTerse(): | |
| 324 | - self.log("\n") | |
| 325 | - self.log.header1("Observation(s)") | |
| 326 | - self.log(str(self.obs)) | |
| 327 | - self.log("\n") | |
| 328 | - | |
| 329 | - # If several observations and binned: prepare stacked irfs | |
| 330 | - if self.obs.size() > 1 and self.m_enumbins > 0: | |
| 331 | - self.set_stacked_irf() | |
| 332 | - | |
| 333 | - # Write header | |
| 334 | - if self.logTerse(): | |
| 335 | - self.log("\n") | |
| 336 | - self.log.header1("Generate pull distribution") | |
| 337 | - | |
| 338 | - # Loop over trials | |
| 339 | - for seed in range(self.m_ntrials): | |
| 340 | - | |
| 341 | - # Make a trial | |
| 342 | - result = self.trial(seed) | |
| 343 | - | |
| 344 | - # Write out result immediately | |
| 345 | - if seed == 0: | |
| 346 | - file = open(self.m_outfile.url(), 'w') | |
| 347 | - writer = csv.DictWriter(file, result['colnames']) | |
| 348 | - headers = {} | |
| 349 | - for n in result['colnames']: | |
| 350 | - headers[n] = n | |
| 351 | - writer.writerow(headers) | |
| 352 | - else: | |
| 353 | - file = open(self.m_outfile.url(), 'a') | |
| 354 | - writer = csv.DictWriter(file, result['colnames']) | |
| 355 | - writer.writerow(result['values']) | |
| 356 | - file.close() | |
| 257 | + self._exposure = expcube.expcube().copy() | |
| 258 | + self._psfcube = psfcube.psfcube().copy() | |
| 259 | + self._bckcube = bkgcube.bkgcube().copy() | |
| 260 | + self._stackmodels = bkgcube.models().copy() | |
| 357 | 261 | |
| 358 | 262 | # Return |
| 359 | 263 | return |
| 360 | 264 | |
| 361 | - | |
| 362 | - def set_obs(self): | |
| 363 | - """ | |
| 364 | - Returns an observation container with a set of CTA observations. | |
| 365 | - | |
| 366 | - Keywords: | |
| 265 | + def _trial(self, seed): | |
| 367 | 266 | """ |
| 267 | + Compute the pull for a single trial. | |
| 368 | 268 | |
| 369 | - # Setup observation definition list | |
| 370 | - obsdeflist = obsutils.set_obs_patterns(self.m_pattern, | |
| 371 | - ra=self["ra"].real(), | |
| 372 | - dec=self["dec"].real(), | |
| 373 | - offset=self["offset"].real()) | |
| 374 | - | |
| 375 | - # Create list of observations | |
| 376 | - obs = obsutils.set_obs_list(obsdeflist, | |
| 377 | - tstart=self["tmin"].real(), | |
| 378 | - duration=self["tmax"].real()-self["tmin"].real(), | |
| 379 | - deadc=self["deadc"].real(), | |
| 380 | - emin=self["emin"].real(), | |
| 381 | - emax=self["emax"].real(), | |
| 382 | - rad=self["rad"].real(), | |
| 383 | - irf=self["irf"].string(), | |
| 384 | - caldb=self["caldb"].string()) | |
| 385 | - | |
| 386 | - # Return observation container | |
| 387 | - return obs | |
| 388 | - | |
| 389 | - | |
| 390 | - def trial(self, seed): | |
| 269 | + Args: | |
| 270 | + seed: Random number generator seed. | |
| 391 | 271 | """ |
| 392 | - Create the pull for a single trial. | |
| 393 | - | |
| 394 | - Parameters: | |
| 395 | - seed - Random number generator seed | |
| 396 | - """ | |
| 397 | - | |
| 398 | 272 | # Write header |
| 399 | - if self.logNormal(): | |
| 400 | - self.log.header2("Trial "+str(seed+1)) | |
| 273 | + if self._logNormal(): | |
| 274 | + self._log.header2("Trial "+str(seed+1)) | |
| 401 | 275 | |
| 402 | 276 | # Simulate events |
| 403 | - obs = obsutils.sim(self.obs, | |
| 404 | - nbins=self.m_enumbins, | |
| 277 | + obs = obsutils.sim(self._obs, | |
| 278 | + nbins=self._enumbins, | |
| 405 | 279 | seed=seed, |
| 406 | - binsz=self.m_binsz, | |
| 407 | - npix=self.m_npix, | |
| 408 | - proj=self.m_proj, | |
| 409 | - coord=self.m_coordsys, | |
| 410 | - edisp=self.m_edisp, | |
| 411 | - log=self.m_log, | |
| 412 | - debug=self.m_debug, | |
| 413 | - chatter=self.m_chatter) | |
| 414 | - | |
| 415 | - # If stacked, add stacked responses and model | |
| 416 | - if self.obs.size() > 1 and self.m_enumbins > 0: | |
| 417 | - if self.m_edisp: | |
| 418 | - obs[0].response(self.m_exposure, self.m_psfcube, | |
| 419 | - self.m_edispcube, self.m_bckcube) | |
| 280 | + binsz=self._binsz, | |
| 281 | + npix=self._npix, | |
| 282 | + proj=self._proj, | |
| 283 | + coord=self._coordsys, | |
| 284 | + edisp=self._edisp, | |
| 285 | + log=self._log_clients, | |
| 286 | + debug=self._debug, | |
| 287 | + chatter=self._chatter) | |
| 288 | + | |
| 289 | + # Set response for a stacked observation | |
| 290 | + if self._obs.size() > 1 and self._enumbins > 0: | |
| 291 | + if self._edisp: | |
| 292 | + obs[0].response(self._exposure, self._psfcube, | |
| 293 | + self._edispcube, self._bckcube) | |
| 420 | 294 | else: |
| 421 | - obs[0].response(self.m_exposure, self.m_psfcube, | |
| 422 | - self.m_bckcube) | |
| 423 | - obs.models(self.m_stackmodels) | |
| 295 | + obs[0].response(self._exposure, self._psfcube, | |
| 296 | + self._bckcube) | |
| 297 | + obs.models(self._stackmodels) | |
| 424 | 298 | |
| 425 | 299 | # Determine number of events in simulation |
| 426 | 300 | nevents = 0.0 |
| ... | ... | @@ -428,26 +302,26 @@ class cspull(ctools.cscript): |
| 428 | 302 | nevents += run.events().number() |
| 429 | 303 | |
| 430 | 304 | # Write simulation results |
| 431 | - if self.logNormal(): | |
| 432 | - self.log.header3("Simulation") | |
| 433 | - self.log.parformat("Number of simulated events") | |
| 434 | - self.log(nevents) | |
| 435 | - self.log("\n") | |
| 305 | + if self._logNormal(): | |
| 306 | + self._log.header3("Simulation") | |
| 307 | + self._log.parformat("Number of simulated events") | |
| 308 | + self._log(nevents) | |
| 309 | + self._log("\n") | |
| 436 | 310 | |
| 437 | 311 | # Fit model |
| 438 | - if self.m_profile: | |
| 439 | - models = obs.models() | |
| 312 | + if self._profile: | |
| 313 | + models = _obs.models() | |
| 440 | 314 | for i in range(models.size()): |
| 441 | 315 | model_name = models[i].name() |
| 442 | - like = obsutils.cterror(obs, model_name, | |
| 443 | - log=self.m_log, | |
| 444 | - debug=self.m_debug, | |
| 445 | - chatter=self.m_chatter) | |
| 316 | + like = obsutils.cterror(_obs, model_name, | |
| 317 | + log=self._log_clients, | |
| 318 | + debug=self._debug, | |
| 319 | + chatter=self._chatter) | |
| 446 | 320 | else: |
| 447 | - like = obsutils.fit(obs, edisp=self.m_edisp, | |
| 448 | - log=self.m_log, | |
| 449 | - debug=self.m_debug, | |
| 450 | - chatter=self.m_chatter) | |
| 321 | + like = obsutils.fit(obs, edisp=self._edisp, | |
| 322 | + log=self._log_clients, | |
| 323 | + debug=self._debug, | |
| 324 | + chatter=self._chatter) | |
| 451 | 325 | |
| 452 | 326 | # Store results |
| 453 | 327 | logL = like.opt().value() |
| ... | ... | @@ -455,8 +329,8 @@ class cspull(ctools.cscript): |
| 455 | 329 | models = like.obs().models() |
| 456 | 330 | |
| 457 | 331 | # Write result header |
| 458 | - if self.logNormal(): | |
| 459 | - self.log.header3("Pulls") | |
| 332 | + if self._logNormal(): | |
| 333 | + self._log.header3("Pulls") | |
| 460 | 334 | |
| 461 | 335 | # Gather results |
| 462 | 336 | colnames = [] |
| ... | ... | @@ -484,7 +358,7 @@ class cspull(ctools.cscript): |
| 484 | 358 | |
| 485 | 359 | # Compute pull |
| 486 | 360 | fitted_value = par.value() |
| 487 | - real_value = self.obs.models()[i][k].value() | |
| 361 | + real_value = self._obs.models()[i][k].value() | |
| 488 | 362 | error = par.error() |
| 489 | 363 | if error != 0.0: |
| 490 | 364 | pull = (fitted_value - real_value) / error |
| ... | ... | @@ -497,14 +371,14 @@ class cspull(ctools.cscript): |
| 497 | 371 | values["Unc_"+name] = error |
| 498 | 372 | |
| 499 | 373 | # Write result |
| 500 | - if self.logNormal(): | |
| 501 | - self.log.parformat(name) | |
| 502 | - self.log(pull) | |
| 503 | - self.log(" (") | |
| 504 | - self.log(fitted_value) | |
| 505 | - self.log(" +/- ") | |
| 506 | - self.log(error) | |
| 507 | - self.log(")\n") | |
| 374 | + if self._logNormal(): | |
| 375 | + self._log.parformat(name) | |
| 376 | + self._log(pull) | |
| 377 | + self._log(" (") | |
| 378 | + self._log(fitted_value) | |
| 379 | + self._log(" +/- ") | |
| 380 | + self._log(error) | |
| 381 | + self._log(")\n") | |
| 508 | 382 | |
| 509 | 383 | # Bundle together results |
| 510 | 384 | result = {'colnames': colnames, 'values': values} |
| ... | ... | @@ -513,18 +387,88 @@ class cspull(ctools.cscript): |
| 513 | 387 | return result |
| 514 | 388 | |
| 515 | 389 | |
| 390 | + # Public methods | |
| 391 | + def run(self): | |
| 392 | + """ | |
| 393 | + Run the script. | |
| 394 | + """ | |
| 395 | + # Switch screen logging on in debug mode | |
| 396 | + if self._logDebug(): | |
| 397 | + self._log.cout(True) | |
| 398 | + | |
| 399 | + # Get parameters | |
| 400 | + self._get_parameters() | |
| 401 | + | |
| 402 | + # Write observation into logger | |
| 403 | + if self._logTerse(): | |
| 404 | + self._log("\n") | |
| 405 | + self._log.header1("Observation(s)") | |
| 406 | + self._log(str(self._obs)) | |
| 407 | + self._log("\n") | |
| 408 | + | |
| 409 | + # If several observations and binned: prepare stacked irfs | |
| 410 | + if self._obs.size() > 1 and self._enumbins > 0: | |
| 411 | + self._set_stacked_irf() | |
| 412 | + | |
| 413 | + # Write header | |
| 414 | + if self._logTerse(): | |
| 415 | + self._log("\n") | |
| 416 | + self._log.header1("Generate pull distribution") | |
| 417 | + | |
| 418 | + # Loop over trials | |
| 419 | + for seed in range(self._ntrials): | |
| 420 | + | |
| 421 | + # Make a trial | |
| 422 | + result = self._trial(seed) | |
| 423 | + | |
| 424 | + # Write out result immediately | |
| 425 | + if seed == 0: | |
| 426 | + file = open(self._outfile.url(), 'w') | |
| 427 | + writer = csv.DictWriter(file, result['colnames']) | |
| 428 | + headers = {} | |
| 429 | + for n in result['colnames']: | |
| 430 | + headers[n] = n | |
| 431 | + writer.writerow(headers) | |
| 432 | + else: | |
| 433 | + file = open(self._outfile.url(), 'a') | |
| 434 | + writer = csv.DictWriter(file, result['colnames']) | |
| 435 | + writer.writerow(result['values']) | |
| 436 | + file.close() | |
| 437 | + | |
| 438 | + # Return | |
| 439 | + return | |
| 440 | + | |
| 441 | + def execute(self): | |
| 442 | + """ | |
| 443 | + Execute the script. | |
| 444 | + """ | |
| 445 | + # Run the script | |
| 446 | + self.run() | |
| 447 | + | |
| 448 | + # Return | |
| 449 | + return | |
| 450 | + | |
| 451 | + def models(self, models): | |
| 452 | + """ | |
| 453 | + Set model. | |
| 454 | + """ | |
| 455 | + # Copy models | |
| 456 | + self.obs.models(models.copy()) | |
| 457 | + | |
| 458 | + # Return | |
| 459 | + return | |
| 460 | + | |
| 461 | + | |
| 516 | 462 | # ======================== # |
| 517 | 463 | # Main routine entry point # |
| 518 | 464 | # ======================== # |
| 519 | 465 | if __name__ == '__main__': |
| 520 | - """ | |
| 521 | - Generates pull distribution for a source model. | |
| 522 | - """ | |
| 466 | + | |
| 523 | 467 | # Create instance of application |
| 524 | 468 | app = cspull(sys.argv) |
| 525 | 469 | |
| 526 | 470 | # Open logfile |
| 527 | - app.logFileOpen() | |
| 471 | + app._logFileOpen() | |
| 528 | 472 | |
| 529 | 473 | # Execute application |
| 530 | 474 | app.execute() | ... | ... |
cscripts/csresmap.par
0 → 100644
| 1 | +############################################################################# | |
| 2 | +# # | |
| 3 | +# CTA Science Analysis Tools # | |
| 4 | +# # | |
| 5 | +# ------------------------------------------------------------------------- # | |
| 6 | +# # | |
| 7 | +# File: csresmap.par # | |
| 8 | +# Version: 1.1.0 # | |
| 9 | +# # | |
| 10 | +# Author: Juergen Knoedlseder # | |
| 11 | +# Jurgen.Knodlseder@irap.omp.eu # | |
| 12 | +# IRAP # | |
| 13 | +# # | |
| 14 | +# Purpose: Parameter file for the csresmap script # | |
| 15 | +# # | |
| 16 | +############################################################################# | |
| 17 | +# | |
| 18 | +# Input and output parameters | |
| 19 | +#============================ | |
| 20 | +inobs, f, h, events.fits,,, "Input event list, counts cube, or observation definition XML file" | |
| 21 | +inmodel, f, a, $CTOOLS/share/models/crab.xml,,, "Input model XML file" | |
| 22 | +modcube, f, a, NONE,,, "Input model cube file (generated with ctmodel)" | |
| 23 | +expcube, f, a, NONE,,, "Input exposure cube file (only needed for stacked analysis)" | |
| 24 | +psfcube, f, a, NONE,,, "Input PSF cube file (only needed for stacked analysis)" | |
| 25 | +edispcube, f, a, NONE,,, "Input energy dispersion cube file (only needed for stacked analysis)" | |
| 26 | +bkgcube, f, a, NONE,,, "Input background cube file (only needed for stacked analysis)" | |
| 27 | +caldb, s, a, prod2,,, "Calibration database" | |
| 28 | +irf, s, a, South_0.5h,,, "Instrument response function" | |
| 29 | +edisp, b, h, no,,, "Apply energy dispersion?" | |
| 30 | +outmap, f, a, resmap.fits,,, "Output residual map file" | |
| 31 | + | |
| 32 | +# | |
| 33 | +# Script parameters | |
| 34 | +#================== | |
| 35 | +ebinalg, s, h, LOG,LIN|LOG|FILE,, "Binning algorithm" | |
| 36 | +emin, r, h, 0.1,,, "Lower energy limit (TeV)" | |
| 37 | +emax, r, h, 100.0,,, "Upper energy limit (TeV)" | |
| 38 | +enumbins, i, h, 20,,, "Number of energy bins (0=unbinned)" | |
| 39 | +ebinfile, f, h, NONE,,, "Name of the file containing the energy bin definition" | |
| 40 | +coordsys, s, a, CEL,CEL|GAL,, "Coordinate System" | |
| 41 | +proj, s, a, CAR,AIT|AZP|CAR|MER|MOL|STG|TAN,, "Projection method" | |
| 42 | +xref, r, a, 83.63,0,360, "First coordinate of image center in degrees (RA or galactic l)" | |
| 43 | +yref, r, a, 22.01,-90,90, "Second coordinate of image center in degrees (DEC or galactic b)" | |
| 44 | +nxpix, i, a, 200,,, "Size of the X axis in pixels" | |
| 45 | +nypix, i, a, 200,,, "Size of the Y axis in pixels" | |
| 46 | +binsz, r, a, 0.02,,, "Pixel size (deg/pixel)" | |
| 47 | +algorithm, s, a, SUBDIV,SUB|SUBDIV|SUBDIVSQRT,, "Residual map computation algorithm" | |
| 48 | + | |
| 49 | +# | |
| 50 | +# Standard parameters | |
| 51 | +#==================== | |
| 52 | +publish, b, h, no,,, "Publish residual map on VO Hub?" | |
| 53 | +chatter, i, h, 2,0,4, "Chattiness of output" | |
| 54 | +clobber, b, h, yes,,, "Overwrite existing output files with new output files?" | |
| 55 | +debug, b, h, no,,, "Debugging mode activated" | |
| 56 | +mode, s, h, ql,,, "Mode of automatic parameters" | |
| 57 | +logfile, f, h, csresmap.log,,, "Log filename" | ... | ... |
cscripts/csresmap.py
| 1 | 1 | #! /usr/bin/env python |
| 2 | 2 | # ========================================================================== |
| 3 | -# Residual map generation script. | |
| 3 | +# Generates a residual map. | |
| 4 | 4 | # |
| 5 | 5 | # Copyright (C) 2014-2016 Michael Mayer |
| 6 | 6 | # |
| ... | ... | @@ -22,57 +22,76 @@ import gammalib |
| 22 | 22 | import ctools |
| 23 | 23 | import sys |
| 24 | 24 | |
| 25 | + | |
| 25 | 26 | # ============== # |
| 26 | -# cstsdist class # | |
| 27 | +# csresmap class # | |
| 27 | 28 | # ============== # |
| 28 | 29 | class csresmap(ctools.cscript): |
| 29 | 30 | """ |
| 31 | + Generates a residual map. | |
| 32 | + | |
| 30 | 33 | This class implements the creation of a residual map. It derives from |
| 31 | 34 | the ctools.cscript class which provides support for parameter files, |
| 32 | 35 | command line arguments, and logging. In that way the Python script |
| 33 | 36 | behaves just as a regular ctool. |
| 34 | 37 | """ |
| 38 | + | |
| 39 | + # Constructors and destructors | |
| 35 | 40 | def __init__(self, *argv): |
| 36 | 41 | """ |
| 37 | 42 | Constructor. |
| 38 | 43 | """ |
| 39 | 44 | # Set name |
| 40 | - self.name = "csresmap" | |
| 41 | - self.version = "1.1.0" | |
| 42 | - | |
| 43 | - # Initialise some members | |
| 44 | - self.obs = None | |
| 45 | - self.algorithm = "SUB" | |
| 46 | - self.resmap = None | |
| 47 | - self.m_modcube = "None" | |
| 48 | - self.m_outmap = "None" | |
| 49 | - self.m_use_maps = False | |
| 50 | - self.m_skip_binning = False | |
| 51 | - self.m_publish = False | |
| 52 | - | |
| 53 | - # Initialise some members | |
| 45 | + self._name = "csresmap" | |
| 46 | + self._version = "1.1.0" | |
| 47 | + | |
| 48 | + # Initialise class members | |
| 49 | + self._algorithm = "SUB" | |
| 50 | + self._resmap = None | |
| 51 | + self._modcube = "NONE" | |
| 52 | + self._outmap = "NONE" | |
| 53 | + self._use_maps = False | |
| 54 | + self._skip_binning = False | |
| 55 | + self._publish = False | |
| 56 | + self._outfile = "" | |
| 57 | + self._use_maps = False | |
| 58 | + self._skip_binning = False | |
| 59 | + self._edisp = False | |
| 60 | + self._xref = 83.63 | |
| 61 | + self._yref = 22.01 | |
| 62 | + self._emin = 0.1 | |
| 63 | + self._emax = 100.0 | |
| 64 | + self._enumbins = 0 | |
| 65 | + self._ebinalg = "LOG" | |
| 66 | + self._coordsys = "CEL" | |
| 67 | + self._proj = "CAR" | |
| 68 | + self._nxpix = 200 | |
| 69 | + self._nypix = 200 | |
| 70 | + self._binsz = 0.02 | |
| 71 | + self._publish = False | |
| 72 | + self._chatter = 2 | |
| 73 | + self._clobber = True | |
| 74 | + self._debug = False | |
| 75 | + self._log_clients = False | |
| 76 | + | |
| 77 | + # Initialise observation | |
| 54 | 78 | if len(argv) > 0 and isinstance(argv[0],gammalib.GObservations): |
| 55 | - self.obs = argv[0] | |
| 56 | - argv = argv[1:] | |
| 79 | + self._obs = argv[0] | |
| 80 | + argv = argv[1:] | |
| 57 | 81 | else: |
| 58 | - self.obs = gammalib.GObservations() | |
| 59 | - self.obs.clear() | |
| 60 | - self.outfile = "" | |
| 61 | - | |
| 62 | - # Make sure that parfile exists | |
| 63 | - file = self.parfile() | |
| 82 | + self._obs = gammalib.GObservations() | |
| 64 | 83 | |
| 65 | 84 | # Initialise application |
| 66 | 85 | if len(argv) == 0: |
| 67 | - ctools.cscript.__init__(self, self.name, self.version) | |
| 86 | + ctools.cscript.__init__(self, self._name, self._version) | |
| 68 | 87 | elif len(argv) ==1: |
| 69 | - ctools.cscript.__init__(self, self.name, self.version, *argv) | |
| 88 | + ctools.cscript.__init__(self, self._name, self._version, *argv) | |
| 70 | 89 | else: |
| 71 | 90 | raise TypeError("Invalid number of arguments given.") |
| 72 | 91 | |
| 73 | 92 | # Set logger properties |
| 74 | - self.log_header() | |
| 75 | - self.log.date(True) | |
| 93 | + self._log_header() | |
| 94 | + self._log.date(True) | |
| 76 | 95 | |
| 77 | 96 | # Return |
| 78 | 97 | return |
| ... | ... | @@ -81,271 +100,148 @@ class csresmap(ctools.cscript): |
| 81 | 100 | """ |
| 82 | 101 | Destructor. |
| 83 | 102 | """ |
| 84 | - # Write separator into logger | |
| 85 | - if self.logTerse(): | |
| 86 | - self.log("\n") | |
| 87 | - | |
| 88 | 103 | # Return |
| 89 | 104 | return |
| 90 | 105 | |
| 91 | - def parfile(self): | |
| 92 | - """ | |
| 93 | - Check if parfile exists. If parfile does not exist then create a | |
| 94 | - default parfile. This kluge avoids shipping the cscript with a parfile. | |
| 95 | - """ | |
| 96 | - # Set parfile name | |
| 97 | - parfile = self.name+".par" | |
| 98 | - | |
| 99 | - try: | |
| 100 | - pars = gammalib.GApplicationPars(parfile) | |
| 101 | - except: | |
| 102 | - # Signal if parfile was not found | |
| 103 | - sys.stdout.write("Parfile "+parfile+" not found. Create default parfile.\n") | |
| 104 | - | |
| 105 | - # Create default parfile | |
| 106 | - pars = gammalib.GApplicationPars() | |
| 107 | - pars.append(gammalib.GApplicationPar("inobs","f","a","events.fits","","","Input event list, counts cube, or observation definition XML file")) | |
| 108 | - pars.append(gammalib.GApplicationPar("modcube","f","a","NONE","","","Input model cube file (generated with ctmodel)")) | |
| 109 | - pars.append(gammalib.GApplicationPar("expcube","f","a","NONE","","","Input exposure cube file (only needed for stacked analysis)")) | |
| 110 | - pars.append(gammalib.GApplicationPar("psfcube","f","a","NONE","","","Input PSF cube file (only needed for stacked analysis)")) | |
| 111 | - pars.append(gammalib.GApplicationPar("edispcube","f","a","NONE","","","Input energy dispersion cube file (only needed for stacked analysis)")) | |
| 112 | - pars.append(gammalib.GApplicationPar("bkgcube","f","a","NONE","","","Input background cube file (only needed for stacked analysis)")) | |
| 113 | - pars.append(gammalib.GApplicationPar("inmodel","f","a","$CTOOLS/share/models/crab.xml","","","Input model XML file")) | |
| 114 | - pars.append(gammalib.GApplicationPar("caldb","s","a","prod2","","","Calibration database")) | |
| 115 | - pars.append(gammalib.GApplicationPar("irf","s","a","South_0.5h","","","Instrument response function")) | |
| 116 | - pars.append(gammalib.GApplicationPar("edisp","b","h","no","","","Apply energy dispersion?")) | |
| 117 | - pars.append(gammalib.GApplicationPar("outmap","f","a","resmap.fits","","","Output residual map file")) | |
| 118 | - pars.append(gammalib.GApplicationPar("ebinalg","s","h","LOG","LIN|LOG|FILE","","Binning algorithm")) | |
| 119 | - pars.append(gammalib.GApplicationPar("emin","r","h","0.1","","","Lower energy limit (TeV)")) | |
| 120 | - pars.append(gammalib.GApplicationPar("emax","r","h","100.0","","","Upper energy limit (TeV)")) | |
| 121 | - pars.append(gammalib.GApplicationPar("enumbins","i","h","20","","","Number of energy bins")) | |
| 122 | - pars.append(gammalib.GApplicationPar("ebinfile","f","h","NONE","","","Name of the file containing the energy bin definition")) | |
| 123 | - pars.append(gammalib.GApplicationPar("coordsys","s","a","CEL","CEL|GAL","","Coordinate System")) | |
| 124 | - pars.append(gammalib.GApplicationPar("proj","s","a","CAR","AIT|AZP|CAR|MER|MOL|STG|TAN","","Projection method")) | |
| 125 | - pars.append(gammalib.GApplicationPar("xref","r","a","83.63","0","360","First coordinate of image center in degrees (RA or galactic l)")) | |
| 126 | - pars.append(gammalib.GApplicationPar("yref","r","a","22.01","-90","90","Second coordinate of image center in degrees (DEC or galactic b)")) | |
| 127 | - pars.append(gammalib.GApplicationPar("nxpix","i","a","200","","","Size of the X axis in pixels")) | |
| 128 | - pars.append(gammalib.GApplicationPar("nypix","i","a","200","","","Size of the Y axis in pixels")) | |
| 129 | - pars.append(gammalib.GApplicationPar("binsz","r","a","0.02","","","Pixel size (deg/pixel)")) | |
| 130 | - pars.append(gammalib.GApplicationPar("algorithm","s","a","SUBDIV","SUB|SUBDIV|SUBDIVSQRT","","Residual map computation algorithm")) | |
| 131 | - pars.append(gammalib.GApplicationPar("publish","b","h","no","","","Publish residual map on VO Hub?")) | |
| 132 | - pars.append_standard() | |
| 133 | - pars.append(gammalib.GApplicationPar("logfile","f","h","csresmap.log","","","Log filename")) | |
| 134 | - pars.save(parfile) | |
| 135 | - | |
| 136 | - # Return | |
| 137 | - return | |
| 138 | 106 | |
| 139 | - def get_parameters(self): | |
| 107 | + # Private methods | |
| 108 | + def _get_parameters(self): | |
| 140 | 109 | """ |
| 141 | 110 | Get parameters from parfile and setup the observation. |
| 142 | 111 | """ |
| 143 | 112 | # Initialise some flags |
| 144 | - self.m_use_maps = False | |
| 145 | - self.m_skip_binning = False | |
| 113 | + self._use_maps = False | |
| 114 | + self._skip_binning = False | |
| 146 | 115 | |
| 147 | 116 | # First check if the inobs parameter is a counts cube |
| 148 | - if self.obs.size() == 0 and self["inobs"].filename() != "NONE": | |
| 117 | + if self._obs.size() == 0 and self["inobs"].filename() != "NONE": | |
| 149 | 118 | filename = gammalib.GFilename(self["inobs"].filename()) |
| 150 | 119 | if filename.is_fits(): |
| 151 | 120 | cta = gammalib.GCTAObservation() |
| 152 | 121 | cta.load(filename) |
| 153 | 122 | if cta.eventtype() == "CountsCube": |
| 154 | - self.m_skip_binning = True | |
| 123 | + self._skip_binning = True | |
| 155 | 124 | |
| 156 | 125 | # If we have a counts cube, then ask whether we also have a model |
| 157 | - if self.m_skip_binning: | |
| 158 | - self.m_modcube = self["modcube"].filename() | |
| 159 | - if self.m_modcube != "NONE": | |
| 160 | - self.m_use_maps = True | |
| 126 | + if self._skip_binning: | |
| 127 | + self._modcube = self["modcube"].filename() | |
| 128 | + if self._modcube != "NONE": | |
| 129 | + self._use_maps = True | |
| 161 | 130 | |
| 162 | 131 | # If not two maps are given, proceed to set up observation |
| 163 | - if not self.m_use_maps: | |
| 132 | + if not self._use_maps: | |
| 164 | 133 | |
| 165 | 134 | # Set observation if not done before |
| 166 | - if self.obs.size() == 0: | |
| 135 | + if self._obs.size() == 0: | |
| 167 | 136 | self._require_inobs("csresmap.get_parameters()") |
| 168 | - self.obs = self._get_observations() | |
| 137 | + self._obs = self._get_observations() | |
| 169 | 138 | |
| 170 | 139 | # Check if we have exactly one binned CTA observation |
| 171 | - if self.obs.size() == 1: | |
| 140 | + if self._obs.size() == 1: | |
| 172 | 141 | |
| 173 | - if self.obs[0].classname() == "GCTAObservation": | |
| 174 | - if self.obs[0].eventtype() == "CountsCube": | |
| 142 | + if self._obs[0].classname() == "GCTAObservation": | |
| 143 | + if self._obs[0].eventtype() == "CountsCube": | |
| 175 | 144 | # Skip ctbin step later on |
| 176 | - self.m_skip_binning = True | |
| 145 | + self._skip_binning = True | |
| 177 | 146 | |
| 178 | 147 | # Set models if we have none |
| 179 | - if self.obs.models().size() == 0: | |
| 180 | - self.obs.models(self["inmodel"].filename()) | |
| 148 | + if self._obs.models().size() == 0: | |
| 149 | + self._obs.models(self["inmodel"].filename()) | |
| 181 | 150 | |
| 182 | 151 | # Skip query for spatial parameters if a binning is provided in the observation |
| 183 | - if not self.m_skip_binning: | |
| 152 | + if not self._skip_binning: | |
| 184 | 153 | # Read other parameters |
| 185 | - self.m_xref = self["xref"].real() | |
| 186 | - self.m_yref = self["yref"].real() | |
| 187 | - self.m_emin = self["emin"].real() | |
| 188 | - self.m_emax = self["emax"].real() | |
| 189 | - self.m_enumbins = self["enumbins"].integer() | |
| 190 | - self.m_ebinalg = self["ebinalg"].string() | |
| 191 | - self.m_coordsys = self["coordsys"].string() | |
| 192 | - self.m_proj = self["proj"].string() | |
| 193 | - self.m_nxpix = self["nxpix"].integer() | |
| 194 | - self.m_nypix = self["nypix"].integer() | |
| 195 | - self.m_binsz = self["binsz"].real() | |
| 154 | + self._xref = self["xref"].real() | |
| 155 | + self._yref = self["yref"].real() | |
| 156 | + self._emin = self["emin"].real() | |
| 157 | + self._emax = self["emax"].real() | |
| 158 | + self._enumbins = self["enumbins"].integer() | |
| 159 | + self._ebinalg = self["ebinalg"].string() | |
| 160 | + self._coordsys = self["coordsys"].string() | |
| 161 | + self._proj = self["proj"].string() | |
| 162 | + self._nxpix = self["nxpix"].integer() | |
| 163 | + self._nypix = self["nypix"].integer() | |
| 164 | + self._binsz = self["binsz"].real() | |
| 196 | 165 | |
| 197 | 166 | # Read energy dispersion flag |
| 198 | - self.m_edisp = self["edisp"].boolean() | |
| 167 | + self._edisp = self["edisp"].boolean() | |
| 199 | 168 | |
| 200 | 169 | # Read algorithm |
| 201 | - self.m_algorithm = self["algorithm"].string() | |
| 170 | + self._algorithm = self["algorithm"].string() | |
| 202 | 171 | |
| 203 | 172 | # Read standard parameters |
| 204 | - self.m_publish = self["publish"].boolean() | |
| 205 | - self.m_log = False # Logging in client tools | |
| 206 | - self.m_chatter = self["chatter"].integer() | |
| 207 | - self.m_clobber = self["clobber"].boolean() | |
| 208 | - self.m_debug = self["debug"].boolean() | |
| 173 | + self._publish = self["publish"].boolean() | |
| 174 | + self._chatter = self["chatter"].integer() | |
| 175 | + self._clobber = self["clobber"].boolean() | |
| 176 | + self._debug = self["debug"].boolean() | |
| 209 | 177 | |
| 210 | 178 | # Read ahead output parameters |
| 211 | 179 | if (self._read_ahead()): |
| 212 | - self.m_outmap = self["outmap"].filename() | |
| 213 | - | |
| 214 | - # Return | |
| 215 | - return | |
| 216 | - | |
| 217 | - def models(self, models): | |
| 218 | - """ | |
| 219 | - Set model. | |
| 220 | - """ | |
| 221 | - # Copy models | |
| 222 | - self.obs.models(models.clone()) | |
| 223 | - | |
| 224 | - # Return | |
| 225 | - return | |
| 226 | - | |
| 227 | - def execute(self): | |
| 228 | - """ | |
| 229 | - Execute the script. | |
| 230 | - """ | |
| 231 | - # Read ahead output parameters | |
| 232 | - self._read_ahead(True) | |
| 233 | - | |
| 234 | - # Run the script | |
| 235 | - self.run() | |
| 236 | - | |
| 237 | - # Save residual map | |
| 238 | - self.save() | |
| 180 | + self._outmap = self["outmap"].filename() | |
| 239 | 181 | |
| 240 | - # Return | |
| 241 | - return | |
| 242 | - | |
| 243 | - def save(self): | |
| 244 | - """ | |
| 245 | - Save residual map. | |
| 246 | - """ | |
| 247 | - # Write header | |
| 248 | - if self.logTerse(): | |
| 249 | - self.log("\n") | |
| 250 | - self.log.header1("Save residual map") | |
| 251 | - | |
| 252 | - # Continue only filename and residual map are valid | |
| 253 | - if self.m_outmap != "None" and self.resmap != None: | |
| 254 | - | |
| 255 | - # Log file name | |
| 256 | - if self.logTerse(): | |
| 257 | - self.log("Save residual map into \""+self.m_outmap+"\".\n") | |
| 258 | - | |
| 259 | - # Save residual map | |
| 260 | - self.resmap.save(self.m_outmap, self.m_clobber) | |
| 182 | + # Write input parameters into logger | |
| 183 | + if self._logTerse(): | |
| 184 | + self._log_parameters() | |
| 185 | + self._log("\n") | |
| 261 | 186 | |
| 262 | 187 | # Return |
| 263 | 188 | return |
| 264 | 189 | |
| 265 | - def publish(self, name=""): | |
| 266 | - """ | |
| 267 | - Publish residual map. | |
| 268 | - """ | |
| 269 | - # Write header | |
| 270 | - if self.logTerse(): | |
| 271 | - self.log("\n") | |
| 272 | - self.log.header1("Publish sky map") | |
| 273 | - | |
| 274 | - # Continue only if residual map is valid | |
| 275 | - if self.resmap != None: | |
| 276 | - | |
| 277 | - # Set default name is user name is empty | |
| 278 | - if not name: | |
| 279 | - user_name = self.name | |
| 280 | - else: | |
| 281 | - user_name = name | |
| 282 | - | |
| 283 | - # Log map name | |
| 284 | - if self.logTerse(): | |
| 285 | - self.log("Publish residual map \""+user_name+"\".\n") | |
| 286 | - | |
| 287 | - # Publish map | |
| 288 | - self.resmap.publish(user_name) | |
| 289 | - | |
| 290 | - # Return | |
| 291 | - return | |
| 292 | 190 | |
| 191 | + # Public methods | |
| 293 | 192 | def run(self): |
| 294 | 193 | """ |
| 295 | 194 | Run the script. |
| 296 | 195 | """ |
| 297 | 196 | # Switch screen logging on in debug mode |
| 298 | - if self.logDebug(): | |
| 299 | - self.log.cout(True) | |
| 197 | + if self._logDebug(): | |
| 198 | + self._log.cout(True) | |
| 300 | 199 | |
| 301 | 200 | # Get parameters |
| 302 | - self.get_parameters() | |
| 303 | - | |
| 304 | - # Write input parameters into logger | |
| 305 | - if self.logTerse(): | |
| 306 | - self.log_parameters() | |
| 307 | - self.log("\n") | |
| 201 | + self._get_parameters() | |
| 308 | 202 | |
| 309 | 203 | # Write observation into logger |
| 310 | - if self.logTerse(): | |
| 311 | - self.log("\n") | |
| 312 | - self.log.header1("Observation") | |
| 313 | - self.log(str(self.obs)) | |
| 314 | - self.log("\n") | |
| 204 | + if self._logTerse(): | |
| 205 | + self._log("\n") | |
| 206 | + self._log.header1("Observation") | |
| 207 | + self._log(str(self._obs)) | |
| 208 | + self._log("\n") | |
| 315 | 209 | |
| 316 | 210 | # Use input file directly if given |
| 317 | - if self.m_use_maps: | |
| 211 | + if self._use_maps: | |
| 318 | 212 | countmap = gammalib.GSkyMap(self["inobs"].filename()) |
| 319 | - modelmap = gammalib.GSkyMap(self.m_modcube) | |
| 213 | + modelmap = gammalib.GSkyMap(self._modcube) | |
| 320 | 214 | |
| 321 | 215 | else: |
| 322 | 216 | |
| 323 | - if self.m_skip_binning: | |
| 324 | - cta_counts_cube = gammalib.GCTAEventCube(self.obs[0].events().clone()) | |
| 217 | + # ... | |
| 218 | + if self._skip_binning: | |
| 219 | + cta_counts_cube = gammalib.GCTAEventCube(self._obs[0].events().clone()) | |
| 325 | 220 | |
| 221 | + # ... | |
| 326 | 222 | else: |
| 327 | 223 | |
| 328 | 224 | # Write header |
| 329 | - if self.logTerse(): | |
| 330 | - self.log("\n") | |
| 331 | - self.log.header1("Generate binned map (ctbin)") | |
| 225 | + if self._logTerse(): | |
| 226 | + self._log("\n") | |
| 227 | + self._log.header1("Generate binned map (ctbin)") | |
| 332 | 228 | |
| 333 | 229 | # Create countsmap |
| 334 | - bin = ctools.ctbin(self.obs) | |
| 335 | - bin["nxpix"].integer(self.m_nxpix) | |
| 336 | - bin["nypix"].integer(self.m_nypix) | |
| 337 | - bin["proj"].string(self.m_proj) | |
| 338 | - bin["coordsys"].string(self.m_coordsys) | |
| 339 | - bin["xref"].real(self.m_xref) | |
| 340 | - bin["yref"].real(self.m_yref) | |
| 341 | - bin["enumbins"].integer(self.m_enumbins) | |
| 342 | - bin["ebinalg"].string(self.m_ebinalg) | |
| 343 | - bin["emin"].real(self.m_emin) | |
| 344 | - bin["emax"].real(self.m_emax) | |
| 345 | - bin["binsz"].real(self.m_binsz) | |
| 346 | - bin["chatter"].integer(self.m_chatter) | |
| 347 | - bin["clobber"].boolean(self.m_clobber) | |
| 348 | - bin["debug"].boolean(self.m_debug) | |
| 230 | + bin = ctools.ctbin(self._obs) | |
| 231 | + bin["nxpix"].integer(self._nxpix) | |
| 232 | + bin["nypix"].integer(self._nypix) | |
| 233 | + bin["proj"].string(self._proj) | |
| 234 | + bin["coordsys"].string(self._coordsys) | |
| 235 | + bin["xref"].real(self._xref) | |
| 236 | + bin["yref"].real(self._yref) | |
| 237 | + bin["enumbins"].integer(self._enumbins) | |
| 238 | + bin["ebinalg"].string(self._ebinalg) | |
| 239 | + bin["emin"].real(self._emin) | |
| 240 | + bin["emax"].real(self._emax) | |
| 241 | + bin["binsz"].real(self._binsz) | |
| 242 | + bin["chatter"].integer(self._chatter) | |
| 243 | + bin["clobber"].boolean(self._clobber) | |
| 244 | + bin["debug"].boolean(self._debug) | |
| 349 | 245 | bin.run() |
| 350 | 246 | |
| 351 | 247 | # Retrieve counts cube |
| ... | ... | @@ -355,17 +251,17 @@ class csresmap(ctools.cscript): |
| 355 | 251 | countmap = cta_counts_cube.map() |
| 356 | 252 | |
| 357 | 253 | # Write header |
| 358 | - if self.logTerse(): | |
| 359 | - self.log("\n") | |
| 360 | - self.log.header1("Generate model map (ctmodel)") | |
| 254 | + if self._logTerse(): | |
| 255 | + self._log("\n") | |
| 256 | + self._log.header1("Generate model map (ctmodel)") | |
| 361 | 257 | |
| 362 | 258 | # Create model map |
| 363 | - model = ctools.ctmodel(self.obs) | |
| 259 | + model = ctools.ctmodel(self._obs) | |
| 364 | 260 | model.cube(cta_counts_cube) |
| 365 | - model["chatter"].integer(self.m_chatter) | |
| 366 | - model["clobber"].boolean(self.m_clobber) | |
| 367 | - model["debug"].boolean(self.m_debug) | |
| 368 | - model["edisp"].boolean(self.m_edisp) | |
| 261 | + model["chatter"].integer(self._chatter) | |
| 262 | + model["clobber"].boolean(self._clobber) | |
| 263 | + model["debug"].boolean(self._debug) | |
| 264 | + model["edisp"].boolean(self._edisp) | |
| 369 | 265 | model.run() |
| 370 | 266 | |
| 371 | 267 | # Get model map into GSkyMap object |
| ... | ... | @@ -376,61 +272,141 @@ class csresmap(ctools.cscript): |
| 376 | 272 | # to be a SWIG feature as SWIG creates a new object when |
| 377 | 273 | # calling bin.cube() |
| 378 | 274 | #residualmap = bin.cube().map() |
| 379 | - self.resmap = countmap.copy() | |
| 380 | - self.resmap.stack_maps() | |
| 275 | + self._resmap = countmap.copy() | |
| 276 | + self._resmap.stack_maps() | |
| 381 | 277 | modelmap.stack_maps() |
| 382 | 278 | |
| 383 | 279 | # Continue calculations depending on given algorithm |
| 384 | - if self.m_algorithm == "SUB": | |
| 280 | + if self._algorithm == "SUB": | |
| 385 | 281 | |
| 386 | 282 | # Subtract maps |
| 387 | - self.resmap -= modelmap | |
| 283 | + self._resmap -= modelmap | |
| 388 | 284 | |
| 389 | - elif self.m_algorithm == "SUBDIV": | |
| 285 | + elif self._algorithm == "SUBDIV": | |
| 390 | 286 | |
| 391 | 287 | # Subtract and divide by model map |
| 392 | - self.resmap -= modelmap | |
| 393 | - self.resmap /= modelmap | |
| 288 | + self._resmap -= modelmap | |
| 289 | + self._resmap /= modelmap | |
| 394 | 290 | #for pixel in modelmap: |
| 395 | 291 | # if pixel != 0.0: |
| 396 | 292 | # pixel = 1.0/pixel |
| 397 | - #self.resmap *= modelmap | |
| 293 | + #self._resmap *= modelmap | |
| 398 | 294 | |
| 399 | - elif self.m_algorithm == "SUBDIVSQRT": | |
| 295 | + elif self._algorithm == "SUBDIVSQRT": | |
| 400 | 296 | |
| 401 | 297 | # subtract and divide by sqrt of model map |
| 402 | - self.resmap -= modelmap | |
| 403 | - self.resmap /= modelmap.sqrt() | |
| 298 | + self._resmap -= modelmap | |
| 299 | + self._resmap /= modelmap.sqrt() | |
| 404 | 300 | #for pixel in modelmap: |
| 405 | 301 | # if pixel != 0.0: |
| 406 | 302 | # pixel = 1.0/math.sqrt(pixel) |
| 407 | - #self.resmap *= modelmap | |
| 303 | + #self._resmap *= modelmap | |
| 408 | 304 | |
| 409 | 305 | else: |
| 410 | 306 | |
| 411 | 307 | # Raise error if algorithm is unkown |
| 412 | - raise TypeError("Algorithm \""+self.m_algorithm+"\" not known") | |
| 308 | + raise TypeError("Algorithm \""+self._algorithm+"\" not known") | |
| 413 | 309 | |
| 414 | 310 | # Optionally publish map |
| 415 | - if self.m_publish: | |
| 311 | + if self._publish: | |
| 416 | 312 | self.publish() |
| 417 | 313 | |
| 418 | 314 | # Return |
| 419 | 315 | return |
| 420 | 316 | |
| 317 | + def execute(self): | |
| 318 | + """ | |
| 319 | + Execute the script. | |
| 320 | + """ | |
| 321 | + # Read ahead output parameters | |
| 322 | + self._read_ahead(True) | |
| 323 | + | |
| 324 | + # Run the script | |
| 325 | + self.run() | |
| 326 | + | |
| 327 | + # Save residual map | |
| 328 | + self.save() | |
| 329 | + | |
| 330 | + # Return | |
| 331 | + return | |
| 332 | + | |
| 333 | + def save(self): | |
| 334 | + """ | |
| 335 | + Save residual map. | |
| 336 | + """ | |
| 337 | + # Write header | |
| 338 | + if self._logTerse(): | |
| 339 | + self._log("\n") | |
| 340 | + self._log.header1("Save residual map") | |
| 341 | + | |
| 342 | + # Get outmap parameter | |
| 343 | + self._outmap = self["outmap"].filename() | |
| 344 | + | |
| 345 | + # Continue only filename and residual map are valid | |
| 346 | + if self._outmap != "NONE" and self._resmap != None: | |
| 347 | + | |
| 348 | + # Log file name | |
| 349 | + if self._logTerse(): | |
| 350 | + self._log("Save residual map into \""+self._outmap+"\".\n") | |
| 351 | + | |
| 352 | + # Save residual map | |
| 353 | + self._resmap.save(self._outmap, self._clobber) | |
| 354 | + | |
| 355 | + # Return | |
| 356 | + return | |
| 357 | + | |
| 358 | + def publish(self, name=""): | |
| 359 | + """ | |
| 360 | + Publish residual map. | |
| 361 | + | |
| 362 | + Kwargs: | |
| 363 | + name: Name of residual map. | |
| 364 | + """ | |
| 365 | + # Write header | |
| 366 | + if self._logTerse(): | |
| 367 | + self._log("\n") | |
| 368 | + self._log.header1("Publish residual map") | |
| 369 | + | |
| 370 | + # Continue only if residual map is valid | |
| 371 | + if self._resmap != None: | |
| 372 | + | |
| 373 | + # Set default name is user name is empty | |
| 374 | + if not name: | |
| 375 | + user_name = self.name | |
| 376 | + else: | |
| 377 | + user_name = name | |
| 378 | + | |
| 379 | + # Log map name | |
| 380 | + if self._logTerse(): | |
| 381 | + self._log("Publish residual map \""+user_name+"\".\n") | |
| 382 | + | |
| 383 | + # Publish map | |
| 384 | + self._resmap.publish(user_name) | |
| 385 | + | |
| 386 | + # Return | |
| 387 | + return | |
| 388 | + | |
| 389 | + def models(self, models): | |
| 390 | + """ | |
| 391 | + Set model. | |
| 392 | + """ | |
| 393 | + # Copy models | |
| 394 | + self._obs.models(models.clone()) | |
| 395 | + | |
| 396 | + # Return | |
| 397 | + return | |
| 398 | + | |
| 421 | 399 | |
| 422 | 400 | # ======================== # |
| 423 | 401 | # Main routine entry point # |
| 424 | 402 | # ======================== # |
| 425 | 403 | if __name__ == '__main__': |
| 426 | - """ | |
| 427 | - Generates residual count map. | |
| 428 | - """ | |
| 404 | + | |
| 429 | 405 | # Create instance of application |
| 430 | 406 | app = csresmap(sys.argv) |
| 431 | 407 | |
| 432 | 408 | # Open logfile |
| 433 | - app.logFileOpen() | |
| 409 | + app._logFileOpen() | |
| 434 | 410 | |
| 435 | 411 | # Execute application |
| 436 | 412 | app.execute() | ... | ... |
cscripts/cssens.par
0 → 100644
| 1 | +############################################################################# | |
| 2 | +# # | |
| 3 | +# CTA Science Analysis Tools # | |
| 4 | +# # | |
| 5 | +# ------------------------------------------------------------------------- # | |
| 6 | +# # | |
| 7 | +# File: cssens.par # | |
| 8 | +# Version: 1.1.0 # | |
| 9 | +# # | |
| 10 | +# Author: Juergen Knoedlseder # | |
| 11 | +# Jurgen.Knodlseder@irap.omp.eu # | |
| 12 | +# IRAP # | |
| 13 | +# # | |
| 14 | +# Purpose: Parameter file for the cssens script # | |
| 15 | +# # | |
| 16 | +############################################################################# | |
| 17 | +# | |
| 18 | +# Input and output parameters | |
| 19 | +#============================ | |
| 20 | +inobs, f, h, NONE,,, "Input event list, counts cube, or observation definition XML file" | |
| 21 | +inmodel, f, a, $CTOOLS/share/models/crab.xml,,, "Input model XML file" | |
| 22 | +srcname, s, a, Crab,,, "Source name" | |
| 23 | +caldb, s, a, prod2,,, "Calibration database" | |
| 24 | +irf, s, a, South_0.5h,,, "Instrument response function" | |
| 25 | +edisp, b, h, no,,, "Apply energy dispersion?" | |
| 26 | +deadc, r, h, 0.95,0,1, "Deadtime correction factor" | |
| 27 | +outfile, f, h, sensitivity.dat,,, "Output sensitivity ASCII file" | |
| 28 | + | |
| 29 | +# | |
| 30 | +# Script parameters | |
| 31 | +#================== | |
| 32 | +offset, r, h, 0.0,,, "Source offset angle (deg)" | |
| 33 | +duration, r, a, 180000.0,,, "Effective exposure time (s)" | |
| 34 | +rad, r, a, 5.0,,, "Radius of ROI (deg)" | |
| 35 | +emin, r, a, 0.020,,, "Lower energy limit (TeV)" | |
| 36 | +emax, r, a, 200.0,,, "Upper energy limit (TeV)" | |
| 37 | +bins, i, a, 21,,, "Number of energy bins for differential sensitivity computation" | |
| 38 | +enumbins, i, h, 0,,, "Number of energy bins for binned analysis (0=unbinned)" | |
| 39 | +npix, i, h, 200,,, "Number of pixels for binned analysis" | |
| 40 | +binsz, r, h, 0.05,,, "Pixel size for binned analysis (deg/pixel)" | |
| 41 | +type, s, h, Differential,Differential|Integral,, "Sensitivity type" | |
| 42 | +sigma, r, h, 5.0,,, "Significance threshold (Gaussian sigma)" | |
| 43 | +max_iter, i, h, 50,,, "Maximum number of iterations" | |
| 44 | +num_avg, i, h, 3,,, "Number of iterations for sliding average" | |
| 45 | + | |
| 46 | +# | |
| 47 | +# Standard parameters | |
| 48 | +#==================== | |
| 49 | +chatter, i, h, 2,0,4, "Chattiness of output" | |
| 50 | +clobber, b, h, yes,,, "Overwrite existing output files with new output files?" | |
| 51 | +debug, b, h, no,,, "Debugging mode activated" | |
| 52 | +mode, s, h, ql,,, "Mode of automatic parameters" | |
| 53 | +logfile, f, h, cspull.log,,, "Log filename" | |
| 54 | + | |
| 55 | + | ... | ... |
cscripts/cssens.py
| ... | ... | @@ -31,6 +31,8 @@ import math |
| 31 | 31 | # ============ # |
| 32 | 32 | class cssens(ctools.cscript): |
| 33 | 33 | """ |
| 34 | + Computes the CTA sensitivity. | |
| 35 | + | |
| 34 | 36 | This class computes the CTA sensitivity for a number of energy bins using |
| 35 | 37 | ctlike. Spectra are fitted in narrow energy bins to simulated data, |
| 36 | 38 | and the flux level is determined that leads to a particular significance. |
| ... | ... | @@ -38,34 +40,48 @@ class cssens(ctools.cscript): |
| 38 | 40 | The significance is determined using the Test Statistic, defined as twice |
| 39 | 41 | the likelihood difference between fitting with and without the test source. |
| 40 | 42 | """ |
| 43 | + | |
| 44 | + # Constructors and destructors | |
| 41 | 45 | def __init__(self, *argv): |
| 42 | 46 | """ |
| 43 | 47 | Constructor. |
| 44 | 48 | """ |
| 45 | 49 | # Set name |
| 46 | - self.name = "cssens" | |
| 47 | - self.version = "1.0.0" | |
| 48 | - | |
| 49 | - # Initialise some parameters | |
| 50 | - self.obs = None | |
| 51 | - self.m_ra = None | |
| 52 | - self.m_dec = None | |
| 53 | - | |
| 54 | - # Make sure that parfile exists | |
| 55 | - file = self.parfile() | |
| 56 | - | |
| 50 | + self._name = "cssens" | |
| 51 | + self._version = "1.1.0" | |
| 52 | + | |
| 53 | + # Initialise class members | |
| 54 | + self._obs = gammalib.GObservations() | |
| 55 | + self._ebounds = gammalib.GEbounds() | |
| 56 | + self._srcname = "" | |
| 57 | + self._outfile = "" | |
| 58 | + self._ra = None | |
| 59 | + self._dec = None | |
| 60 | + self._edisp = False | |
| 61 | + self._emin = 0.020 | |
| 62 | + self._emax = 200.0 | |
| 63 | + self._bins = 21 | |
| 64 | + self._enumbins = 0 | |
| 65 | + self._npix = 200 | |
| 66 | + self._binsz = 0.05 | |
| 67 | + self._type = "Differential" | |
| 68 | + self._ts_thres = 25.0 | |
| 69 | + self._max_iter = 50 | |
| 70 | + self._num_avg = 3 | |
| 71 | + self._log_clients = False | |
| 72 | + self._debug = False | |
| 73 | + | |
| 57 | 74 | # Initialise application |
| 58 | 75 | if len(argv) == 0: |
| 59 | - ctools.cscript.__init__(self, self.name, self.version) | |
| 76 | + ctools.cscript.__init__(self, self._name, self._version) | |
| 60 | 77 | elif len(argv) ==1: |
| 61 | - ctools.cscript.__init__(self, self.name, self.version, *argv) | |
| 78 | + ctools.cscript.__init__(self, self._name, self._version, *argv) | |
| 62 | 79 | else: |
| 63 | 80 | raise TypeError("Invalid number of arguments given.") |
| 64 | 81 | |
| 65 | 82 | # Set logger properties |
| 66 | - self.logFileOpen() | |
| 67 | - self.log_header() | |
| 68 | - self.log.date(True) | |
| 83 | + self._log_header() | |
| 84 | + self._log.date(True) | |
| 69 | 85 | |
| 70 | 86 | # Return |
| 71 | 87 | return |
| ... | ... | @@ -74,216 +90,79 @@ class cssens(ctools.cscript): |
| 74 | 90 | """ |
| 75 | 91 | Destructor. |
| 76 | 92 | """ |
| 77 | - # Write separator into logger | |
| 78 | - if self.logTerse(): | |
| 79 | - self.log("\n") | |
| 80 | - | |
| 81 | 93 | # Return |
| 82 | 94 | return |
| 83 | 95 | |
| 84 | - def parfile(self): | |
| 85 | - """ | |
| 86 | - Check if parfile exists. If parfile does not exist then create a | |
| 87 | - default parfile. This kluge avoids shipping the cscript with a parfile. | |
| 88 | - """ | |
| 89 | - # Set parfile name | |
| 90 | - parfile = self.name+".par" | |
| 91 | - | |
| 92 | - try: | |
| 93 | - pars = gammalib.GApplicationPars(parfile) | |
| 94 | - except: | |
| 95 | - # Signal if parfile was not found | |
| 96 | - print("Parfile "+parfile+" not found. Create default parfile.") | |
| 97 | - | |
| 98 | - # Create default parfile | |
| 99 | - pars = gammalib.GApplicationPars() | |
| 100 | - pars.append(gammalib.GApplicationPar("inobs","f","h","NONE","","","Input event list, counts cube, or observation definition XML file")) | |
| 101 | - pars.append(gammalib.GApplicationPar("inmodel","f","a","$CTOOLS/share/models/crab.xml","","","Input model XML file")) | |
| 102 | - pars.append(gammalib.GApplicationPar("srcname","s","a","Crab","","","Source name")) | |
| 103 | - pars.append(gammalib.GApplicationPar("caldb","s","a","prod2","","","Calibration database")) | |
| 104 | - pars.append(gammalib.GApplicationPar("irf","s","a","South_0.5h","","","Instrument response function")) | |
| 105 | - pars.append(gammalib.GApplicationPar("deadc","r","h","0.95","0","1","Deadtime correction factor")) | |
| 106 | - pars.append(gammalib.GApplicationPar("outfile","f","h","sensitivity.dat","","","Output sensitivity ASCII file")) | |
| 107 | - pars.append(gammalib.GApplicationPar("offset","r","h","0.0","","","Source offset angle (deg)")) | |
| 108 | - pars.append(gammalib.GApplicationPar("duration","r","a","180000.0","","","Effective exposure time (s)")) | |
| 109 | - pars.append(gammalib.GApplicationPar("rad","r","a","5.0","","","Radius of ROI (deg)")) | |
| 110 | - pars.append(gammalib.GApplicationPar("edisp","b","h","no","","","Apply energy dispersion?")) | |
| 111 | - pars.append(gammalib.GApplicationPar("emin","r","a","0.020","","","Lower energy limit (TeV)")) | |
| 112 | - pars.append(gammalib.GApplicationPar("emax","r","a","200.0","","","Upper energy limit (TeV)")) | |
| 113 | - pars.append(gammalib.GApplicationPar("bins","i","a","21","","","Number of energy bins for differential sensitivity computation")) | |
| 114 | - pars.append(gammalib.GApplicationPar("enumbins","i","h","0","","","Number of energy bins (0=unbinned)")) | |
| 115 | - pars.append(gammalib.GApplicationPar("npix","i","h","200","","","Number of pixels for binned")) | |
| 116 | - pars.append(gammalib.GApplicationPar("binsz","r","h","0.05","","","Pixel size for binned (deg/pixel)")) | |
| 117 | - pars.append(gammalib.GApplicationPar("type","s","h","Differential","Differential|Integral","","Sensitivity type")) | |
| 118 | - pars.append(gammalib.GApplicationPar("sigma","r","h","5.0","","","Significance threshold")) | |
| 119 | - pars.append(gammalib.GApplicationPar("max_iter","i","h","50","","","Maximum number of iterations")) | |
| 120 | - pars.append(gammalib.GApplicationPar("num_avg","i","h","3","","","Number of iterations for sliding average")) | |
| 121 | - pars.append_standard() | |
| 122 | - pars.append(gammalib.GApplicationPar("logfile","f","h","cssens.log","","","Log filename")) | |
| 123 | - pars.save(parfile) | |
| 124 | - | |
| 125 | - # Return | |
| 126 | - return | |
| 127 | 96 | |
| 128 | - def get_parameters(self): | |
| 97 | + # Private methods | |
| 98 | + def _get_parameters(self): | |
| 129 | 99 | """ |
| 130 | 100 | Get user parameters from parfile. |
| 131 | 101 | """ |
| 132 | 102 | # Set observation if not done before |
| 133 | - if self.obs == None or self.obs.size() == 0: | |
| 134 | - self.obs = self.set_obs() | |
| 103 | + if self._obs == None or self._obs.size() == 0: | |
| 104 | + self._obs = self._set_obs() | |
| 135 | 105 | |
| 136 | 106 | # Set models if we have none |
| 137 | - if self.obs.models().size() == 0: | |
| 138 | - self.obs.models(self["inmodel"].filename()) | |
| 107 | + if self._obs.models().size() == 0: | |
| 108 | + self._obs.models(self["inmodel"].filename()) | |
| 139 | 109 | |
| 140 | 110 | # Get source name |
| 141 | - self.m_srcname = self["srcname"].string() | |
| 111 | + self._srcname = self["srcname"].string() | |
| 142 | 112 | |
| 143 | 113 | # Read further parameters |
| 144 | - self.m_outfile = self["outfile"].filename() | |
| 145 | - self.m_emin = self["emin"].real() | |
| 146 | - self.m_emax = self["emax"].real() | |
| 147 | - self.m_bins = self["bins"].integer() | |
| 114 | + self._outfile = self["outfile"].filename() | |
| 115 | + self._emin = self["emin"].real() | |
| 116 | + self._emax = self["emax"].real() | |
| 117 | + self._bins = self["bins"].integer() | |
| 148 | 118 | |
| 149 | 119 | # Read parameters for binned if requested |
| 150 | - self.m_enumbins = self["enumbins"].integer() | |
| 151 | - if not self.m_enumbins == 0: | |
| 152 | - self.m_npix = self["npix"].integer() | |
| 153 | - self.m_binsz = self["binsz"].real() | |
| 154 | - else: | |
| 155 | - # Set dummy values (required by obsutils) | |
| 156 | - self.m_npix = 0 | |
| 157 | - self.m_binsz = 0.0 | |
| 120 | + self._enumbins = self["enumbins"].integer() | |
| 121 | + if not self._enumbins == 0: | |
| 122 | + self._npix = self["npix"].integer() | |
| 123 | + self._binsz = self["binsz"].real() | |
| 158 | 124 | |
| 159 | 125 | # Read remaining parameters |
| 160 | - self.m_edisp = self["edisp"].boolean() | |
| 161 | - self.m_ts_thres = self["sigma"].real()*self["sigma"].real() | |
| 162 | - self.m_max_iter = self["max_iter"].integer() | |
| 163 | - self.m_num_avg = self["num_avg"].integer() | |
| 164 | - self.m_type = self["type"].string() | |
| 126 | + self._edisp = self["edisp"].boolean() | |
| 127 | + self._ts_thres = self["sigma"].real()*self["sigma"].real() | |
| 128 | + self._max_iter = self["max_iter"].integer() | |
| 129 | + self._num_avg = self["num_avg"].integer() | |
| 130 | + self._type = self["type"].string() | |
| 165 | 131 | |
| 166 | 132 | # Set some fixed parameters |
| 167 | - self.m_log = False # Logging in client tools | |
| 168 | - self.m_debug = self["debug"].boolean() # Debugging in client tools | |
| 133 | + self._debug = self["debug"].boolean() # Debugging in client tools | |
| 169 | 134 | |
| 170 | 135 | # Derive some parameters |
| 171 | - self.m_ebounds = gammalib.GEbounds(self.m_bins, | |
| 172 | - gammalib.GEnergy(self.m_emin, "TeV"), | |
| 173 | - gammalib.GEnergy(self.m_emax, "TeV")) | |
| 136 | + self._ebounds = gammalib.GEbounds(self._bins, | |
| 137 | + gammalib.GEnergy(self._emin, "TeV"), | |
| 138 | + gammalib.GEnergy(self._emax, "TeV")) | |
| 174 | 139 | |
| 175 | - # Return | |
| 176 | - return | |
| 177 | - | |
| 178 | - def execute(self): | |
| 179 | - """ | |
| 180 | - Execute the script. | |
| 181 | - """ | |
| 182 | - # Run the script | |
| 183 | - self.run() | |
| 140 | + # Write input parameters into logger | |
| 141 | + if self._logTerse(): | |
| 142 | + self._log_parameters() | |
| 143 | + self._log("\n") | |
| 184 | 144 | |
| 185 | 145 | # Return |
| 186 | 146 | return |
| 187 | 147 | |
| 188 | - def run(self): | |
| 189 | - """ | |
| 190 | - Run the script. | |
| 148 | + def _set_obs(self, lpnt=0.0, bpnt=0.0, emin=0.1, emax=100.0): | |
| 191 | 149 | """ |
| 192 | - # Switch screen logging on in debug mode | |
| 193 | - if self.logDebug(): | |
| 194 | - self.log.cout(True) | |
| 195 | - | |
| 196 | - # Get parameters | |
| 197 | - self.get_parameters() | |
| 198 | - | |
| 199 | - # Write input parameters into logger | |
| 200 | - if self.logTerse(): | |
| 201 | - self.log_parameters() | |
| 202 | - self.log("\n") | |
| 203 | - | |
| 204 | - # Initialise script | |
| 205 | - colnames = ['loge', 'emin', 'emax', 'crab_flux', 'photon_flux', | |
| 206 | - 'energy_flux', 'sensitivity'] | |
| 207 | - results = [] | |
| 208 | - | |
| 209 | - # Initialise models | |
| 210 | - full_model, bkg_model = self.set_models() | |
| 211 | - | |
| 212 | - # Write models into logger | |
| 213 | - if self.logTerse(): | |
| 214 | - self.log("\n") | |
| 215 | - self.log.header1("Models") | |
| 216 | - self.log.header2("Background model") | |
| 217 | - self.log(str(bkg_model)) | |
| 218 | - self.log("\n\n") | |
| 219 | - self.log.header2("Full model") | |
| 220 | - self.log(str(full_model)) | |
| 221 | - self.log("\n") | |
| 222 | - | |
| 223 | - # Write heder | |
| 224 | - if self.logTerse(): | |
| 225 | - self.log("\n") | |
| 226 | - self.log.header1("Sensitivity determination") | |
| 227 | - self.log.parformat("Type") | |
| 228 | - self.log(self.m_type) | |
| 229 | - self.log("\n") | |
| 230 | - | |
| 231 | - # Loop over energy bins | |
| 232 | - for ieng in range(self.m_ebounds.size()): | |
| 233 | - | |
| 234 | - # Set energies | |
| 235 | - if self.m_type == "Differential": | |
| 236 | - emin = self.m_ebounds.emin(ieng) | |
| 237 | - emax = self.m_ebounds.emax(ieng) | |
| 238 | - elif self.m_type == "Integral": | |
| 239 | - emin = self.m_ebounds.emin(ieng) | |
| 240 | - emax = self.m_ebounds.emax() | |
| 241 | - else: | |
| 242 | - msg = "Invalid sensitivity type \""+self.m_type+"\" encountered."+ \ | |
| 243 | - " Either use \"Differential\" or \"Integral\"." | |
| 244 | - raise RuntimeError(msg) | |
| 150 | + Set an observation container. | |
| 245 | 151 | |
| 246 | - # Determine sensitivity | |
| 247 | - result = self.get_sensitivity(self.obs, emin, emax, | |
| 248 | - bkg_model, full_model) | |
| 152 | + Kwargs: | |
| 153 | + lpnt: Galactic longitude of pointing [deg] (default: 0.0) | |
| 154 | + bpnt: Galactic latitude of pointing [deg] (default: 0.0) | |
| 155 | + emin: Minimum energy [TeV] (default: 0.1) | |
| 156 | + emax: Maximum energy [TeV] (default: 100.0) | |
| 249 | 157 | |
| 250 | - # Write results | |
| 251 | - if ieng == 0: | |
| 252 | - f = open(self.m_outfile.url(), 'w') | |
| 253 | - writer = csv.DictWriter(f, colnames) | |
| 254 | - headers = {} | |
| 255 | - for n in colnames: | |
| 256 | - headers[n] = n | |
| 257 | - writer.writerow(headers) | |
| 258 | - #writer.writerow(dict((_,_) for _ in colnames)) | |
| 259 | - writer.writerow(result) | |
| 260 | - f.close() | |
| 261 | - else: | |
| 262 | - f = open(self.m_outfile.url(), 'a') | |
| 263 | - writer = csv.DictWriter(f, colnames) | |
| 264 | - writer.writerow(result) | |
| 265 | - f.close() | |
| 266 | - | |
| 267 | - # Append results | |
| 268 | - results.append(result) | |
| 269 | - | |
| 270 | - # Return | |
| 271 | - return | |
| 272 | - | |
| 273 | - def set_obs(self, lpnt=0.0, bpnt=0.0, emin=0.1, emax=100.0): | |
| 158 | + Returns: | |
| 159 | + Observation container. | |
| 274 | 160 | """ |
| 275 | - Returns an observation container. | |
| 276 | - | |
| 277 | - Keywords: | |
| 278 | - lpnt - Galactic longitude of pointing [deg] (default: 0.0) | |
| 279 | - bpnt - Galactic latitude of pointing [deg] (default: 0.0) | |
| 280 | - emin - Minimum energy [TeV] (default: 0.1) | |
| 281 | - emax - Maximum energy [TeV] (default: 100.0) | |
| 282 | - """ | |
| 283 | - # If an observation was provided on input then load it from XML file | |
| 161 | + # If an observation was provided on input then load it from XML | |
| 162 | + # file | |
| 284 | 163 | filename = self["inobs"].filename() |
| 285 | 164 | if filename != "NONE" and filename != "": |
| 286 | - obs = self.get_observations() | |
| 165 | + obs = self._get_observations() | |
| 287 | 166 | |
| 288 | 167 | # ... otherwise allocate a single observation |
| 289 | 168 | else: |
| ... | ... | @@ -311,56 +190,46 @@ class cssens(ctools.cscript): |
| 311 | 190 | obs.append(run) |
| 312 | 191 | |
| 313 | 192 | # Set source position |
| 314 | - offset = self["offset"].real() | |
| 193 | + offset = self["offset"].real() | |
| 315 | 194 | pntdir.lb_deg(lpnt, bpnt+offset) |
| 316 | - self.m_ra = pntdir.ra_deg() | |
| 317 | - self.m_dec = pntdir.dec_deg() | |
| 195 | + self._ra = pntdir.ra_deg() | |
| 196 | + self._dec = pntdir.dec_deg() | |
| 318 | 197 | |
| 319 | 198 | # Return observation container |
| 320 | 199 | return obs |
| 321 | 200 | |
| 322 | - def set_obs_ebounds(self, emin, emax): | |
| 323 | - """ | |
| 324 | - Set energy boundaries for observation in container. | |
| 325 | - | |
| 326 | - Parameters: | |
| 327 | - emin - Minimum energy | |
| 328 | - emax - Maximum energy | |
| 201 | + def _set_models(self, fitspat=False, fitspec=False): | |
| 329 | 202 | """ |
| 330 | - # Loop over all observations in container | |
| 331 | - for obs in self.obs: | |
| 332 | - | |
| 333 | - # Set energy boundaries | |
| 334 | - ebounds = gammalib.GEbounds(emin, emax) | |
| 335 | - obs.events().ebounds(ebounds) | |
| 203 | + Set full model and background model. | |
| 336 | 204 | |
| 337 | - # Return | |
| 338 | - return | |
| 205 | + Kwargs: | |
| 206 | + fitspat: Fit spatial parameter (default: False). | |
| 207 | + fitspec: Fit spectral parameters (default: False). | |
| 339 | 208 | |
| 340 | - def set_models(self, fitpos=False, fitspec=False): | |
| 341 | - """ | |
| 342 | - Set full and background model. | |
| 209 | + Returns: | |
| 210 | + Tuple containing full model and background model. | |
| 343 | 211 | """ |
| 344 | 212 | # Retrieve full model from observation container |
| 345 | - full_model = self.obs.models().copy() | |
| 213 | + full_model = self._obs.models().copy() | |
| 346 | 214 | |
| 347 | 215 | # Get source model |
| 348 | - model = full_model[self.m_srcname] | |
| 216 | + model = full_model[self._srcname] | |
| 349 | 217 | |
| 350 | 218 | # Check that model has a Prefactor |
| 351 | 219 | if not model.has_par("Prefactor"): |
| 352 | - msg = "Model \""+self.m_srcname+"\" has no parameter \"Prefactor\"."+ \ | |
| 353 | - " Only spectral models with a \"Prefactor\" parameter are supported." | |
| 220 | + msg = "Model \""+self._srcname+"\" has no parameter "+\ | |
| 221 | + "\"Prefactor\". Only spectral models with a "+\ | |
| 222 | + "\"Prefactor\" parameter are supported." | |
| 354 | 223 | raise RuntimeError(msg) |
| 355 | 224 | |
| 356 | 225 | # Set source position |
| 357 | - if self.m_ra != None and self.m_dec != None: | |
| 226 | + if self._ra != None and self._dec != None: | |
| 358 | 227 | if model.has_par("RA") and model.has_par("DEC"): |
| 359 | - model["RA"].value(self.m_ra) | |
| 360 | - model["DEC"].value(self.m_dec) | |
| 228 | + model["RA"].value(self._ra) | |
| 229 | + model["DEC"].value(self._dec) | |
| 361 | 230 | |
| 362 | 231 | # Fit or fix spatial parameters |
| 363 | - if fitpos: | |
| 232 | + if fitspat: | |
| 364 | 233 | if model.has_par("RA"): |
| 365 | 234 | model["RA"].free() |
| 366 | 235 | if model.has_par("DEC"): |
| ... | ... | @@ -397,27 +266,71 @@ class cssens(ctools.cscript): |
| 397 | 266 | |
| 398 | 267 | # Create background model |
| 399 | 268 | bkg_model = full_model.copy() |
| 400 | - bkg_model.remove(self.m_srcname) | |
| 269 | + bkg_model.remove(self._srcname) | |
| 401 | 270 | |
| 402 | 271 | # Return models |
| 403 | 272 | return full_model, bkg_model |
| 404 | 273 | |
| 405 | - def get_sensitivity(self, obs, emin, emax, bkg_model, full_model): | |
| 274 | + def _set_obs_ebounds(self, emin, emax): | |
| 275 | + """ | |
| 276 | + Set energy boundaries for observation container. | |
| 277 | + | |
| 278 | + Sets the energy boundaries for all observations in the observation | |
| 279 | + container. | |
| 280 | + | |
| 281 | + Args: | |
| 282 | + emin: Minimum energy | |
| 283 | + emax: Maximum energy | |
| 284 | + """ | |
| 285 | + # Loop over all observations in container | |
| 286 | + for obs in self._obs: | |
| 287 | + | |
| 288 | + # Set energy boundaries | |
| 289 | + ebounds = gammalib.GEbounds(emin, emax) | |
| 290 | + obs.events().ebounds(ebounds) | |
| 291 | + | |
| 292 | + # Return | |
| 293 | + return | |
| 294 | + | |
| 295 | + def _get_crab_flux(self, emin, emax): | |
| 296 | + """ | |
| 297 | + Return Crab photon flux in a given energy interval. | |
| 298 | + | |
| 299 | + Args: | |
| 300 | + emin: Minimum energy | |
| 301 | + emax: Maximum energy | |
| 302 | + | |
| 303 | + Returns: | |
| 304 | + Crab photon flux in specified energy interval. | |
| 305 | + """ | |
| 306 | + # Set Crab TeV spectral model based on a power law | |
| 307 | + crab = gammalib.GModelSpectralPlaw(5.7e-16, -2.48, | |
| 308 | + gammalib.GEnergy(0.3, "TeV")) | |
| 309 | + | |
| 310 | + # Determine flux | |
| 311 | + flux = crab.flux(emin, emax) | |
| 312 | + | |
| 313 | + # Return flux | |
| 314 | + return flux | |
| 315 | + | |
| 316 | + def _get_sensitivity(self, emin, emax, bkg_model, full_model): | |
| 406 | 317 | """ |
| 407 | 318 | Determine sensitivity for given observations. |
| 408 | 319 | |
| 409 | - Parameters: | |
| 410 | - obs - Observation container | |
| 411 | - emin - Minimum energy for fitting and flux computation | |
| 412 | - emax - Maximum energy for fitting and flux computation | |
| 413 | - bkg_model - Background model | |
| 414 | - full_model - Source model | |
| 320 | + Args: | |
| 321 | + emin: Minimum energy for fitting and flux computation | |
| 322 | + emax: Maximum energy for fitting and flux computation | |
| 323 | + bkg_model: Background model | |
| 324 | + full_model: Source model | |
| 325 | + | |
| 326 | + Returns: | |
| 327 | + Result dictionary | |
| 415 | 328 | """ |
| 416 | 329 | # Set TeV->erg conversion factor |
| 417 | 330 | tev2erg = 1.6021764 |
| 418 | 331 | |
| 419 | 332 | # Set energy boundaries |
| 420 | - self.set_obs_ebounds(emin, emax) | |
| 333 | + self._set_obs_ebounds(emin, emax) | |
| 421 | 334 | |
| 422 | 335 | # Determine energy boundaries from first observation in the container |
| 423 | 336 | loge = math.log10(math.sqrt(emin.TeV()*emax.TeV())) |
| ... | ... | @@ -426,23 +339,23 @@ class cssens(ctools.cscript): |
| 426 | 339 | |
| 427 | 340 | # Compute Crab unit (this is the factor with which the Prefactor needs |
| 428 | 341 | # to be multiplied to get 1 Crab |
| 429 | - crab_flux = self.get_crab_flux(emin, emax) | |
| 430 | - src_flux = full_model[self.m_srcname].spectral().flux(emin, emax) | |
| 342 | + crab_flux = self._get_crab_flux(emin, emax) | |
| 343 | + src_flux = full_model[self._srcname].spectral().flux(emin, emax) | |
| 431 | 344 | crab_unit = crab_flux/src_flux |
| 432 | 345 | |
| 433 | 346 | # Write header |
| 434 | - if self.logTerse(): | |
| 435 | - self.log("\n") | |
| 436 | - self.log.header2("Energies: "+str(emin)+" - "+str(emax)) | |
| 437 | - self.log.parformat("Crab flux") | |
| 438 | - self.log(crab_flux) | |
| 439 | - self.log(" ph/cm2/s\n") | |
| 440 | - self.log.parformat("Source model flux") | |
| 441 | - self.log(src_flux) | |
| 442 | - self.log(" ph/cm2/s\n") | |
| 443 | - self.log.parformat("Crab unit factor") | |
| 444 | - self.log(crab_unit) | |
| 445 | - self.log("\n") | |
| 347 | + if self._logTerse(): | |
| 348 | + self._log("\n") | |
| 349 | + self._log.header2("Energies: "+str(emin)+" - "+str(emax)) | |
| 350 | + self._log.parformat("Crab flux") | |
| 351 | + self._log(crab_flux) | |
| 352 | + self._log(" ph/cm2/s\n") | |
| 353 | + self._log.parformat("Source model flux") | |
| 354 | + self._log(src_flux) | |
| 355 | + self._log(" ph/cm2/s\n") | |
| 356 | + self._log.parformat("Crab unit factor") | |
| 357 | + self._log(crab_unit) | |
| 358 | + self._log("\n") | |
| 446 | 359 | |
| 447 | 360 | # Initialise loop |
| 448 | 361 | crab_flux_value = [] |
| ... | ... | @@ -459,20 +372,23 @@ class cssens(ctools.cscript): |
| 459 | 372 | iter += 1 |
| 460 | 373 | |
| 461 | 374 | # Write header |
| 462 | - if self.logExplicit(): | |
| 463 | - self.log.header2("Iteration "+str(iter)) | |
| 375 | + if self._logExplicit(): | |
| 376 | + self._log.header2("Iteration "+str(iter)) | |
| 464 | 377 | |
| 465 | 378 | # Set source model. crab_prefactor is the Prefactor that |
| 466 | 379 | # corresponds to 1 Crab |
| 467 | 380 | src_model = full_model.copy() |
| 468 | - crab_prefactor = src_model[self.m_srcname]['Prefactor'].value() * crab_unit | |
| 469 | - src_model[self.m_srcname]['Prefactor'].value(crab_prefactor * test_crab_flux) | |
| 470 | - obs.models(src_model) | |
| 381 | + crab_prefactor = src_model[self._srcname]['Prefactor'].value() * \ | |
| 382 | + crab_unit | |
| 383 | + src_model[self._srcname]['Prefactor'].value(crab_prefactor * \ | |
| 384 | + test_crab_flux) | |
| 385 | + self._obs.models(src_model) | |
| 471 | 386 | |
| 472 | 387 | # Simulate events |
| 473 | - sim = obsutils.sim(obs, nbins=self.m_enumbins, seed=iter, | |
| 474 | - binsz=self.m_binsz, npix=self.m_npix, | |
| 475 | - log=self.m_log, debug=self.m_debug, edisp=self.m_edisp) | |
| 388 | + sim = obsutils.sim(self._obs, nbins=self._enumbins, seed=iter, | |
| 389 | + binsz=self._binsz, npix=self._npix, | |
| 390 | + log=self._log_clients, debug=self._debug, | |
| 391 | + edisp=self._edisp) | |
| 476 | 392 | |
| 477 | 393 | # Determine number of events in simulation |
| 478 | 394 | nevents = 0.0 |
| ... | ... | @@ -480,15 +396,16 @@ class cssens(ctools.cscript): |
| 480 | 396 | nevents += run.events().number() |
| 481 | 397 | |
| 482 | 398 | # Write simulation results |
| 483 | - if self.logExplicit(): | |
| 484 | - self.log.header3("Simulation") | |
| 485 | - self.log.parformat("Number of simulated events") | |
| 486 | - self.log(nevents) | |
| 487 | - self.log("\n") | |
| 399 | + if self._logExplicit(): | |
| 400 | + self._log.header3("Simulation") | |
| 401 | + self._log.parformat("Number of simulated events") | |
| 402 | + self._log(nevents) | |
| 403 | + self._log("\n") | |
| 488 | 404 | |
| 489 | 405 | # Fit background only |
| 490 | 406 | sim.models(bkg_model) |
| 491 | - like = obsutils.fit(sim, log=self.m_log, debug=self.m_debug, edisp=self.m_edisp) | |
| 407 | + like = obsutils.fit(sim, log=self._log_clients, | |
| 408 | + debug=self._debug, edisp=self._edisp) | |
| 492 | 409 | result_bgm = like.obs().models().copy() |
| 493 | 410 | LogL_bgm = like.opt().value() |
| 494 | 411 | npred_bgm = like.obs().npred() |
| ... | ... | @@ -497,36 +414,31 @@ class cssens(ctools.cscript): |
| 497 | 414 | quality_bgm = npred_bgm-nevents |
| 498 | 415 | |
| 499 | 416 | # Write background fit results |
| 500 | - if self.logExplicit(): | |
| 501 | - self.log.header3("Background model fit") | |
| 502 | - self.log.parformat("log likelihood") | |
| 503 | - self.log(LogL_bgm) | |
| 504 | - self.log("\n") | |
| 505 | - self.log.parformat("Number of predicted events") | |
| 506 | - self.log(npred_bgm) | |
| 507 | - self.log("\n") | |
| 508 | - self.log.parformat("Fit quality") | |
| 509 | - self.log(quality_bgm) | |
| 510 | - self.log("\n") | |
| 511 | - | |
| 512 | - # Start over if the fit quality was bad | |
| 513 | - #if abs(quality_bgm) > 3.0: | |
| 514 | - # if self.logExplicit(): | |
| 515 | - # self.log("Fit quality outside required range. Start over.\n") | |
| 516 | - # continue | |
| 417 | + if self._logExplicit(): | |
| 418 | + self._log.header3("Background model fit") | |
| 419 | + self._log.parformat("log likelihood") | |
| 420 | + self._log(LogL_bgm) | |
| 421 | + self._log("\n") | |
| 422 | + self._log.parformat("Number of predicted events") | |
| 423 | + self._log(npred_bgm) | |
| 424 | + self._log("\n") | |
| 425 | + self._log.parformat("Fit quality") | |
| 426 | + self._log(quality_bgm) | |
| 427 | + self._log("\n") | |
| 517 | 428 | |
| 518 | 429 | # Write model fit results |
| 519 | - if self.logExplicit(): | |
| 430 | + if self._logExplicit(): | |
| 520 | 431 | for model in result_bgm: |
| 521 | - self.log.parformat("Model") | |
| 522 | - self.log(model.name()) | |
| 523 | - self.log("\n") | |
| 432 | + self._log.parformat("Model") | |
| 433 | + self._log(model.name()) | |
| 434 | + self._log("\n") | |
| 524 | 435 | for par in model: |
| 525 | - self.log(str(par)+"\n") | |
| 436 | + self._log(str(par)+"\n") | |
| 526 | 437 | |
| 527 | 438 | # Fit background and test source |
| 528 | 439 | sim.models(src_model) |
| 529 | - like = obsutils.fit(sim, log=self.m_log, debug=self.m_debug, edisp=self.m_edisp) | |
| 440 | + like = obsutils.fit(sim, log=self._log_clients, | |
| 441 | + debug=self._debug, edisp=self._edisp) | |
| 530 | 442 | result_all = like.obs().models().copy() |
| 531 | 443 | LogL_all = like.opt().value() |
| 532 | 444 | npred_all = like.obs().npred() |
| ... | ... | @@ -536,56 +448,52 @@ class cssens(ctools.cscript): |
| 536 | 448 | quality_all = npred_all-nevents |
| 537 | 449 | |
| 538 | 450 | # Write background and test source fit results |
| 539 | - if self.logExplicit(): | |
| 540 | - self.log.header3("Background and test source model fit") | |
| 541 | - self.log.parformat("Test statistics") | |
| 542 | - self.log(ts) | |
| 543 | - self.log("\n") | |
| 544 | - self.log.parformat("log likelihood") | |
| 545 | - self.log(LogL_all) | |
| 546 | - self.log("\n") | |
| 547 | - self.log.parformat("Number of predicted events") | |
| 548 | - self.log(npred_all) | |
| 549 | - self.log("\n") | |
| 550 | - self.log.parformat("Fit quality") | |
| 551 | - self.log(quality_all) | |
| 552 | - self.log("\n") | |
| 451 | + if self._logExplicit(): | |
| 452 | + self._log.header3("Background and test source model fit") | |
| 453 | + self._log.parformat("Test statistics") | |
| 454 | + self._log(ts) | |
| 455 | + self._log("\n") | |
| 456 | + self._log.parformat("log likelihood") | |
| 457 | + self._log(LogL_all) | |
| 458 | + self._log("\n") | |
| 459 | + self._log.parformat("Number of predicted events") | |
| 460 | + self._log(npred_all) | |
| 461 | + self._log("\n") | |
| 462 | + self._log.parformat("Fit quality") | |
| 463 | + self._log(quality_all) | |
| 464 | + self._log("\n") | |
| 553 | 465 | # |
| 554 | 466 | for model in result_all: |
| 555 | - self.log.parformat("Model") | |
| 556 | - self.log(model.name()) | |
| 557 | - self.log("\n") | |
| 467 | + self._log.parformat("Model") | |
| 468 | + self._log(model.name()) | |
| 469 | + self._log("\n") | |
| 558 | 470 | for par in model: |
| 559 | - self.log(str(par)+"\n") | |
| 560 | - | |
| 561 | - # Start over if the fit quality was bad | |
| 562 | - #if abs(quality_all) > 3.0: | |
| 563 | - # if self.logExplicit(): | |
| 564 | - # self.log("Fit quality outside required range. Start over.\n") | |
| 565 | - # continue | |
| 471 | + self._log(str(par)+"\n") | |
| 566 | 472 | |
| 567 | 473 | # Start over if TS was non-positive |
| 568 | 474 | if ts <= 0.0: |
| 569 | - if self.logExplicit(): | |
| 570 | - self.log("Non positive TS. Start over.\n") | |
| 475 | + if self._logExplicit(): | |
| 476 | + self._log("Non positive TS. Start over.\n") | |
| 571 | 477 | continue |
| 572 | 478 | |
| 573 | 479 | # Get fitted Crab, photon and energy fluxes |
| 574 | - crab_flux = result_all[self.m_srcname]['Prefactor'].value() / crab_prefactor | |
| 575 | - crab_flux_err = result_all[self.m_srcname]['Prefactor'].error() / crab_prefactor | |
| 576 | - photon_flux = result_all[self.m_srcname].spectral().flux(emin, emax) | |
| 577 | - energy_flux = result_all[self.m_srcname].spectral().eflux(emin, emax) | |
| 480 | + crab_flux = result_all[self._srcname]['Prefactor'].value() / \ | |
| 481 | + crab_prefactor | |
| 482 | + crab_flux_err = result_all[self._srcname]['Prefactor'].error() / \ | |
| 483 | + crab_prefactor | |
| 484 | + photon_flux = result_all[self._srcname].spectral().flux(emin, emax) | |
| 485 | + energy_flux = result_all[self._srcname].spectral().eflux(emin, emax) | |
| 578 | 486 | |
| 579 | 487 | # Compute differential sensitivity in unit erg/cm2/s |
| 580 | 488 | energy = gammalib.GEnergy(e_mean, "TeV") |
| 581 | 489 | time = gammalib.GTime() |
| 582 | - sensitivity = result_all[self.m_srcname].spectral().eval(energy, time) * \ | |
| 490 | + sensitivity = result_all[self._srcname].spectral().eval(energy, time) * \ | |
| 583 | 491 | e_mean*erg_mean * 1.0e6 |
| 584 | 492 | |
| 585 | 493 | # Compute flux correction factor based on average TS |
| 586 | 494 | correct = 1.0 |
| 587 | 495 | if ts > 0: |
| 588 | - correct = math.sqrt(self.m_ts_thres/ts) | |
| 496 | + correct = math.sqrt(self._ts_thres/ts) | |
| 589 | 497 | |
| 590 | 498 | # Compute extrapolated fluxes |
| 591 | 499 | crab_flux = correct * crab_flux |
| ... | ... | @@ -598,41 +506,41 @@ class cssens(ctools.cscript): |
| 598 | 506 | sensitivity_value.append(sensitivity) |
| 599 | 507 | |
| 600 | 508 | # Write background and test source fit results |
| 601 | - if self.logExplicit(): | |
| 602 | - self.log.parformat("Photon flux") | |
| 603 | - self.log(photon_flux) | |
| 604 | - self.log(" ph/cm2/s\n") | |
| 605 | - self.log.parformat("Energy flux") | |
| 606 | - self.log(energy_flux) | |
| 607 | - self.log(" erg/cm2/s\n") | |
| 608 | - self.log.parformat("Crab flux") | |
| 609 | - self.log(crab_flux*1000.0) | |
| 610 | - self.log(" mCrab\n") | |
| 611 | - self.log.parformat("Differential sensitivity") | |
| 612 | - self.log(sensitivity) | |
| 613 | - self.log(" erg/cm2/s\n") | |
| 509 | + if self._logExplicit(): | |
| 510 | + self._log.parformat("Photon flux") | |
| 511 | + self._log(photon_flux) | |
| 512 | + self._log(" ph/cm2/s\n") | |
| 513 | + self._log.parformat("Energy flux") | |
| 514 | + self._log(energy_flux) | |
| 515 | + self._log(" erg/cm2/s\n") | |
| 516 | + self._log.parformat("Crab flux") | |
| 517 | + self._log(crab_flux*1000.0) | |
| 518 | + self._log(" mCrab\n") | |
| 519 | + self._log.parformat("Differential sensitivity") | |
| 520 | + self._log(sensitivity) | |
| 521 | + self._log(" erg/cm2/s\n") | |
| 614 | 522 | for model in result_all: |
| 615 | - self.log.parformat("Model") | |
| 616 | - self.log(model.name()) | |
| 617 | - self.log("\n") | |
| 523 | + self._log.parformat("Model") | |
| 524 | + self._log(model.name()) | |
| 525 | + self._log("\n") | |
| 618 | 526 | for par in model: |
| 619 | - self.log(str(par)+"\n") | |
| 620 | - elif self.logTerse(): | |
| 621 | - self.log.parformat("Iteration "+str(iter)) | |
| 622 | - self.log("TS=") | |
| 623 | - self.log(ts) | |
| 624 | - self.log(" ") | |
| 625 | - self.log("corr=") | |
| 626 | - self.log(correct) | |
| 627 | - self.log(" ") | |
| 628 | - self.log(photon_flux) | |
| 629 | - self.log(" ph/cm2/s = ") | |
| 630 | - self.log(energy_flux) | |
| 631 | - self.log(" erg/cm2/s = ") | |
| 632 | - self.log(crab_flux*1000.0) | |
| 633 | - self.log(" mCrab = ") | |
| 634 | - self.log(sensitivity) | |
| 635 | - self.log(" erg/cm2/s\n") | |
| 527 | + self._log(str(par)+"\n") | |
| 528 | + elif self._logTerse(): | |
| 529 | + self._log.parformat("Iteration "+str(iter)) | |
| 530 | + self._log("TS=") | |
| 531 | + self._log(ts) | |
| 532 | + self._log(" ") | |
| 533 | + self._log("corr=") | |
| 534 | + self._log(correct) | |
| 535 | + self._log(" ") | |
| 536 | + self._log(photon_flux) | |
| 537 | + self._log(" ph/cm2/s = ") | |
| 538 | + self._log(energy_flux) | |
| 539 | + self._log(" erg/cm2/s = ") | |
| 540 | + self._log(crab_flux*1000.0) | |
| 541 | + self._log(" mCrab = ") | |
| 542 | + self._log(sensitivity) | |
| 543 | + self._log(" erg/cm2/s\n") | |
| 636 | 544 | |
| 637 | 545 | # Compute sliding average of extrapolated fitted prefactor, |
| 638 | 546 | # photon and energy flux. This damps out fluctuations and |
| ... | ... | @@ -642,7 +550,7 @@ class cssens(ctools.cscript): |
| 642 | 550 | energy_flux = 0.0 |
| 643 | 551 | sensitivity = 0.0 |
| 644 | 552 | num = 0.0 |
| 645 | - for k in range(self.m_num_avg): | |
| 553 | + for k in range(self._num_avg): | |
| 646 | 554 | inx = len(crab_flux_value) - k - 1 |
| 647 | 555 | if inx >= 0: |
| 648 | 556 | crab_flux += crab_flux_value[inx] |
| ... | ... | @@ -656,7 +564,7 @@ class cssens(ctools.cscript): |
| 656 | 564 | sensitivity /= num |
| 657 | 565 | |
| 658 | 566 | # Compare average flux to last average |
| 659 | - if iter > self.m_num_avg: | |
| 567 | + if iter > self._num_avg: | |
| 660 | 568 | if test_crab_flux > 0: |
| 661 | 569 | ratio = crab_flux/test_crab_flux |
| 662 | 570 | |
| ... | ... | @@ -665,70 +573,71 @@ class cssens(ctools.cscript): |
| 665 | 573 | # 2. The flux correction factor is small |
| 666 | 574 | if ratio >= 0.99 and ratio <= 1.01 and \ |
| 667 | 575 | correct >= 0.9 and correct <= 1.1: |
| 668 | - if self.logTerse(): | |
| 669 | - self.log(" Converged ("+str(ratio)+")\n") | |
| 576 | + if self._logTerse(): | |
| 577 | + self._log(" Converged ("+str(ratio)+")\n") | |
| 670 | 578 | break |
| 671 | 579 | else: |
| 672 | - if self.logTerse(): | |
| 673 | - self.log(" Flux is zero.\n") | |
| 580 | + if self._logTerse(): | |
| 581 | + self._log(" Flux is zero.\n") | |
| 674 | 582 | break |
| 675 | 583 | |
| 676 | 584 | # Use average for next iteration |
| 677 | 585 | test_crab_flux = crab_flux |
| 678 | 586 | |
| 679 | 587 | # Exit loop if number of trials exhausted |
| 680 | - if (iter >= self.m_max_iter): | |
| 681 | - if self.logTerse(): | |
| 682 | - self.log(" Test ended after "+str(self.m_max_iter)+" iterations.\n") | |
| 588 | + if (iter >= self._max_iter): | |
| 589 | + if self._logTerse(): | |
| 590 | + self._log(" Test ended after "+str(self._max_iter)+ | |
| 591 | + " iterations.\n") | |
| 683 | 592 | break |
| 684 | 593 | |
| 685 | 594 | # Write fit results |
| 686 | - if self.logTerse(): | |
| 687 | - self.log.header3("Fit results") | |
| 688 | - self.log.parformat("Test statistics") | |
| 689 | - self.log(ts) | |
| 690 | - self.log("\n") | |
| 691 | - self.log.parformat("Photon flux") | |
| 692 | - self.log(photon_flux) | |
| 693 | - self.log(" ph/cm2/s\n") | |
| 694 | - self.log.parformat("Energy flux") | |
| 695 | - self.log(energy_flux) | |
| 696 | - self.log(" erg/cm2/s\n") | |
| 697 | - self.log.parformat("Crab flux") | |
| 698 | - self.log(crab_flux*1000.0) | |
| 699 | - self.log(" mCrab\n") | |
| 700 | - self.log.parformat("Differential sensitivity") | |
| 701 | - self.log(sensitivity) | |
| 702 | - self.log(" erg/cm2/s\n") | |
| 703 | - self.log.parformat("Number of simulated events") | |
| 704 | - self.log(nevents) | |
| 705 | - self.log("\n") | |
| 706 | - self.log.header3("Background and test source model fitting") | |
| 707 | - self.log.parformat("log likelihood") | |
| 708 | - self.log(LogL_all) | |
| 709 | - self.log("\n") | |
| 710 | - self.log.parformat("Number of predicted events") | |
| 711 | - self.log(npred_all) | |
| 712 | - self.log("\n") | |
| 595 | + if self._logTerse(): | |
| 596 | + self._log.header3("Fit results") | |
| 597 | + self._log.parformat("Test statistics") | |
| 598 | + self._log(ts) | |
| 599 | + self._log("\n") | |
| 600 | + self._log.parformat("Photon flux") | |
| 601 | + self._log(photon_flux) | |
| 602 | + self._log(" ph/cm2/s\n") | |
| 603 | + self._log.parformat("Energy flux") | |
| 604 | + self._log(energy_flux) | |
| 605 | + self._log(" erg/cm2/s\n") | |
| 606 | + self._log.parformat("Crab flux") | |
| 607 | + self._log(crab_flux*1000.0) | |
| 608 | + self._log(" mCrab\n") | |
| 609 | + self._log.parformat("Differential sensitivity") | |
| 610 | + self._log(sensitivity) | |
| 611 | + self._log(" erg/cm2/s\n") | |
| 612 | + self._log.parformat("Number of simulated events") | |
| 613 | + self._log(nevents) | |
| 614 | + self._log("\n") | |
| 615 | + self._log.header3("Background and test source model fitting") | |
| 616 | + self._log.parformat("log likelihood") | |
| 617 | + self._log(LogL_all) | |
| 618 | + self._log("\n") | |
| 619 | + self._log.parformat("Number of predicted events") | |
| 620 | + self._log(npred_all) | |
| 621 | + self._log("\n") | |
| 713 | 622 | for model in result_all: |
| 714 | - self.log.parformat("Model") | |
| 715 | - self.log(model.name()) | |
| 716 | - self.log("\n") | |
| 623 | + self._log.parformat("Model") | |
| 624 | + self._log(model.name()) | |
| 625 | + self._log("\n") | |
| 717 | 626 | for par in model: |
| 718 | - self.log(str(par)+"\n") | |
| 719 | - self.log.header3("Background model fit") | |
| 720 | - self.log.parformat("log likelihood") | |
| 721 | - self.log(LogL_bgm) | |
| 722 | - self.log("\n") | |
| 723 | - self.log.parformat("Number of predicted events") | |
| 724 | - self.log(npred_bgm) | |
| 725 | - self.log("\n") | |
| 627 | + self._log(str(par)+"\n") | |
| 628 | + self._log.header3("Background model fit") | |
| 629 | + self._log.parformat("log likelihood") | |
| 630 | + self._log(LogL_bgm) | |
| 631 | + self._log("\n") | |
| 632 | + self._log.parformat("Number of predicted events") | |
| 633 | + self._log(npred_bgm) | |
| 634 | + self._log("\n") | |
| 726 | 635 | for model in result_bgm: |
| 727 | - self.log.parformat("Model") | |
| 728 | - self.log(model.name()) | |
| 729 | - self.log("\n") | |
| 636 | + self._log.parformat("Model") | |
| 637 | + self._log(model.name()) | |
| 638 | + self._log("\n") | |
| 730 | 639 | for par in model: |
| 731 | - self.log(str(par)+"\n") | |
| 640 | + self._log(str(par)+"\n") | |
| 732 | 641 | |
| 733 | 642 | # Store result |
| 734 | 643 | result = {'loge': loge, 'emin': emin.TeV(), 'emax': emax.TeV(), \ |
| ... | ... | @@ -739,29 +648,110 @@ class cssens(ctools.cscript): |
| 739 | 648 | # Return result |
| 740 | 649 | return result |
| 741 | 650 | |
| 742 | - def get_crab_flux(self, emin, emax): | |
| 651 | + | |
| 652 | + # Public methods | |
| 653 | + def run(self): | |
| 743 | 654 | """ |
| 744 | - Determine the Crab photon flux in a given energy interval. | |
| 655 | + Run the script. | |
| 745 | 656 | """ |
| 746 | - # Set Crab spectral model | |
| 747 | - crab = gammalib.GModelSpectralPlaw(5.7e-16, -2.48, gammalib.GEnergy(0.3, "TeV")) | |
| 657 | + # Switch screen logging on in debug mode | |
| 658 | + if self._logDebug(): | |
| 659 | + self._log.cout(True) | |
| 748 | 660 | |
| 749 | - # Determine flux | |
| 750 | - flux = crab.flux(emin, emax) | |
| 661 | + # Get parameters | |
| 662 | + self._get_parameters() | |
| 663 | + | |
| 664 | + # Initialise script | |
| 665 | + colnames = ['loge', 'emin', 'emax', 'crab_flux', 'photon_flux', | |
| 666 | + 'energy_flux', 'sensitivity'] | |
| 667 | + results = [] | |
| 668 | + | |
| 669 | + # Initialise models | |
| 670 | + full_model, bkg_model = self._set_models() | |
| 671 | + | |
| 672 | + # Write models into logger | |
| 673 | + if self._logTerse(): | |
| 674 | + self._log("\n") | |
| 675 | + self._log.header1("Models") | |
| 676 | + self._log.header2("Background model") | |
| 677 | + self._log(str(bkg_model)) | |
| 678 | + self._log("\n\n") | |
| 679 | + self._log.header2("Full model") | |
| 680 | + self._log(str(full_model)) | |
| 681 | + self._log("\n") | |
| 682 | + | |
| 683 | + # Write header | |
| 684 | + if self._logTerse(): | |
| 685 | + self._log("\n") | |
| 686 | + self._log.header1("Sensitivity determination") | |
| 687 | + self._log.parformat("Type") | |
| 688 | + self._log(self._type) | |
| 689 | + self._log("\n") | |
| 690 | + | |
| 691 | + # Loop over energy bins | |
| 692 | + for ieng in range(self._ebounds.size()): | |
| 693 | + | |
| 694 | + # Set energies | |
| 695 | + if self._type == "Differential": | |
| 696 | + emin = self._ebounds.emin(ieng) | |
| 697 | + emax = self._ebounds.emax(ieng) | |
| 698 | + elif self._type == "Integral": | |
| 699 | + emin = self._ebounds.emin(ieng) | |
| 700 | + emax = self._ebounds.emax() | |
| 701 | + else: | |
| 702 | + msg = "Invalid sensitivity type \""+self._type+"\" "+\ | |
| 703 | + "encountered. Either specify \"Differential\" or "+\ | |
| 704 | + "\"Integral\"." | |
| 705 | + raise RuntimeError(msg) | |
| 706 | + | |
| 707 | + # Determine sensitivity | |
| 708 | + result = self._get_sensitivity(emin, emax, | |
| 709 | + bkg_model, full_model) | |
| 710 | + | |
| 711 | + # Write results | |
| 712 | + if ieng == 0: | |
| 713 | + f = open(self._outfile.url(), 'w') | |
| 714 | + writer = csv.DictWriter(f, colnames) | |
| 715 | + headers = {} | |
| 716 | + for n in colnames: | |
| 717 | + headers[n] = n | |
| 718 | + writer.writerow(headers) | |
| 719 | + writer.writerow(result) | |
| 720 | + f.close() | |
| 721 | + else: | |
| 722 | + f = open(self._outfile.url(), 'a') | |
| 723 | + writer = csv.DictWriter(f, colnames) | |
| 724 | + writer.writerow(result) | |
| 725 | + f.close() | |
| 726 | + | |
| 727 | + # Append results | |
| 728 | + results.append(result) | |
| 729 | + | |
| 730 | + # Return | |
| 731 | + return | |
| 732 | + | |
| 733 | + def execute(self): | |
| 734 | + """ | |
| 735 | + Execute the script. | |
| 736 | + """ | |
| 737 | + # Run the script | |
| 738 | + self.run() | |
| 739 | + | |
| 740 | + # Return | |
| 741 | + return | |
| 751 | 742 | |
| 752 | - # Return flux | |
| 753 | - return flux | |
| 754 | 743 | |
| 755 | 744 | |
| 756 | 745 | # ======================== # |
| 757 | 746 | # Main routine entry point # |
| 758 | 747 | # ======================== # |
| 759 | 748 | if __name__ == '__main__': |
| 760 | - """ | |
| 761 | - CTA ctlike-based sensitivity estimator. | |
| 762 | - """ | |
| 749 | + | |
| 763 | 750 | # Create instance of application |
| 764 | 751 | app = cssens(sys.argv) |
| 765 | 752 | |
| 753 | + # Open logfile | |
| 754 | + app._logFileOpen() | |
| 755 | + | |
| 766 | 756 | # Run application |
| 767 | 757 | app.execute() | ... | ... |
cscripts/csspec.par
0 → 100644
| 1 | +############################################################################# | |
| 2 | +# # | |
| 3 | +# CTA Science Analysis Tools # | |
| 4 | +# # | |
| 5 | +# ------------------------------------------------------------------------- # | |
| 6 | +# # | |
| 7 | +# File: csspec.par # | |
| 8 | +# Version: 1.1.0 # | |
| 9 | +# # | |
| 10 | +# Author: Juergen Knoedlseder # | |
| 11 | +# Jurgen.Knodlseder@irap.omp.eu # | |
| 12 | +# IRAP # | |
| 13 | +# # | |
| 14 | +# Purpose: Parameter file for the csspec script # | |
| 15 | +# # | |
| 16 | +############################################################################# | |
| 17 | +# | |
| 18 | +# Input and output parameters | |
| 19 | +#============================ | |
| 20 | +inobs, f, h, events.fits,,, "Input event list, counts cube, or observation definition XML file" | |
| 21 | +inmodel, f, a, $CTOOLS/share/models/crab.xml,,, "Input model XML file" | |
| 22 | +srcname, s, a, Crab,,, "Source name" | |
| 23 | +expcube, f, a, NONE,,, "Input exposure cube file (only needed for stacked analysis)" | |
| 24 | +psfcube, f, a, NONE,,, "Input PSF cube file (only needed for stacked analysis)" | |
| 25 | +edispcube, f, a, NONE,,, "Input energy dispersion cube file (only needed for stacked analysis)" | |
| 26 | +bkgcube, f, a, NONE,,, "Input background cube file (only needed for stacked analysis)" | |
| 27 | +caldb, s, a, prod2,,, "Calibration database" | |
| 28 | +irf, s, a, South_0.5h,,, "Instrument response function" | |
| 29 | +edisp, b, h, no,,, "Apply energy dispersion?" | |
| 30 | +outfile, f, a, spectrum.fits,,, "Output spectrum file" | |
| 31 | + | |
| 32 | +# | |
| 33 | +# Script parameters | |
| 34 | +#================== | |
| 35 | +emin, r, a, 0.1,,, "Lower energy limit (TeV)" | |
| 36 | +emax, r, a, 100.0,,, "Upper energy limit (TeV)" | |
| 37 | +enumbins, i, a, 20,,, "Number of energy bins (0=unbinned)" | |
| 38 | +ebinalg, s, a, LOG,LIN|LOG|FILE,, "Binning algorithm" | |
| 39 | +ebinfile, f, a, NONE,,, "Name of the file containing the energy bin definition" | |
| 40 | +calc_ts, b, h, yes,,, "Compute TS value in each bin" | |
| 41 | +calc_ulim, b, h, yes,,, "Compute upper limit in each bin" | |
| 42 | +fix_srcs, b, h, yes,,, "Fix other skymodel parameters" | |
| 43 | +fix_bkg, b, h, no,,, "Fix background parameters" | |
| 44 | + | |
| 45 | +# | |
| 46 | +# Standard parameters | |
| 47 | +#==================== | |
| 48 | +chatter, i, h, 2,0,4, "Chattiness of output" | |
| 49 | +clobber, b, h, yes,,, "Overwrite existing output files with new output files?" | |
| 50 | +debug, b, h, no,,, "Debugging mode activated" | |
| 51 | +mode, s, h, ql,,, "Mode of automatic parameters" | |
| 52 | +logfile, f, h, csspec.log,,, "Log filename" | ... | ... |
cscripts/csspec.py
| 1 | 1 | #! /usr/bin/env python |
| 2 | 2 | # ========================================================================== |
| 3 | -# Spectral points generation script. | |
| 3 | +# Generates a spectrum. | |
| 4 | 4 | # |
| 5 | 5 | # Copyright (C) 2014-2016 Michael Mayer |
| 6 | 6 | # |
| ... | ... | @@ -28,47 +28,57 @@ import sys |
| 28 | 28 | # ============ # |
| 29 | 29 | class csspec(ctools.cscript): |
| 30 | 30 | """ |
| 31 | + Generates a spectrum. | |
| 32 | + | |
| 31 | 33 | This class implements the creation of spectral points. It derives from |
| 32 | 34 | the ctools.cscript class which provides support for parameter files, |
| 33 | 35 | command line arguments, and logging. In that way the Python script |
| 34 | 36 | behaves just as a regular ctool. |
| 35 | 37 | """ |
| 38 | + | |
| 39 | + # Constructors and destructors | |
| 36 | 40 | def __init__(self, *argv): |
| 37 | 41 | """ |
| 38 | 42 | Constructor. |
| 39 | 43 | """ |
| 40 | - | |
| 41 | 44 | # Set name |
| 42 | - self.name = "csspec" | |
| 43 | - self.version = "1.1.0" | |
| 44 | - | |
| 45 | - # Initialise some members | |
| 46 | - self.obs = gammalib.GObservations() | |
| 47 | - self.fits = None | |
| 45 | + self._name = "csspec" | |
| 46 | + self._version = "1.1.0" | |
| 48 | 47 | |
| 49 | 48 | # Initialise some members |
| 49 | + self._ebounds = gammalib.GEbounds() | |
| 50 | + self._fits = None | |
| 51 | + self._binned_mode = False | |
| 52 | + self._srcname = "" | |
| 53 | + self._edisp = False | |
| 54 | + self._outfile = "NONE" | |
| 55 | + self._calc_ulimit = True | |
| 56 | + self._calc_ts = True | |
| 57 | + self._fix_bkg = False | |
| 58 | + self._fix_srcs = True | |
| 59 | + self._chatter = 2 | |
| 60 | + self._clobber = True | |
| 61 | + self._debug = False | |
| 62 | + self._log_clients = False | |
| 63 | + | |
| 64 | + # Initialise observation | |
| 50 | 65 | if len(argv) > 0 and isinstance(argv[0],gammalib.GObservations): |
| 51 | - self.obs = argv[0] | |
| 52 | - argv = argv[1:] | |
| 66 | + self._obs = argv[0] | |
| 67 | + argv = argv[1:] | |
| 53 | 68 | else: |
| 54 | - self.obs = gammalib.GObservations() | |
| 55 | - self.obs.clear() | |
| 56 | - self.m_outfile = "" | |
| 57 | - | |
| 58 | - # Make sure that parfile exists | |
| 59 | - file = self.parfile() | |
| 69 | + self._obs = gammalib.GObservations() | |
| 60 | 70 | |
| 61 | 71 | # Initialise application |
| 62 | 72 | if len(argv) == 0: |
| 63 | - ctools.cscript.__init__(self, self.name, self.version) | |
| 73 | + ctools.cscript.__init__(self, self._name, self._version) | |
| 64 | 74 | elif len(argv) ==1: |
| 65 | - ctools.cscript.__init__(self, self.name, self.version, *argv) | |
| 75 | + ctools.cscript.__init__(self, self._name, self._version, *argv) | |
| 66 | 76 | else: |
| 67 | 77 | raise TypeError("Invalid number of arguments given.") |
| 68 | 78 | |
| 69 | 79 | # Set logger properties |
| 70 | - self.log_header() | |
| 71 | - self.log.date(True) | |
| 80 | + self._log_header() | |
| 81 | + self._log.date(True) | |
| 72 | 82 | |
| 73 | 83 | # Return |
| 74 | 84 | return |
| ... | ... | @@ -77,121 +87,81 @@ class csspec(ctools.cscript): |
| 77 | 87 | """ |
| 78 | 88 | Destructor. |
| 79 | 89 | """ |
| 80 | - # Write separator into logger | |
| 81 | - if self.logTerse(): | |
| 82 | - self.log("\n") | |
| 83 | - | |
| 84 | 90 | # Return |
| 85 | 91 | return |
| 86 | 92 | |
| 87 | - def parfile(self): | |
| 88 | - """ | |
| 89 | - Check if parfile exists. If parfile does not exist then create a | |
| 90 | - default parfile. This kluge avoids shipping the cscript with a parfile. | |
| 91 | - """ | |
| 92 | - # Set parfile name | |
| 93 | - parfile = self.name+".par" | |
| 94 | - | |
| 95 | - try: | |
| 96 | - pars = gammalib.GApplicationPars(parfile) | |
| 97 | - except: | |
| 98 | - # Signal if parfile was not found | |
| 99 | - sys.stdout.write("Parfile "+parfile+" not found. Create default parfile.\n") | |
| 100 | - | |
| 101 | - # Create default parfile | |
| 102 | - pars = gammalib.GApplicationPars() | |
| 103 | - pars.append(gammalib.GApplicationPar("inobs","f","a","events.fits","","","Input event list, counts cube, or observation definition XML file")) | |
| 104 | - pars.append(gammalib.GApplicationPar("inmodel","f","a","$CTOOLS/share/models/crab.xml","","","Input model XML file")) | |
| 105 | - pars.append(gammalib.GApplicationPar("srcname","s","a","Crab","","","Source name")) | |
| 106 | - pars.append(gammalib.GApplicationPar("expcube","f","a","NONE","","","Input exposure cube file (only needed for stacked analysis)")) | |
| 107 | - pars.append(gammalib.GApplicationPar("psfcube","f","a","NONE","","","Input PSF cube file (only needed for stacked analysis)")) | |
| 108 | - pars.append(gammalib.GApplicationPar("edispcube","f","a","NONE","","","Input energy dispersion cube file (only needed for stacked analysis)")) | |
| 109 | - pars.append(gammalib.GApplicationPar("bkgcube","f","a","NONE","","","Input background cube file (only needed for stacked analysis)")) | |
| 110 | - pars.append(gammalib.GApplicationPar("caldb","s","a","prod2","","","Calibration database")) | |
| 111 | - pars.append(gammalib.GApplicationPar("irf","s","a","South_0.5h","","","Instrument response function")) | |
| 112 | - pars.append(gammalib.GApplicationPar("edisp","b","h","no","","","Apply energy dispersion?")) | |
| 113 | - pars.append(gammalib.GApplicationPar("outfile","f","a","spectrum.fits","","","Output spectrum file")) | |
| 114 | - pars.append(gammalib.GApplicationPar("emin","r","a","0.1","","","Lower energy limit for spectral points (TeV)")) | |
| 115 | - pars.append(gammalib.GApplicationPar("emax","r","a","100.0","","","Upper energy limit for spectral points (TeV)")) | |
| 116 | - pars.append(gammalib.GApplicationPar("enumbins","i","a","20","1","10000","Number of spectral points")) | |
| 117 | - pars.append(gammalib.GApplicationPar("ebinalg","s","a","LOG","FILE|LIN|LOG","", "Algorithm for defining energy bins")) | |
| 118 | - pars.append(gammalib.GApplicationPar("ebinfile","f","a","NONE","","", "Name of the file containing the energy bin definition")) | |
| 119 | - pars.append(gammalib.GApplicationPar("calc_ts","b","h","yes","yes|no","","Compute TS value in each bin")) | |
| 120 | - pars.append(gammalib.GApplicationPar("calc_ulim","b","h","yes","yes|no","","Compute upper limit in each bin")) | |
| 121 | - pars.append(gammalib.GApplicationPar("fix_srcs","b","h","yes","yes|no","","Fix other skymodel parameters")) | |
| 122 | - pars.append(gammalib.GApplicationPar("fix_bkg","b","h","no","yes|no","","Fix background parameters")) | |
| 123 | - pars.append_standard() | |
| 124 | - pars.append(gammalib.GApplicationPar("logfile","f","h","csspec.log","","","Log filename")) | |
| 125 | - pars.save(parfile) | |
| 126 | 93 | |
| 127 | - # Return | |
| 128 | - return | |
| 129 | - | |
| 130 | - def get_parameters(self): | |
| 94 | + # Private methods | |
| 95 | + def _get_parameters(self): | |
| 131 | 96 | """ |
| 132 | 97 | Get parameters from parfile and setup the observation. |
| 133 | 98 | """ |
| 134 | 99 | # Set observation if not done before |
| 135 | - if self.obs == None or self.obs.size() == 0: | |
| 100 | + if self._obs == None or self._obs.size() == 0: | |
| 136 | 101 | self._require_inobs("csspec::get_parameters()") |
| 137 | - self.obs = self._get_observations() | |
| 102 | + self._obs = self._get_observations() | |
| 138 | 103 | |
| 139 | 104 | # Check if we have one binned cta observation, i.e. if we are in binned mode |
| 140 | - self.m_binned_mode = False | |
| 141 | - if self.obs.size() == 1: | |
| 142 | - if self.obs[0].classname() == "GCTAObservation": | |
| 143 | - if self.obs[0].eventtype() == "CountsCube": | |
| 144 | - self.m_binned_mode = True | |
| 105 | + self._binned_mode = False | |
| 106 | + if self._obs.size() == 1: | |
| 107 | + if self._obs[0].classname() == "GCTAObservation": | |
| 108 | + if self._obs[0].eventtype() == "CountsCube": | |
| 109 | + self._binned_mode = True | |
| 145 | 110 | |
| 146 | 111 | # Set models if we have none |
| 147 | - if self.obs.models().size() == 0: | |
| 148 | - self.obs.models(self["inmodel"].filename()) | |
| 112 | + if self._obs.models().size() == 0: | |
| 113 | + self._obs.models(self["inmodel"].filename()) | |
| 149 | 114 | |
| 150 | 115 | # Get source name |
| 151 | - self.m_srcname = self["srcname"].string() | |
| 116 | + self._srcname = self["srcname"].string() | |
| 152 | 117 | |
| 153 | 118 | # Set ebounds |
| 154 | - self.set_ebounds() | |
| 119 | + self._set_ebounds() | |
| 155 | 120 | |
| 156 | 121 | # Get edisp flag |
| 157 | - self.m_edisp = self["edisp"].boolean() | |
| 158 | - | |
| 159 | - # Read other parameters | |
| 160 | - self.m_outfile = self["outfile"].filename() | |
| 122 | + self._edisp = self["edisp"].boolean() | |
| 161 | 123 | |
| 162 | 124 | # Get other parameeters |
| 163 | - self.m_calc_ulimit = self["calc_ulim"].boolean() | |
| 164 | - self.m_calc_ts = self["calc_ts"].boolean() | |
| 165 | - self.m_fix_bkg = self["fix_bkg"].boolean() | |
| 166 | - self.m_fix_srcs = self["fix_srcs"].boolean() | |
| 125 | + self._calc_ulimit = self["calc_ulim"].boolean() | |
| 126 | + self._calc_ts = self["calc_ts"].boolean() | |
| 127 | + self._fix_bkg = self["fix_bkg"].boolean() | |
| 128 | + self._fix_srcs = self["fix_srcs"].boolean() | |
| 167 | 129 | |
| 168 | 130 | # Set some fixed parameters |
| 169 | - self.m_log = False # Logging in client tools | |
| 170 | - self.m_chatter = self["chatter"].integer() | |
| 171 | - self.m_clobber = self["clobber"].boolean() | |
| 172 | - self.m_debug = self["debug"].boolean() | |
| 131 | + self._chatter = self["chatter"].integer() | |
| 132 | + self._clobber = self["clobber"].boolean() | |
| 133 | + self._debug = self["debug"].boolean() | |
| 134 | + | |
| 135 | + # Read ahead output parameters | |
| 136 | + if (self._read_ahead()): | |
| 137 | + self._outfile = self["outfile"].filename() | |
| 138 | + | |
| 139 | + # Write input parameters into logger | |
| 140 | + if self._logTerse(): | |
| 141 | + self._log_parameters() | |
| 142 | + self._log("\n") | |
| 173 | 143 | |
| 174 | 144 | # Return |
| 175 | 145 | return |
| 176 | 146 | |
| 177 | - def set_ebounds(self): | |
| 147 | + def _set_ebounds(self): | |
| 178 | 148 | """ |
| 179 | 149 | Set energy boundaries. |
| 180 | 150 | """ |
| 181 | 151 | # Get ebounds |
| 182 | - if self.m_binned_mode: | |
| 152 | + if self._binned_mode: | |
| 183 | 153 | |
| 184 | 154 | # Extract cube ebounds |
| 185 | - cube_ebounds = self.obs[0].events().ebounds() | |
| 155 | + cube_ebounds = self._obs[0].events().ebounds() | |
| 186 | 156 | |
| 187 | 157 | # Read user parameters |
| 188 | - self.m_enumbins = self["enumbins"].integer() | |
| 189 | - self.m_emin = self["emin"].real() - 1e-6 # Rounding tolerance | |
| 190 | - self.m_emax = self["emax"].real() + 1e-6 # Rounding tolerance | |
| 158 | + enumbins = self["enumbins"].integer() | |
| 159 | + emin_val = self["emin"].real() - 1e-6 # Rounding tolerance | |
| 160 | + emax_val = self["emax"].real() + 1e-6 # Rounding tolerance | |
| 191 | 161 | |
| 192 | 162 | # Set energy range |
| 193 | - emin = gammalib.GEnergy(self.m_emin, "TeV") | |
| 194 | - emax = gammalib.GEnergy(self.m_emax, "TeV") | |
| 163 | + emin = gammalib.GEnergy(emin_val, "TeV") | |
| 164 | + emax = gammalib.GEnergy(emax_val, "TeV") | |
| 195 | 165 | |
| 196 | 166 | # Determine all cube layers that overlap with the [emin,emax] |
| 197 | 167 | # energy range. |
| ... | ... | @@ -210,14 +180,14 @@ class csspec(ctools.cscript): |
| 210 | 180 | raise RuntimeError(msg) |
| 211 | 181 | |
| 212 | 182 | # Determine number of layers to use for each spectral bin |
| 213 | - n_layers = int(len(use_layers) / self.m_enumbins) | |
| 183 | + n_layers = int(len(use_layers) / enumbins) | |
| 214 | 184 | |
| 215 | 185 | # Don't allow zero layers |
| 216 | 186 | if n_layers == 0: |
| 217 | 187 | n_layers = 1 |
| 218 | 188 | |
| 219 | 189 | # Create energy boundaries |
| 220 | - self.m_ebounds = gammalib.GEbounds() | |
| 190 | + self._ebounds = gammalib.GEbounds() | |
| 221 | 191 | i_start = 0 |
| 222 | 192 | i_stop = n_layers - 1 |
| 223 | 193 | while i_start < len(use_layers): |
| ... | ... | @@ -225,51 +195,13 @@ class csspec(ctools.cscript): |
| 225 | 195 | i_stop = len(use_layers) - 1 |
| 226 | 196 | ebinmin = cube_ebounds.emin(use_layers[i_start]) |
| 227 | 197 | ebinmax = cube_ebounds.emax(use_layers[i_stop]) |
| 228 | - self.m_ebounds.append(ebinmin, ebinmax) | |
| 198 | + self._ebounds.append(ebinmin, ebinmax) | |
| 229 | 199 | i_start += n_layers |
| 230 | 200 | i_stop += n_layers |
| 231 | - #for i in range(len(use_layers))[::n_layers]: | |
| 232 | - # i_start = i | |
| 233 | - # i_stop = i + n_layers - 1 | |
| 234 | - # if i_stop >= len(use_layers): | |
| 235 | - # i_stop = len(use_layers) - 1 | |
| 236 | - # ebinmin = cube_ebounds.emin(use_layers[i_start]) | |
| 237 | - # ebinmax = cube_ebounds.emax(use_layers[i_stop]) | |
| 238 | - # self.m_ebounds.append(ebinmin, ebinmax) | |
| 239 | 201 | |
| 240 | 202 | # Unbinned mode |
| 241 | 203 | else: |
| 242 | - self.m_ebounds = self._create_ebounds() | |
| 243 | - | |
| 244 | - # Return | |
| 245 | - return | |
| 246 | - | |
| 247 | - def models(self, models): | |
| 248 | - """ | |
| 249 | - Set model. | |
| 250 | - """ | |
| 251 | - # Copy models | |
| 252 | - self.obs.models(models.clone()) | |
| 253 | - | |
| 254 | - # Return | |
| 255 | - return | |
| 256 | - | |
| 257 | - def spectrum(self): | |
| 258 | - """ | |
| 259 | - Return spectrum as FITS object. | |
| 260 | - """ | |
| 261 | - # Return | |
| 262 | - return self.fits | |
| 263 | - | |
| 264 | - def execute(self): | |
| 265 | - """ | |
| 266 | - Execute the script. | |
| 267 | - """ | |
| 268 | - # Run the script | |
| 269 | - self.run() | |
| 270 | - | |
| 271 | - # Save residual map | |
| 272 | - self.fits.saveto(self.m_outfile, self.m_clobber) | |
| 204 | + self._ebounds = self._create_ebounds() | |
| 273 | 205 | |
| 274 | 206 | # Return |
| 275 | 207 | return |
| ... | ... | @@ -279,91 +211,86 @@ class csspec(ctools.cscript): |
| 279 | 211 | Run the script. |
| 280 | 212 | """ |
| 281 | 213 | # Switch screen logging on in debug mode |
| 282 | - if self.logDebug(): | |
| 283 | - self.log.cout(True) | |
| 214 | + if self._logDebug(): | |
| 215 | + self._log.cout(True) | |
| 284 | 216 | |
| 285 | 217 | # Get parameters |
| 286 | - self.get_parameters() | |
| 287 | - | |
| 288 | - # Write input parameters into logger | |
| 289 | - if self.logTerse(): | |
| 290 | - self.log_parameters() | |
| 291 | - self.log("\n") | |
| 218 | + self._get_parameters() | |
| 292 | 219 | |
| 293 | 220 | # Write spectral binning into header |
| 294 | - if self.logTerse(): | |
| 295 | - self.log("\n") | |
| 296 | - self.log.header1("Spectral binning") | |
| 297 | - if self.m_binned_mode: | |
| 298 | - cube_ebounds = self.obs[0].events().ebounds() | |
| 299 | - self.log.parformat("Counts cube energy range") | |
| 300 | - self.log(str(cube_ebounds.emin())) | |
| 301 | - self.log(" - ") | |
| 302 | - self.log(str(cube_ebounds.emax())) | |
| 303 | - self.log("\n") | |
| 304 | - for i in range(self.m_ebounds.size()): | |
| 305 | - self.log.parformat("Bin "+str(i+1)) | |
| 306 | - self.log(str(self.m_ebounds.emin(i))) | |
| 307 | - self.log(" - ") | |
| 308 | - self.log(str(self.m_ebounds.emax(i))) | |
| 309 | - self.log("\n") | |
| 221 | + if self._logTerse(): | |
| 222 | + self._log("\n") | |
| 223 | + self._log.header1("Spectral binning") | |
| 224 | + if self._binned_mode: | |
| 225 | + cube_ebounds = self._obs[0].events().ebounds() | |
| 226 | + self._log.parformat("Counts cube energy range") | |
| 227 | + self._log(str(cube_ebounds.emin())) | |
| 228 | + self._log(" - ") | |
| 229 | + self._log(str(cube_ebounds.emax())) | |
| 230 | + self._log("\n") | |
| 231 | + for i in range(self._ebounds.size()): | |
| 232 | + self._log.parformat("Bin "+str(i+1)) | |
| 233 | + self._log(str(self._ebounds.emin(i))) | |
| 234 | + self._log(" - ") | |
| 235 | + self._log(str(self._ebounds.emax(i))) | |
| 236 | + self._log("\n") | |
| 310 | 237 | |
| 311 | 238 | # Write observation into logger |
| 312 | - if self.logTerse(): | |
| 313 | - self.log("\n") | |
| 314 | - self.log.header1("Observation") | |
| 315 | - self.log(str(self.obs)) | |
| 316 | - self.log("\n") | |
| 239 | + if self._logTerse(): | |
| 240 | + self._log("\n") | |
| 241 | + self._log.header1("Observation") | |
| 242 | + self._log(str(self._obs)) | |
| 243 | + self._log("\n") | |
| 317 | 244 | |
| 318 | 245 | # Write header |
| 319 | - if self.logTerse(): | |
| 320 | - self.log("\n") | |
| 321 | - self.log.header1("Adjust model parameters") | |
| 246 | + if self._logTerse(): | |
| 247 | + self._log("\n") | |
| 248 | + self._log.header1("Adjust model parameters") | |
| 322 | 249 | |
| 323 | 250 | # Adjust model parameters dependent on input user parameters |
| 324 | - for model in self.obs.models(): | |
| 251 | + for model in self._obs.models(): | |
| 325 | 252 | |
| 326 | 253 | # Set TS flag for all models to false. |
| 327 | 254 | # Source of interest will be set to true later |
| 328 | 255 | model.tscalc(False) |
| 329 | 256 | |
| 330 | 257 | # Log model name |
| 331 | - if self.logExplicit(): | |
| 332 | - self.log.header3(model.name()) | |
| 258 | + if self._logExplicit(): | |
| 259 | + self._log.header3(model.name()) | |
| 333 | 260 | |
| 334 | 261 | # Deal with the source of interest |
| 335 | - if model.name() == self.m_srcname: | |
| 262 | + if model.name() == self._srcname: | |
| 336 | 263 | for par in model: |
| 337 | - if par.is_free() and self.logExplicit(): | |
| 338 | - self.log(" Fixing \""+par.name()+"\"\n") | |
| 264 | + if par.is_free() and self._logExplicit(): | |
| 265 | + self._log(" Fixing \""+par.name()+"\"\n") | |
| 339 | 266 | par.fix() |
| 340 | 267 | normpar = model.spectral()[0] |
| 341 | - if normpar.is_fixed() and self.logExplicit(): | |
| 342 | - self.log(" Freeing \""+normpar.name()+"\"\n") | |
| 268 | + if normpar.is_fixed() and self._logExplicit(): | |
| 269 | + self._log(" Freeing \""+normpar.name()+"\"\n") | |
| 343 | 270 | normpar.free() |
| 344 | - if self.m_calc_ts: | |
| 271 | + if self._calc_ts: | |
| 345 | 272 | model.tscalc(True) |
| 346 | 273 | |
| 347 | - elif self.m_fix_bkg and not model.classname() == "GModelSky": | |
| 274 | + elif self._fix_bkg and not model.classname() == "GModelSky": | |
| 348 | 275 | for par in model: |
| 349 | - if par.is_free() and self.logExplicit(): | |
| 350 | - self.log(" Fixing \""+par.name()+"\"\n") | |
| 276 | + if par.is_free() and self._logExplicit(): | |
| 277 | + self._log(" Fixing \""+par.name()+"\"\n") | |
| 351 | 278 | par.fix() |
| 352 | 279 | |
| 353 | - elif self.m_fix_srcs and model.classname() == "GModelSky": | |
| 280 | + elif self._fix_srcs and model.classname() == "GModelSky": | |
| 354 | 281 | for par in model: |
| 355 | - if par.is_free() and self.logExplicit(): | |
| 356 | - self.log(" Fixing \""+par.name()+"\"\n") | |
| 282 | + if par.is_free() and self._logExplicit(): | |
| 283 | + self._log(" Fixing \""+par.name()+"\"\n") | |
| 357 | 284 | par.fix() |
| 358 | 285 | |
| 359 | 286 | # Write header |
| 360 | - if self.logTerse(): | |
| 361 | - self.log("\n") | |
| 362 | - self.log.header1("Generate spectrum") | |
| 363 | - self.log(str(self.m_ebounds)) | |
| 287 | + if self._logTerse(): | |
| 288 | + self._log("\n") | |
| 289 | + self._log.header1("Generate spectrum") | |
| 290 | + self._log(str(self._ebounds)) | |
| 364 | 291 | |
| 365 | 292 | # Initialise FITS Table with extension "SPECTRUM" |
| 366 | - table = gammalib.GFitsBinTable(self.m_ebounds.size()) | |
| 293 | + table = gammalib.GFitsBinTable(self._ebounds.size()) | |
| 367 | 294 | table.extname("SPECTRUM") |
| 368 | 295 | |
| 369 | 296 | # Add Header for compatibility with gammalib.GMWLSpectrum |
| ... | ... | @@ -371,14 +298,15 @@ class csspec(ctools.cscript): |
| 371 | 298 | table.card("TELESCOP", "CTA", "Name of Telescope") |
| 372 | 299 | |
| 373 | 300 | # Create FITS table columns |
| 374 | - energy = gammalib.GFitsTableDoubleCol("Energy", self.m_ebounds.size()) | |
| 375 | - energy_low = gammalib.GFitsTableDoubleCol("ed_Energy", self.m_ebounds.size()) | |
| 376 | - energy_high = gammalib.GFitsTableDoubleCol("eu_Energy", self.m_ebounds.size()) | |
| 377 | - flux = gammalib.GFitsTableDoubleCol("Flux", self.m_ebounds.size()) | |
| 378 | - flux_err = gammalib.GFitsTableDoubleCol("e_Flux", self.m_ebounds.size()) | |
| 379 | - TSvalues = gammalib.GFitsTableDoubleCol("TS", self.m_ebounds.size()) | |
| 380 | - ulim_values = gammalib.GFitsTableDoubleCol("UpperLimit", self.m_ebounds.size()) | |
| 381 | - Npred_values = gammalib.GFitsTableDoubleCol("Npred", self.m_ebounds.size()) | |
| 301 | + nrows = self._ebounds.size() | |
| 302 | + energy = gammalib.GFitsTableDoubleCol("Energy", nrows) | |
| 303 | + energy_low = gammalib.GFitsTableDoubleCol("ed_Energy", nrows) | |
| 304 | + energy_high = gammalib.GFitsTableDoubleCol("eu_Energy", nrows) | |
| 305 | + flux = gammalib.GFitsTableDoubleCol("Flux", nrows) | |
| 306 | + flux_err = gammalib.GFitsTableDoubleCol("e_Flux", nrows) | |
| 307 | + TSvalues = gammalib.GFitsTableDoubleCol("TS", nrows) | |
| 308 | + ulim_values = gammalib.GFitsTableDoubleCol("UpperLimit", nrows) | |
| 309 | + Npred_values = gammalib.GFitsTableDoubleCol("Npred", nrows) | |
| 382 | 310 | energy.unit("TeV") |
| 383 | 311 | energy_low.unit("TeV") |
| 384 | 312 | energy_high.unit("TeV") |
| ... | ... | @@ -387,17 +315,17 @@ class csspec(ctools.cscript): |
| 387 | 315 | ulim_values.unit("erg/cm2/s") |
| 388 | 316 | |
| 389 | 317 | # Loop over energy bins |
| 390 | - for i in range(self.m_ebounds.size()): | |
| 318 | + for i in range(nrows): | |
| 391 | 319 | |
| 392 | 320 | # Log information |
| 393 | - if self.logExplicit(): | |
| 394 | - self.log("\n") | |
| 395 | - self.log.header2("Energy bin "+str(i+1)) | |
| 321 | + if self._logExplicit(): | |
| 322 | + self._log("\n") | |
| 323 | + self._log.header2("Energy bin "+str(i+1)) | |
| 396 | 324 | |
| 397 | 325 | # Get energy boundaries |
| 398 | - emin = self.m_ebounds.emin(i) | |
| 399 | - emax = self.m_ebounds.emax(i) | |
| 400 | - elogmean = self.m_ebounds.elogmean(i) | |
| 326 | + emin = self._ebounds.emin(i) | |
| 327 | + emax = self._ebounds.emax(i) | |
| 328 | + elogmean = self._ebounds.elogmean(i) | |
| 401 | 329 | elogmean2 = elogmean.MeV() * elogmean.MeV() |
| 402 | 330 | |
| 403 | 331 | # Store energy as TeV |
| ... | ... | @@ -407,15 +335,15 @@ class csspec(ctools.cscript): |
| 407 | 335 | energy_low[i] = (elogmean - emin).TeV() |
| 408 | 336 | energy_high[i] = (emax - elogmean).TeV() |
| 409 | 337 | |
| 410 | - # use ctselect for unbinned analysis | |
| 411 | - if not self.m_binned_mode: | |
| 338 | + # Use ctselect for unbinned analysis | |
| 339 | + if not self._binned_mode: | |
| 412 | 340 | |
| 413 | 341 | # Log information |
| 414 | - if self.logExplicit(): | |
| 415 | - self.log.header3("Selecting events") | |
| 342 | + if self._logExplicit(): | |
| 343 | + self._log.header3("Selecting events") | |
| 416 | 344 | |
| 417 | 345 | # Select events |
| 418 | - select = ctools.ctselect(self.obs) | |
| 346 | + select = ctools.ctselect(self._obs) | |
| 419 | 347 | select["emin"] = emin.TeV() |
| 420 | 348 | select["emax"] = emax.TeV() |
| 421 | 349 | select["tmin"] = "UNDEFINED" |
| ... | ... | @@ -428,15 +356,15 @@ class csspec(ctools.cscript): |
| 428 | 356 | # Retrieve observation |
| 429 | 357 | obs = select.obs() |
| 430 | 358 | |
| 431 | - # use ctcubemask for binned analysis | |
| 359 | + # Use ctcubemask for binned analysis | |
| 432 | 360 | else: |
| 433 | 361 | |
| 434 | 362 | # Header |
| 435 | - if self.logExplicit(): | |
| 436 | - self.log.header3("Filtering cube") | |
| 363 | + if self._logExplicit(): | |
| 364 | + self._log.header3("Filtering cube") | |
| 437 | 365 | |
| 438 | 366 | # Select layers |
| 439 | - cubemask = ctools.ctcubemask(self.obs) | |
| 367 | + cubemask = ctools.ctcubemask(self._obs) | |
| 440 | 368 | cubemask["regfile"] = "NONE" |
| 441 | 369 | cubemask["ra"] = "UNDEFINED" |
| 442 | 370 | cubemask["dec"] = "UNDEFINED" |
| ... | ... | @@ -449,22 +377,22 @@ class csspec(ctools.cscript): |
| 449 | 377 | obs = cubemask.obs() |
| 450 | 378 | |
| 451 | 379 | # Header |
| 452 | - if self.logExplicit(): | |
| 453 | - self.log.header3("Performing fit") | |
| 380 | + if self._logExplicit(): | |
| 381 | + self._log.header3("Performing fit") | |
| 454 | 382 | |
| 455 | 383 | # Likelihood |
| 456 | 384 | like = ctools.ctlike(obs) |
| 457 | - like["edisp"] = self.m_edisp | |
| 385 | + like["edisp"] = self._edisp | |
| 458 | 386 | like.run() |
| 459 | 387 | |
| 460 | 388 | # Skip bin if no event was present |
| 461 | 389 | if like.obs().logL() == 0.0: |
| 462 | 390 | |
| 463 | 391 | # Log information |
| 464 | - if self.logExplicit(): | |
| 465 | - self.log("No event in this bin. ") | |
| 466 | - self.log("Likelihood is zero. ") | |
| 467 | - self.log("Bin is skipped.") | |
| 392 | + if self._logExplicit(): | |
| 393 | + self._log("No event in this bin. ") | |
| 394 | + self._log("Likelihood is zero. ") | |
| 395 | + self._log("Bin is skipped.") | |
| 468 | 396 | |
| 469 | 397 | # Set all values to 0 |
| 470 | 398 | flux[i] = 0.0 |
| ... | ... | @@ -476,19 +404,19 @@ class csspec(ctools.cscript): |
| 476 | 404 | |
| 477 | 405 | # Get results |
| 478 | 406 | fitted_models = like.obs().models() |
| 479 | - source = fitted_models[self.m_srcname] | |
| 407 | + source = fitted_models[self._srcname] | |
| 480 | 408 | |
| 481 | 409 | # Calculate Upper Limit |
| 482 | 410 | ulimit_value = -1.0 |
| 483 | - if self.m_calc_ulimit: | |
| 411 | + if self._calc_ulimit: | |
| 484 | 412 | |
| 485 | 413 | # Logging information |
| 486 | - if self.logExplicit(): | |
| 487 | - self.log.header3("Computing upper limit") | |
| 414 | + if self._logExplicit(): | |
| 415 | + self._log.header3("Computing upper limit") | |
| 488 | 416 | |
| 489 | 417 | # Create upper limit object |
| 490 | 418 | ulimit = ctools.ctulimit(like.obs()) |
| 491 | - ulimit["srcname"] = self.m_srcname | |
| 419 | + ulimit["srcname"] = self._srcname | |
| 492 | 420 | ulimit["eref"] = elogmean.TeV() |
| 493 | 421 | |
| 494 | 422 | # Try to run upper limit and catch exceptions |
| ... | ... | @@ -496,23 +424,23 @@ class csspec(ctools.cscript): |
| 496 | 424 | ulimit.run() |
| 497 | 425 | ulimit_value = ulimit.diff_ulimit() |
| 498 | 426 | except: |
| 499 | - if self.logExplicit(): | |
| 500 | - self.log("Upper limit calculation failed.") | |
| 427 | + if self._logExplicit(): | |
| 428 | + self._log("Upper limit calculation failed.") | |
| 501 | 429 | ulimit_value = -1.0 |
| 502 | 430 | |
| 503 | 431 | # Get TS value |
| 504 | 432 | TS = -1.0 |
| 505 | - if self.m_calc_ts: | |
| 433 | + if self._calc_ts: | |
| 506 | 434 | TS = source.ts() |
| 507 | 435 | |
| 508 | 436 | # Compute Npred value (only works for unbinned analysis) |
| 509 | 437 | Npred = 0.0 |
| 510 | - if not self.m_binned_mode: | |
| 438 | + if not self._binned_mode: | |
| 511 | 439 | for observation in like.obs(): |
| 512 | 440 | Npred += observation.npred(source) |
| 513 | 441 | |
| 514 | 442 | # Get differential flux |
| 515 | - fitted_flux = source.spectral().eval(elogmean,gammalib.GTime()) | |
| 443 | + fitted_flux = source.spectral().eval(elogmean) | |
| 516 | 444 | |
| 517 | 445 | # Compute flux error |
| 518 | 446 | parvalue = source.spectral()[0].value() |
| ... | ... | @@ -532,17 +460,17 @@ class csspec(ctools.cscript): |
| 532 | 460 | ulim_values[i] = ulimit_value * elogmean2 * gammalib.MeV2erg |
| 533 | 461 | |
| 534 | 462 | # Log information |
| 535 | - if self.logTerse(): | |
| 536 | - self.log("\n") | |
| 537 | - self.log.parformat("Bin "+str(i+1)) | |
| 538 | - self.log(str(flux[i])) | |
| 539 | - self.log(" +/- ") | |
| 540 | - self.log(str(flux_err[i])) | |
| 541 | - if self.m_calc_ulimit and ulim_values[i] > 0.0: | |
| 542 | - self.log(" [< "+str(ulim_values[i])+"]") | |
| 543 | - self.log(" erg/cm2/s") | |
| 544 | - if self.m_calc_ts and TSvalues[i] > 0.0: | |
| 545 | - self.log(" (TS = "+str(TS)+")") | |
| 463 | + if self._logTerse(): | |
| 464 | + self._log("\n") | |
| 465 | + self._log.parformat("Bin "+str(i+1)) | |
| 466 | + self._log(str(flux[i])) | |
| 467 | + self._log(" +/- ") | |
| 468 | + self._log(str(flux_err[i])) | |
| 469 | + if self._calc_ulimit and ulim_values[i] > 0.0: | |
| 470 | + self._log(" [< "+str(ulim_values[i])+"]") | |
| 471 | + self._log(" erg/cm2/s") | |
| 472 | + if self._calc_ts and TSvalues[i] > 0.0: | |
| 473 | + self._log(" (TS = "+str(TS)+")") | |
| 546 | 474 | |
| 547 | 475 | # Append filled columns to fits table |
| 548 | 476 | table.append(energy) |
| ... | ... | @@ -555,8 +483,69 @@ class csspec(ctools.cscript): |
| 555 | 483 | table.append(Npred_values) |
| 556 | 484 | |
| 557 | 485 | # Create the FITS file now |
| 558 | - self.fits = gammalib.GFits() | |
| 559 | - self.fits.append(table) | |
| 486 | + self._fits = gammalib.GFits() | |
| 487 | + self._fits.append(table) | |
| 488 | + | |
| 489 | + # Return | |
| 490 | + return | |
| 491 | + | |
| 492 | + def execute(self): | |
| 493 | + """ | |
| 494 | + Execute the script. | |
| 495 | + """ | |
| 496 | + # Read ahead output parameters | |
| 497 | + self._read_ahead(True) | |
| 498 | + | |
| 499 | + # Run the script | |
| 500 | + self.run() | |
| 501 | + | |
| 502 | + # Save spectrum | |
| 503 | + self.save() | |
| 504 | + | |
| 505 | + # Return | |
| 506 | + return | |
| 507 | + | |
| 508 | + def save(self): | |
| 509 | + """ | |
| 510 | + Save spectrum. | |
| 511 | + """ | |
| 512 | + # Write header | |
| 513 | + if self._logTerse(): | |
| 514 | + self._log("\n") | |
| 515 | + self._log.header1("Save spectrum") | |
| 516 | + | |
| 517 | + # Get outmap parameter | |
| 518 | + self._outfile = self["outfile"].filename() | |
| 519 | + | |
| 520 | + # Continue only filename and residual map are valid | |
| 521 | + if self._outfile != "NONE" and self._fits != None: | |
| 522 | + | |
| 523 | + # Log file name | |
| 524 | + if self._logTerse(): | |
| 525 | + self._log("Save spectrum into \""+self._outfile+"\".\n") | |
| 526 | + | |
| 527 | + # Save spectrum | |
| 528 | + self._fits.saveto(self._outfile, self._clobber) | |
| 529 | + | |
| 530 | + # Return | |
| 531 | + return | |
| 532 | + | |
| 533 | + def spectrum(self): | |
| 534 | + """ | |
| 535 | + Return spectrum FITS file. | |
| 536 | + | |
| 537 | + Returns: | |
| 538 | + FITS file containing spectrum. | |
| 539 | + """ | |
| 540 | + # Return | |
| 541 | + return self._fits | |
| 542 | + | |
| 543 | + def models(self, models): | |
| 544 | + """ | |
| 545 | + Set model. | |
| 546 | + """ | |
| 547 | + # Copy models | |
| 548 | + self._obs.models(models.clone()) | |
| 560 | 549 | |
| 561 | 550 | # Return |
| 562 | 551 | return |
| ... | ... | @@ -566,14 +555,12 @@ class csspec(ctools.cscript): |
| 566 | 555 | # Main routine entry point # |
| 567 | 556 | # ======================== # |
| 568 | 557 | if __name__ == '__main__': |
| 569 | - """ | |
| 570 | - Generates spectral points. | |
| 571 | - """ | |
| 558 | + | |
| 572 | 559 | # Create instance of application |
| 573 | 560 | app = csspec(sys.argv) |
| 574 | 561 | |
| 575 | 562 | # Open logfile |
| 576 | - app.logFileOpen() | |
| 563 | + app._logFileOpen() | |
| 577 | 564 | |
| 578 | 565 | # Execute application |
| 579 | 566 | app.execute() | ... | ... |
cscripts/cstsdist.par
0 → 100644
| 1 | +############################################################################# | |
| 2 | +# # | |
| 3 | +# CTA Science Analysis Tools # | |
| 4 | +# # | |
| 5 | +# ------------------------------------------------------------------------- # | |
| 6 | +# # | |
| 7 | +# File: cstsdist.par # | |
| 8 | +# Version: 1.1.0 # | |
| 9 | +# # | |
| 10 | +# Author: Juergen Knoedlseder # | |
| 11 | +# Jurgen.Knodlseder@irap.omp.eu # | |
| 12 | +# IRAP # | |
| 13 | +# # | |
| 14 | +# Purpose: Parameter file for the cstsdist script # | |
| 15 | +# # | |
| 16 | +############################################################################# | |
| 17 | +# | |
| 18 | +# Input and output parameters | |
| 19 | +#============================ | |
| 20 | +inobs, f, h, NONE,,, "Input event list, counts cube, or observation definition XML file" | |
| 21 | +inmodel, f, a, $CTOOLS/share/models/crab.xml,,, "Input model XML file" | |
| 22 | +srcname, s, a, Crab,,, "Source name" | |
| 23 | +expcube, f, a, NONE,,, "Input exposure cube file (only needed for stacked analysis)" | |
| 24 | +psfcube, f, a, NONE,,, "Input PSF cube file (only needed for stacked analysis)" | |
| 25 | +edispcube, f, a, NONE,,, "Input energy dispersion cube file (only needed for stacked analysis)" | |
| 26 | +bkgcube, f, a, NONE,,, "Input background cube file (only needed for stacked analysis)" | |
| 27 | +caldb, s, a, prod2,,, "Calibration database" | |
| 28 | +irf, s, a, South_0.5h,,, "Instrument response function" | |
| 29 | +edisp, b, h, no,,, "Apply energy dispersion?" | |
| 30 | +deadc, r, h, 0.95,0,1, "Deadtime correction factor" | |
| 31 | +outfile, f, a, ts.dat,,, "Output Test Statistic distribution file" | |
| 32 | + | |
| 33 | +# | |
| 34 | +# Script parameters | |
| 35 | +#================== | |
| 36 | +ntrials, i, a, 10,,, "Number of trials" | |
| 37 | +ra, r, a, 83.63,0,360, "RA of pointing (deg)" | |
| 38 | +dec, r, a, 22.01,-90,90, "Dec of pointing (deg)" | |
| 39 | +emin, r, a, 0.1,,, "Lower energy limit (TeV)" | |
| 40 | +emax, r, a, 100.0,,, "Upper energy limit (TeV)" | |
| 41 | +enumbins, i, a, 0,,, "Number of energy bins (0=unbinned)" | |
| 42 | +tmin, r, h, 0.0,,, "Start time (MET in s)" | |
| 43 | +tmax, r, a, 1800.0,,, "Duration (s)" | |
| 44 | +npix, i, a, 200,,, "Number of pixels for binned" | |
| 45 | +binsz, r, a, 0.05,,, "Pixel size for binned (deg/pixel)" | |
| 46 | +rad, r, h, 5.0,0,180, "Radius of ROI (deg)" | |
| 47 | +pattern, s, h, single,single|four,, "Observation pattern" | |
| 48 | +offset, r, h, 1.5,,, "Observation pattern offset (deg)" | |
| 49 | + | |
| 50 | +# | |
| 51 | +# Standard parameters | |
| 52 | +#==================== | |
| 53 | +chatter, i, h, 2,0,4, "Chattiness of output" | |
| 54 | +clobber, b, h, yes,,, "Overwrite existing output files with new output files?" | |
| 55 | +debug, b, h, no,,, "Debugging mode activated" | |
| 56 | +mode, s, h, ql,,, "Mode of automatic parameters" | |
| 57 | +logfile, f, h, cstsdist.log,,, "Log filename" | ... | ... |
cscripts/cstsdist.py
| 1 | 1 | #! /usr/bin/env python |
| 2 | 2 | # ========================================================================== |
| 3 | -# This script generates the TS distribution for a particular model based | |
| 4 | -# on Monte-Carlo simulations. | |
| 3 | +# Generates the TS distribution for a particular model | |
| 5 | 4 | # |
| 6 | 5 | # Copyright (C) 2011-2016 Juergen Knoedlseder |
| 7 | 6 | # |
| ... | ... | @@ -31,38 +30,48 @@ import csv |
| 31 | 30 | # ============== # |
| 32 | 31 | class cstsdist(ctools.cscript): |
| 33 | 32 | """ |
| 33 | + Generates Test Statistic distribution for a model. | |
| 34 | + | |
| 35 | + | |
| 34 | 36 | This class implements the TS distribution generation script. It derives |
| 35 | 37 | from the ctools.cscript class which provides support for parameter |
| 36 | 38 | files, command line arguments, and logging. In that way the Python |
| 37 | 39 | script behaves just as a regular ctool. |
| 38 | 40 | """ |
| 41 | + | |
| 42 | + # Constructors and destructors | |
| 39 | 43 | def __init__(self, *argv): |
| 40 | 44 | """ |
| 41 | 45 | Constructor. |
| 42 | 46 | """ |
| 43 | 47 | # Set name |
| 44 | - self.name = "cstsdist" | |
| 45 | - self.version = "1.1.0" | |
| 48 | + self._name = "cstsdist" | |
| 49 | + self._version = "1.1.0" | |
| 46 | 50 | |
| 47 | 51 | # Initialise some members |
| 48 | - self.obs = None | |
| 49 | - self.bkg_model = None | |
| 50 | - self.full_model = None | |
| 51 | - | |
| 52 | - # Make sure that parfile exists | |
| 53 | - file = self.parfile() | |
| 52 | + self._obs = gammalib.GObservations() | |
| 53 | + self._pattern = "single" | |
| 54 | + self._srcname = "" | |
| 55 | + self._enumbins = 0 | |
| 56 | + self._npix = 0 | |
| 57 | + self._binsz = 0.0 | |
| 58 | + self._outfile = "ts.dat" | |
| 59 | + self._ntrials = 10 | |
| 60 | + self._edisp = False | |
| 61 | + self._debug = False | |
| 62 | + self._log_clients = False | |
| 54 | 63 | |
| 55 | 64 | # Initialise application |
| 56 | 65 | if len(argv) == 0: |
| 57 | - ctools.cscript.__init__(self, self.name, self.version) | |
| 66 | + ctools.cscript.__init__(self, self._name, self._version) | |
| 58 | 67 | elif len(argv) ==1: |
| 59 | - ctools.cscript.__init__(self, self.name, self.version, *argv) | |
| 68 | + ctools.cscript.__init__(self, self._name, self._version, *argv) | |
| 60 | 69 | else: |
| 61 | 70 | raise TypeError("Invalid number of arguments given.") |
| 62 | 71 | |
| 63 | 72 | # Set logger properties |
| 64 | - self.log_header() | |
| 65 | - self.log.date(True) | |
| 73 | + self._log_header() | |
| 74 | + self._log.date(True) | |
| 66 | 75 | |
| 67 | 76 | # Return |
| 68 | 77 | return |
| ... | ... | @@ -71,219 +80,109 @@ class cstsdist(ctools.cscript): |
| 71 | 80 | """ |
| 72 | 81 | Destructor. |
| 73 | 82 | """ |
| 74 | - # Write separator into logger | |
| 75 | - if self.logTerse(): | |
| 76 | - self.log("\n") | |
| 77 | - | |
| 78 | 83 | # Return |
| 79 | 84 | return |
| 80 | 85 | |
| 81 | - def parfile(self): | |
| 82 | - """ | |
| 83 | - Check if parfile exists. If parfile does not exist then create a | |
| 84 | - default parfile. This kluge avoids shipping the cscript with a parfile. | |
| 85 | - """ | |
| 86 | - # Set parfile name | |
| 87 | - parfile = self.name+".par" | |
| 88 | - | |
| 89 | - try: | |
| 90 | - pars = gammalib.GApplicationPars(parfile) | |
| 91 | - except: | |
| 92 | - # Signal if parfile was not found | |
| 93 | - sys.stdout.write("Parfile "+parfile+" not found. Create default parfile.\n") | |
| 94 | - | |
| 95 | - # Create default parfile | |
| 96 | - pars = gammalib.GApplicationPars() | |
| 97 | - pars.append(gammalib.GApplicationPar("inobs","f","h","NONE","","","Input event list, counts cube, or observation definition XML file")) | |
| 98 | - pars.append(gammalib.GApplicationPar("inmodel","f","a","$CTOOLS/share/models/crab.xml","","","Input model XML file")) | |
| 99 | - pars.append(gammalib.GApplicationPar("srcname","s","a","Crab","","","Source name")) | |
| 100 | - pars.append(gammalib.GApplicationPar("expcube","s","a","NONE","","","Input exposure cube file (only needed for stacked analysis)")) | |
| 101 | - pars.append(gammalib.GApplicationPar("psfcube","s","a","NONE","","","Input PSF cube file (only needed for stacked analysis)")) | |
| 102 | - pars.append(gammalib.GApplicationPar("edispcube","f","a","NONE","","","Input energy dispersion cube file (only needed for stacked analysis)")) | |
| 103 | - pars.append(gammalib.GApplicationPar("bkgcube","s","a","NONE","","","Input background cube file (only needed for stacked analysis)")) | |
| 104 | - pars.append(gammalib.GApplicationPar("caldb","s","a","prod2","","","Calibration database")) | |
| 105 | - pars.append(gammalib.GApplicationPar("irf","s","a","South_0.5h","","","Instrument response function")) | |
| 106 | - pars.append(gammalib.GApplicationPar("deadc","r","h","0.95","","","Deadtime correction factor")) | |
| 107 | - pars.append(gammalib.GApplicationPar("edisp","b","h","no","","","Apply energy dispersion?")) | |
| 108 | - pars.append(gammalib.GApplicationPar("outfile","f","a","ts.dat","","","Output Test Statistics distribution file")) | |
| 109 | - pars.append(gammalib.GApplicationPar("ntrials","i","a","10","","","Number of trials")) | |
| 110 | - pars.append(gammalib.GApplicationPar("ra","r","a","83.63","0","360","RA of pointing (deg)")) | |
| 111 | - pars.append(gammalib.GApplicationPar("dec","r","a","22.01","-90","90","Dec of pointing (deg)")) | |
| 112 | - pars.append(gammalib.GApplicationPar("emin","r","a","0.1","","","Lower energy limit (TeV)")) | |
| 113 | - pars.append(gammalib.GApplicationPar("emax","r","a","100.0","","","Upper energy limit (TeV)")) | |
| 114 | - pars.append(gammalib.GApplicationPar("enumbins","i","a","0","","","Number of energy bins (0=unbinned)")) | |
| 115 | - pars.append(gammalib.GApplicationPar("tmin","r","h","0.0","","","Start time (MET in s)")) | |
| 116 | - pars.append(gammalib.GApplicationPar("tmax","r","a","1800.0","","","Observation duration (in s)")) | |
| 117 | - pars.append(gammalib.GApplicationPar("npix","i","a","200","","","Number of pixels for binned")) | |
| 118 | - pars.append(gammalib.GApplicationPar("binsz","r","a","0.05","","","Pixel size for binned (deg/pixel)")) | |
| 119 | - pars.append(gammalib.GApplicationPar("rad","r","h","5.0","","","Radius of ROI (deg)")) | |
| 120 | - pars.append(gammalib.GApplicationPar("pattern","s","h","single","","","Observation pattern (single/four)")) | |
| 121 | - pars.append(gammalib.GApplicationPar("offset","r","h","1.5","","","Observation pattern offset (deg)")) | |
| 122 | - pars.append_standard() | |
| 123 | - pars.append(gammalib.GApplicationPar("logfile","f","h","cstsdist.log","","","Log filename")) | |
| 124 | - pars.save(parfile) | |
| 125 | - | |
| 126 | - # Return | |
| 127 | - return | |
| 128 | 86 | |
| 129 | - def get_parameters(self): | |
| 87 | + # Private methods | |
| 88 | + def _get_parameters(self): | |
| 130 | 89 | """ |
| 131 | 90 | Get parameters from parfile and setup the observation. |
| 132 | 91 | """ |
| 133 | 92 | |
| 134 | 93 | # Set observation if not done before |
| 135 | - if self.obs == None or self.obs.size() == 0: | |
| 136 | - self.obs = self._get_observations() | |
| 94 | + if self._obs == None or self._obs.size() == 0: | |
| 95 | + self._obs = self._get_observations() | |
| 137 | 96 | |
| 138 | 97 | # Check for requested pattern and use above |
| 139 | 98 | # observation parameters to set wobble pattern |
| 140 | - self.m_pattern = self["pattern"].string() | |
| 141 | - if self.m_pattern == "four": | |
| 142 | - self.obs = self.set_obs() | |
| 99 | + self._pattern = self["pattern"].string() | |
| 100 | + if self._pattern == "four": | |
| 101 | + self._obs = self._set_obs() | |
| 143 | 102 | |
| 144 | 103 | # Get source name |
| 145 | - self.m_srcname = self["srcname"].string() | |
| 104 | + self._srcname = self["srcname"].string() | |
| 146 | 105 | |
| 147 | 106 | # Get number of energy bins |
| 148 | - self.m_enumbins = self["enumbins"].integer() | |
| 107 | + self._enumbins = self["enumbins"].integer() | |
| 149 | 108 | |
| 150 | 109 | # Read parameters for binned if requested |
| 151 | - if not self.m_enumbins == 0: | |
| 152 | - self.m_npix = self["npix"].integer() | |
| 153 | - self.m_binsz = self["binsz"].real() | |
| 154 | - else: | |
| 155 | - # Set dummy values (required by obsutils) | |
| 156 | - self.m_npix = 0 | |
| 157 | - self.m_binsz = 0.0 | |
| 110 | + if not self._enumbins == 0: | |
| 111 | + self._npix = self["npix"].integer() | |
| 112 | + self._binsz = self["binsz"].real() | |
| 158 | 113 | |
| 159 | 114 | # Set models if we have none |
| 160 | - if self.obs.models().size() == 0: | |
| 161 | - self.obs.models(self["inmodel"].filename()) | |
| 115 | + if self._obs.models().size() == 0: | |
| 116 | + self._obs.models(self["inmodel"].filename()) | |
| 162 | 117 | |
| 163 | 118 | # Get other parameters |
| 164 | - self.m_outfile = self["outfile"].filename() | |
| 165 | - self.m_ntrials = self["ntrials"].integer() | |
| 166 | - self.m_edisp = self["edisp"].boolean() | |
| 167 | - self.m_offset = self["offset"].real() | |
| 119 | + self._outfile = self["outfile"].filename() | |
| 120 | + self._ntrials = self["ntrials"].integer() | |
| 121 | + self._edisp = self["edisp"].boolean() | |
| 122 | + self._debug = self["debug"].boolean() | |
| 168 | 123 | |
| 169 | - # Set some fixed parameters | |
| 170 | - self.m_log = False # Logging in client tools | |
| 171 | - self.m_debug = self["debug"].boolean() # Debugging in client tools | |
| 124 | + # Write input parameters into logger | |
| 125 | + if self._logTerse(): | |
| 126 | + self._log_parameters() | |
| 127 | + self._log("\n") | |
| 172 | 128 | |
| 173 | 129 | # Return |
| 174 | 130 | return |
| 175 | 131 | |
| 176 | - def models(self, models): | |
| 132 | + def _set_obs(self): | |
| 177 | 133 | """ |
| 178 | - Set model. | |
| 179 | - """ | |
| 180 | - # Copy models | |
| 181 | - self.obs.models(models.copy()) | |
| 182 | - | |
| 183 | - # Return | |
| 184 | - return | |
| 134 | + Set an observation container. | |
| 185 | 135 | |
| 186 | - def execute(self): | |
| 136 | + Returns: | |
| 137 | + Observation container. | |
| 187 | 138 | """ |
| 188 | - Execute the script. | |
| 189 | - """ | |
| 190 | - # Run the script | |
| 191 | - self.run() | |
| 192 | - | |
| 193 | - # Return | |
| 194 | - return | |
| 195 | - | |
| 196 | - def run(self): | |
| 197 | - """ | |
| 198 | - Run the script. | |
| 199 | - """ | |
| 200 | - # Switch screen logging on in debug mode | |
| 201 | - if self.logDebug(): | |
| 202 | - self.log.cout(True) | |
| 203 | - | |
| 204 | - # Get parameters | |
| 205 | - self.get_parameters() | |
| 206 | - | |
| 207 | - # Write input parameters into logger | |
| 208 | - if self.logTerse(): | |
| 209 | - self.log_parameters() | |
| 210 | - self.log("\n") | |
| 211 | - | |
| 212 | - # Initialise models | |
| 213 | - full_model, bkg_model = self.set_models() | |
| 214 | - | |
| 215 | - # Write models into logger | |
| 216 | - if self.logTerse(): | |
| 217 | - self.log("\n") | |
| 218 | - self.log.header1("Models") | |
| 219 | - self.log.header2("Background model") | |
| 220 | - self.log(str(bkg_model)) | |
| 221 | - self.log("\n\n") | |
| 222 | - self.log.header2("Full model") | |
| 223 | - self.log(str(full_model)) | |
| 224 | - self.log("\n") | |
| 225 | - | |
| 226 | - # Write observation into logger | |
| 227 | - if self.logTerse(): | |
| 228 | - self.log("\n") | |
| 229 | - self.log.header1("Observation") | |
| 230 | - self.log(str(self.obs)) | |
| 231 | - self.log("\n") | |
| 232 | 139 | |
| 233 | - # Write models into logger | |
| 234 | - if self.logTerse(): | |
| 235 | - self.log("\n") | |
| 236 | - self.log.header1("Test model") | |
| 237 | - self.log(str(self.full_model)) | |
| 238 | - self.log("\n") | |
| 239 | - | |
| 240 | - # Write header | |
| 241 | - if self.logTerse(): | |
| 242 | - self.log("\n") | |
| 243 | - self.log.header1("Generate TS distribution") | |
| 140 | + # Setup observation definition list | |
| 141 | + obsdeflist = obsutils.set_obs_patterns(self._pattern, | |
| 142 | + ra=self["ra"].real(), | |
| 143 | + dec=self["dec"].real(), | |
| 144 | + offset=self["offset"].real()) | |
| 244 | 145 | |
| 245 | - # Loop over trials | |
| 246 | - for seed in range(self.m_ntrials): | |
| 146 | + # Create list of observations | |
| 147 | + obs = obsutils.set_obs_list(obsdeflist, | |
| 148 | + tstart=self["tmin"].real(), | |
| 149 | + duration=self["tmax"].real()-self["tmin"].real(), | |
| 150 | + deadc=self["deadc"].real(), | |
| 151 | + emin=self["emin"].real(), | |
| 152 | + emax=self["emax"].real(), | |
| 153 | + rad=self["rad"].real(), | |
| 154 | + irf=self["irf"].string(), | |
| 155 | + caldb=self["caldb"].string()) | |
| 247 | 156 | |
| 248 | - # Make a trial | |
| 249 | - result = self.trial(seed, full_model, bkg_model) | |
| 157 | + # Return observation container | |
| 158 | + return obs | |
| 250 | 159 | |
| 251 | - # Write out result immediately | |
| 252 | - if seed == 0: | |
| 253 | - file = open(self.m_outfile.url(), 'w') | |
| 254 | - writer = csv.DictWriter(file, result['colnames']) | |
| 255 | - headers = {} | |
| 256 | - for n in result['colnames']: | |
| 257 | - headers[n] = n | |
| 258 | - writer.writerow(headers) | |
| 259 | - #writer.writerow(dict((_,_) for _ in result['colnames'])) | |
| 260 | - else: | |
| 261 | - file = open(self.m_outfile.url(), 'a') | |
| 262 | - writer = csv.DictWriter(file, result['colnames']) | |
| 263 | - writer.writerow(result['values']) | |
| 264 | - file.close() | |
| 160 | + def _set_models(self, fitspat=False, fitspec=False): | |
| 161 | + """ | |
| 162 | + Set full model and background model. | |
| 265 | 163 | |
| 266 | - # Return | |
| 267 | - return | |
| 164 | + Kwargs: | |
| 165 | + fitspat: Fit spatial parameter (default: False). | |
| 166 | + fitspec: Fit spectral parameters (default: False). | |
| 268 | 167 | |
| 269 | - def set_models(self, fitpos=False, fitspec=False): | |
| 270 | - """ | |
| 271 | - Set full and background model. | |
| 168 | + Returns: | |
| 169 | + Tuple containing full model and background model. | |
| 272 | 170 | """ |
| 273 | 171 | # Retrieve full model from observation container |
| 274 | - full_model = self.obs.models().copy() | |
| 172 | + full_model = self._obs.models().copy() | |
| 275 | 173 | |
| 276 | 174 | # Get source model |
| 277 | - model = full_model[self.m_srcname] | |
| 175 | + model = full_model[self._srcname] | |
| 278 | 176 | |
| 279 | 177 | # Check that model has a Prefactor |
| 280 | 178 | if not model.has_par("Prefactor"): |
| 281 | - msg = "Model \""+self.m_srcname+"\" has no parameter \"Prefactor\"."+ \ | |
| 282 | - " Only spectral models with a \"Prefactor\" parameter are supported." | |
| 179 | + msg = "Model \""+self._srcname+"\" has no parameter "+\ | |
| 180 | + "\"Prefactor\". Only spectral models with a "+\ | |
| 181 | + "\"Prefactor\" parameter are supported." | |
| 283 | 182 | raise RuntimeError(msg) |
| 284 | 183 | |
| 285 | 184 | # Fit or fix spatial parameters |
| 286 | - if fitpos: | |
| 185 | + if fitspat: | |
| 287 | 186 | if model.has_par("RA"): |
| 288 | 187 | model["RA"].free() |
| 289 | 188 | if model.has_par("DEC"): |
| ... | ... | @@ -320,55 +219,35 @@ class cstsdist(ctools.cscript): |
| 320 | 219 | |
| 321 | 220 | # Create background model |
| 322 | 221 | bkg_model = full_model.copy() |
| 323 | - bkg_model.remove(self.m_srcname) | |
| 222 | + bkg_model.remove(self._srcname) | |
| 324 | 223 | |
| 325 | 224 | # Return models |
| 326 | 225 | return full_model, bkg_model |
| 327 | 226 | |
| 328 | - def set_obs(self): | |
| 329 | - """ | |
| 330 | - Returns an observation container with a set of CTA observations. | |
| 331 | - | |
| 332 | - Keywords: | |
| 333 | - """ | |
| 334 | - | |
| 335 | - # Setup observation definition list | |
| 336 | - obsdeflist = obsutils.set_obs_patterns(self.m_pattern, | |
| 337 | - ra=self["ra"].real(), | |
| 338 | - dec=self["dec"].real(), | |
| 339 | - offset=self["offset"].real()) | |
| 340 | - | |
| 341 | - # Create list of observations | |
| 342 | - obs = obsutils.set_obs_list(obsdeflist, | |
| 343 | - tstart=self["tmin"].real(), | |
| 344 | - duration=self["tmax"].real()-self["tmin"].real(), | |
| 345 | - deadc=self["deadc"].real(), | |
| 346 | - emin=self["emin"].real(), | |
| 347 | - emax=self["emax"].real(), | |
| 348 | - rad=self["rad"].real(), | |
| 349 | - irf=self["irf"].string(), caldb=self["caldb"].string()) | |
| 350 | - | |
| 351 | - # Return observation container | |
| 352 | - return obs | |
| 353 | - | |
| 354 | - def trial(self, seed, full_model, bkg_model): | |
| 227 | + def _trial(self, seed, full_model, bkg_model): | |
| 355 | 228 | """ |
| 356 | 229 | Create the TS for a single trial. |
| 357 | 230 | |
| 358 | - Parameters: | |
| 359 | - seed - Random number generator seed | |
| 231 | + Args: | |
| 232 | + seed: Random number generator seed | |
| 233 | + full_model: Full model | |
| 234 | + bkg_model: Background model | |
| 235 | + | |
| 236 | + Returns: | |
| 237 | + Result dictionary | |
| 360 | 238 | """ |
| 361 | 239 | # Write header |
| 362 | - if self.logExplicit(): | |
| 363 | - self.log.header2("Trial "+str(seed+1)) | |
| 240 | + if self._logExplicit(): | |
| 241 | + self._log.header2("Trial "+str(seed+1)) | |
| 364 | 242 | |
| 365 | 243 | # Simulate events |
| 366 | - sim = obsutils.sim(self.obs, | |
| 367 | - nbins=self.m_enumbins, | |
| 244 | + sim = obsutils.sim(self._obs, | |
| 245 | + nbins=self._enumbins, | |
| 368 | 246 | seed=seed, |
| 369 | - binsz=self.m_binsz, | |
| 370 | - npix=self.m_npix, | |
| 371 | - log=self.m_log, debug=self.m_debug) | |
| 247 | + binsz=self._binsz, | |
| 248 | + npix=self._npix, | |
| 249 | + log=self._log_clients, | |
| 250 | + debug=self._debug) | |
| 372 | 251 | |
| 373 | 252 | # Determine number of events in simulation |
| 374 | 253 | nevents = 0.0 |
| ... | ... | @@ -376,72 +255,76 @@ class cstsdist(ctools.cscript): |
| 376 | 255 | nevents += run.events().number() |
| 377 | 256 | |
| 378 | 257 | # Write simulation results |
| 379 | - if self.logExplicit(): | |
| 380 | - self.log.header3("Simulation") | |
| 381 | - self.log.parformat("Number of simulated events") | |
| 382 | - self.log(nevents) | |
| 383 | - self.log("\n") | |
| 258 | + if self._logExplicit(): | |
| 259 | + self._log.header3("Simulation") | |
| 260 | + self._log.parformat("Number of simulated events") | |
| 261 | + self._log(nevents) | |
| 262 | + self._log("\n") | |
| 384 | 263 | |
| 385 | 264 | # Fit background only |
| 386 | 265 | sim.models(bkg_model) |
| 387 | - like_bgm = obsutils.fit(sim, log=self.m_log, debug=self.m_debug) | |
| 266 | + like_bgm = obsutils.fit(sim, | |
| 267 | + log=self._log_clients, | |
| 268 | + debug=self._debug) | |
| 388 | 269 | result_bgm = like_bgm.obs().models().copy() |
| 389 | 270 | LogL_bgm = like_bgm.opt().value() |
| 390 | 271 | npred_bgm = like_bgm.obs().npred() |
| 391 | 272 | |
| 392 | 273 | # Write background fit results |
| 393 | - if self.logExplicit(): | |
| 394 | - self.log.header3("Background model fit") | |
| 395 | - self.log.parformat("log likelihood") | |
| 396 | - self.log(LogL_bgm) | |
| 397 | - self.log("\n") | |
| 398 | - self.log.parformat("Number of predicted events") | |
| 399 | - self.log(npred_bgm) | |
| 400 | - self.log("\n") | |
| 274 | + if self._logExplicit(): | |
| 275 | + self._log.header3("Background model fit") | |
| 276 | + self._log.parformat("log likelihood") | |
| 277 | + self._log(LogL_bgm) | |
| 278 | + self._log("\n") | |
| 279 | + self._log.parformat("Number of predicted events") | |
| 280 | + self._log(npred_bgm) | |
| 281 | + self._log("\n") | |
| 401 | 282 | for model in result_bgm: |
| 402 | - self.log.parformat("Model") | |
| 403 | - self.log(model.name()) | |
| 404 | - self.log("\n") | |
| 283 | + self._log.parformat("Model") | |
| 284 | + self._log(model.name()) | |
| 285 | + self._log("\n") | |
| 405 | 286 | for par in model: |
| 406 | - self.log(str(par)+"\n") | |
| 287 | + self._log(str(par)+"\n") | |
| 407 | 288 | |
| 408 | 289 | # Fit background and test source |
| 409 | 290 | sim.models(full_model) |
| 410 | - like_all = obsutils.fit(sim, log=self.m_log, debug=self.m_debug) | |
| 291 | + like_all = obsutils.fit(sim, | |
| 292 | + log=self._log_clients, | |
| 293 | + debug=self._debug) | |
| 411 | 294 | result_all = like_all.obs().models().copy() |
| 412 | 295 | LogL_all = like_all.opt().value() |
| 413 | 296 | npred_all = like_all.obs().npred() |
| 414 | 297 | ts = 2.0*(LogL_bgm-LogL_all) |
| 415 | 298 | |
| 416 | 299 | # Write background and test source fit results |
| 417 | - if self.logExplicit(): | |
| 418 | - self.log.header3("Background and test source model fit") | |
| 419 | - self.log.parformat("Test statistics") | |
| 420 | - self.log(ts) | |
| 421 | - self.log("\n") | |
| 422 | - self.log.parformat("log likelihood") | |
| 423 | - self.log(LogL_all) | |
| 424 | - self.log("\n") | |
| 425 | - self.log.parformat("Number of predicted events") | |
| 426 | - self.log(npred_all) | |
| 427 | - self.log("\n") | |
| 300 | + if self._logExplicit(): | |
| 301 | + self._log.header3("Background and test source model fit") | |
| 302 | + self._log.parformat("Test statistics") | |
| 303 | + self._log(ts) | |
| 304 | + self._log("\n") | |
| 305 | + self._log.parformat("log likelihood") | |
| 306 | + self._log(LogL_all) | |
| 307 | + self._log("\n") | |
| 308 | + self._log.parformat("Number of predicted events") | |
| 309 | + self._log(npred_all) | |
| 310 | + self._log("\n") | |
| 428 | 311 | for model in result_all: |
| 429 | - self.log.parformat("Model") | |
| 430 | - self.log(model.name()) | |
| 431 | - self.log("\n") | |
| 312 | + self._log.parformat("Model") | |
| 313 | + self._log(model.name()) | |
| 314 | + self._log("\n") | |
| 432 | 315 | for par in model: |
| 433 | - self.log(str(par)+"\n") | |
| 316 | + self._log(str(par)+"\n") | |
| 434 | 317 | |
| 435 | 318 | # Write result |
| 436 | - elif self.logTerse(): | |
| 437 | - self.log.parformat("Trial "+str(seed)) | |
| 438 | - self.log("TS=") | |
| 439 | - self.log(ts) | |
| 440 | - self.log(" Prefactor=") | |
| 441 | - self.log(result_all[self.m_srcname]["Prefactor"].value()) | |
| 442 | - self.log("+/-") | |
| 443 | - self.log(result_all[self.m_srcname]["Prefactor"].error()) | |
| 444 | - self.log("\n") | |
| 319 | + elif self._logTerse(): | |
| 320 | + self._log.parformat("Trial "+str(seed)) | |
| 321 | + self._log("TS=") | |
| 322 | + self._log(ts) | |
| 323 | + self._log(" Prefactor=") | |
| 324 | + self._log(result_all[self._srcname]["Prefactor"].value()) | |
| 325 | + self._log("+/-") | |
| 326 | + self._log(result_all[self._srcname]["Prefactor"].error()) | |
| 327 | + self._log("\n") | |
| 445 | 328 | |
| 446 | 329 | # Initialise results |
| 447 | 330 | colnames = [] |
| ... | ... | @@ -498,18 +381,105 @@ class cstsdist(ctools.cscript): |
| 498 | 381 | return result |
| 499 | 382 | |
| 500 | 383 | |
| 384 | + # Public methods | |
| 385 | + def run(self): | |
| 386 | + """ | |
| 387 | + Run the script. | |
| 388 | + """ | |
| 389 | + # Switch screen logging on in debug mode | |
| 390 | + if self._logDebug(): | |
| 391 | + self._log.cout(True) | |
| 392 | + | |
| 393 | + # Get parameters | |
| 394 | + self._get_parameters() | |
| 395 | + | |
| 396 | + # Initialise models | |
| 397 | + full_model, bkg_model = self._set_models() | |
| 398 | + | |
| 399 | + # Write models into logger | |
| 400 | + if self._logTerse(): | |
| 401 | + self._log("\n") | |
| 402 | + self._log.header1("Models") | |
| 403 | + self._log.header2("Background model") | |
| 404 | + self._log(str(bkg_model)) | |
| 405 | + self._log("\n\n") | |
| 406 | + self._log.header2("Full model") | |
| 407 | + self._log(str(full_model)) | |
| 408 | + self._log("\n") | |
| 409 | + | |
| 410 | + # Write observation into logger | |
| 411 | + if self._logTerse(): | |
| 412 | + self._log("\n") | |
| 413 | + self._log.header1("Observation") | |
| 414 | + self._log(str(self._obs)) | |
| 415 | + self._log("\n") | |
| 416 | + | |
| 417 | + # Write models into logger | |
| 418 | + if self._logTerse(): | |
| 419 | + self._log("\n") | |
| 420 | + self._log.header1("Test model") | |
| 421 | + self._log(str(full_model)) | |
| 422 | + self._log("\n") | |
| 423 | + | |
| 424 | + # Write header | |
| 425 | + if self._logTerse(): | |
| 426 | + self._log("\n") | |
| 427 | + self._log.header1("Generate TS distribution") | |
| 428 | + | |
| 429 | + # Loop over trials | |
| 430 | + for seed in range(self._ntrials): | |
| 431 | + | |
| 432 | + # Make a trial | |
| 433 | + result = self._trial(seed, full_model, bkg_model) | |
| 434 | + | |
| 435 | + # Write out result immediately | |
| 436 | + if seed == 0: | |
| 437 | + file = open(self._outfile.url(), 'w') | |
| 438 | + writer = csv.DictWriter(file, result['colnames']) | |
| 439 | + headers = {} | |
| 440 | + for n in result['colnames']: | |
| 441 | + headers[n] = n | |
| 442 | + writer.writerow(headers) | |
| 443 | + else: | |
| 444 | + file = open(self._outfile.url(), 'a') | |
| 445 | + writer = csv.DictWriter(file, result['colnames']) | |
| 446 | + writer.writerow(result['values']) | |
| 447 | + file.close() | |
| 448 | + | |
| 449 | + # Return | |
| 450 | + return | |
| 451 | + | |
| 452 | + def models(self, models): | |
| 453 | + """ | |
| 454 | + Set model. | |
| 455 | + """ | |
| 456 | + # Copy models | |
| 457 | + self._obs.models(models.copy()) | |
| 458 | + | |
| 459 | + # Return | |
| 460 | + return | |
| 461 | + | |
| 462 | + def execute(self): | |
| 463 | + """ | |
| 464 | + Execute the script. | |
| 465 | + """ | |
| 466 | + # Run the script | |
| 467 | + self.run() | |
| 468 | + | |
| 469 | + # Return | |
| 470 | + return | |
| 471 | + | |
| 472 | + | |
| 501 | 473 | # ======================== # |
| 502 | 474 | # Main routine entry point # |
| 503 | 475 | # ======================== # |
| 504 | 476 | if __name__ == '__main__': |
| 505 | - """ | |
| 506 | - Generates TS distribution. | |
| 507 | - """ | |
| 477 | + | |
| 508 | 478 | # Create instance of application |
| 509 | 479 | app = cstsdist(sys.argv) |
| 510 | 480 | |
| 511 | 481 | # Open logfile |
| 512 | - app.logFileOpen() | |
| 482 | + app._logFileOpen() | |
| 513 | 483 | |
| 514 | 484 | # Execute application |
| 515 | 485 | app.execute() | ... | ... |
cscripts/cstsmapmerge.par
0 → 100644
| 1 | +############################################################################# | |
| 2 | +# # | |
| 3 | +# CTA Science Analysis Tools # | |
| 4 | +# # | |
| 5 | +# ------------------------------------------------------------------------- # | |
| 6 | +# # | |
| 7 | +# File: cstsmapmerge.par # | |
| 8 | +# Version: 1.1.0 # | |
| 9 | +# # | |
| 10 | +# Author: Juergen Knoedlseder # | |
| 11 | +# Jurgen.Knodlseder@irap.omp.eu # | |
| 12 | +# IRAP # | |
| 13 | +# # | |
| 14 | +# Purpose: Parameter file for the cstsmapmerge script # | |
| 15 | +# # | |
| 16 | +############################################################################# | |
| 17 | +# | |
| 18 | +# Input and output parameters | |
| 19 | +#============================ | |
| 20 | +inmaps, s, a, tsmap.fits,,, "Input TS map FITS files" | |
| 21 | +outmap, f, a, NONE,,, "Output TS map FITS file" | |
| 22 | + | |
| 23 | +# | |
| 24 | +# Script parameters | |
| 25 | +#================== | |
| 26 | +overwrite, b, h, yes,,, "Overwrite previously filled bins?" | |
| 27 | +delete, b, h, no,,, "Delete merged files?" | |
| 28 | + | |
| 29 | +# | |
| 30 | +# Standard parameters | |
| 31 | +#==================== | |
| 32 | +chatter, i, h, 2,0,4, "Chattiness of output" | |
| 33 | +clobber, b, h, yes,,, "Overwrite existing output files with new output files?" | |
| 34 | +debug, b, h, no,,, "Debugging mode activated" | |
| 35 | +mode, s, h, ql,,, "Mode of automatic parameters" | |
| 36 | +logfile, f, h, cstsmapmerge.log,,, "Log filename" | |
| 37 | + | |
| 38 | + | ... | ... |
cscripts/cstsmapmerge.py
| 1 | 1 | #!/usr/bin/env python |
| 2 | 2 | # ========================================================================== |
| 3 | -# Merges sliced TS map files into one map | |
| 3 | +# Merge Test Statistic maps | |
| 4 | 4 | # |
| 5 | 5 | # Copyright (C) 2015-2016 Michael Mayer |
| 6 | 6 | # |
| ... | ... | @@ -30,30 +30,42 @@ import os |
| 30 | 30 | # ================== # |
| 31 | 31 | class cstsmapmerge(ctools.cscript): |
| 32 | 32 | """ |
| 33 | - This class merges TS map files into one TS map | |
| 33 | + Merge Test Statistic maps. | |
| 34 | 34 | """ |
| 35 | + | |
| 36 | + # Constructors and destructors | |
| 35 | 37 | def __init__(self, *argv): |
| 36 | 38 | """ |
| 37 | 39 | Constructor. |
| 38 | 40 | """ |
| 39 | 41 | # Set name |
| 40 | - self.name = "cstsmapmerge" | |
| 41 | - self.version = "1.1.0" | |
| 42 | + self._name = "cstsmapmerge" | |
| 43 | + self._version = "1.1.0" | |
| 42 | 44 | |
| 43 | - # Make sure that parfile exists | |
| 44 | - file = self.parfile() | |
| 45 | + # Initialise class members | |
| 46 | + self._files = None | |
| 47 | + self._in_filename = "" | |
| 48 | + self._tsmap = gammalib.GSkyMap() # Empty sky map | |
| 49 | + self._statusmap = gammalib.GSkyMap() # Empty sky map | |
| 50 | + self._maps = [] | |
| 51 | + self._mapnames = [] | |
| 52 | + self._merged_files = [] | |
| 53 | + self._overwrite = True | |
| 54 | + self._delete = False | |
| 55 | + self._outmap = "NONE" | |
| 56 | + self._read_ahead = False | |
| 45 | 57 | |
| 46 | 58 | # Initialise application |
| 47 | 59 | if len(argv) == 0: |
| 48 | - ctools.cscript.__init__(self, self.name, self.version) | |
| 60 | + ctools.cscript.__init__(self, self._name, self._version) | |
| 49 | 61 | elif len(argv) == 1: |
| 50 | - ctools.cscript.__init__(self, self.name, self.version, *argv) | |
| 62 | + ctools.cscript.__init__(self, self._name, self._version, *argv) | |
| 51 | 63 | else: |
| 52 | 64 | raise TypeError("Invalid number of arguments given.") |
| 53 | 65 | |
| 54 | 66 | # Set logger properties |
| 55 | - self.log_header() | |
| 56 | - self.log.date(True) | |
| 67 | + self._log_header() | |
| 68 | + self._log.date(True) | |
| 57 | 69 | |
| 58 | 70 | # Return |
| 59 | 71 | return |
| ... | ... | @@ -65,98 +77,79 @@ class cstsmapmerge(ctools.cscript): |
| 65 | 77 | # Return |
| 66 | 78 | return |
| 67 | 79 | |
| 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 | 80 | |
| 97 | - def get_parameters(self): | |
| 81 | + # Private methods | |
| 82 | + def _get_parameters(self): | |
| 98 | 83 | """ |
| 99 | - Get parameters from parfile and setup the observation. | |
| 84 | + Get parameters from parfile. | |
| 100 | 85 | """ |
| 101 | - # Get input models | |
| 102 | - self.inmodels = self["inmaps"].string() | |
| 86 | + # Get input maps string | |
| 87 | + inmaps = self["inmaps"].string() | |
| 103 | 88 | |
| 104 | - # Interpet inmodels string | |
| 105 | 89 | # Handle ascii files |
| 106 | - if "@" == self.inmodels[0]: | |
| 107 | - self.files = open(self.inmodels.replace("@","")).read().splitlines() | |
| 90 | + if "@" == inmaps[0]: | |
| 91 | + self._files = open(inmaps.replace("@","")).read().splitlines() | |
| 108 | 92 | |
| 109 | 93 | # Handle wild card strings |
| 110 | - elif "*" in self.inmodels: | |
| 111 | - self.files = glob.glob(self.inmodels) | |
| 94 | + elif "*" in inmaps: | |
| 95 | + self._files = glob.glob(inmaps) | |
| 112 | 96 | |
| 113 | 97 | # Handle space-separated list |
| 114 | - elif " " in self.inmodels: | |
| 115 | - self.files = self.inmodels.split(" ") | |
| 98 | + elif " " in inmaps: | |
| 99 | + self._files = inmaps.split(" ") | |
| 116 | 100 | |
| 117 | - # Handle comma-separated list | |
| 118 | - elif "," in self.inmodels: | |
| 119 | - self.files = self.inmodels.split(",") | |
| 101 | + # Handle semi-colon separated list | |
| 102 | + elif ";" in inmaps: | |
| 103 | + self._files = inmaps.split(";") | |
| 120 | 104 | |
| 121 | 105 | # Throw exception if input models cannot be decoded |
| 122 | 106 | 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" | |
| 107 | + msg = "Parameter \"inmaps\" must contain either an @ASCII "\ | |
| 108 | + "file, a semi-colon-separated or whitespace-separated "\ | |
| 109 | + "list of files or a wildcard string." | |
| 126 | 110 | raise RuntimeError(msg) |
| 127 | 111 | |
| 128 | 112 | # Check number of files. We need at least two files. |
| 129 | - if len(self.files) <= 1: | |
| 113 | + if len(self._files) <= 1: | |
| 130 | 114 | msg = "Need at least two files to start merging, "+\ |
| 131 | - str(len(self.files))+" files given." | |
| 115 | + str(len(self._files))+" file(s) given." | |
| 132 | 116 | raise RuntimeError(msg) |
| 133 | - | |
| 134 | - # Get output file | |
| 135 | - self.outmap = self["outmap"].filename() | |
| 136 | - | |
| 117 | + | |
| 137 | 118 | # Get other parameters |
| 138 | - self.overwrite = self["overwrite"].boolean() | |
| 139 | - self.delete = self["delete"].boolean() | |
| 119 | + self._overwrite = self["overwrite"].boolean() | |
| 120 | + self._delete = self["delete"].boolean() | |
| 140 | 121 | |
| 122 | + # Read ahead output filename | |
| 123 | + if self._read_ahead: | |
| 124 | + self._outmap = self["outmap"].filename() | |
| 125 | + | |
| 126 | + # Write input parameters into logger | |
| 127 | + if self._logTerse(): | |
| 128 | + self._log_parameters() | |
| 129 | + self._log("\n") | |
| 130 | + | |
| 141 | 131 | # Return |
| 142 | 132 | return |
| 143 | 133 | |
| 144 | - def init_map(self, fitsfile): | |
| 134 | + def _init_ts_map(self, fitsfile): | |
| 145 | 135 | """ |
| 136 | + Initialise Test Statistic map. | |
| 146 | 137 | """ |
| 147 | 138 | # Set filename |
| 148 | - self.in_filename = fitsfile | |
| 139 | + self._in_filename = fitsfile | |
| 149 | 140 | |
| 150 | 141 | # 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"]) | |
| 142 | + fits = gammalib.GFits(fitsfile) | |
| 143 | + | |
| 144 | + # Read TS and status maps | |
| 145 | + self._tsmap = gammalib.GSkyMap() | |
| 146 | + self._tsmap.read(fits[0]) | |
| 147 | + self._statusmap = gammalib.GSkyMap() | |
| 148 | + self._statusmap.read(fits["STATUS MAP"]) | |
| 156 | 149 | |
| 157 | 150 | # Get other maps |
| 158 | - self.maps = [] | |
| 159 | - self.mapnames = [] | |
| 151 | + self._maps = [] | |
| 152 | + self._mapnames = [] | |
| 160 | 153 | |
| 161 | 154 | # Loop over extensions |
| 162 | 155 | for hdu in fits: |
| ... | ... | @@ -167,8 +160,8 @@ class cstsmapmerge(ctools.cscript): |
| 167 | 160 | # Add present maps |
| 168 | 161 | skymap = gammalib.GSkyMap() |
| 169 | 162 | skymap.read(hdu) |
| 170 | - self.maps.append(skymap) | |
| 171 | - self.mapnames.append(hdu.extname()) | |
| 163 | + self._maps.append(skymap) | |
| 164 | + self._mapnames.append(hdu.extname()) | |
| 172 | 165 | |
| 173 | 166 | # Close FITS file |
| 174 | 167 | fits.close() |
| ... | ... | @@ -176,11 +169,17 @@ class cstsmapmerge(ctools.cscript): |
| 176 | 169 | # Return |
| 177 | 170 | return |
| 178 | 171 | |
| 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) | |
| 172 | + def _merge_ts_map(self, fitsfile): | |
| 173 | + """ | |
| 174 | + Merge TS map from FITS file into output TS map. | |
| 175 | + | |
| 176 | + Args: | |
| 177 | + fitsfile: FITS file to be merged. | |
| 178 | + """ | |
| 179 | + # Open FITS file | |
| 180 | + fits = gammalib.GFits(fitsfile) | |
| 181 | + | |
| 182 | + # Read TS and status maps | |
| 184 | 183 | add_tsmap = gammalib.GSkyMap() |
| 185 | 184 | add_tsmap.read(fits[0]) |
| 186 | 185 | add_statusmap = gammalib.GSkyMap() |
| ... | ... | @@ -203,175 +202,240 @@ class cstsmapmerge(ctools.cscript): |
| 203 | 202 | # Close FITS file |
| 204 | 203 | fits.close() |
| 205 | 204 | |
| 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+"\"") | |
| 205 | + # Compare size of maps | |
| 206 | + if not len(add_maps) == len(self._maps): | |
| 207 | + msg = "Cannot merge map \""+fitsfile+"\" into map \""+\ | |
| 208 | + self._in_filename+"\" since the number of parameters "\ | |
| 209 | + "between both maps is different." | |
| 210 | + raise RuntimeError(msg) | |
| 209 | 211 | |
| 210 | 212 | # Loop over bins |
| 211 | - for i in range(self.tsmap.npix()): | |
| 213 | + for i in range(self._tsmap.npix()): | |
| 214 | + | |
| 215 | + # Consider only bins that have been computed | |
| 212 | 216 | if add_statusmap[i] > 0.5: |
| 213 | 217 | |
| 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." | |
| 218 | + # Raise exception if this bin has already been computed | |
| 219 | + if self._statusmap[i] > 0.5 and not self._overwrite: | |
| 220 | + msg = "Attempt to merge bin which apparently has "+\ | |
| 221 | + "already been merged. File \""+fitsfile+"\" "+\ | |
| 222 | + "contains already merged bins. Set hidden "+\ | |
| 223 | + "parameter \"overwrite=yes\" to avoid this error." | |
| 220 | 224 | raise RuntimeError(msg) |
| 221 | 225 | |
| 222 | 226 | # Copy TS values |
| 223 | - self.tsmap[i] = add_tsmap[i] | |
| 227 | + self._tsmap[i] = add_tsmap[i] | |
| 224 | 228 | |
| 225 | 229 | # Copy status |
| 226 | - self.statusmap[i] = add_statusmap[i] | |
| 230 | + self._statusmap[i] = add_statusmap[i] | |
| 227 | 231 | |
| 228 | 232 | # Loop over maps and copy entries |
| 229 | - for j in range(len(self.maps)): | |
| 230 | - self.maps[j][i] = add_maps[j][i] | |
| 233 | + for j in range(len(self._maps)): | |
| 234 | + self._maps[j][i] = add_maps[j][i] | |
| 231 | 235 | |
| 232 | 236 | # Return |
| 233 | 237 | return |
| 234 | 238 | |
| 239 | + def _get_number_of_ts_pixels(self, fitsfile): | |
| 240 | + """ | |
| 241 | + Return number of pixels with TS values. | |
| 242 | + | |
| 243 | + Args: | |
| 244 | + fitsfile: FITS file to be merged. | |
| 245 | + | |
| 246 | + Returns: | |
| 247 | + Number of pixels for which TS has been computed. | |
| 248 | + """ | |
| 249 | + # Get status map for this file | |
| 250 | + status = gammalib.GSkyMap(fitsfile+"[STATUS MAP]") | |
| 251 | + | |
| 252 | + # Count number of pixels with TS status set | |
| 253 | + count = 0 | |
| 254 | + for pix in status: | |
| 255 | + if pix > 0.5: | |
| 256 | + count += 1 | |
| 257 | + | |
| 258 | + # Return number of pixels | |
| 259 | + return count | |
| 260 | + | |
| 261 | + | |
| 262 | + # Public methods | |
| 235 | 263 | def run(self): |
| 236 | 264 | """ |
| 237 | 265 | Run the script. |
| 238 | 266 | """ |
| 239 | 267 | # Switch screen logging on in debug mode |
| 240 | - if self.logDebug(): | |
| 241 | - self.log.cout(True) | |
| 268 | + if self._logDebug(): | |
| 269 | + self._log.cout(True) | |
| 242 | 270 | |
| 243 | 271 | # Get parameters |
| 244 | - self.get_parameters() | |
| 272 | + self._get_parameters() | |
| 245 | 273 | |
| 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") | |
| 274 | + # Write header into logger | |
| 275 | + if self._logTerse(): | |
| 276 | + self._log("\n") | |
| 277 | + self._log.header1("Merge TS maps") | |
| 255 | 278 | |
| 256 | 279 | # Initialise file to start with |
| 257 | - file0 = "" | |
| 258 | - | |
| 259 | - self.added_files = [] | |
| 280 | + file0 = "" | |
| 281 | + self._merged_files = [] | |
| 260 | 282 | |
| 261 | - # Test files for the entry status map | |
| 262 | - # use the first one to appear useful | |
| 263 | - for fitsfile in self.files: | |
| 283 | + # Test files for the entry status map. Use the first one to appear | |
| 284 | + # useful | |
| 285 | + for fitsfile in self._files: | |
| 286 | + | |
| 287 | + # Skip file if it's not a FITS file | |
| 264 | 288 | if not gammalib.GFilename(fitsfile).is_fits(): |
| 265 | - self.log("Skipping file \""+fitsfile+" (not a FITS file)\n") | |
| 289 | + if self._logExplicit(): | |
| 290 | + self._log(gammalib.parformat("Skip file")) | |
| 291 | + self._log(fitsfile) | |
| 292 | + self._log(" (not a FITS file)\n") | |
| 293 | + continue | |
| 294 | + | |
| 295 | + # Open FITS file | |
| 266 | 296 | fits = gammalib.GFits(fitsfile) |
| 267 | - | |
| 297 | + | |
| 298 | + # If file contains a status map then use it | |
| 268 | 299 | if fits.contains("STATUS MAP"): |
| 269 | - self.log("Using file \""+fitsfile+"\" as initialising map\n") | |
| 300 | + fits.close() | |
| 270 | 301 | file0 = fitsfile |
| 302 | + if self._logTerse(): | |
| 303 | + self._log(gammalib.parformat("Initial TS map file")) | |
| 304 | + self._log(fitsfile) | |
| 305 | + count = self._get_number_of_ts_pixels(fitsfile) | |
| 306 | + self._log(" (%d TS pixels computed)" % count) | |
| 307 | + self._log("\n") | |
| 271 | 308 | break |
| 309 | + | |
| 310 | + # ... otherwise signal that file is useless | |
| 272 | 311 | 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 | |
| 312 | + fits.close() | |
| 313 | + if self._logExplicit(): | |
| 314 | + self._log(gammalib.parformat("Skip file")) | |
| 315 | + self._log(fitsfile) | |
| 316 | + self._log(" (no \"STATUS MAP\" extension)\n") | |
| 317 | + continue | |
| 318 | + | |
| 319 | + # Signal if no suitable file was found | |
| 277 | 320 | 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") | |
| 321 | + if self._logTerse(): | |
| 322 | + self._log("None of the provided files seems to be a sliced " | |
| 323 | + "TS map file (none has a \"STATUS MAP\" " | |
| 324 | + "extension).\n") | |
| 280 | 325 | |
| 281 | - # Otherwise merge files | |
| 326 | + # ... otherwise merge files | |
| 282 | 327 | else: |
| 283 | 328 | |
| 284 | - # copy file list | |
| 285 | - workfiles = self.files | |
| 329 | + # Copy file list | |
| 330 | + workfiles = self._files | |
| 286 | 331 | |
| 287 | 332 | # Remove entry which will be used to initalise the map |
| 288 | 333 | workfiles.remove(file0) |
| 289 | 334 | |
| 290 | 335 | # Initialise map from first file |
| 291 | - self.init_map(file0) | |
| 336 | + self._init_ts_map(file0) | |
| 292 | 337 | |
| 293 | 338 | # Append to added files |
| 294 | - self.added_files.append(file0) | |
| 339 | + self._merged_files.append(file0) | |
| 295 | 340 | |
| 296 | 341 | # Loop over files |
| 297 | 342 | for fitsfile in workfiles: |
| 298 | 343 | |
| 299 | 344 | # Skip if file is not FITS |
| 300 | 345 | if not gammalib.GFilename(fitsfile).is_fits(): |
| 301 | - if self.logTerse(): | |
| 302 | - self.log("Skipping file \""+fitsfile+" (not a FITS file)\n") | |
| 346 | + if self._logExplicit(): | |
| 347 | + self._log(gammalib.parformat("Skip file")) | |
| 348 | + self._log(fitsfile) | |
| 349 | + self._log(" (not a FITS file)\n") | |
| 303 | 350 | continue |
| 351 | + | |
| 352 | + # Open FITS file | |
| 353 | + fits = gammalib.GFits(fitsfile) | |
| 304 | 354 | |
| 305 | 355 | # Skip if file does not contain status map |
| 306 | - fits = gammalib.GFits(fitsfile) | |
| 307 | 356 | if not fits.contains("STATUS MAP"): |
| 308 | - if self.logTerse(): | |
| 309 | - self.log("Skipping file \""+fitsfile+" (not a FITS file)\n") | |
| 357 | + fits.close() | |
| 358 | + if self._logExplicit(): | |
| 359 | + self._log(gammalib.parformat("Skip file")) | |
| 360 | + self._log(fitsfile) | |
| 361 | + self._log(" (no \"STATUS MAP\" extension)\n") | |
| 310 | 362 | continue |
| 363 | + | |
| 364 | + # Close FITS file | |
| 365 | + fits.close() | |
| 311 | 366 | |
| 312 | 367 | # Logging |
| 313 | - if self.logTerse(): | |
| 314 | - self.log("Adding TS map slice \""+fitsfile+"\"\n") | |
| 368 | + if self._logTerse(): | |
| 369 | + self._log(gammalib.parformat("Merge TS map file")) | |
| 370 | + self._log(fitsfile) | |
| 371 | + count = self._get_number_of_ts_pixels(fitsfile) | |
| 372 | + self._log(" (%d TS pixels computed)" % count) | |
| 373 | + self._log("\n") | |
| 315 | 374 | |
| 316 | - # Add file | |
| 317 | - self.add(fitsfile) | |
| 375 | + # Merge TS map | |
| 376 | + self._merge_ts_map(fitsfile) | |
| 318 | 377 | |
| 319 | - # Append to added files | |
| 320 | - self.added_files.append(fitsfile) | |
| 378 | + # Append FITS file to merged files | |
| 379 | + self._merged_files.append(fitsfile) | |
| 321 | 380 | |
| 322 | 381 | # Return |
| 323 | 382 | return |
| 324 | 383 | |
| 325 | 384 | def save(self): |
| 326 | 385 | """ |
| 327 | - Save merged tsmap file and remove slices if requested | |
| 386 | + Save TS map and remove slices if requested. | |
| 328 | 387 | """ |
| 329 | - | |
| 330 | - # Logging | |
| 331 | - if self.logExplicit(): | |
| 332 | - self.log("\n") | |
| 333 | - self.log.header1("Saving merged TS map") | |
| 334 | - self.log("\n") | |
| 388 | + # Write header | |
| 389 | + if self._logTerse(): | |
| 390 | + self._log("\n") | |
| 391 | + self._log.header1("Save TS map") | |
| 392 | + | |
| 393 | + # Get output filename in case it was not read ahead | |
| 394 | + self._outmap = self["outmap"].filename() | |
| 395 | + | |
| 396 | + # Log filename | |
| 397 | + if self._logTerse(): | |
| 398 | + self._log(gammalib.parformat("TS map file")) | |
| 399 | + self._log(self._outmap.url()) | |
| 400 | + self._log("\n") | |
| 335 | 401 | |
| 336 | 402 | # Create FITS file |
| 337 | 403 | fits = gammalib.GFits() |
| 338 | 404 | |
| 339 | 405 | # Write TS map into primary |
| 340 | - self.tsmap.write(fits) | |
| 406 | + self._tsmap.write(fits) | |
| 341 | 407 | |
| 342 | 408 | # Loop over maps and write them to fits |
| 343 | - for i in range(len(self.maps)): | |
| 344 | - self.maps[i].write(fits) | |
| 409 | + for i in range(len(self._maps)): | |
| 410 | + self._maps[i].write(fits) | |
| 345 | 411 | |
| 346 | 412 | # Set map names as extensions |
| 347 | - for i in range(len(self.mapnames)): | |
| 348 | - fits[i+1].extname(self.mapnames[i]) | |
| 413 | + for i in range(len(self._mapnames)): | |
| 414 | + fits[i+1].extname(self._mapnames[i]) | |
| 349 | 415 | |
| 350 | 416 | # Check if map is fully done |
| 351 | 417 | done = True |
| 352 | - for pix in self.statusmap: | |
| 418 | + for pix in self._statusmap: | |
| 353 | 419 | if pix < 0.5: |
| 354 | 420 | done = False |
| 355 | 421 | break |
| 356 | 422 | |
| 357 | - # Write Status map if we are not done yet | |
| 423 | + # Write status map if we are not done yet | |
| 358 | 424 | if not done: |
| 359 | - self.statusmap.write(fits) | |
| 425 | + self._statusmap.write(fits) | |
| 360 | 426 | fits[fits.size()-1].extname("STATUS MAP") |
| 361 | 427 | |
| 362 | 428 | # 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) | |
| 429 | + fits.saveto(self._outmap, self._clobber()) | |
| 430 | + | |
| 431 | + # Delete TS input maps if requested | |
| 432 | + if self._delete: | |
| 433 | + for filename in self._merged_files: | |
| 434 | + os.remove(filename) | |
| 435 | + if self._logTerse(): | |
| 436 | + self._log(gammalib.parformat("Deleted input file")) | |
| 437 | + self._log(filename) | |
| 438 | + self._log("\n") | |
| 375 | 439 | |
| 376 | 440 | # Return |
| 377 | 441 | return |
| ... | ... | @@ -380,10 +444,13 @@ class cstsmapmerge(ctools.cscript): |
| 380 | 444 | """ |
| 381 | 445 | Execute the script. |
| 382 | 446 | """ |
| 447 | + # Set read ahead flag | |
| 448 | + self._read_ahead = True | |
| 449 | + | |
| 383 | 450 | # Run the script |
| 384 | 451 | self.run() |
| 385 | 452 | |
| 386 | - # Save ds9 file if required | |
| 453 | + # Save TS map if required | |
| 387 | 454 | self.save() |
| 388 | 455 | |
| 389 | 456 | # Return |
| ... | ... | @@ -394,14 +461,12 @@ class cstsmapmerge(ctools.cscript): |
| 394 | 461 | # Main routine entry point # |
| 395 | 462 | # ======================== # |
| 396 | 463 | if __name__ == '__main__': |
| 397 | - """ | |
| 398 | - Merges ts map slices. | |
| 399 | - """ | |
| 464 | + | |
| 400 | 465 | # Create instance of application |
| 401 | 466 | app = cstsmapmerge(sys.argv) |
| 402 | 467 | |
| 403 | 468 | # Open logfile |
| 404 | - app.logFileOpen() | |
| 469 | + app._logFileOpen() | |
| 405 | 470 | |
| 406 | 471 | # Execute application |
| 407 | 472 | app.execute() | ... | ... |
test/test_cscripts.sh.in
| ... | ... | @@ -173,9 +173,9 @@ else |
| 173 | 173 | $ECHO " merged_models.xml file is not valid" |
| 174 | 174 | exit 1 |
| 175 | 175 | fi |
| 176 | -# === comma-separated === | |
| 176 | +# === semi-colon separated === | |
| 177 | 177 | @PYTHON_COVERAGE@@abs_top_srcdir@/cscripts/csmodelmerge.py \ |
| 178 | - inmodels="data/crab.xml,data/source1.xml" \ | |
| 178 | + inmodels="data/crab.xml;data/source1.xml" \ | |
| 179 | 179 | outmodel="merged_models2.xml" > csmodelmerge.log |
| 180 | 180 | $ECHO -n "." |
| 181 | 181 | if [ -s "merged_models2.xml" ] |
| ... | ... | @@ -218,10 +218,10 @@ rm models.txt |
| 218 | 218 | # Test cstsmapmerge |
| 219 | 219 | # ================= |
| 220 | 220 | $ECHO -n "Test cstsmapmerge: " |
| 221 | -# === comma-separated === | |
| 221 | +# === semi-colon separated === | |
| 222 | 222 | chmod +x @abs_top_srcdir@/cscripts/cstsmapmerge.py |
| 223 | 223 | @PYTHON_COVERAGE@@abs_top_srcdir@/cscripts/cstsmapmerge.py \ |
| 224 | - inmaps="data/tsmap_0.fits,data/tsmap_1.fits" \ | |
| 224 | + inmaps="data/tsmap_0.fits;data/tsmap_1.fits" \ | |
| 225 | 225 | outmap="merged_tsmap1.fits" > cstsmapmerge.log |
| 226 | 226 | $ECHO -n "." |
| 227 | 227 | if [ -s "merged_tsmap1.fits" ] | ... | ... |