Commit e6c90a83bf3dfaa7479e1588f446501fc7bfc985
Merge branch '1365-write-cslightcrv' into integration
Showing
3 changed files
with
668 additions
and
8 deletions
scripts/Makefile.am
| ... | ... | @@ -6,13 +6,13 @@ binscripts = cta_kb_bkgrates.py cta_root2irf.py cta_make_nodes.py \ |
| 6 | 6 | |
| 7 | 7 | # Scripts to be distributed in pythondir |
| 8 | 8 | pythonscripts = cspull.py cssens.py cstsdist.py cscaldb.py csresmap.py cshessobs.py \ |
| 9 | - csobsdef.py csspec.py \ | |
| 9 | + csobsdef.py csspec.py cslightcrv.py \ | |
| 10 | 10 | lsmodel.py \ |
| 11 | 11 | obsutils.py |
| 12 | 12 | |
| 13 | 13 | # Scripts for which symbolic links will be created in bindir |
| 14 | 14 | linkscripts = cspull cssens cstsdist cscaldb csresmap \ |
| 15 | - csobsdef csspec cshessobs\ | |
| 15 | + csobsdef csspec cshessobs cslightcrv \ | |
| 16 | 16 | lsmodel |
| 17 | 17 | |
| 18 | 18 | # Distribute scripts | ... | ... |
scripts/cslightcrv.py
0 → 100755
| 1 | +#! /usr/bin/env python | |
| 2 | +# ========================================================================== | |
| 3 | +# Light curve generation script. | |
| 4 | +# | |
| 5 | +# Copyright (C) 2014-2015 Michael Mayer | |
| 6 | +# | |
| 7 | +# This program is free software: you can redistribute it and/or modify | |
| 8 | +# it under the terms of the GNU General Public License as published by | |
| 9 | +# the Free Software Foundation, either version 3 of the License, or | |
| 10 | +# (at your option) any later version. | |
| 11 | +# | |
| 12 | +# This program is distributed in the hope that it will be useful, | |
| 13 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 14 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 15 | +# GNU General Public License for more details. | |
| 16 | +# | |
| 17 | +# You should have received a copy of the GNU General Public License | |
| 18 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 19 | +# | |
| 20 | +# ========================================================================== | |
| 21 | +import gammalib | |
| 22 | +import ctools | |
| 23 | +import sys | |
| 24 | + | |
| 25 | +# ============ # | |
| 26 | +# csspec class # | |
| 27 | +# ============ # | |
| 28 | +class cslightcrv(ctools.cscript): | |
| 29 | + """ | |
| 30 | + This class implements the creation of a light curve. It derives from | |
| 31 | + the ctools.cscript class which provides support for parameter files, | |
| 32 | + command line arguments, and logging. In that way the Python script | |
| 33 | + behaves just as a regular ctool. | |
| 34 | + """ | |
| 35 | + def __init__(self, *argv): | |
| 36 | + """ | |
| 37 | + Constructor. | |
| 38 | + """ | |
| 39 | + | |
| 40 | + # Set name | |
| 41 | + self.name = "cslightcrv" | |
| 42 | + self.version = "1.0.0" | |
| 43 | + | |
| 44 | + # Initialise some members | |
| 45 | + self.obs = None | |
| 46 | + | |
| 47 | + # Initialise some members | |
| 48 | + if isinstance(argv[0],gammalib.GObservations): | |
| 49 | + self.obs = argv[0] | |
| 50 | + argv = argv[1:] | |
| 51 | + else: | |
| 52 | + self.obs = gammalib.GObservations() | |
| 53 | + self.obs.clear() | |
| 54 | + self.m_outfile = "" | |
| 55 | + | |
| 56 | + # Make sure that parfile exists | |
| 57 | + file = self.parfile() | |
| 58 | + | |
| 59 | + # Initialise application | |
| 60 | + if len(argv) == 0: | |
| 61 | + ctools.cscript.__init__(self, self.name, self.version) | |
| 62 | + elif len(argv) ==1: | |
| 63 | + ctools.cscript.__init__(self, self.name, self.version, *argv) | |
| 64 | + else: | |
| 65 | + raise TypeError("Invalid number of arguments given.") | |
| 66 | + | |
| 67 | + # Set logger properties | |
| 68 | + self.log_header() | |
| 69 | + self.log.date(True) | |
| 70 | + | |
| 71 | + # Return | |
| 72 | + return | |
| 73 | + | |
| 74 | + def __del__(self): | |
| 75 | + """ | |
| 76 | + Destructor. | |
| 77 | + """ | |
| 78 | + # Write separator into logger | |
| 79 | + if self.logTerse(): | |
| 80 | + self.log("\n") | |
| 81 | + | |
| 82 | + # Return | |
| 83 | + return | |
| 84 | + | |
| 85 | + def parfile(self): | |
| 86 | + """ | |
| 87 | + Check if parfile exists. If parfile does not exist then create a | |
| 88 | + default parfile. This kluge avoids shipping the cscript with a parfile. | |
| 89 | + """ | |
| 90 | + # Set parfile name | |
| 91 | + parfile = self.name+".par" | |
| 92 | + | |
| 93 | + try: | |
| 94 | + pars = gammalib.GApplicationPars(parfile) | |
| 95 | + except: | |
| 96 | + # Signal if parfile was not found | |
| 97 | + sys.stdout.write("Parfile "+parfile+" not found. Create default parfile.\n") | |
| 98 | + | |
| 99 | + # Create default parfile | |
| 100 | + pars = gammalib.GApplicationPars() | |
| 101 | + pars.append(gammalib.GApplicationPar("inobs","f","a","events.fits","","","Event list, counts cube, or observation definition file")) | |
| 102 | + pars.append(gammalib.GApplicationPar("inmodel","f","a","$CTOOLS/share/models/crab.xml","","","Source model")) | |
| 103 | + pars.append(gammalib.GApplicationPar("srcname","s","a","Crab","","","Source name")) | |
| 104 | + pars.append(gammalib.GApplicationPar("outfile","f","a","lightcurve.fits","","","Output file name")) | |
| 105 | + pars.append(gammalib.GApplicationPar("expcube","f","a","NONE","","","Exposure cube file (only needed for stacked analysis)")) | |
| 106 | + pars.append(gammalib.GApplicationPar("psfcube","f","a","NONE","","","PSF cube file (only needed for stacked analysis)")) | |
| 107 | + pars.append(gammalib.GApplicationPar("bkgcube","s","a","NONE","","","Background cube file (only needed for stacked analysis)")) | |
| 108 | + pars.append(gammalib.GApplicationPar("caldb","s","a","dummy","","","Calibration database")) | |
| 109 | + pars.append(gammalib.GApplicationPar("irf","s","a","cta_dummy_irf","","","Instrument response function")) | |
| 110 | + pars.append(gammalib.GApplicationPar("tmin","r","a","51544.5","","days","Lightcurve Time start [MJD]")) | |
| 111 | + pars.append(gammalib.GApplicationPar("tmax","r","a","51544.6","","days","Lightcurve Time stop [MJD]")) | |
| 112 | + pars.append(gammalib.GApplicationPar("tbins","i","a","5","","","Number of time bins points")) | |
| 113 | + pars.append(gammalib.GApplicationPar("tbinalg","s", "a","GTI","FILE|LIN|GTI","", "Algorithm for defining energy bins")) | |
| 114 | + pars.append(gammalib.GApplicationPar("tbinfile","s", "a","tbins.fits","","", "File defining the time binning")) | |
| 115 | + pars.append(gammalib.GApplicationPar("binned","b","a","no","yes|no","","Use binned analysis in each energy bin")) | |
| 116 | + pars.append(gammalib.GApplicationPar("nebins","i","h","20","","","Number of energy bins per light curve point")) | |
| 117 | + pars.append(gammalib.GApplicationPar("coordsys","s","a","CEL","CEL|GAL","","Coordinate System")) | |
| 118 | + pars.append(gammalib.GApplicationPar("proj","s","a","CAR","AIT|AZP|CAR|MER|MOL|STG|TAN","","Projection method")) | |
| 119 | + pars.append(gammalib.GApplicationPar("xref","r","a","83.63","0","360","First coordinate of image center in degrees (RA or galactic l)")) | |
| 120 | + pars.append(gammalib.GApplicationPar("yref","r","a","22.01","-90","90","Second coordinate of image center in degrees (DEC or galactic b)")) | |
| 121 | + pars.append(gammalib.GApplicationPar("nxpix","i","a","200","","","Size of the X axis in pixels")) | |
| 122 | + pars.append(gammalib.GApplicationPar("nypix","i","a","200","","","Size of the Y axis in pixels")) | |
| 123 | + pars.append(gammalib.GApplicationPar("binsz","r","a","0.02","","","Pixel size (deg/pixel)")) | |
| 124 | + pars.append(gammalib.GApplicationPar("emin","r","a","0.1","","","Lower energy limit for binned analysis (TeV)")) | |
| 125 | + pars.append(gammalib.GApplicationPar("emax","r","a","100.0","","","Upper energy limit for binned analysis (TeV)")) | |
| 126 | + pars.append(gammalib.GApplicationPar("calc_ts","b","h","yes","yes|no","","Compute TS value in each bin")) | |
| 127 | + pars.append(gammalib.GApplicationPar("calc_ulim","b","h","yes","yes|no","","Compute upper limit in each bin")) | |
| 128 | + pars.append(gammalib.GApplicationPar("fix_srcs","b","h","yes","yes|no","","Fix other skymodel parameters")) | |
| 129 | + pars.append(gammalib.GApplicationPar("fix_bkg","b","h","no","yes|no","","Fix background parameters")) | |
| 130 | + pars.append_standard() | |
| 131 | + pars.append(gammalib.GApplicationPar("logfile","f","h","cslightcrv.log","","","Log filename")) | |
| 132 | + pars.save(parfile) | |
| 133 | + | |
| 134 | + # Return | |
| 135 | + return | |
| 136 | + | |
| 137 | + def create_tbounds(self): | |
| 138 | + | |
| 139 | + # Create time bin container | |
| 140 | + self.m_tbins = gammalib.GGti() | |
| 141 | + | |
| 142 | + # check for binning algorithm | |
| 143 | + if self["tbinalg"].string() == "FILE": | |
| 144 | + try: | |
| 145 | + self.m_tbins.load(self["tbinfile"].filename()) | |
| 146 | + except: | |
| 147 | + csv = gammalib.GCsv(self["tbinfile"].filename()) | |
| 148 | + for i in range(csv.nrows()): | |
| 149 | + tmin = gammalib.GTime() | |
| 150 | + tmax = gammalib.GTime() | |
| 151 | + tmin.mjd(csv.real(i,0)) | |
| 152 | + tmax.mjd(csv.real(i,1)) | |
| 153 | + self.m_tbins.append(tmin,tmax) | |
| 154 | + elif self["tbinalg"].string() == "LIN": | |
| 155 | + # Use linear time binning | |
| 156 | + time_min = self["tmin"].real() | |
| 157 | + time_max = self["tmax"].real() | |
| 158 | + nbins = self["tbins"].integer() | |
| 159 | + step = (time_max - time_min) / float(nbins) | |
| 160 | + for i in range(nbins): | |
| 161 | + tmin = gammalib.GTime() | |
| 162 | + tmin.mjd(time_min + i*step)# ref) | |
| 163 | + tmax = gammalib.GTime() | |
| 164 | + tmax.mjd(time_min + (i+1)*step)#ref) | |
| 165 | + self.m_tbins.append(tmin,tmax) | |
| 166 | + elif self["tbinalg"].string() == "GTI": | |
| 167 | + # Use GTIs of observations | |
| 168 | + for obs in self.obs: | |
| 169 | + for i in range(obs.events().gti().size()): | |
| 170 | + self.m_tbins.append(obs.events().gti().tstart(i),obs.events().gti().tstop(i)) | |
| 171 | + else: | |
| 172 | + raise AttributeError("tbinalg=\""+self["tbinalg"].string()+"\" unkown. Must be one of \"FILE\", \"LIN\" or \"GTI\"") | |
| 173 | + | |
| 174 | + # Return | |
| 175 | + return | |
| 176 | + | |
| 177 | + def get_parameters(self): | |
| 178 | + """ | |
| 179 | + Get parameters from parfile and setup the observation. | |
| 180 | + """ | |
| 181 | + # Set observation if not done before | |
| 182 | + if self.obs == None or self.obs.size() == 0: | |
| 183 | + self.require_inobs("cslightcrv::get_parameters()") | |
| 184 | + self.obs = self.get_observations() | |
| 185 | + | |
| 186 | + # Set models if we have none | |
| 187 | + if self.obs.models().size() == 0: | |
| 188 | + self.obs.models(self["inmodel"].filename()) | |
| 189 | + | |
| 190 | + # Get source name | |
| 191 | + self.m_srcname = self["srcname"].string() | |
| 192 | + | |
| 193 | + # Get ebounds | |
| 194 | + self.create_tbounds() | |
| 195 | + | |
| 196 | + # Get binning flag | |
| 197 | + self.m_binned = self["binned"].boolean() | |
| 198 | + if self.m_binned: | |
| 199 | + self.m_xref = self["xref"].real() | |
| 200 | + self.m_yref = self["yref"].real() | |
| 201 | + self.m_nxpix = self["nxpix"].integer() | |
| 202 | + self.m_nypix = self["nypix"].integer() | |
| 203 | + self.m_binsz = self["binsz"].real() | |
| 204 | + self.m_coordsys = self["coordsys"].string() | |
| 205 | + self.m_proj = self["proj"].string() | |
| 206 | + self.m_ebins = self["nebins"].integer() | |
| 207 | + self.m_emin = self["emin"].real() | |
| 208 | + self.m_emax = self["emax"].real() | |
| 209 | + | |
| 210 | + # Read other parameters | |
| 211 | + self.m_outfile = self["outfile"].filename() | |
| 212 | + | |
| 213 | + # Get other parameeters | |
| 214 | + self.m_calc_ulimit = self["calc_ulim"].boolean() | |
| 215 | + self.m_calc_ts = self["calc_ts"].boolean() | |
| 216 | + self.m_fix_bkg = self["fix_bkg"].boolean() | |
| 217 | + self.m_fix_srcs = self["fix_srcs"].boolean() | |
| 218 | + | |
| 219 | + # Set some fixed parameters | |
| 220 | + self.m_log = False # Logging in client tools | |
| 221 | + self.m_chatter = self["chatter"].integer() | |
| 222 | + self.m_clobber = self["clobber"].boolean() | |
| 223 | + self.m_debug = self["debug"].boolean() | |
| 224 | + | |
| 225 | + # Return | |
| 226 | + return | |
| 227 | + | |
| 228 | + def models(self, models): | |
| 229 | + """ | |
| 230 | + Set model. | |
| 231 | + """ | |
| 232 | + # Copy models | |
| 233 | + self.obs.models(models.clone()) | |
| 234 | + | |
| 235 | + # Return | |
| 236 | + return | |
| 237 | + | |
| 238 | + def execute(self): | |
| 239 | + """ | |
| 240 | + Execute the script. | |
| 241 | + """ | |
| 242 | + # Run the script | |
| 243 | + self.run() | |
| 244 | + | |
| 245 | + # Save residual map | |
| 246 | + self.fits.saveto(self.m_outfile, self.m_clobber) | |
| 247 | + | |
| 248 | + # Return | |
| 249 | + return | |
| 250 | + | |
| 251 | + def run(self): | |
| 252 | + """ | |
| 253 | + Run the script. | |
| 254 | + """ | |
| 255 | + # Switch screen logging on in debug mode | |
| 256 | + if self.logDebug(): | |
| 257 | + self.log.cout(True) | |
| 258 | + | |
| 259 | + # Get parameters | |
| 260 | + self.get_parameters() | |
| 261 | + | |
| 262 | + # Write input parameters into logger | |
| 263 | + if self.logTerse(): | |
| 264 | + self.log_parameters() | |
| 265 | + self.log("\n") | |
| 266 | + | |
| 267 | + # Write observation into logger | |
| 268 | + if self.logTerse(): | |
| 269 | + self.log("\n") | |
| 270 | + self.log.header1("Observation") | |
| 271 | + self.log(str(self.obs)) | |
| 272 | + self.log("\n") | |
| 273 | + | |
| 274 | + # Write header | |
| 275 | + if self.logTerse(): | |
| 276 | + self.log("\n") | |
| 277 | + self.log.header1("Adjust model parameters") | |
| 278 | + | |
| 279 | + # Adjust model parameters dependent on input user parameters | |
| 280 | + for model in self.obs.models(): | |
| 281 | + | |
| 282 | + # Set TS flag for all models to false. | |
| 283 | + # Source of interest will be set to true later | |
| 284 | + model.tscalc(False) | |
| 285 | + | |
| 286 | + # Log model name | |
| 287 | + if self.logExplicit(): | |
| 288 | + self.log.header3(model.name()) | |
| 289 | + | |
| 290 | + # Deal with the source of interest | |
| 291 | + if model.name() == self.m_srcname: | |
| 292 | + if self.m_calc_ts: | |
| 293 | + model.tscalc(True) | |
| 294 | + | |
| 295 | + elif self.m_fix_bkg and not model.classname() == "GModelSky": | |
| 296 | + for par in model: | |
| 297 | + if par.is_free() and self.logExplicit(): | |
| 298 | + self.log(" Fixing \""+par.name()+"\"\n") | |
| 299 | + par.fix() | |
| 300 | + | |
| 301 | + elif self.m_fix_srcs and model.classname() == "GModelSky": | |
| 302 | + for par in model: | |
| 303 | + if par.is_free() and self.logExplicit(): | |
| 304 | + self.log(" Fixing \""+par.name()+"\"\n") | |
| 305 | + par.fix() | |
| 306 | + | |
| 307 | + # Write header | |
| 308 | + if self.logTerse(): | |
| 309 | + self.log("\n") | |
| 310 | + self.log.header1("Generate lightcurve") | |
| 311 | + | |
| 312 | + # Initialise FITS Table with extension "LIGHTCURVE" | |
| 313 | + table = gammalib.GFitsBinTable(self.m_tbins.size()) | |
| 314 | + table.extname("LIGHTCURVE") | |
| 315 | + | |
| 316 | + # Add Header for compatibility with gammalib.GMWLSpectrum | |
| 317 | + table.card("INSTRUME", "CTA", "Name of Instrument") | |
| 318 | + table.card("TELESCOP", "CTA", "Name of Telescope") | |
| 319 | + | |
| 320 | + # Create FITS table columns | |
| 321 | + MJD = gammalib.GFitsTableDoubleCol("MJD", self.m_tbins.size()) | |
| 322 | + MJD.unit("days") | |
| 323 | + e_MJD = gammalib.GFitsTableDoubleCol("e_MJD", self.m_tbins.size()) | |
| 324 | + e_MJD.unit("days") | |
| 325 | + | |
| 326 | + # Create a FITS column for every free parameter | |
| 327 | + columns = [] | |
| 328 | + for par in self.obs.models()[self.m_srcname]: | |
| 329 | + if par.is_free(): | |
| 330 | + col = gammalib.GFitsTableDoubleCol(par.name(), self.m_tbins.size()) | |
| 331 | + col.unit(par.unit()) | |
| 332 | + columns.append(col) | |
| 333 | + e_col = gammalib.GFitsTableDoubleCol("e_"+par.name(), self.m_tbins.size()) | |
| 334 | + e_col.unit(par.unit()) | |
| 335 | + columns.append(e_col) | |
| 336 | + | |
| 337 | + # Create TS and upper limit columns | |
| 338 | + TSvalues = gammalib.GFitsTableDoubleCol("TS", self.m_tbins.size()) | |
| 339 | + ulim_values = gammalib.GFitsTableDoubleCol("UpperLimit", self.m_tbins.size()) | |
| 340 | + ulim_values.unit("ph/cm2/s") | |
| 341 | + | |
| 342 | + # Loop over energy bins | |
| 343 | + for i in range(self.m_tbins.size()): | |
| 344 | + | |
| 345 | + # Log information | |
| 346 | + if self.logTerse(): | |
| 347 | + self.log("\n") | |
| 348 | + self.log.header2("Time bin "+str(i)) | |
| 349 | + | |
| 350 | + # Get time boundaries | |
| 351 | + tmin = self.m_tbins.tstart(i) | |
| 352 | + tmax = self.m_tbins.tstop(i) | |
| 353 | + | |
| 354 | + # Compute time bin center and time width | |
| 355 | + tmean = (tmin + tmax) | |
| 356 | + tmean *= 0.5 | |
| 357 | + twidth = (tmax - tmin) | |
| 358 | + twidth *= 0.5 | |
| 359 | + | |
| 360 | + # Store time as MJD | |
| 361 | + MJD[i] = tmean.mjd() | |
| 362 | + e_MJD[i] = twidth.days() | |
| 363 | + | |
| 364 | + # Log information | |
| 365 | + if self.logExplicit(): | |
| 366 | + self.log.header3("Selecting events") | |
| 367 | + | |
| 368 | + # Select events | |
| 369 | + select = ctools.ctselect(self.obs) | |
| 370 | + select["emin"].value("UNDEFINED") | |
| 371 | + select["emax"].value("UNDEFINED") | |
| 372 | + select["tmin"].real(tmin.convert(select.time_reference())) | |
| 373 | + select["tmax"].real(tmax.convert(select.time_reference())) | |
| 374 | + select["rad"].value("UNDEFINED") | |
| 375 | + select["ra"].value("UNDEFINED") | |
| 376 | + select["dec"].value("UNDEFINED") | |
| 377 | + select.run() | |
| 378 | + | |
| 379 | + # Retrieve observation | |
| 380 | + obs = select.obs() | |
| 381 | + | |
| 382 | + # Binned analysis | |
| 383 | + if self.m_binned: | |
| 384 | + | |
| 385 | + # Header | |
| 386 | + if self.logTerse(): | |
| 387 | + self.log.header3("Binning events") | |
| 388 | + | |
| 389 | + # Bin events | |
| 390 | + bin = ctools.ctbin(select.obs()) | |
| 391 | + bin["usepnt"].boolean(False) | |
| 392 | + bin["ebinalg"].string("LOG") | |
| 393 | + bin["xref"].real(self.m_xref) | |
| 394 | + bin["yref"].real(self.m_yref) | |
| 395 | + bin["binsz"].real(self.m_binsz) | |
| 396 | + bin["nxpix"].integer(self.m_nxpix) | |
| 397 | + bin["nypix"].integer(self.m_nypix) | |
| 398 | + bin["enumbins"].integer(self.m_ebins) | |
| 399 | + bin["emin"].real(self.m_emin) | |
| 400 | + bin["emax"].real(self.m_emax) | |
| 401 | + bin["coordsys"].string(self.m_coordsys) | |
| 402 | + bin["proj"].string(self.m_proj) | |
| 403 | + bin.run() | |
| 404 | + | |
| 405 | + # Header | |
| 406 | + if self.logTerse(): | |
| 407 | + self.log.header3("Creating exposure cube") | |
| 408 | + | |
| 409 | + # Create exposure cube | |
| 410 | + expcube = ctools.ctexpcube(select.obs()) | |
| 411 | + expcube["incube"].filename("NONE") | |
| 412 | + expcube["usepnt"].boolean(False) | |
| 413 | + expcube["ebinalg"].string("LOG") | |
| 414 | + expcube["xref"].real(self.m_xref) | |
| 415 | + expcube["yref"].real(self.m_yref) | |
| 416 | + expcube["binsz"].real(self.m_binsz) | |
| 417 | + expcube["nxpix"].integer(self.m_nxpix) | |
| 418 | + expcube["nypix"].integer(self.m_nypix) | |
| 419 | + expcube["enumbins"].integer(self.m_ebins) | |
| 420 | + expcube["emin"].real(self.m_emin) | |
| 421 | + expcube["emax"].real(self.m_emax) | |
| 422 | + expcube["coordsys"].string(self.m_coordsys) | |
| 423 | + expcube["proj"].string(self.m_proj) | |
| 424 | + expcube.run() | |
| 425 | + | |
| 426 | + # Header | |
| 427 | + if self.logTerse(): | |
| 428 | + self.log.header3("Creating PSF cube") | |
| 429 | + | |
| 430 | + # Create psf cube | |
| 431 | + psfcube = ctools.ctpsfcube(select.obs()) | |
| 432 | + psfcube["incube"].filename("NONE") | |
| 433 | + psfcube["usepnt"].boolean(False) | |
| 434 | + psfcube["ebinalg"].string("LOG") | |
| 435 | + psfcube["xref"].real(self.m_xref) | |
| 436 | + psfcube["yref"].real(self.m_yref) | |
| 437 | + psfcube["binsz"].real(self.m_binsz) | |
| 438 | + psfcube["nxpix"].integer(self.m_nxpix) | |
| 439 | + psfcube["nypix"].integer(self.m_nypix) | |
| 440 | + psfcube["enumbins"].integer(self.m_ebins) | |
| 441 | + psfcube["emin"].real(self.m_emin) | |
| 442 | + psfcube["emax"].real(self.m_emax) | |
| 443 | + psfcube["coordsys"].string(self.m_coordsys) | |
| 444 | + psfcube["proj"].string(self.m_proj) | |
| 445 | + psfcube.run() | |
| 446 | + | |
| 447 | + # Header | |
| 448 | + if self.logTerse(): | |
| 449 | + self.log.header3("Creating background cube") | |
| 450 | + | |
| 451 | + # Create background cube | |
| 452 | + bkgcube = ctools.ctbkgcube(select.obs()) | |
| 453 | + bkgcube["incube"].filename("NONE") | |
| 454 | + bkgcube["usepnt"].boolean(False) | |
| 455 | + bkgcube["ebinalg"].string("LOG") | |
| 456 | + bkgcube["xref"].real(self.m_xref) | |
| 457 | + bkgcube["yref"].real(self.m_yref) | |
| 458 | + bkgcube["binsz"].real(self.m_binsz) | |
| 459 | + bkgcube["nxpix"].integer(self.m_nxpix) | |
| 460 | + bkgcube["nypix"].integer(self.m_nypix) | |
| 461 | + bkgcube["enumbins"].integer(self.m_ebins) | |
| 462 | + bkgcube["emin"].real(self.m_emin) | |
| 463 | + bkgcube["emax"].real(self.m_emax) | |
| 464 | + bkgcube["coordsys"].string(self.m_coordsys) | |
| 465 | + bkgcube["proj"].string(self.m_proj) | |
| 466 | + bkgcube.run() | |
| 467 | + | |
| 468 | + # Set new binned observation | |
| 469 | + obs = bin.obs() | |
| 470 | + | |
| 471 | + # Set precomputed binned response | |
| 472 | + obs[0].response(expcube.expcube(), psfcube.psfcube(), bkgcube.cube()) | |
| 473 | + | |
| 474 | + # Get new models | |
| 475 | + models = bkgcube.models() | |
| 476 | + | |
| 477 | + # Fix background models if required | |
| 478 | + if self.m_fix_bkg: | |
| 479 | + for model in models: | |
| 480 | + if not model.classname() == "GModelSky": | |
| 481 | + for par in model: | |
| 482 | + par.fix() | |
| 483 | + | |
| 484 | + # Set new models to binned observation | |
| 485 | + obs.models(models) | |
| 486 | + | |
| 487 | + # Header | |
| 488 | + if self.logTerse(): | |
| 489 | + self.log.header3("Performing fit") | |
| 490 | + | |
| 491 | + # Likelihood | |
| 492 | + like = ctools.ctlike(obs) | |
| 493 | + like.run() | |
| 494 | + | |
| 495 | + # Skip bin if no event was present | |
| 496 | + if like.obs().logL() == 0.0: | |
| 497 | + | |
| 498 | + # Log information | |
| 499 | + if self.logTerse(): | |
| 500 | + self.log("No event in this time bin. Bin is skipped\n") | |
| 501 | + | |
| 502 | + # Set all values to 0 | |
| 503 | + for col in columns: | |
| 504 | + col[i] = 0.0 | |
| 505 | + TSvalues[i] = 0.0 | |
| 506 | + ulim_values[i] = 0.0 | |
| 507 | + continue | |
| 508 | + | |
| 509 | + # Get results | |
| 510 | + fitted_models = like.obs().models() | |
| 511 | + source = fitted_models[self.m_srcname] | |
| 512 | + | |
| 513 | + # Calculate Upper Limit | |
| 514 | + ulimit_value = -1.0 | |
| 515 | + if self.m_calc_ulimit: | |
| 516 | + | |
| 517 | + # Logging information | |
| 518 | + if self.logTerse(): | |
| 519 | + self.log.header3("Computing upper limit") | |
| 520 | + | |
| 521 | + # Create upper limit object | |
| 522 | + ulimit = ctools.ctulimit(like.obs()) | |
| 523 | + ulimit["srcname"].string(self.m_srcname) | |
| 524 | + ulimit["eref"].real(1.0) | |
| 525 | + | |
| 526 | + # Try to run upper limit and catch exceptions | |
| 527 | + try: | |
| 528 | + ulimit.run() | |
| 529 | + ulimit_value = ulimit.flux_ulimit() | |
| 530 | + except: | |
| 531 | + if self.logTerse(): | |
| 532 | + self.log("Upper limit calculation failed\n") | |
| 533 | + ulimit_value = -1.0 | |
| 534 | + | |
| 535 | + # Get TS value | |
| 536 | + TS = -1.0 | |
| 537 | + if self.m_calc_ts: | |
| 538 | + TS = source.ts() | |
| 539 | + | |
| 540 | + # Set values for storage | |
| 541 | + TSvalues[i] = TS | |
| 542 | + | |
| 543 | + # Set FITS column values | |
| 544 | + for col in columns: | |
| 545 | + if "e_" == col.name()[:2]: | |
| 546 | + col[i] = source.spectral()[col.name()[2:]].error() | |
| 547 | + else: | |
| 548 | + col[i] = source.spectral()[col.name()].value() | |
| 549 | + | |
| 550 | + # Store upper limit value if available | |
| 551 | + if ulimit_value > 0.0: | |
| 552 | + ulim_values[i] = ulimit_value | |
| 553 | + | |
| 554 | + # Log information | |
| 555 | + if self.logExplicit(): | |
| 556 | + self.log.header3("Results of bin "+str(i)+": MJD "+str(tmin.mjd())+"-"+str(tmax.mjd())) | |
| 557 | + for col in columns: | |
| 558 | + if "e_" == col.name()[:2]: | |
| 559 | + continue | |
| 560 | + value = source.spectral()[col.name()].value() | |
| 561 | + error = source.spectral()[col.name()].error() | |
| 562 | + unit = source.spectral()[col.name()].unit() | |
| 563 | + self.log(" > "+col.name()+": "+str(value)+" +- "+str(error)+" "+unit+"\n") | |
| 564 | + if self.m_calc_ts and TSvalues[i] > 0.0: | |
| 565 | + self.log(" > TS = "+str(TS)+" \n") | |
| 566 | + if self.m_calc_ulimit and ulim_values[i] > 0.0: | |
| 567 | + self.log(" > UL = "+str(ulim_values[i])+" [ph/cm2/s]") | |
| 568 | + self.log("\n") | |
| 569 | + | |
| 570 | + # Append filles columns to fits table | |
| 571 | + table.append(MJD) | |
| 572 | + table.append(e_MJD) | |
| 573 | + for col in columns: | |
| 574 | + table.append(col) | |
| 575 | + table.append(TSvalues) | |
| 576 | + table.append(ulim_values) | |
| 577 | + | |
| 578 | + # Create the FITS file now | |
| 579 | + self.fits = gammalib.GFits() | |
| 580 | + self.fits.append(table) | |
| 581 | + | |
| 582 | + # Return | |
| 583 | + return | |
| 584 | + | |
| 585 | + | |
| 586 | +# ======================== # | |
| 587 | +# Main routine entry point # | |
| 588 | +# ======================== # | |
| 589 | +if __name__ == '__main__': | |
| 590 | + """ | |
| 591 | + Generates light curve. | |
| 592 | + """ | |
| 593 | + # Create instance of application | |
| 594 | + app = cslightcrv(sys.argv) | |
| 595 | + | |
| 596 | + # Open logfile | |
| 597 | + app.logFileOpen() | |
| 598 | + | |
| 599 | + # Execute application | |
| 600 | + app.execute() | ... | ... |
test/test_cscripts.sh.in
| ... | ... | @@ -190,9 +190,9 @@ fi |
| 190 | 190 | $ECHO " ok" |
| 191 | 191 | |
| 192 | 192 | # |
| 193 | -# Test csspec | |
| 194 | -# =========== | |
| 195 | -$ECHO -n "Test csspec: " | |
| 193 | +# Test csspec (unbinned) | |
| 194 | +# ===================== | |
| 195 | +$ECHO -n "Test csspec (unbinned): " | |
| 196 | 196 | chmod +x @abs_top_srcdir@/scripts/csspec.py |
| 197 | 197 | @abs_top_srcdir@/scripts/csspec.py \ |
| 198 | 198 | inobs="data/crab_events.fits" \ |
| ... | ... | @@ -216,9 +216,9 @@ fi |
| 216 | 216 | $ECHO " ok" |
| 217 | 217 | |
| 218 | 218 | # |
| 219 | -# Test csspec Run2 | |
| 220 | -# ================ | |
| 221 | -$ECHO -n "Test csspec: " | |
| 219 | +# Test csspec (binned) | |
| 220 | +# ==================== | |
| 221 | +$ECHO -n "Test csspec (binned): " | |
| 222 | 222 | chmod +x @abs_top_srcdir@/scripts/csspec.py |
| 223 | 223 | @abs_top_srcdir@/scripts/csspec.py \ |
| 224 | 224 | inobs="data/crab_events.fits" \ |
| ... | ... | @@ -249,3 +249,63 @@ else |
| 249 | 249 | fi |
| 250 | 250 | $ECHO " ok" |
| 251 | 251 | |
| 252 | +# | |
| 253 | +# Test cslightcrv (unbinned) | |
| 254 | +# ========================== | |
| 255 | +$ECHO -n "Test cslightcrv (unbinned): " | |
| 256 | +chmod +x @abs_top_srcdir@/scripts/cslightcrv.py | |
| 257 | +@abs_top_srcdir@/scripts/cslightcrv.py \ | |
| 258 | + inobs="data/crab_events.fits" \ | |
| 259 | + inmodel="data/crab.xml" \ | |
| 260 | + caldb="irf" \ | |
| 261 | + irf="cta_dummy_irf" \ | |
| 262 | + tbins=3 \ | |
| 263 | + tmin=51544.5 \ | |
| 264 | + tmax=51544.53 \ | |
| 265 | + srcname="Crab" \ | |
| 266 | + tbinalg="LIN" \ | |
| 267 | + binned=no \ | |
| 268 | + outfile="lightcurve.fits" > cslightcrv.log | |
| 269 | +$ECHO -n "." | |
| 270 | +if [ -s "lightcurve.fits" ] | |
| 271 | +then | |
| 272 | + $ECHO -n "." | |
| 273 | +else | |
| 274 | + $ECHO " lightcurve.fits file is not valid" | |
| 275 | + exit 1 | |
| 276 | +fi | |
| 277 | +$ECHO " ok" | |
| 278 | + | |
| 279 | +# | |
| 280 | +# Test cslightcrv (binned) | |
| 281 | +# ======================== | |
| 282 | +$ECHO -n "Test cslightcrv (binned): " | |
| 283 | +chmod +x @abs_top_srcdir@/scripts/cslightcrv.py | |
| 284 | +@abs_top_srcdir@/scripts/cslightcrv.py \ | |
| 285 | + inobs="data/crab_events.fits" \ | |
| 286 | + inmodel="data/crab.xml" \ | |
| 287 | + caldb="irf" \ | |
| 288 | + irf="cta_dummy_irf" \ | |
| 289 | + tbinalg="GTI" \ | |
| 290 | + srcname="Crab" \ | |
| 291 | + emin=0.1 \ | |
| 292 | + emax=100.0 \ | |
| 293 | + binned=yes \ | |
| 294 | + nxpix=10 \ | |
| 295 | + nypix=10 \ | |
| 296 | + binsz=0.1 \ | |
| 297 | + nebins=2 \ | |
| 298 | + coordsys="CEL" \ | |
| 299 | + xref=83.63 \ | |
| 300 | + yref=22.01 \ | |
| 301 | + proj="CAR" \ | |
| 302 | + outfile="lightcurve.fits" > cslightcrv.log | |
| 303 | +$ECHO -n "." | |
| 304 | +if [ -s "lightcurve.fits" ] | |
| 305 | +then | |
| 306 | + $ECHO -n "." | |
| 307 | +else | |
| 308 | + $ECHO " lightcurve.fits file is not valid" | |
| 309 | + exit 1 | |
| 310 | +fi | |
| 311 | +$ECHO " ok" | ... | ... |