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,10 +110,11 @@ class csspec(ctools.cscript): | ||
| 110 | pars.append(gammalib.GApplicationPar("caldb","s","a","prod2","","","Calibration database")) | 110 | pars.append(gammalib.GApplicationPar("caldb","s","a","prod2","","","Calibration database")) |
| 111 | pars.append(gammalib.GApplicationPar("irf","s","a","South_50h","","","Instrument response function")) | 111 | pars.append(gammalib.GApplicationPar("irf","s","a","South_50h","","","Instrument response function")) |
| 112 | pars.append(gammalib.GApplicationPar("edisp","b","h","no","","","Apply energy dispersion?")) | 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 | pars.append(gammalib.GApplicationPar("calc_ts","b","h","yes","yes|no","","Compute TS value in each bin")) | 118 | pars.append(gammalib.GApplicationPar("calc_ts","b","h","yes","yes|no","","Compute TS value in each bin")) |
| 118 | pars.append(gammalib.GApplicationPar("calc_ulim","b","h","yes","yes|no","","Compute upper limit in each bin")) | 119 | pars.append(gammalib.GApplicationPar("calc_ulim","b","h","yes","yes|no","","Compute upper limit in each bin")) |
| 119 | pars.append(gammalib.GApplicationPar("fix_srcs","b","h","yes","yes|no","","Fix other skymodel parameters")) | 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,7 +130,6 @@ class csspec(ctools.cscript): | ||
| 129 | """ | 130 | """ |
| 130 | Get parameters from parfile and setup the observation. | 131 | Get parameters from parfile and setup the observation. |
| 131 | """ | 132 | """ |
| 132 | - | ||
| 133 | # Set observation if not done before | 133 | # Set observation if not done before |
| 134 | if self.obs == None or self.obs.size() == 0: | 134 | if self.obs == None or self.obs.size() == 0: |
| 135 | self.require_inobs("csspec::get_parameters()") | 135 | self.require_inobs("csspec::get_parameters()") |
| @@ -149,41 +149,8 @@ class csspec(ctools.cscript): | @@ -149,41 +149,8 @@ class csspec(ctools.cscript): | ||
| 149 | # Get source name | 149 | # Get source name |
| 150 | self.m_srcname = self["srcname"].string() | 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 | # Get edisp flag | 155 | # Get edisp flag |
| 189 | self.m_edisp = self["edisp"].boolean() | 156 | self.m_edisp = self["edisp"].boolean() |
| @@ -206,6 +173,66 @@ class csspec(ctools.cscript): | @@ -206,6 +173,66 @@ class csspec(ctools.cscript): | ||
| 206 | # Return | 173 | # Return |
| 207 | return | 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 | def models(self, models): | 236 | def models(self, models): |
| 210 | """ | 237 | """ |
| 211 | Set model. | 238 | Set model. |
| @@ -252,6 +279,24 @@ class csspec(ctools.cscript): | @@ -252,6 +279,24 @@ class csspec(ctools.cscript): | ||
| 252 | self.log_parameters() | 279 | self.log_parameters() |
| 253 | self.log("\n") | 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 | # Write observation into logger | 300 | # Write observation into logger |
| 256 | if self.logTerse(): | 301 | if self.logTerse(): |
| 257 | self.log("\n") | 302 | self.log("\n") |
| @@ -316,26 +361,25 @@ class csspec(ctools.cscript): | @@ -316,26 +361,25 @@ class csspec(ctools.cscript): | ||
| 316 | 361 | ||
| 317 | # Create FITS table columns | 362 | # Create FITS table columns |
| 318 | energy = gammalib.GFitsTableDoubleCol("Energy", self.m_ebounds.size()) | 363 | energy = gammalib.GFitsTableDoubleCol("Energy", self.m_ebounds.size()) |
| 319 | - energy.unit("TeV") | ||
| 320 | energy_low = gammalib.GFitsTableDoubleCol("ed_Energy", self.m_ebounds.size()) | 364 | energy_low = gammalib.GFitsTableDoubleCol("ed_Energy", self.m_ebounds.size()) |
| 321 | - energy_low.unit("TeV") | ||
| 322 | energy_high = gammalib.GFitsTableDoubleCol("eu_Energy", self.m_ebounds.size()) | 365 | energy_high = gammalib.GFitsTableDoubleCol("eu_Energy", self.m_ebounds.size()) |
| 323 | - energy_high.unit("TeV") | ||
| 324 | flux = gammalib.GFitsTableDoubleCol("Flux", self.m_ebounds.size()) | 366 | flux = gammalib.GFitsTableDoubleCol("Flux", self.m_ebounds.size()) |
| 325 | - flux.unit("erg/cm2/s") | ||
| 326 | flux_err = gammalib.GFitsTableDoubleCol("e_Flux", self.m_ebounds.size()) | 367 | flux_err = gammalib.GFitsTableDoubleCol("e_Flux", self.m_ebounds.size()) |
| 327 | - flux_err.unit("erg/cm2/s") | ||
| 328 | TSvalues = gammalib.GFitsTableDoubleCol("TS", self.m_ebounds.size()) | 368 | TSvalues = gammalib.GFitsTableDoubleCol("TS", self.m_ebounds.size()) |
| 329 | ulim_values = gammalib.GFitsTableDoubleCol("UpperLimit", self.m_ebounds.size()) | 369 | ulim_values = gammalib.GFitsTableDoubleCol("UpperLimit", self.m_ebounds.size()) |
| 330 | - ulim_values.unit("erg/cm2/s") | ||
| 331 | Npred_values = gammalib.GFitsTableDoubleCol("Npred", self.m_ebounds.size()) | 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 | # Loop over energy bins | 378 | # Loop over energy bins |
| 335 | for i in range(self.m_ebounds.size()): | 379 | for i in range(self.m_ebounds.size()): |
| 336 | 380 | ||
| 337 | # Log information | 381 | # Log information |
| 338 | - if self.logTerse(): | 382 | + if self.logExplicit(): |
| 339 | self.log("\n") | 383 | self.log("\n") |
| 340 | self.log.header2("Energy bin "+str(i+1)) | 384 | self.log.header2("Energy bin "+str(i+1)) |
| 341 | 385 | ||
| @@ -377,9 +421,10 @@ class csspec(ctools.cscript): | @@ -377,9 +421,10 @@ class csspec(ctools.cscript): | ||
| 377 | else: | 421 | else: |
| 378 | 422 | ||
| 379 | # Header | 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 | cubemask = ctools.ctcubemask(self.obs) | 428 | cubemask = ctools.ctcubemask(self.obs) |
| 384 | cubemask["regfile"] = "NONE" | 429 | cubemask["regfile"] = "NONE" |
| 385 | cubemask["ra"] = "UNDEFINED" | 430 | cubemask["ra"] = "UNDEFINED" |
| @@ -393,7 +438,7 @@ class csspec(ctools.cscript): | @@ -393,7 +438,7 @@ class csspec(ctools.cscript): | ||
| 393 | obs = cubemask.obs() | 438 | obs = cubemask.obs() |
| 394 | 439 | ||
| 395 | # Header | 440 | # Header |
| 396 | - if self.logTerse(): | 441 | + if self.logExplicit(): |
| 397 | self.log.header3("Performing fit") | 442 | self.log.header3("Performing fit") |
| 398 | 443 | ||
| 399 | # Likelihood | 444 | # Likelihood |
| @@ -405,8 +450,10 @@ class csspec(ctools.cscript): | @@ -405,8 +450,10 @@ class csspec(ctools.cscript): | ||
| 405 | if like.obs().logL() == 0.0: | 450 | if like.obs().logL() == 0.0: |
| 406 | 451 | ||
| 407 | # Log information | 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 | # Set all values to 0 | 458 | # Set all values to 0 |
| 412 | flux[i] = 0.0 | 459 | flux[i] = 0.0 |
| @@ -425,21 +472,21 @@ class csspec(ctools.cscript): | @@ -425,21 +472,21 @@ class csspec(ctools.cscript): | ||
| 425 | if self.m_calc_ulimit: | 472 | if self.m_calc_ulimit: |
| 426 | 473 | ||
| 427 | # Logging information | 474 | # Logging information |
| 428 | - if self.logTerse(): | 475 | + if self.logExplicit(): |
| 429 | self.log.header3("Computing upper limit") | 476 | self.log.header3("Computing upper limit") |
| 430 | 477 | ||
| 431 | # Create upper limit object | 478 | # Create upper limit object |
| 432 | ulimit = ctools.ctulimit(like.obs()) | 479 | ulimit = ctools.ctulimit(like.obs()) |
| 433 | ulimit["srcname"] = self.m_srcname | 480 | ulimit["srcname"] = self.m_srcname |
| 434 | - ulimit["eref"] = elogmean.TeV() | 481 | + ulimit["eref"] = elogmean.TeV() |
| 435 | 482 | ||
| 436 | # Try to run upper limit and catch exceptions | 483 | # Try to run upper limit and catch exceptions |
| 437 | try: | 484 | try: |
| 438 | ulimit.run() | 485 | ulimit.run() |
| 439 | ulimit_value = ulimit.diff_ulimit() | 486 | ulimit_value = ulimit.diff_ulimit() |
| 440 | except: | 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 | ulimit_value = -1.0 | 490 | ulimit_value = -1.0 |
| 444 | 491 | ||
| 445 | # Get TS value | 492 | # Get TS value |
| @@ -474,15 +521,17 @@ class csspec(ctools.cscript): | @@ -474,15 +521,17 @@ class csspec(ctools.cscript): | ||
| 474 | ulim_values[i] = ulimit_value * elogmean2 * gammalib.MeV2erg | 521 | ulim_values[i] = ulimit_value * elogmean2 * gammalib.MeV2erg |
| 475 | 522 | ||
| 476 | # Log information | 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 | self.log("\n") | 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 | # Append filled columns to fits table | 536 | # Append filled columns to fits table |
| 488 | table.append(energy) | 537 | table.append(energy) |