Commit 0b326d4d27cad519dd0769d62ac37db94c890b22
1 parent
97afb37d
debugging
Showing
3 changed files
with
69 additions
and
94 deletions
cscripts/csresspec.par
| ... | ... | @@ -32,11 +32,11 @@ outfile, f, a, resspec.fits,,, "Output residual spectrum file" |
| 32 | 32 | # Script parameters |
| 33 | 33 | #================== |
| 34 | 34 | statistic, s, h, DEFAULT,DEFAULT|CSTAT|WSTAT|CHI2,, "Optimization statistic" |
| 35 | -components b, h, no,,, "Calculate model for individual components" | |
| 35 | +components,b, h, no,,, "Calculate model for individual components" | |
| 36 | 36 | ebinalg, s, h, LOG,LIN|LOG|FILE,, "Binning algorithm" |
| 37 | 37 | emin, r, a, 0.1,,, "Lower energy limit (TeV)" |
| 38 | 38 | emax, r, a, 100.0,,, "Upper energy limit (TeV)" |
| 39 | -enumbins, i, h, 20,,, "Number of model cube energy bins" | |
| 39 | +enumbins, i, a, 20,,, "Number of model cube energy bins" | |
| 40 | 40 | ebinfile, f, a, NONE,,, "Name of the file containing the energy bin definition" |
| 41 | 41 | stack, b, a, no,,, "Stack observations" |
| 42 | 42 | coordsys, s, a, CEL,CEL|GAL,, "Coordinate System" |
| ... | ... | @@ -46,7 +46,7 @@ yref, r, a, 22.01,-90,90, "Second coordinate of image/source region center |
| 46 | 46 | nxpix, i, a, 200,,, "Size of the X axis in pixels" |
| 47 | 47 | nypix, i, a, 200,,, "Size of the Y axis in pixels" |
| 48 | 48 | binsz, r, a, 0.02,,, "Pixel size (deg/pixel)" |
| 49 | -mask b, a, no,,, "Mask data to calculate residuals in ROI" | |
| 49 | +mask, b, a, no,,, "Mask data to calculate residuals in ROI" | |
| 50 | 50 | ra, r, a, 83.63,0,360, "RA for ROI centre (degrees)" |
| 51 | 51 | dec, r, a, 22.01,-90,90, "Dec for ROI centre (degrees)" |
| 52 | 52 | rad, r, a, 3.0,0,180, "Radius of ROI (degrees)" | ... | ... |
cscripts/csresspec.py
| ... | ... | @@ -23,6 +23,7 @@ import ctools |
| 23 | 23 | from cscripts import obsutils |
| 24 | 24 | import sys |
| 25 | 25 | |
| 26 | + | |
| 26 | 27 | # =============== # |
| 27 | 28 | # csresspec class # |
| 28 | 29 | # =============== # |
| ... | ... | @@ -108,12 +109,12 @@ class csresspec(ctools.csobservation): |
| 108 | 109 | self['emax'].real() |
| 109 | 110 | self['enumbins'].integer() |
| 110 | 111 | msg = 'User defined energy binning will be used for %s unbinned observations.' % n_unbinned |
| 111 | - self._log_value(gammalib.TERSE, msg) | |
| 112 | + self._log_string(gammalib.TERSE, msg) | |
| 112 | 113 | if n_cta > n_unbinned: |
| 113 | 114 | n_notunbin = n_cta - n_unbinned |
| 114 | 115 | msg = 'The intrinsic binning will be used for the remaining %s CTA observations.' % ( |
| 115 | 116 | n_notunbin) |
| 116 | - self._log_value(gammalib.TERSE, msg) | |
| 117 | + self._log_string(gammalib.TERSE, msg) | |
| 117 | 118 | |
| 118 | 119 | # If there is more than one observation, and observations are all |
| 119 | 120 | # unbinned or all onoff query user to know if they wish stacked results |
| ... | ... | @@ -121,13 +122,13 @@ class csresspec(ctools.csobservation): |
| 121 | 122 | n_unbinned == self.obs().size() or n_onoff == self.obs().size()): |
| 122 | 123 | self._stack = self['stack'].boolean() |
| 123 | 124 | # If we are to stack event lists query parameters for cube creation |
| 124 | - if n_unbinned == self.obs().size(): | |
| 125 | + if self._stack and n_unbinned == self.obs().size(): | |
| 125 | 126 | self['coordsys'].string() |
| 126 | 127 | self['proj'].string() |
| 127 | 128 | self['xref'].real() |
| 128 | 129 | self['yref'].real() |
| 129 | - self['nxpix'].real() | |
| 130 | - self['nypix'].real() | |
| 130 | + self['nxpix'].integer() | |
| 131 | + self['nypix'].integer() | |
| 131 | 132 | self['binsz'].real() |
| 132 | 133 | |
| 133 | 134 | # If we are not using a precomputed model and no models are available |
| ... | ... | @@ -144,13 +145,14 @@ class csresspec(ctools.csobservation): |
| 144 | 145 | self['ra'].real() |
| 145 | 146 | self['dec'].real() |
| 146 | 147 | self['rad'].real() |
| 148 | + self['regfile'].filename() | |
| 147 | 149 | |
| 148 | 150 | # Unless all observations are On/Off, or we are using precomputed model |
| 149 | 151 | # maps query whether to use energy dispersion |
| 150 | 152 | if n_onoff == n_cta or self._use_maps: |
| 151 | 153 | msg = 'Energy dispersion is applied based on the input data/model ' \ |
| 152 | 154 | + 'and not according to the edisp parameter' |
| 153 | - self._log_value(gammalib.TERSE, msg) | |
| 155 | + self._log_string(gammalib.TERSE, msg) | |
| 154 | 156 | else: |
| 155 | 157 | self['edisp'].boolean() |
| 156 | 158 | |
| ... | ... | @@ -180,13 +182,13 @@ class csresspec(ctools.csobservation): |
| 180 | 182 | # If On/Off use the GCTAOnOffObservation constructor |
| 181 | 183 | if self.obs()[0].classname() == 'GCTAOnOffObservation': |
| 182 | 184 | msg = 'Stacking %s On/Off observations.' % (self.obs().size()) |
| 183 | - self._log_value(gammalib.TERSE, msg) | |
| 185 | + self._log_string(gammalib.TERSE, msg) | |
| 184 | 186 | stacked_obs = gammalib.GCTAOnOffObservation(self.obs()) |
| 185 | 187 | |
| 186 | 188 | # If event list then bin observations |
| 187 | 189 | elif self.obs()[0].classname() == 'GCTAObservation': |
| 188 | 190 | msg = 'Stacking %s event lists.' % (self.obs().size()) |
| 189 | - self._log_value(gammalib.TERSE, msg) | |
| 191 | + self._log_string(gammalib.TERSE, msg) | |
| 190 | 192 | stacked_obs = obsutils.get_stacked_obs(self, self.obs()) |
| 191 | 193 | |
| 192 | 194 | # Return |
| ... | ... | @@ -227,25 +229,43 @@ class csresspec(ctools.csobservation): |
| 227 | 229 | cntcube['emax'] = self['emax'].real() |
| 228 | 230 | cntcube.run() |
| 229 | 231 | |
| 230 | - # Retrieve a new oberservation container | |
| 232 | + # Retrieve the binned observation container | |
| 231 | 233 | binned_obs = cntcube.obs().copy() |
| 232 | 234 | |
| 233 | - # Retrieve models | |
| 234 | - models = obs.models() | |
| 235 | + # Compute binned response | |
| 236 | + response = obsutils.get_stacked_response(obs, ra, dec, | |
| 237 | + binsz=0.02, | |
| 238 | + nxpix=npix, | |
| 239 | + nypix=npix, | |
| 240 | + coordsys='CEL', | |
| 241 | + proj='TAN', | |
| 242 | + emin=self['emin'].real(), | |
| 243 | + emax=self['emax'].real(), | |
| 244 | + edisp=self['edisp'].boolean()) | |
| 245 | + | |
| 246 | + if self['edisp'].boolean(): | |
| 247 | + binned_obs[0].response(response['expcube'], response['psfcube'], | |
| 248 | + response['edispcube'], response['bkgcube']) | |
| 249 | + else: | |
| 250 | + binned_obs[0].response(response['expcube'], response['psfcube'], | |
| 251 | + response['bkgcube']) | |
| 235 | 252 | |
| 236 | - # Set models for new oberservation container | |
| 253 | + # Get new models | |
| 254 | + models = response['models'] | |
| 255 | + | |
| 256 | + # Set models for observation container | |
| 237 | 257 | binned_obs.models(models) |
| 238 | 258 | |
| 239 | 259 | # Check if energy boundaries provided by user extend beyond |
| 240 | 260 | # the content of the event list |
| 241 | - if self['emin'].real() > obs[0].emin().TeV: | |
| 261 | + if self['emin'].real() > obs[0].events().emin().TeV(): | |
| 242 | 262 | emin = 'INDEF' |
| 243 | 263 | else: |
| 244 | - emin = obs[0].emin().TeV | |
| 245 | - if self['emax'].real() < obs[0].emax().TeV: | |
| 264 | + emin = obs[0].events().emin().TeV() | |
| 265 | + if self['emax'].real() < obs[0].events().emax().TeV(): | |
| 246 | 266 | emax = 'INDEF' |
| 247 | 267 | else: |
| 248 | - emax = obs[0].emax().TeV | |
| 268 | + emax = obs[0].events().emax().TeV() | |
| 249 | 269 | |
| 250 | 270 | # Put ROI and E bound info in dictionary |
| 251 | 271 | info = {'was_list': True, 'roi_ra': ra, 'roi_dec': dec, 'roi_rad': rad, |
| ... | ... | @@ -254,47 +274,6 @@ class csresspec(ctools.csobservation): |
| 254 | 274 | # Return new oberservation container |
| 255 | 275 | return binned_obs, info |
| 256 | 276 | |
| 257 | - def _add_binned_response(self, obs): | |
| 258 | - """ | |
| 259 | - Add response to binned observation | |
| 260 | - :param obs: `~gammalib.GObservations' observation container | |
| 261 | - :return: obs: `~gammalib.GObservations' observation container with response | |
| 262 | - """ | |
| 263 | - | |
| 264 | - # use counts cube to extract geometry | |
| 265 | - cube = obs[0].events() | |
| 266 | - proj = cube.counts().projection() | |
| 267 | - | |
| 268 | - response = obsutils.get_stacked_response(obs, | |
| 269 | - proj.crval(0), | |
| 270 | - proj.crval(1), | |
| 271 | - binsz=max(abs(proj.cdelt(0)), | |
| 272 | - abs(proj.cdelt(1))), | |
| 273 | - # always ensures coverage of whole cube | |
| 274 | - nxpix=cube.nx(), | |
| 275 | - nypix=cube.ny(), | |
| 276 | - coordsys=proj.coordsys(), | |
| 277 | - proj=proj.code(), | |
| 278 | - emin=cube.emin().TeV(), | |
| 279 | - emax=cube.emax().TeV(), | |
| 280 | - edisp=self['edisp'].boolean()) | |
| 281 | - | |
| 282 | - if self['edisp'].boolean(): | |
| 283 | - obs[0].response(response['expcube'], response['psfcube'], | |
| 284 | - response['edispcube'], response['bkgcube']) | |
| 285 | - else: | |
| 286 | - obs[0].response(response['expcube'], response['psfcube'], | |
| 287 | - response['bkgcube']) | |
| 288 | - | |
| 289 | - # Get new models | |
| 290 | - models = response['models'] | |
| 291 | - | |
| 292 | - # Set models for observation container | |
| 293 | - obs.models(models) | |
| 294 | - | |
| 295 | - # Return observation container | |
| 296 | - return obs | |
| 297 | - | |
| 298 | 277 | def _masked_cube(self, cube, ra, dec, rad, emin='INDEF', emax='INDEF', |
| 299 | 278 | regfile='NONE'): |
| 300 | 279 | """ |
| ... | ... | @@ -325,7 +304,9 @@ class csresspec(ctools.csobservation): |
| 325 | 304 | cubemask['regfile'] = regfile |
| 326 | 305 | cubemask.run() |
| 327 | 306 | |
| 328 | - return cubemask.cube() | |
| 307 | + # Return | |
| 308 | + # Note: we return a copy to avoid memory leaks in SWIG | |
| 309 | + return cubemask.cube().copy() | |
| 329 | 310 | |
| 330 | 311 | def _cube_to_spectrum(self, cube, evlist_info): |
| 331 | 312 | """ |
| ... | ... | @@ -352,8 +333,8 @@ class csresspec(ctools.csobservation): |
| 352 | 333 | regfile=self['regfile']) |
| 353 | 334 | |
| 354 | 335 | # Extract skymap and clip at 0 to null masked areas |
| 355 | - counts = cube.counts() | |
| 356 | - counts = counts.clip(0) | |
| 336 | + counts = cube.counts().copy() | |
| 337 | + counts = counts.clip(0.) | |
| 357 | 338 | |
| 358 | 339 | # Convert skymap into GNdarray count spectrum |
| 359 | 340 | counts = counts.total_counts() |
| ... | ... | @@ -372,7 +353,7 @@ class csresspec(ctools.csobservation): |
| 372 | 353 | :return: `~gammalib.GFitsBinTable' |
| 373 | 354 | """ |
| 374 | 355 | # Create FITS table columns |
| 375 | - nrows = self._ebounds.size() | |
| 356 | + nrows = ebounds.size() | |
| 376 | 357 | energy_low = gammalib.GFitsTableDoubleCol('ed_Energy', nrows) |
| 377 | 358 | energy_high = gammalib.GFitsTableDoubleCol('eu_Energy', nrows) |
| 378 | 359 | counts_col = gammalib.GFitsTableDoubleCol('Counts', nrows) |
| ... | ... | @@ -391,6 +372,9 @@ class csresspec(ctools.csobservation): |
| 391 | 372 | |
| 392 | 373 | # Initialise FITS Table with extension set to obs id |
| 393 | 374 | table = gammalib.GFitsBinTable(nrows) |
| 375 | + # If name not empty add leading blank | |
| 376 | + if obs_id != '': | |
| 377 | + obs_id = ' ' + obs_id | |
| 394 | 378 | table.extname('RESIDUALS ' + obs_id) |
| 395 | 379 | |
| 396 | 380 | # Add Header card to specify algorithm used for residual computation |
| ... | ... | @@ -402,7 +386,7 @@ class csresspec(ctools.csobservation): |
| 402 | 386 | table.append(energy_high) |
| 403 | 387 | table.append(counts_col) |
| 404 | 388 | table.append(model_col) |
| 405 | - table.append(residuals) | |
| 389 | + table.append(resid_col) | |
| 406 | 390 | |
| 407 | 391 | return table |
| 408 | 392 | |
| ... | ... | @@ -427,8 +411,8 @@ class csresspec(ctools.csobservation): |
| 427 | 411 | column = gammalib.GFitsTableDoubleCol(name, table.nrows()) |
| 428 | 412 | |
| 429 | 413 | # Fill data |
| 430 | - for s, value in enumerate(data): | |
| 431 | - column[i] = data[i] | |
| 414 | + for i, value in enumerate(data): | |
| 415 | + column[i] = value | |
| 432 | 416 | |
| 433 | 417 | # Append new column to table |
| 434 | 418 | table.append(column) |
| ... | ... | @@ -456,45 +440,36 @@ class csresspec(ctools.csobservation): |
| 456 | 440 | self.obs(self._stack_observations()) |
| 457 | 441 | |
| 458 | 442 | # Loop over observations and calculate residuals |
| 459 | - for s, obs in enumerate(self.obs()): | |
| 443 | + for s, observation in enumerate(self.obs()): | |
| 460 | 444 | |
| 461 | 445 | # Retrieve and store obs id |
| 462 | - obs_id = obs.id() | |
| 463 | - # If observation id is empty replace with incremental number | |
| 464 | - if obs_id == '': | |
| 446 | + obs_id = observation.id() | |
| 447 | + # If observation id is empty and there is more than one observation | |
| 448 | + # replace with incremental number | |
| 449 | + if obs_id == '' and self.obs().size() > 1: | |
| 465 | 450 | obs_id = str(s) |
| 466 | 451 | |
| 467 | 452 | # Turn into observation container and assign models |
| 468 | - obs = gammalib.GObservations(obs) | |
| 453 | + obs = gammalib.GObservations() | |
| 454 | + obs.append(observation) | |
| 469 | 455 | obs.models(self.obs().models()) |
| 470 | 456 | |
| 471 | - # if 3D observations | |
| 457 | + # if 3D observation | |
| 472 | 458 | if obs[0].classname() == 'GCTAObservation': |
| 473 | 459 | |
| 474 | 460 | ## Prepare Observations |
| 475 | 461 | |
| 476 | 462 | # If already binned set the evlist_info dictionary to have |
| 477 | 463 | # attribute was_list False |
| 478 | - was_list = False | |
| 479 | 464 | if obs[0].eventtype() == 'CountsCube': |
| 480 | 465 | evlist_info = {'was_list': False} |
| 481 | 466 | # Otherwise bin now |
| 482 | 467 | else: |
| 483 | 468 | # we remember if we binned an event list |
| 484 | 469 | # so that we can mask only the ROI for residual calculation |
| 485 | - was_list = True | |
| 486 | - obs, evlist_info = self._bin_evlist( | |
| 487 | - obs) | |
| 488 | - | |
| 489 | - # If binned response is present or model cube provided pass | |
| 490 | - if obs[0].has_response() or self._use_maps: | |
| 491 | - pass | |
| 492 | - # Otherwise calculate binned response now | |
| 493 | - else: | |
| 494 | - obs = self._add_binned_response(obs) | |
| 470 | + obs, evlist_info = self._bin_evlist(obs) | |
| 495 | 471 | |
| 496 | 472 | ## Calculate Model and residuals |
| 497 | - | |
| 498 | 473 | # If model cube is provided load it |
| 499 | 474 | if self._use_maps: |
| 500 | 475 | modcube = gammalib.GCTAEventCube(self['inmodel'].filename()) |
| ... | ... | @@ -522,13 +497,13 @@ class csresspec(ctools.csobservation): |
| 522 | 497 | residuals) |
| 523 | 498 | |
| 524 | 499 | ## Calculate models of individual components if requested |
| 525 | - if self._components: | |
| 500 | + if self['components'].boolean(): | |
| 526 | 501 | for component in obs.models(): |
| 527 | - # Extract component name and set model cube models to | |
| 502 | + # Set model cube models to | |
| 528 | 503 | # individual component |
| 529 | - name = component.name() | |
| 530 | - component = gammalib.GModels(component) | |
| 531 | - modelcube.obs().models(component) | |
| 504 | + model_cont = gammalib.GModels() | |
| 505 | + model_cont.append(component) | |
| 506 | + modelcube.obs().models(model_cont) | |
| 532 | 507 | |
| 533 | 508 | # Run model cube |
| 534 | 509 | modelcube.run() |
| ... | ... | @@ -538,7 +513,8 @@ class csresspec(ctools.csobservation): |
| 538 | 513 | model = self._cube_to_spectrum(modcube, evlist_info) |
| 539 | 514 | |
| 540 | 515 | # append component to table |
| 541 | - table = self._append_column(table, name, model) | |
| 516 | + table = self._append_column(table, component.name(), | |
| 517 | + model) | |
| 542 | 518 | |
| 543 | 519 | # otherwise, if On/Off |
| 544 | 520 | elif obs[0].classname() == 'GCTAOnOffObservation': |
| ... | ... | @@ -561,7 +537,6 @@ class csresspec(ctools.csobservation): |
| 561 | 537 | |
| 562 | 538 | # Continue only if FITS file is valid |
| 563 | 539 | if self._fits != None: |
| 564 | - | |
| 565 | 540 | # Get outfile parameter |
| 566 | 541 | outfile = self['outfile'].filename() |
| 567 | 542 | |
| ... | ... | @@ -574,11 +549,11 @@ class csresspec(ctools.csobservation): |
| 574 | 549 | # Return |
| 575 | 550 | return |
| 576 | 551 | |
| 552 | + | |
| 577 | 553 | # ======================== # |
| 578 | 554 | # Main routine entry point # |
| 579 | 555 | # ======================== # |
| 580 | 556 | if __name__ == '__main__': |
| 581 | - | |
| 582 | 557 | # Create instance of application |
| 583 | 558 | app = csresspec(sys.argv) |
| 584 | 559 | ... | ... |
cscripts/obsutils.py