Commit d0742fe74ee7a903675937093c10a0b23cba4e9c
1 parent
6011bf73
Change implementation of stacked cube handling in csspec.
Showing
1 changed file
with
114 additions
and
65 deletions
cscripts/csspec.py
| ... | ... | @@ -110,10 +110,11 @@ class csspec(ctools.cscript): |
| 110 | 110 | pars.append(gammalib.GApplicationPar("caldb","s","a","prod2","","","Calibration database")) |
| 111 | 111 | pars.append(gammalib.GApplicationPar("irf","s","a","South_50h","","","Instrument response function")) |
| 112 | 112 | pars.append(gammalib.GApplicationPar("edisp","b","h","no","","","Apply energy dispersion?")) |
| 113 | - pars.append(gammalib.GApplicationPar("emin","r","h","0.1","","","Lower energy limit for spectral points(TeV)")) | |
| 114 | - pars.append(gammalib.GApplicationPar("emax","r","h","100.0","","","Upper energy limit for spectral points(TeV)")) | |
| 115 | - pars.append(gammalib.GApplicationPar("enumbins","i","a","20","","","Number of spectral points")) | |
| 116 | - pars.append(gammalib.GApplicationPar("ebinalg","s", "h","LOG","FILE|LIN|LOG","", "Algorithm for defining energy bins")) | |
| 113 | + pars.append(gammalib.GApplicationPar("emin","r","a","0.1","","","Lower energy limit for spectral points (TeV)")) | |
| 114 | + pars.append(gammalib.GApplicationPar("emax","r","a","100.0","","","Upper energy limit for spectral points (TeV)")) | |
| 115 | + pars.append(gammalib.GApplicationPar("enumbins","i","a","20","1","10000","Number of spectral points")) | |
| 116 | + pars.append(gammalib.GApplicationPar("ebinalg","s","a","LOG","FILE|LIN|LOG","", "Algorithm for defining energy bins")) | |
| 117 | + pars.append(gammalib.GApplicationPar("ebinfile","f","a","NONE","","", "Name of the file containing the energy bin definition")) | |
| 117 | 118 | pars.append(gammalib.GApplicationPar("calc_ts","b","h","yes","yes|no","","Compute TS value in each bin")) |
| 118 | 119 | pars.append(gammalib.GApplicationPar("calc_ulim","b","h","yes","yes|no","","Compute upper limit in each bin")) |
| 119 | 120 | pars.append(gammalib.GApplicationPar("fix_srcs","b","h","yes","yes|no","","Fix other skymodel parameters")) |
| ... | ... | @@ -129,7 +130,6 @@ class csspec(ctools.cscript): |
| 129 | 130 | """ |
| 130 | 131 | Get parameters from parfile and setup the observation. |
| 131 | 132 | """ |
| 132 | - | |
| 133 | 133 | # Set observation if not done before |
| 134 | 134 | if self.obs == None or self.obs.size() == 0: |
| 135 | 135 | self.require_inobs("csspec::get_parameters()") |
| ... | ... | @@ -149,41 +149,8 @@ class csspec(ctools.cscript): |
| 149 | 149 | # Get source name |
| 150 | 150 | self.m_srcname = self["srcname"].string() |
| 151 | 151 | |
| 152 | - # Get ebounds | |
| 153 | - if self.m_binned_mode: | |
| 154 | - | |
| 155 | - # Extract cube ebounds | |
| 156 | - cube_ebounds = self.obs[0].events().ebounds() | |
| 157 | - | |
| 158 | - # Read user parameters | |
| 159 | - self.m_enumbins = self["enumbins"].integer() | |
| 160 | - self.m_emin = self["emin"].real() - 1e-6 #rounding tolerance | |
| 161 | - self.m_emax = self["emax"].real() + 1e-6 #rounding tolerance | |
| 162 | - | |
| 163 | - # Compute number of energy layers used for one spectral bin | |
| 164 | - n_layers = cube_ebounds.size() / self.m_enumbins | |
| 165 | - | |
| 166 | - # Don't allow zero layers | |
| 167 | - if n_layers == 0: | |
| 168 | - n_layers = 1 | |
| 169 | - | |
| 170 | - # Create new ebounds object and fill it | |
| 171 | - self.m_ebounds = gammalib.GEbounds() | |
| 172 | - for i in range(cube_ebounds.size())[::n_layers]: | |
| 173 | - if i + n_layers > cube_ebounds.size(): | |
| 174 | - break | |
| 175 | - | |
| 176 | - # Get new emin and emax of bin | |
| 177 | - emin = cube_ebounds.emin(i) | |
| 178 | - emax = cube_ebounds.emax(i + n_layers - 1) | |
| 179 | - | |
| 180 | - # Append energy bin if within user range | |
| 181 | - if self.m_emin <= emin.TeV() and self.m_emax >= emax.TeV(): | |
| 182 | - self.m_ebounds.append(emin, emax) | |
| 183 | - | |
| 184 | - # Unbinned mode | |
| 185 | - else: | |
| 186 | - self.m_ebounds = self.create_ebounds() | |
| 152 | + # Set ebounds | |
| 153 | + self.set_ebounds() | |
| 187 | 154 | |
| 188 | 155 | # Get edisp flag |
| 189 | 156 | self.m_edisp = self["edisp"].boolean() |
| ... | ... | @@ -206,6 +173,66 @@ class csspec(ctools.cscript): |
| 206 | 173 | # Return |
| 207 | 174 | return |
| 208 | 175 | |
| 176 | + def set_ebounds(self): | |
| 177 | + """ | |
| 178 | + Set energy boundaries. | |
| 179 | + """ | |
| 180 | + # Get ebounds | |
| 181 | + if self.m_binned_mode: | |
| 182 | + | |
| 183 | + # Extract cube ebounds | |
| 184 | + cube_ebounds = self.obs[0].events().ebounds() | |
| 185 | + | |
| 186 | + # Read user parameters | |
| 187 | + self.m_enumbins = self["enumbins"].integer() | |
| 188 | + self.m_emin = self["emin"].real() - 1e-6 # Rounding tolerance | |
| 189 | + self.m_emax = self["emax"].real() + 1e-6 # Rounding tolerance | |
| 190 | + | |
| 191 | + # Set energy range | |
| 192 | + emin = gammalib.GEnergy(self.m_emin, "TeV") | |
| 193 | + emax = gammalib.GEnergy(self.m_emax, "TeV") | |
| 194 | + | |
| 195 | + # Determine all cube layers that overlap with the [emin,emax] | |
| 196 | + # energy range. | |
| 197 | + use_layers = [] | |
| 198 | + for i in range(cube_ebounds.size()): | |
| 199 | + if cube_ebounds.emin(i) < emax and cube_ebounds.emax(i) > emin: | |
| 200 | + use_layers.append(i) | |
| 201 | + | |
| 202 | + # If no layers overlap then throw an exception | |
| 203 | + if (len(use_layers) == 0): | |
| 204 | + msg = "Energy range ["+str(cube_ebounds.emin(i))+ \ | |
| 205 | + ", "+str(cube_ebounds.emax(i))+"] of counts "+ \ | |
| 206 | + "cube does not overlap with specified energy range ["+ \ | |
| 207 | + str(emin)+", "+str(emax)+"]. Specify "+ \ | |
| 208 | + "overlapping energy range." | |
| 209 | + raise gammalib.GException.invalid_argument("csspec", msg) | |
| 210 | + | |
| 211 | + # Determine number of layers to use for each spectral bin | |
| 212 | + n_layers = int(len(use_layers) / self.m_enumbins) | |
| 213 | + | |
| 214 | + # Don't allow zero layers | |
| 215 | + if n_layers == 0: | |
| 216 | + n_layers = 1 | |
| 217 | + | |
| 218 | + # Create energy boundaries | |
| 219 | + self.m_ebounds = gammalib.GEbounds() | |
| 220 | + for i in range(len(use_layers))[::n_layers]: | |
| 221 | + i_start = i | |
| 222 | + i_stop = i + n_layers - 1 | |
| 223 | + if i_stop >= len(use_layers): | |
| 224 | + i_stop = len(use_layers) - 1 | |
| 225 | + ebinmin = cube_ebounds.emin(use_layers[i_start]) | |
| 226 | + ebinmax = cube_ebounds.emax(use_layers[i_stop]) | |
| 227 | + self.m_ebounds.append(ebinmin, ebinmax) | |
| 228 | + | |
| 229 | + # Unbinned mode | |
| 230 | + else: | |
| 231 | + self.m_ebounds = self.create_ebounds() | |
| 232 | + | |
| 233 | + # Return | |
| 234 | + return | |
| 235 | + | |
| 209 | 236 | def models(self, models): |
| 210 | 237 | """ |
| 211 | 238 | Set model. |
| ... | ... | @@ -252,6 +279,24 @@ class csspec(ctools.cscript): |
| 252 | 279 | self.log_parameters() |
| 253 | 280 | self.log("\n") |
| 254 | 281 | |
| 282 | + # Write spectral binning into header | |
| 283 | + if self.logTerse(): | |
| 284 | + self.log("\n") | |
| 285 | + self.log.header1("Spectral binning") | |
| 286 | + if self.m_binned_mode: | |
| 287 | + cube_ebounds = self.obs[0].events().ebounds() | |
| 288 | + self.log.parformat("Counts cube energy range") | |
| 289 | + self.log(str(cube_ebounds.emin())) | |
| 290 | + self.log(" - ") | |
| 291 | + self.log(str(cube_ebounds.emax())) | |
| 292 | + self.log("\n") | |
| 293 | + for i in range(self.m_ebounds.size()): | |
| 294 | + self.log.parformat("Bin "+str(i+1)) | |
| 295 | + self.log(str(self.m_ebounds.emin(i))) | |
| 296 | + self.log(" - ") | |
| 297 | + self.log(str(self.m_ebounds.emax(i))) | |
| 298 | + self.log("\n") | |
| 299 | + | |
| 255 | 300 | # Write observation into logger |
| 256 | 301 | if self.logTerse(): |
| 257 | 302 | self.log("\n") |
| ... | ... | @@ -316,26 +361,25 @@ class csspec(ctools.cscript): |
| 316 | 361 | |
| 317 | 362 | # Create FITS table columns |
| 318 | 363 | energy = gammalib.GFitsTableDoubleCol("Energy", self.m_ebounds.size()) |
| 319 | - energy.unit("TeV") | |
| 320 | 364 | energy_low = gammalib.GFitsTableDoubleCol("ed_Energy", self.m_ebounds.size()) |
| 321 | - energy_low.unit("TeV") | |
| 322 | 365 | energy_high = gammalib.GFitsTableDoubleCol("eu_Energy", self.m_ebounds.size()) |
| 323 | - energy_high.unit("TeV") | |
| 324 | 366 | flux = gammalib.GFitsTableDoubleCol("Flux", self.m_ebounds.size()) |
| 325 | - flux.unit("erg/cm2/s") | |
| 326 | 367 | flux_err = gammalib.GFitsTableDoubleCol("e_Flux", self.m_ebounds.size()) |
| 327 | - flux_err.unit("erg/cm2/s") | |
| 328 | 368 | TSvalues = gammalib.GFitsTableDoubleCol("TS", self.m_ebounds.size()) |
| 329 | 369 | ulim_values = gammalib.GFitsTableDoubleCol("UpperLimit", self.m_ebounds.size()) |
| 330 | - ulim_values.unit("erg/cm2/s") | |
| 331 | 370 | Npred_values = gammalib.GFitsTableDoubleCol("Npred", self.m_ebounds.size()) |
| 332 | - | |
| 371 | + energy.unit("TeV") | |
| 372 | + energy_low.unit("TeV") | |
| 373 | + energy_high.unit("TeV") | |
| 374 | + flux.unit("erg/cm2/s") | |
| 375 | + flux_err.unit("erg/cm2/s") | |
| 376 | + ulim_values.unit("erg/cm2/s") | |
| 333 | 377 | |
| 334 | 378 | # Loop over energy bins |
| 335 | 379 | for i in range(self.m_ebounds.size()): |
| 336 | 380 | |
| 337 | 381 | # Log information |
| 338 | - if self.logTerse(): | |
| 382 | + if self.logExplicit(): | |
| 339 | 383 | self.log("\n") |
| 340 | 384 | self.log.header2("Energy bin "+str(i+1)) |
| 341 | 385 | |
| ... | ... | @@ -377,9 +421,10 @@ class csspec(ctools.cscript): |
| 377 | 421 | else: |
| 378 | 422 | |
| 379 | 423 | # Header |
| 380 | - if self.logTerse(): | |
| 381 | - self.log.header3("Selecting events") | |
| 424 | + if self.logExplicit(): | |
| 425 | + self.log.header3("Filtering cube") | |
| 382 | 426 | |
| 427 | + # Select layers | |
| 383 | 428 | cubemask = ctools.ctcubemask(self.obs) |
| 384 | 429 | cubemask["regfile"] = "NONE" |
| 385 | 430 | cubemask["ra"] = "UNDEFINED" |
| ... | ... | @@ -393,7 +438,7 @@ class csspec(ctools.cscript): |
| 393 | 438 | obs = cubemask.obs() |
| 394 | 439 | |
| 395 | 440 | # Header |
| 396 | - if self.logTerse(): | |
| 441 | + if self.logExplicit(): | |
| 397 | 442 | self.log.header3("Performing fit") |
| 398 | 443 | |
| 399 | 444 | # Likelihood |
| ... | ... | @@ -405,8 +450,10 @@ class csspec(ctools.cscript): |
| 405 | 450 | if like.obs().logL() == 0.0: |
| 406 | 451 | |
| 407 | 452 | # Log information |
| 408 | - if self.logTerse(): | |
| 409 | - self.log("No event in this bin. Likelihood is zero. Bin is skipped\n") | |
| 453 | + if self.logExplicit(): | |
| 454 | + self.log("No event in this bin. ") | |
| 455 | + self.log("Likelihood is zero. ") | |
| 456 | + self.log("Bin is skipped.") | |
| 410 | 457 | |
| 411 | 458 | # Set all values to 0 |
| 412 | 459 | flux[i] = 0.0 |
| ... | ... | @@ -425,21 +472,21 @@ class csspec(ctools.cscript): |
| 425 | 472 | if self.m_calc_ulimit: |
| 426 | 473 | |
| 427 | 474 | # Logging information |
| 428 | - if self.logTerse(): | |
| 475 | + if self.logExplicit(): | |
| 429 | 476 | self.log.header3("Computing upper limit") |
| 430 | 477 | |
| 431 | 478 | # Create upper limit object |
| 432 | 479 | ulimit = ctools.ctulimit(like.obs()) |
| 433 | 480 | ulimit["srcname"] = self.m_srcname |
| 434 | - ulimit["eref"] = elogmean.TeV() | |
| 481 | + ulimit["eref"] = elogmean.TeV() | |
| 435 | 482 | |
| 436 | 483 | # Try to run upper limit and catch exceptions |
| 437 | 484 | try: |
| 438 | 485 | ulimit.run() |
| 439 | 486 | ulimit_value = ulimit.diff_ulimit() |
| 440 | 487 | except: |
| 441 | - if self.logTerse(): | |
| 442 | - self.log("Upper limit calculation failed\n") | |
| 488 | + if self.logExplicit(): | |
| 489 | + self.log("Upper limit calculation failed.") | |
| 443 | 490 | ulimit_value = -1.0 |
| 444 | 491 | |
| 445 | 492 | # Get TS value |
| ... | ... | @@ -474,15 +521,17 @@ class csspec(ctools.cscript): |
| 474 | 521 | ulim_values[i] = ulimit_value * elogmean2 * gammalib.MeV2erg |
| 475 | 522 | |
| 476 | 523 | # Log information |
| 477 | - if self.logExplicit(): | |
| 478 | - self.log("Bin "+str(i)+" ["+str(emin.TeV())+"-"+str(emax.TeV())+"] TeV: ") | |
| 479 | - self.log("Flux = "+str(flux[i])) | |
| 480 | - self.log(" +- "+str(flux_err[i])+" [erg/cm2/s]") | |
| 481 | - if self.m_calc_ts and TSvalues[i] > 0.0: | |
| 482 | - self.log(", TS = "+str(TS)) | |
| 483 | - if self.m_calc_ulimit and ulim_values[i] > 0.0: | |
| 484 | - self.log(", UL = "+str(ulim_values[i])+" [erg/cm2/s]") | |
| 524 | + if self.logTerse(): | |
| 485 | 525 | self.log("\n") |
| 526 | + self.log.parformat("Bin "+str(i+1)) | |
| 527 | + self.log(str(flux[i])) | |
| 528 | + self.log(" +/- ") | |
| 529 | + self.log(str(flux_err[i])) | |
| 530 | + if self.m_calc_ulimit and ulim_values[i] > 0.0: | |
| 531 | + self.log(" [< "+str(ulim_values[i])+"]") | |
| 532 | + self.log(" erg/cm2/s") | |
| 533 | + if self.m_calc_ts and TSvalues[i] > 0.0: | |
| 534 | + self.log(" (TS = "+str(TS)+")") | |
| 486 | 535 | |
| 487 | 536 | # Append filled columns to fits table |
| 488 | 537 | table.append(energy) | ... | ... |