Commit 2f2afb6330b79c6e70b3c264e848fef177bceb32
Merge branch 'integration' into devel
Showing
17 changed files
with
557 additions
and
163 deletions
cscripts/Makefile.am
| ... | ... | @@ -164,6 +164,7 @@ testdata = $(top_srcdir)/test/data/crab.xml \ |
| 164 | 164 | $(top_srcdir)/test/data/crab_psfcube.fits.gz \ |
| 165 | 165 | $(top_srcdir)/test/data/crab_edispcube.fits.gz \ |
| 166 | 166 | $(top_srcdir)/test/data/crab_bkgcube.fits.gz \ |
| 167 | + $(top_srcdir)/test/data/crab_onoff.xml \ | |
| 167 | 168 | $(top_srcdir)/test/data/crab_offaxis1.fits.gz \ |
| 168 | 169 | $(top_srcdir)/test/data/crab_offaxis2.fits.gz \ |
| 169 | 170 | $(top_srcdir)/test/data/crab_exclusion.fits.gz \ | ... | ... |
cscripts/cslightcrv.par
| ... | ... | @@ -16,12 +16,13 @@ |
| 16 | 16 | # |
| 17 | 17 | # Input and output parameters |
| 18 | 18 | #============================ |
| 19 | -inobs, f, a, events.fits,,, "Input event list or observation definition XML file" | |
| 20 | -inmodel, f, a, $CTOOLS/share/models/crab.xml,,, "Input model definition XML file" | |
| 21 | -srcname, s, a, Crab,,, "Source name" | |
| 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?" | |
| 19 | +inobs, f, a, events.fits,,, "Input event list or observation definition XML file" | |
| 20 | +inmodel, f, a, $CTOOLS/share/models/crab.xml,,, "Input model definition XML file" | |
| 21 | +srcname, s, a, Crab,,, "Source name" | |
| 22 | +caldb, s, a, prod2,,, "Calibration database" | |
| 23 | +irf, s, a, South_0.5h,,, "Instrument response function" | |
| 24 | +inexclusion, f, h, NONE,,, "Sky map of exclusion regions for On/Off analysis" | |
| 25 | +edisp, b, h, no,,, "Apply energy dispersion in Cube analysis?" | |
| 25 | 26 | outfile, f, a, lightcurve.fits,,, "Output light curve file" |
| 26 | 27 | |
| 27 | 28 | # |
| ... | ... | @@ -32,16 +33,25 @@ tmin, t, a, MJD 51544.5,,,"Lightcurve start time (UTC string, JD, MJD or ME |
| 32 | 33 | tmax, t, a, MJD 51544.6,,,"Lightcurve stop time (UTC string, JD, MJD or MET in seconds)" |
| 33 | 34 | tbins, i, a, 5,1,10000, "Number of time bins" |
| 34 | 35 | tbinfile, f, a, NONE,,, "File defining the time binning" |
| 36 | +method, s, a, 3D, 3D|ONOFF,, "Analysis method" | |
| 35 | 37 | emin, r, a, 0.1,,, "Lower energy limit of events (TeV)" |
| 36 | 38 | emax, r, a, 100.0,,, "Upper energy limit of events (TeV)" |
| 37 | -enumbins, i, a, 0,0,100, "Number of energy bins for binned (0=unbinned)" | |
| 39 | +enumbins, i, a, 0,0,100, "Number of energy bins for binned (0=unbinned for 3D analysis only)" | |
| 38 | 40 | coordsys, s, a, CEL,CEL|GAL,, "Coordinate System" |
| 39 | 41 | proj, s, a, CAR,AIT|AZP|CAR|GLS|MER|MOL|SFL|SIN|STG|TAN,, "Projection method" |
| 40 | -xref, r, a, 83.63,0,360, "First coordinate of image center in degrees (RA or galactic l)" | |
| 41 | -yref, r, a, 22.01,-90,90, "Second coordinate of image center in degrees (DEC or galactic b)" | |
| 42 | +xref, r, a, 83.63,0,360, "First coordinate of image/source region center in degrees (RA or galactic l)" | |
| 43 | +yref, r, a, 22.01,-90,90, "Second coordinate of image/source region center in degrees (DEC or galactic b)" | |
| 42 | 44 | nxpix, i, a, 200,,, "Size of the X axis in pixels" |
| 43 | 45 | nypix, i, a, 200,,, "Size of the Y axis in pixels" |
| 44 | 46 | binsz, r, a, 0.02,,, "Pixel size (deg/pixel)" |
| 47 | +srcshape, s, h, CIRCLE,CIRCLE,, "Shape of the source region" | |
| 48 | +rad, r, a, 0.2,0,180, "Radius of source region circle (deg)" | |
| 49 | +bkgmethod, s, h, REFLECTED,REFLECTED,, "Method for background estimation" | |
| 50 | +bkgregmin, i, h, 2,1,1000, "Minimum number of background regions" | |
| 51 | +maxoffset, r, h, 4.0,,, "Maximum offset of source from camera center to accept observation" | |
| 52 | +etruemin, r, h, 0.01,,, "Minimum true energy (TeV)" | |
| 53 | +etruemax, r, h, 300.0,,, "Maximum true energy (TeV)" | |
| 54 | +etruebins, i, h, 30,,, "Number of bins per decade for true energy bins" | |
| 45 | 55 | statistic, s, h, DEFAULT,DEFAULT|CSTAT|WSTAT|CHI2,, "Optimization statistic" |
| 46 | 56 | calc_ts, b, h, yes,,, "Compute TS value for each bin?" |
| 47 | 57 | calc_ulim, b, h, yes,,, "Compute upper limit for each bin?" | ... | ... |
cscripts/cslightcrv.py
| ... | ... | @@ -74,6 +74,7 @@ class cslightcrv(ctools.csobservation): |
| 74 | 74 | # Initialise some members |
| 75 | 75 | self._srcname = '' |
| 76 | 76 | self._tbins = gammalib.GGti() |
| 77 | + self._onoff = False | |
| 77 | 78 | self._stacked = False |
| 78 | 79 | self._fits = gammalib.GFits() |
| 79 | 80 | |
| ... | ... | @@ -103,8 +104,13 @@ class cslightcrv(ctools.csobservation): |
| 103 | 104 | # Get time boundaries |
| 104 | 105 | self._tbins = self._create_tbounds() |
| 105 | 106 | |
| 107 | + # Set On/Off analysis flag and query relevant user parameters | |
| 108 | + self._onoff = self._is_onoff() | |
| 109 | + | |
| 110 | + # If cube analysis is selected | |
| 106 | 111 | # Set stacked analysis flag and query relevant user parameters |
| 107 | - self._stacked = self._is_stacked() | |
| 112 | + if not self._onoff: | |
| 113 | + self._stacked = self._is_stacked() | |
| 108 | 114 | |
| 109 | 115 | # Query the hidden parameters, just in case |
| 110 | 116 | self['edisp'].boolean() |
| ... | ... | @@ -357,40 +363,6 @@ class cslightcrv(ctools.csobservation): |
| 357 | 363 | # Return upper limit tuple |
| 358 | 364 | return ul_diff, ul_flux, ul_eflux |
| 359 | 365 | |
| 360 | - def _bin_observation(self, obs): | |
| 361 | - """ | |
| 362 | - Bin an observation if a binned analysis was requested | |
| 363 | - | |
| 364 | - Parameters | |
| 365 | - ---------- | |
| 366 | - obs : `~gammalib.GObservations` | |
| 367 | - Observation container | |
| 368 | - | |
| 369 | - Returns | |
| 370 | - ------- | |
| 371 | - obs : `~gammalib.GObservations` | |
| 372 | - Observation container where the first observation is a binned observation | |
| 373 | - """ | |
| 374 | - # Get new observation container with binned observation | |
| 375 | - new_obs = obsutils.get_stacked_obs(self, obs) | |
| 376 | - | |
| 377 | - # Extract models | |
| 378 | - models = new_obs.models() | |
| 379 | - | |
| 380 | - # Fix background models if required | |
| 381 | - if self['fix_bkg'].boolean(): | |
| 382 | - for model in models: | |
| 383 | - if model.classname() != 'GModelSky': | |
| 384 | - for par in model: | |
| 385 | - par.fix() | |
| 386 | - | |
| 387 | - # Put back models | |
| 388 | - new_obs.models(models) | |
| 389 | - | |
| 390 | - # Return new oberservation container | |
| 391 | - return new_obs | |
| 392 | - | |
| 393 | - | |
| 394 | 366 | # Public methods |
| 395 | 367 | def run(self): |
| 396 | 368 | """ |
| ... | ... | @@ -483,31 +455,116 @@ class cslightcrv(ctools.csobservation): |
| 483 | 455 | # Retrieve observation |
| 484 | 456 | obs = select.obs() |
| 485 | 457 | |
| 486 | - # If a stacked analysis is requested then bin the events | |
| 487 | - # and compute the stacked response functions and setup | |
| 488 | - # an observation container with a single stacked observation. | |
| 489 | - if self._stacked: | |
| 490 | - obs = self._bin_observation(obs) | |
| 458 | + # Deal with stacked and On/Off Observations | |
| 459 | + if self._stacked or self._onoff: | |
| 460 | + | |
| 461 | + # If a stacked analysis is requested bin the events | |
| 462 | + # and compute the stacked response functions and setup | |
| 463 | + # an observation container with a single stacked observation. | |
| 464 | + if self._stacked: | |
| 465 | + new_obs = obsutils.get_stacked_obs(self, obs) | |
| 466 | + | |
| 467 | + # ... otherwise if On/Off analysis is requested generate | |
| 468 | + # the On/Off observations and response | |
| 469 | + elif self._onoff: | |
| 470 | + new_obs = obsutils.get_onoff_obs(self, obs) | |
| 471 | + | |
| 472 | + # Extract models | |
| 473 | + models = new_obs.models() | |
| 474 | + | |
| 475 | + # Fix background models if required | |
| 476 | + if self['fix_bkg'].boolean(): | |
| 477 | + for model in models: | |
| 478 | + if model.classname() != 'GModelSky': | |
| 479 | + for par in model: | |
| 480 | + par.fix() | |
| 481 | + | |
| 482 | + # Put back models | |
| 483 | + new_obs.models(models) | |
| 484 | + | |
| 485 | + # Continue with new oberservation container | |
| 486 | + obs = new_obs | |
| 491 | 487 | |
| 492 | 488 | # Header |
| 493 | 489 | self._log_header3(gammalib.EXPLICIT, 'Fitting the data') |
| 494 | 490 | |
| 495 | 491 | # Do maximum likelihood model fitting |
| 496 | - like = ctools.ctlike(obs) | |
| 497 | - like['edisp'] = self['edisp'].boolean() | |
| 498 | - like.run() | |
| 492 | + if obs.size() > 0: | |
| 493 | + like = ctools.ctlike(obs) | |
| 494 | + like['edisp'] = self['edisp'].boolean() | |
| 495 | + like.run() | |
| 496 | + | |
| 497 | + # Skip bin if no event was present | |
| 498 | + if like.obs().logL() == 0.0: | |
| 499 | 499 | |
| 500 | - # Skip bin if no event was present | |
| 501 | - if like.obs().logL() == 0.0: | |
| 500 | + # Signal skipping of bin | |
| 501 | + self._log_value(gammalib.TERSE, 'Warning', | |
| 502 | + 'No event in this time bin, skip bin.') | |
| 502 | 503 | |
| 503 | - # Signal skipping of bin | |
| 504 | + # Set all results to 0 | |
| 505 | + for par in pars: | |
| 506 | + result['values'][par] = 0.0 | |
| 507 | + result['values']['e_'+par] = 0.0 | |
| 508 | + | |
| 509 | + # Append result | |
| 510 | + results.append(result) | |
| 511 | + | |
| 512 | + # Continue with next time bin | |
| 513 | + continue | |
| 514 | + | |
| 515 | + # Retrieve model fitting results for source of interest | |
| 516 | + source = like.obs().models()[self._srcname] | |
| 517 | + | |
| 518 | + # Extract parameter values | |
| 519 | + for par in pars: | |
| 520 | + result['values'][par] = source[par].value() | |
| 521 | + result['values']['e_'+par] = source[par].error() | |
| 522 | + | |
| 523 | + # Calculate upper limit (-1 if not computed) | |
| 524 | + #ul_diff, ul_flux, ul_eflux = self._compute_ulimit(like.obs()) | |
| 525 | + ul_diff, ul_flux, ul_eflux = self._compute_ulimit(obs) | |
| 526 | + if ul_diff > 0.0: | |
| 527 | + result['ul_diff'] = ul_diff | |
| 528 | + result['ul_flux'] = ul_flux | |
| 529 | + result['ul_eflux'] = ul_eflux | |
| 530 | + | |
| 531 | + # Extract Test Statistic value | |
| 532 | + if self['calc_ts'].boolean(): | |
| 533 | + result['ts'] = source.ts() | |
| 534 | + | |
| 535 | + # Append result to list of dictionaries | |
| 536 | + results.append(result) | |
| 537 | + | |
| 538 | + # Log results for this time bin | |
| 539 | + self._log.header3('Results') | |
| 540 | + pars = self._get_free_par_names() | |
| 541 | + for par in pars: | |
| 542 | + value = source[par].value() | |
| 543 | + error = source[par].error() | |
| 544 | + unit = source[par].unit() | |
| 545 | + self._log_value(gammalib.NORMAL, par, | |
| 546 | + str(value)+' +/- '+str(error)+' '+unit) | |
| 547 | + if ul_diff > 0.0: | |
| 548 | + self._log_value(gammalib.NORMAL, 'Upper flux limit', | |
| 549 | + str(result['ul_diff'])+' ph/cm2/s/MeV') | |
| 550 | + self._log_value(gammalib.NORMAL, 'Upper flux limit', | |
| 551 | + str(result['ul_flux'])+' ph/cm2/s') | |
| 552 | + self._log_value(gammalib.NORMAL, 'Upper flux limit', | |
| 553 | + str(result['ul_eflux'])+' erg/cm2/s') | |
| 554 | + if self['calc_ts'].boolean(): | |
| 555 | + self._log_value(gammalib.NORMAL, 'Test Statistic', result['ts']) | |
| 556 | + | |
| 557 | + # Otherwise, if observations size is 0, signal bin is skipped and | |
| 558 | + # fill results table with zeros | |
| 559 | + else: | |
| 504 | 560 | self._log_value(gammalib.TERSE, 'Warning', |
| 505 | - 'No event in this time bin, skip bin.') | |
| 561 | + 'No observations available in this time bin', | |
| 562 | + 'Skip bin.') | |
| 506 | 563 | |
| 507 | 564 | # Set all results to 0 |
| 508 | 565 | for par in pars: |
| 509 | - result['values'][par] = 0.0 | |
| 510 | - result['values']['e_'+par] = 0.0 | |
| 566 | + result['values'][par] = 0.0 | |
| 567 | + result['values']['e_' + par] = 0.0 | |
| 511 | 568 | |
| 512 | 569 | # Append result |
| 513 | 570 | results.append(result) |
| ... | ... | @@ -515,48 +572,6 @@ class cslightcrv(ctools.csobservation): |
| 515 | 572 | # Continue with next time bin |
| 516 | 573 | continue |
| 517 | 574 | |
| 518 | - # Retrieve model fitting results for source of interest | |
| 519 | - source = like.obs().models()[self._srcname] | |
| 520 | - | |
| 521 | - # Extract parameter values | |
| 522 | - for par in pars: | |
| 523 | - result['values'][par] = source[par].value() | |
| 524 | - result['values']['e_'+par] = source[par].error() | |
| 525 | - | |
| 526 | - # Calculate upper limit (-1 if not computed) | |
| 527 | - #ul_diff, ul_flux, ul_eflux = self._compute_ulimit(like.obs()) | |
| 528 | - ul_diff, ul_flux, ul_eflux = self._compute_ulimit(obs) | |
| 529 | - if ul_diff > 0.0: | |
| 530 | - result['ul_diff'] = ul_diff | |
| 531 | - result['ul_flux'] = ul_flux | |
| 532 | - result['ul_eflux'] = ul_eflux | |
| 533 | - | |
| 534 | - # Extract Test Statistic value | |
| 535 | - if self['calc_ts'].boolean(): | |
| 536 | - result['ts'] = source.ts() | |
| 537 | - | |
| 538 | - # Append result to list of dictionaries | |
| 539 | - results.append(result) | |
| 540 | - | |
| 541 | - # Log results for this time bin | |
| 542 | - self._log.header3('Results') | |
| 543 | - pars = self._get_free_par_names() | |
| 544 | - for par in pars: | |
| 545 | - value = source[par].value() | |
| 546 | - error = source[par].error() | |
| 547 | - unit = source[par].unit() | |
| 548 | - self._log_value(gammalib.NORMAL, par, | |
| 549 | - str(value)+' +/- '+str(error)+' '+unit) | |
| 550 | - if ul_diff > 0.0: | |
| 551 | - self._log_value(gammalib.NORMAL, 'Upper flux limit', | |
| 552 | - str(result['ul_diff'])+' ph/cm2/s/MeV') | |
| 553 | - self._log_value(gammalib.NORMAL, 'Upper flux limit', | |
| 554 | - str(result['ul_flux'])+' ph/cm2/s') | |
| 555 | - self._log_value(gammalib.NORMAL, 'Upper flux limit', | |
| 556 | - str(result['ul_eflux'])+' erg/cm2/s') | |
| 557 | - if self['calc_ts'].boolean(): | |
| 558 | - self._log_value(gammalib.NORMAL, 'Test Statistic', result['ts']) | |
| 559 | - | |
| 560 | 575 | # Create FITS table from results |
| 561 | 576 | table = self._create_fits_table(results) |
| 562 | 577 | ... | ... |
cscripts/csphasecrv.par
| ... | ... | @@ -21,7 +21,8 @@ inmodel, f, a, $CTOOLS/share/models/crab.xml,,, "Input model definition XML fi |
| 21 | 21 | srcname, s, a, Crab,,, "Source name" |
| 22 | 22 | caldb, s, a, prod2,,, "Calibration database" |
| 23 | 23 | irf, s, a, South_0.5h,,, "Instrument response function" |
| 24 | -edisp, b, h, no,,, "Apply energy dispersion?" | |
| 24 | +inexclusion, f, h, NONE,,, "Sky map of exclusion regions for On/Off analysis" | |
| 25 | +edisp, b, h, no,,, "Apply energy dispersion in Cube analysis?" | |
| 25 | 26 | outfile, f, a, phasecrv.fits,,, "Output fits file name." |
| 26 | 27 | |
| 27 | 28 | # |
| ... | ... | @@ -30,16 +31,25 @@ outfile, f, a, phasecrv.fits,,, "Output fits file name." |
| 30 | 31 | phbinalg, s, a, LIN,LIN|FILE,, "Algorithm for defining phase bins" |
| 31 | 32 | phbins, i, a, 5,1,10000, "Number of phase bins" |
| 32 | 33 | phbinfile, f, a, NONE,,, "File defining the phase binning" |
| 34 | +method, s, a, 3D, 3D|ONOFF,, "Analysis method" | |
| 33 | 35 | emin, r, a, 0.1,,, "Lower energy limit of events (TeV)" |
| 34 | 36 | emax, r, a, 100.0,,, "Upper energy limit of events (TeV)" |
| 35 | -enumbins, i, a, 0,0,100, "Number of energy bins for binned (0=unbinned)" | |
| 37 | +enumbins, i, a, 0,0,100, "Number of energy bins for binned (0=unbinned for 3D analysis only))" | |
| 36 | 38 | coordsys, s, a, CEL,CEL|GAL,, "Coordinate System" |
| 37 | 39 | proj, s, a, CAR,AIT|AZP|CAR|GLS|MER|MOL|SFL|SIN|STG|TAN,, "Projection method" |
| 38 | -xref, r, a, 83.63,0,360, "First coordinate of image center in degrees (RA or galactic l)" | |
| 39 | -yref, r, a, 22.01,-90,90, "Second coordinate of image center in degrees (DEC or galactic b)" | |
| 40 | +xref, r, a, 83.63,0,360, "First coordinate of image/source region center in degrees (RA or galactic l)" | |
| 41 | +yref, r, a, 22.01,-90,90, "Second coordinate of image/source region center in degrees (DEC or galactic b)" | |
| 40 | 42 | nxpix, i, a, 200,,, "Size of the X axis in pixels" |
| 41 | 43 | nypix, i, a, 200,,, "Size of the Y axis in pixels" |
| 42 | 44 | binsz, r, a, 0.02,,, "Pixel size (deg/pixel)" |
| 45 | +srcshape, s, h, CIRCLE,CIRCLE,, "Shape of the source region" | |
| 46 | +rad, r, a, 0.2,0,180, "Radius of source region circle (deg)" | |
| 47 | +bkgmethod, s, h, REFLECTED,REFLECTED,, "Method for background estimation" | |
| 48 | +bkgregmin, i, h, 2,1,1000, "Minimum number of background regions" | |
| 49 | +maxoffset, r, h, 4.0,,, "Maximum offset of source from camera center to accept observation" | |
| 50 | +etruemin, r, h, 0.01,,, "Minimum true energy (TeV)" | |
| 51 | +etruemax, r, h, 300.0,,, "Maximum true energy (TeV)" | |
| 52 | +etruebins, i, h, 30,,, "Number of bins per decade for true energy bins" | |
| 43 | 53 | statistic, s, h, DEFAULT,DEFAULT|CSTAT|WSTAT|CHI2,, "Optimization statistic" |
| 44 | 54 | |
| 45 | 55 | # | ... | ... |
cscripts/csphasecrv.py
| ... | ... | @@ -63,6 +63,7 @@ class csphasecrv(ctools.csobservation): |
| 63 | 63 | # [[ph1min,ph1max], [ph2min,ph2max],..] |
| 64 | 64 | self._srcname = '' |
| 65 | 65 | self._phbins = [[0.0,1.0]] |
| 66 | + self._onoff = False | |
| 66 | 67 | self._stacked = False |
| 67 | 68 | self._fits = gammalib.GFits() |
| 68 | 69 | self._fitmodels = {} |
| ... | ... | @@ -92,8 +93,13 @@ class csphasecrv(ctools.csobservation): |
| 92 | 93 | # Get phase boundaries |
| 93 | 94 | self._phbins = self._create_tbounds() |
| 94 | 95 | |
| 96 | + # Set On/Off analysis flag and query relevant user parameters | |
| 97 | + self._onoff = self._is_onoff() | |
| 98 | + | |
| 99 | + # If cube analysis is selected | |
| 95 | 100 | # Set stacked analysis flag and query relevant user parameters |
| 96 | - self._stacked = self._is_stacked() | |
| 101 | + if not self._onoff: | |
| 102 | + self._stacked = self._is_stacked() | |
| 97 | 103 | |
| 98 | 104 | # Query the hidden parameters, just in case |
| 99 | 105 | self['edisp'].boolean() |
| ... | ... | @@ -236,11 +242,20 @@ class csphasecrv(ctools.csobservation): |
| 236 | 242 | |
| 237 | 243 | # Store fit results |
| 238 | 244 | phname = str(phmin)+'-'+str(phmax) |
| 239 | - source = self._fitmodels[phname][self._srcname] | |
| 240 | - for par in pars: | |
| 241 | - result['values'][par] = source[par].value() | |
| 242 | - result['values']['e_'+par] = source[par].error() | |
| 243 | - | |
| 245 | + | |
| 246 | + # If the model contains the source of interest fill results | |
| 247 | + try: | |
| 248 | + source = self._fitmodels[phname][self._srcname] | |
| 249 | + for par in pars: | |
| 250 | + result['values'][par] = source[par].value() | |
| 251 | + result['values']['e_'+par] = source[par].error() | |
| 252 | + | |
| 253 | + # ... otherwise fills with zeros | |
| 254 | + except: | |
| 255 | + for par in pars: | |
| 256 | + result['values'][par] = 0. | |
| 257 | + result['values']['e_'+par] = 0. | |
| 258 | + | |
| 244 | 259 | # Append result to list of dictionaries |
| 245 | 260 | results.append(result) |
| 246 | 261 | |
| ... | ... | @@ -348,36 +363,57 @@ class csphasecrv(ctools.csobservation): |
| 348 | 363 | select['dec'] = 'UNDEFINED' |
| 349 | 364 | select['expr'] = 'PHASE>'+str(phbin[0])+' && PHASE<'+str(phbin[1]) |
| 350 | 365 | select.run() |
| 351 | - | |
| 366 | + | |
| 367 | + # Set phase string | |
| 368 | + phstr = str(phbin[0]) + '-' + str(phbin[1]) | |
| 369 | + | |
| 352 | 370 | # Add phase to observation id |
| 353 | 371 | for i in range(0,select.obs().size()): |
| 354 | 372 | oldid = select.obs()[i].id() |
| 355 | - select.obs()[i].id(oldid+'_'+str(phbin[0])+'-'+str(phbin[1])) | |
| 373 | + select.obs()[i].id(oldid+'_'+phstr) | |
| 356 | 374 | obs = select.obs() |
| 357 | 375 | |
| 358 | - # If a stacked analysis is requested then bin the events | |
| 359 | - # and compute the stacked response functions and setup | |
| 376 | + # If an On/Off analysis is requested generate the On/Off observations | |
| 377 | + if self._onoff: | |
| 378 | + obs = obsutils.get_onoff_obs(self, select.obs()) | |
| 379 | + | |
| 380 | + # ... otherwise, if stacked analysis is requested then bin the | |
| 381 | + # events and compute the stacked response functions and setup | |
| 360 | 382 | # an observation container with a single stacked observation. |
| 361 | - if self._stacked: | |
| 383 | + elif self._stacked: | |
| 362 | 384 | obs = obsutils.get_stacked_obs(self, select.obs()) |
| 363 | - | |
| 385 | + | |
| 364 | 386 | # Header |
| 365 | 387 | self._log_header3(gammalib.EXPLICIT, 'Fitting the data') |
| 366 | - | |
| 367 | - # Do maximum likelihood model fitting | |
| 368 | - like = ctools.ctlike(obs) | |
| 369 | - like['edisp'] = self['edisp'].boolean() | |
| 370 | - like.run() | |
| 371 | - | |
| 372 | - # Renormalize models to phase selection | |
| 373 | - # TODO move the scaling from the temporal to the spectral component | |
| 374 | - for model in like.obs().models(): | |
| 375 | - scaled_norm = model['Normalization'].value()/(phbin[1]-phbin[0]) | |
| 376 | - model['Normalization'].value(scaled_norm) | |
| 377 | - | |
| 378 | - # Store fit model | |
| 379 | - self._fitmodels[str(phbin[0])+'-'+str(phbin[1])] = \ | |
| 380 | - like.obs().models().copy() | |
| 388 | + | |
| 389 | + # The On/Off analysis can produce empty observation containers, | |
| 390 | + # e.g., when on-axis observations are used. To avoid ctlike asking | |
| 391 | + # for a new observation container (or hang, if in interactive mode) | |
| 392 | + # we'll run ctlike only if the size is >0 | |
| 393 | + if obs.size() > 0: | |
| 394 | + | |
| 395 | + # Do maximum likelihood model fitting | |
| 396 | + like = ctools.ctlike(obs) | |
| 397 | + like['edisp'] = self['edisp'].boolean() | |
| 398 | + like.run() | |
| 399 | + | |
| 400 | + # Renormalize models to phase selection | |
| 401 | + # TODO move the scaling from the temporal to the spectral component | |
| 402 | + for model in like.obs().models(): | |
| 403 | + scaled_norm = model['Normalization'].value()/(phbin[1]-phbin[0]) | |
| 404 | + model['Normalization'].value(scaled_norm) | |
| 405 | + | |
| 406 | + # Store fit model | |
| 407 | + self._fitmodels[phstr] = like.obs().models().copy() | |
| 408 | + | |
| 409 | + # ... otherwise we set an empty model container | |
| 410 | + else: | |
| 411 | + self._log_string(gammalib.TERSE, | |
| 412 | + 'PHASE %f - %f: no observations available' | |
| 413 | + ' for fitting' %(phbin[0], phbin[1])) | |
| 414 | + | |
| 415 | + # Set empty models container | |
| 416 | + self._fitmodels[phstr] = gammalib.GModels() | |
| 381 | 417 | |
| 382 | 418 | # Create FITS file |
| 383 | 419 | self._create_fits() | ... | ... |
cscripts/obsutils.py
| ... | ... | @@ -760,3 +760,71 @@ def get_stacked_obs(cls, obs): |
| 760 | 760 | |
| 761 | 761 | # Return new oberservation container |
| 762 | 762 | return new_obs |
| 763 | + | |
| 764 | + | |
| 765 | +# ================================ # | |
| 766 | +# Get On/Off observation container # | |
| 767 | +# ================================ # | |
| 768 | +def get_onoff_obs(cls, obs): | |
| 769 | + """ | |
| 770 | + Create On/Off observations container from given observations | |
| 771 | + | |
| 772 | + Parameters | |
| 773 | + ---------- | |
| 774 | + cls : `~ctools.cscript` | |
| 775 | + cscript class | |
| 776 | + obs : `~gammalib.GObservations` | |
| 777 | + Observation container | |
| 778 | + | |
| 779 | + Returns | |
| 780 | + ------- | |
| 781 | + onoff_obs : `~gammalib.GObservations` | |
| 782 | + Observation container with On/Off observations | |
| 783 | + """ | |
| 784 | + # Write header | |
| 785 | + if cls._logExplicit(): | |
| 786 | + cls._log.header3('Creating On/Off observations') | |
| 787 | + | |
| 788 | + # Create On/Off observations | |
| 789 | + phagen = cscripts.csphagen(obs) | |
| 790 | + phagen['inexclusion'] = cls['inexclusion'].value() | |
| 791 | + phagen['emin'] = cls['emin'].real() | |
| 792 | + phagen['emax'] = cls['emax'].real() | |
| 793 | + phagen['enumbins'] = cls['enumbins'].integer() | |
| 794 | + phagen['ebinalg'] = 'LOG' | |
| 795 | + phagen['srcshape'] = cls['srcshape'].string() | |
| 796 | + phagen['coordsys'] = cls['coordsys'].string() | |
| 797 | + if cls['coordsys'].string() == 'CEL': | |
| 798 | + phagen['ra'] = cls['xref'].real() | |
| 799 | + phagen['dec'] = cls['yref'].real() | |
| 800 | + elif cls['coordsys'].string() == 'GAL': | |
| 801 | + phagen['glon'] = cls['xref'].real() | |
| 802 | + phagen['glat'] = cls['yref'].real() | |
| 803 | + if cls['srcshape'].string() == 'CIRCLE': | |
| 804 | + phagen['rad'] = cls['rad'].real() | |
| 805 | + phagen['bkgmethod'] = cls['bkgmethod'].string() | |
| 806 | + if cls['bkgmethod'].string() == 'REFLECTED': | |
| 807 | + phagen['bkgregmin'] = cls['bkgregmin'].integer() | |
| 808 | + phagen['maxoffset'] = cls['maxoffset'].real() | |
| 809 | + phagen['stack'] = True | |
| 810 | + phagen['etruemin'] = cls['etruemin'].real() | |
| 811 | + phagen['etruemax'] = cls['etruemax'].real() | |
| 812 | + phagen['etruebins'] = cls['etruebins'].integer() | |
| 813 | + phagen['chatter'] = cls['chatter'].integer() | |
| 814 | + phagen['clobber'] = cls['clobber'].boolean() | |
| 815 | + phagen['debug'] = cls['debug'].boolean() | |
| 816 | + phagen.run() | |
| 817 | + | |
| 818 | + # Clone resulting observation container | |
| 819 | + onoff_obs = phagen.obs().copy() | |
| 820 | + | |
| 821 | + # On/Off observations are created with CSTAT as default statistic | |
| 822 | + # We will change this to the user choice | |
| 823 | + if cls['statistic'].string() == 'DEFAULT': | |
| 824 | + pass | |
| 825 | + else: | |
| 826 | + for observation in onoff_obs: | |
| 827 | + observation.statistic(cls['statistic'].string()) | |
| 828 | + | |
| 829 | + # Return On/Off oberservation container | |
| 830 | + return onoff_obs | ... | ... |
doc/source/users/reference_manual/cslightcrv.rst
| ... | ... | @@ -42,13 +42,19 @@ General parameters |
| 42 | 42 | ``irf [string]`` |
| 43 | 43 | Instrumental response function. |
| 44 | 44 | |
| 45 | +``(inexclusion = NONE) [file]`` | |
| 46 | + Optional FITS file containing a WCS map in the first hdu that defines sky | |
| 47 | + regions not to be used for background estimation in ``ONOFF`` analysis (where | |
| 48 | + map value != 0). | |
| 49 | + | |
| 45 | 50 | ``(edisp = no) [boolean]`` |
| 46 | - Applies energy dispersion to response computation. | |
| 51 | + Applies energy dispersion to response computation (for ``3D`` analysis only, | |
| 52 | + energy dispersion is always taken into account in ``ONOFF`` analysis). | |
| 47 | 53 | |
| 48 | 54 | ``outfile [file]`` |
| 49 | 55 | Name of the light curve output file. |
| 50 | 56 | |
| 51 | -``(tbinalg = GTI) <FILE|LIN|GTI> [string]`` | |
| 57 | +``tbinalg <FILE|LIN|GTI> [string]`` | |
| 52 | 58 | Algorithm for defining time bins. |
| 53 | 59 | |
| 54 | 60 | ``tmin [time]`` |
| ... | ... | @@ -63,6 +69,10 @@ General parameters |
| 63 | 69 | ``tbinfile [file]`` |
| 64 | 70 | File defining the time binning. |
| 65 | 71 | |
| 72 | +``method <3D|ONOFF> [string]`` | |
| 73 | + Selects between ``3D`` analysis (3D spatial/energy likelihood) and ``ONOFF`` | |
| 74 | + analysis (1D likelihood with background from Off regions). | |
| 75 | + | |
| 66 | 76 | ``emin [real]`` |
| 67 | 77 | Lower energy limit of events (in TeV). |
| 68 | 78 | |
| ... | ... | @@ -70,7 +80,7 @@ General parameters |
| 70 | 80 | Upper energy limit of events (in TeV). |
| 71 | 81 | |
| 72 | 82 | ``enumbins [integer]`` |
| 73 | - Number of energy bins per light curve bin (0=unbinned). | |
| 83 | + Number of energy bins per light curve bin (0=unbinned for ``3D`` analysis only). | |
| 74 | 84 | |
| 75 | 85 | ``coordsys <CEL|GAL> [string]`` |
| 76 | 86 | Coordinate system (CEL - celestial, GAL - galactic). |
| ... | ... | @@ -79,19 +89,52 @@ General parameters |
| 79 | 89 | Projection method. |
| 80 | 90 | |
| 81 | 91 | ``xref [real]`` |
| 82 | - Right Ascension / Galactic longitude of image centre (J2000, in degrees). | |
| 92 | + Right Ascension / Galactic longitude of image centre for ``3D`` analysis or | |
| 93 | + source region centre for ``ONOFF`` analysis (J2000, in degrees). | |
| 83 | 94 | |
| 84 | 95 | ``yref [real]`` |
| 85 | - Declination / Galactic latitude of image centre (J2000, in degrees). | |
| 96 | + Declination / Galactic latitude of image centre for ``3D`` analysis or | |
| 97 | + source region centre for ``ONOFF`` analysis (J2000, in degrees). | |
| 86 | 98 | |
| 87 | 99 | ``nxpix [integer]`` |
| 88 | - Size of the Right Ascension / Galactic longitude axis (in pixels). | |
| 100 | + Size of the Right Ascension / Galactic longitude axis for ``3D`` analysis (in pixels). | |
| 89 | 101 | |
| 90 | 102 | ``nypix [integer]`` |
| 91 | - Size of the Declination / Galactic latitude axis (in pixels). | |
| 103 | + Size of the Declination / Galactic latitude axis for ``3D`` analysis (in pixels). | |
| 92 | 104 | |
| 93 | 105 | ``binsz [real]`` |
| 94 | - Pixel size (in degrees/pixel). | |
| 106 | + Pixel size for ``3D`` analysis (in degrees/pixel). | |
| 107 | + | |
| 108 | +``(srcshape = CIRCLE) [string]`` | |
| 109 | + Shape of the source region for ``ONOFF`` analysis. | |
| 110 | + ``CIRCLE``: circular region around given position. | |
| 111 | + | |
| 112 | +``rad [real]`` | |
| 113 | + Radius of source region circle for ``ONOFF`` analysis (deg) | |
| 114 | + | |
| 115 | +``(bkgmethod = REFLECTED) [string]`` | |
| 116 | + Method for background estimation in ``ONOFF`` analysis. | |
| 117 | + ``REFLECTED:`` background evaluated in regions with the same shape as | |
| 118 | + source region reflected w.r.t. pointing direction for each observation. | |
| 119 | + | |
| 120 | +``(bkgregmin = 2) [integer]`` | |
| 121 | + Minimum number of background regions that are required for an observation in | |
| 122 | + ``ONOFF`` analysis. If this number of background regions is not available the | |
| 123 | + observation is skipped. | |
| 124 | + | |
| 125 | +``(maxoffset = 4.0) [real]`` | |
| 126 | + Maximum offset in degrees of source from camera center to accept the | |
| 127 | + observation for ``ONOFF`` analysis. | |
| 128 | + | |
| 129 | +``(etruemin = 0.01) [real]`` | |
| 130 | + Minimum true energy to evaluate instrumental response in ``ONOFF`` analysis (TeV). | |
| 131 | + | |
| 132 | +``(etruemax = 0.01) [real]`` | |
| 133 | + Maximum true energy to evaluate instrumental response in ``ONOFF`` analysis (TeV). | |
| 134 | + | |
| 135 | +``(etruebins = 30) [integer]`` | |
| 136 | + Number of bins per decade for true energy bins to evaluate instrumental | |
| 137 | + response in ``ONOFF`` analysis. | |
| 95 | 138 | |
| 96 | 139 | ``(statistic = DEFAULT) <DEFAULT|CSTAT|WSTAT|CHI2> [string]`` |
| 97 | 140 | Optimization statistic. ``DEFAULT`` uses the default statistic for all | ... | ... |
doc/source/users/reference_manual/csphasecrv.rst
| ... | ... | @@ -10,14 +10,16 @@ Synopsis |
| 10 | 10 | -------- |
| 11 | 11 | |
| 12 | 12 | This script computes spectra by performing a maximum likelihood fit using |
| 13 | -:doc:`ctlike` in a series of phase bins for pulsars. The phase bins can be | |
| 13 | +:doc:`ctlike` in a series of phase bins for periodic sources. The input event | |
| 14 | +list must have a ``PHASE`` column containing the phase values, that can be | |
| 15 | +assigned using :doc:`ctphase`. The phase bins can be | |
| 14 | 16 | either specified in an ASCII file or as an interval divided into equally sized |
| 15 | 17 | phase bins. The format of the ASCII file is one row per phase bin, each |
| 16 | 18 | specifying the start of stop value of the phase bin, separated by a whitespace. |
| 17 | 19 | The phase goes from 0.0 to 1.0. |
| 18 | 20 | |
| 19 | -On output the script writes the fitting results into a FITS file. The script | |
| 20 | -also produces one XML file per phase bin that contains the fitting results for | |
| 21 | +The script writes the fit results into a FITS file. The script | |
| 22 | +also produces one XML file per phase bin that contains the best-fit model for | |
| 21 | 23 | that bin. |
| 22 | 24 | |
| 23 | 25 | |
| ... | ... | @@ -39,8 +41,14 @@ General parameters |
| 39 | 41 | ``irf [string]`` |
| 40 | 42 | Instrumental response function. |
| 41 | 43 | |
| 44 | +``(inexclusion = NONE) [file]`` | |
| 45 | + Optional FITS file containing a WCS map in the first hdu that defines sky | |
| 46 | + regions not to be used for background estimation in ``ONOFF`` analysis (where | |
| 47 | + map value != 0). | |
| 48 | + | |
| 42 | 49 | ``(edisp = no) [boolean]`` |
| 43 | - Applies energy dispersion to response computation. | |
| 50 | + Applies energy dispersion to response computation (for ``3D`` analysis only, | |
| 51 | + energy dispersion is always taken into account in ``ONOFF`` analysis). | |
| 44 | 52 | |
| 45 | 53 | ``outfile [file]`` |
| 46 | 54 | Name of the XML output file. The phase interval will be automatically |
| ... | ... | @@ -55,6 +63,10 @@ General parameters |
| 55 | 63 | ``phbinfile [file]`` |
| 56 | 64 | File defining the phase binning. |
| 57 | 65 | |
| 66 | +``method <3D|ONOFF> [string]`` | |
| 67 | + Selects between 3D analysis (3D spatial/energy likelihood) and ONOFF | |
| 68 | + analysis (1D likelihood with background from Off regions). | |
| 69 | + | |
| 58 | 70 | ``emin [real]`` |
| 59 | 71 | Lower energy limit of events (in TeV). |
| 60 | 72 | |
| ... | ... | @@ -71,19 +83,52 @@ General parameters |
| 71 | 83 | Projection method. |
| 72 | 84 | |
| 73 | 85 | ``xref [real]`` |
| 74 | - Right Ascension / Galactic longitude of image centre (J2000, in degrees). | |
| 86 | + Right Ascension / Galactic longitude of image centre for ``3D`` analysis or | |
| 87 | + source region centre for ``ONOFF`` analysis (J2000, in degrees). | |
| 75 | 88 | |
| 76 | 89 | ``yref [real]`` |
| 77 | - Declination / Galactic latitude of image centre (J2000, in degrees). | |
| 90 | + Declination / Galactic latitude of image centre for ``3D`` analysis or | |
| 91 | + source region centre for ``ONOFF`` analysis (J2000, in degrees). | |
| 78 | 92 | |
| 79 | 93 | ``nxpix [integer]`` |
| 80 | - Size of the Right Ascension / Galactic longitude axis (in pixels). | |
| 94 | + Size of the Right Ascension / Galactic longitude axis for ``3D`` analysis (in pixels). | |
| 81 | 95 | |
| 82 | 96 | ``nypix [integer]`` |
| 83 | - Size of the Declination / Galactic latitude axis (in pixels). | |
| 97 | + Size of the Declination / Galactic latitude axis for ``3D`` analysis (in pixels). | |
| 84 | 98 | |
| 85 | 99 | ``binsz [real]`` |
| 86 | - Pixel size (in degrees/pixel). | |
| 100 | + Pixel size for ``3D`` analysis (in degrees/pixel). | |
| 101 | + | |
| 102 | +``(srcshape = CIRCLE) [string]`` | |
| 103 | + Shape of the source region for ``ONOFF`` analysis. | |
| 104 | + ``CIRCLE``: circular region around given position. | |
| 105 | + | |
| 106 | +``rad [real]`` | |
| 107 | + Radius of source region circle for ``ONOFF`` analysis (deg) | |
| 108 | + | |
| 109 | +``(bkgmethod = REFLECTED) [string]`` | |
| 110 | + Method for background estimation in ``ONOFF`` analysis. | |
| 111 | + ``REFLECTED:`` background evaluated in regions with the same shape as | |
| 112 | + source region reflected w.r.t. pointing direction for each observation. | |
| 113 | + | |
| 114 | +``(bkgregmin = 2) [integer]`` | |
| 115 | + Minimum number of background regions that are required for an observation in | |
| 116 | + ``ONOFF`` analysis. If this number of background regions is not available the | |
| 117 | + observation is skipped. | |
| 118 | + | |
| 119 | +``(maxoffset = 4.0) [real]`` | |
| 120 | + Maximum offset in degrees of source from camera center to accept the | |
| 121 | + observation for ``ONOFF`` analysis. | |
| 122 | + | |
| 123 | +``(etruemin = 0.01) [real]`` | |
| 124 | + Minimum true energy to evaluate instrumental response in ``ONOFF`` analysis (TeV). | |
| 125 | + | |
| 126 | +``(etruemax = 0.01) [real]`` | |
| 127 | + Maximum true energy to evaluate instrumental response in ``ONOFF`` analysis (TeV). | |
| 128 | + | |
| 129 | +``(etruebins = 30) [integer]`` | |
| 130 | + Number of bins per decade for true energy bins to evaluate instrumental | |
| 131 | + response in ``ONOFF`` analysis. | |
| 87 | 132 | |
| 88 | 133 | ``(statistic = DEFAULT) <DEFAULT|CSTAT|WSTAT|CHI2> [string]`` |
| 89 | 134 | Optimization statistic. ``DEFAULT`` uses the default statistic for all |
| ... | ... | @@ -129,4 +174,5 @@ Standard parameters |
| 129 | 174 | Related tools or scripts |
| 130 | 175 | ------------------------ |
| 131 | 176 | |
| 177 | +:doc:`ctphase` | |
| 132 | 178 | :doc:`ctlike` | ... | ... |
doc/source/users/tutorials/howto/howto_lightcurve.rst
| ... | ... | @@ -34,12 +34,13 @@ The time interval is linearly divided into 20 time bins. |
| 34 | 34 | Input model definition XML file [$CTOOLS/share/models/crab.xml] models.xml |
| 35 | 35 | Source name [Crab] Src001 |
| 36 | 36 | Algorithm for defining time bins (FILE|LIN|GTI) [GTI] LIN |
| 37 | - Lightcurve start time (MJD) [51544.5] 59235.5 | |
| 38 | - Lightcurve stop time (MJD) [51544.6] 59236.0 | |
| 37 | + Lightcurve start time (UTC string, JD, MJD or MET in seconds) [MJD 51544.5] MJD 59235.5 | |
| 38 | + Lightcurve stop time (UTC string, JD, MJD or MET in seconds) [MJD 51544.6] MJD 59236.0 | |
| 39 | 39 | Number of time bins (1-10000) [5] 20 |
| 40 | - Number of energy bins for binned (0=unbinned) (0-100) [0] | |
| 40 | + Analysis method (3D|ONOFF) [3D] | |
| 41 | 41 | Lower energy limit of events (TeV) [0.1] |
| 42 | 42 | Upper energy limit of events (TeV) [100.0] |
| 43 | + Number of energy bins for binned (0=unbinned for Cube analysis only) (0-100) [0] | |
| 43 | 44 | Output light curve file [lightcurve.fits] |
| 44 | 45 | |
| 45 | 46 | The resulting light curve is shown in the figure below. | ... | ... |
pyext/ctool.i
| ... | ... | @@ -100,6 +100,7 @@ public: |
| 100 | 100 | %rename(_get_skydir) get_skydir; |
| 101 | 101 | %rename(_set_outfile_name) set_outfile_name; |
| 102 | 102 | %rename(_is_stacked) is_stacked; |
| 103 | + %rename(_is_onoff) is_onoff; | |
| 103 | 104 | %rename(_set_response) set_response; |
| 104 | 105 | %rename(_set_edisp) set_edisp; |
| 105 | 106 | %rename(_restore_edisp) restore_edisp; |
| ... | ... | @@ -146,6 +147,7 @@ public: |
| 146 | 147 | |
| 147 | 148 | // Protected methods that query user parameters |
| 148 | 149 | bool is_stacked(void); |
| 150 | + bool is_onoff(void); | |
| 149 | 151 | |
| 150 | 152 | // Protected support methods |
| 151 | 153 | void set_response(GObservations& obs); | ... | ... |
src/support/ctool.cpp
| ... | ... | @@ -1195,6 +1195,54 @@ bool ctool::is_stacked(void) |
| 1195 | 1195 | |
| 1196 | 1196 | |
| 1197 | 1197 | /***********************************************************************//** |
| 1198 | + * @brief Query user parameters for On/Off analysis | |
| 1199 | + * | |
| 1200 | + * @return True if an On/Off analysis should be done. | |
| 1201 | + * | |
| 1202 | + * Queries the parameter "method", and if this is "ONOFF" signal that an On/ | |
| 1203 | + * Off analysis is requested. In that case, all necessary input parameters of | |
| 1204 | + * csphagen are queried: "inexclusion", "emin", "emax", "enumbins", | |
| 1205 | + * "coordsys", "xref", "yref", "srcshape", "rad", "bkgmethod", "bkgregmin", | |
| 1206 | + * "maxoffset", "etruemin", "etruemax", and "etruebins". | |
| 1207 | + * | |
| 1208 | + * Using this method assures that the parameters are always queried in the | |
| 1209 | + * same order. | |
| 1210 | + ***************************************************************************/ | |
| 1211 | +bool ctool::is_onoff(void) | |
| 1212 | +{ | |
| 1213 | + // Set onoff flag | |
| 1214 | + bool onoff = ((*this)["method"].string() == "ONOFF"); | |
| 1215 | + | |
| 1216 | + // Query analysis method chosen | |
| 1217 | + if (onoff) { | |
| 1218 | + | |
| 1219 | + // Query csphagen parameters | |
| 1220 | + (*this)["inexclusion"].filename(); | |
| 1221 | + (*this)["emin"].real(); | |
| 1222 | + (*this)["emax"].real(); | |
| 1223 | + (*this)["enumbins"].integer(); | |
| 1224 | + (*this)["coordsys"].string(); | |
| 1225 | + (*this)["xref"].real(); | |
| 1226 | + (*this)["yref"].real(); | |
| 1227 | + if ((*this)["srcshape"].string() == "CIRCLE"){ | |
| 1228 | + (*this)["rad"].real(); | |
| 1229 | + } | |
| 1230 | + if ((*this)["bkgmethod"].string() == "REFLECTED"){ | |
| 1231 | + (*this)["bkgregmin"].integer(); | |
| 1232 | + } | |
| 1233 | + (*this)["maxoffset"].real(); | |
| 1234 | + (*this)["etruemin"].real(); | |
| 1235 | + (*this)["etruemax"].real(); | |
| 1236 | + (*this)["etruebins"].integer(); | |
| 1237 | + | |
| 1238 | + } // endif: method was ONOFF | |
| 1239 | + | |
| 1240 | + // Return onoff flag | |
| 1241 | + return onoff; | |
| 1242 | +} | |
| 1243 | + | |
| 1244 | + | |
| 1245 | +/***********************************************************************//** | |
| 1198 | 1246 | * @brief Set response for all CTA observations in container |
| 1199 | 1247 | * |
| 1200 | 1248 | * @param[in,out] obs Observation container | ... | ... |
src/support/ctool.hpp
test/data/crab_offaxis1.fits.gz
No preview for this file type
test/data/crab_onoff.xml
0 → 100644
| 1 | +<?xml version="1.0" standalone="no"?> | |
| 2 | +<source_library title="source library"> | |
| 3 | + <source name="Crab" type="PointSource"> | |
| 4 | + <spectrum type="PowerLaw"> | |
| 5 | + <parameter name="Prefactor" scale="1e-16" value="5.7" min="1e-07" max="1000.0" free="1"/> | |
| 6 | + <parameter name="Index" scale="-1" value="2.48" min="0.0" max="+5.0" free="1"/> | |
| 7 | + <parameter name="PivotEnergy" scale="1e6" value="0.3" min="0.01" max="1000.0" free="0"/> | |
| 8 | + </spectrum> | |
| 9 | + <spatialModel type="PointSource"> | |
| 10 | + <parameter name="RA" scale="1.0" value="83.6331" min="-360" max="360" free="0"/> | |
| 11 | + <parameter name="DEC" scale="1.0" value="22.0145" min="-90" max="90" free="0"/> | |
| 12 | + </spatialModel> | |
| 13 | + </source> | |
| 14 | + <source name="Background" type="RadialAcceptance" instrument="CTAOnOff"> | |
| 15 | + <spectrum type="PowerLaw"> | |
| 16 | + <parameter name="Prefactor" scale="1e-6" value="61.8" min="0.0" max="1000.0" free="1"/> | |
| 17 | + <parameter name="Index" scale="-1" value="1.85" min="0.0" max="+5.0" free="1"/> | |
| 18 | + <parameter name="PivotEnergy" scale="1e6" value="1.0" min="0.01" max="1000.0" free="0"/> | |
| 19 | + </spectrum> | |
| 20 | + <radialModel type="Gaussian"> | |
| 21 | + <parameter name="Sigma" scale="1.0" value="3.0" min="0.01" max="10.0" free="1"/> | |
| 22 | + </radialModel> | |
| 23 | + </source> | |
| 24 | +</source_library> | ... | ... |
test/test_cscript.py
test/test_cslightcrv.py
| ... | ... | @@ -42,6 +42,10 @@ class Test(test): |
| 42 | 42 | # Call base class constructor |
| 43 | 43 | test.__init__(self) |
| 44 | 44 | |
| 45 | + # Add off-axis events for classical analysis | |
| 46 | + self._offaxis_events = self._datadir + '/crab_offaxis1.fits' | |
| 47 | + self._model_onoff = self._datadir + '/crab_onoff.xml' | |
| 48 | + | |
| 45 | 49 | # Return |
| 46 | 50 | return |
| 47 | 51 | |
| ... | ... | @@ -73,7 +77,7 @@ class Test(test): |
| 73 | 77 | ' inmodel="'+self._model+'" srcname="Crab"'+ \ |
| 74 | 78 | ' caldb="'+self._caldb+'" irf="'+self._irf+'"'+ \ |
| 75 | 79 | ' tbinalg="LIN" tmin="MJD 51544.50" tmax="MJD 51544.53"'+ \ |
| 76 | - ' tbins=3 enumbins=0 emin=0.1 emax=100.0'+ \ | |
| 80 | + ' tbins=3 method="3D" enumbins=0 emin=0.1 emax=100.0'+ \ | |
| 77 | 81 | ' outfile="lightcurve_cmd1.fits"'+ \ |
| 78 | 82 | ' logfile="cslightcrv_cmd1.log" chatter=1' |
| 79 | 83 | |
| ... | ... | @@ -86,14 +90,14 @@ class Test(test): |
| 86 | 90 | 'Check successful execution from command line') |
| 87 | 91 | |
| 88 | 92 | # Check light curve |
| 89 | - self._check_light_curve('lightcurve_cmd1.fits', 3) | |
| 93 | + self._check_light_curve('lightcurve_cmd1.fits', 3, 1.6e-16) | |
| 90 | 94 | |
| 91 | 95 | # Setup cslightcrv command |
| 92 | 96 | cmd = cslightcrv+' inobs="events_that_do_not_exist.fits"'+ \ |
| 93 | 97 | ' inmodel="'+self._model+'" srcname="Crab"'+ \ |
| 94 | 98 | ' caldb="'+self._caldb+'" irf="'+self._irf+'"'+ \ |
| 95 | 99 | ' tbinalg="LIN" tmin="MJD 51544.50" tmax="MJD 51544.53"'+ \ |
| 96 | - ' tbins=3 enumbins=0 emin=0.1 emax=100.0'+ \ | |
| 100 | + ' tbins=3 method="3D" enumbins=0 emin=0.1 emax=100.0'+ \ | |
| 97 | 101 | ' outfile="lightcurve_cmd1.fits"'+ \ |
| 98 | 102 | ' logfile="cslightcrv_cmd2.log" debug=yes' |
| 99 | 103 | |
| ... | ... | @@ -123,6 +127,7 @@ class Test(test): |
| 123 | 127 | lcrv['tmin'] = 'MJD 51544.50' |
| 124 | 128 | lcrv['tmax'] = 'MJD 51544.53' |
| 125 | 129 | lcrv['tbins'] = 3 |
| 130 | + lcrv['method'] = '3D' | |
| 126 | 131 | lcrv['enumbins'] = 0 |
| 127 | 132 | lcrv['emin'] = 0.1 |
| 128 | 133 | lcrv['emax'] = 100.0 |
| ... | ... | @@ -137,7 +142,7 @@ class Test(test): |
| 137 | 142 | lcrv.save() |
| 138 | 143 | |
| 139 | 144 | # Check light curve |
| 140 | - self._check_light_curve('cslightcrv_py1.fits', 3) | |
| 145 | + self._check_light_curve('cslightcrv_py1.fits', 3, 1.6e-16) | |
| 141 | 146 | |
| 142 | 147 | # Now use FILE as time bin algorithm. For this we need first to |
| 143 | 148 | # create an ASCII file. We use now 6 time bins. The ASCII file |
| ... | ... | @@ -159,6 +164,7 @@ class Test(test): |
| 159 | 164 | lcrv['irf'] = self._irf |
| 160 | 165 | lcrv['tbinalg'] = 'FILE' |
| 161 | 166 | lcrv['tbinfile'] = 'cslightcrv_py2.dat' |
| 167 | + lcrv['method'] = '3D' | |
| 162 | 168 | lcrv['enumbins'] = 0 |
| 163 | 169 | lcrv['emin'] = 0.1 |
| 164 | 170 | lcrv['emax'] = 100.0 |
| ... | ... | @@ -171,7 +177,7 @@ class Test(test): |
| 171 | 177 | lcrv.execute() |
| 172 | 178 | |
| 173 | 179 | # Check light curve |
| 174 | - self._check_light_curve('cslightcrv_py2.fits', 2) | |
| 180 | + self._check_light_curve('cslightcrv_py2.fits', 2, 1.6e-16) | |
| 175 | 181 | |
| 176 | 182 | # Now we setup an observation container on input. We attached the |
| 177 | 183 | # model to the observation container so that cslightcrv should |
| ... | ... | @@ -188,6 +194,7 @@ class Test(test): |
| 188 | 194 | lcrv['caldb'] = self._caldb |
| 189 | 195 | lcrv['irf'] = self._irf |
| 190 | 196 | lcrv['tbinalg'] = 'GTI' |
| 197 | + lcrv['method'] = '3D' | |
| 191 | 198 | lcrv['enumbins'] = 0 |
| 192 | 199 | lcrv['emin'] = 0.1 |
| 193 | 200 | lcrv['emax'] = 100.0 |
| ... | ... | @@ -199,9 +206,9 @@ class Test(test): |
| 199 | 206 | lcrv.execute() |
| 200 | 207 | |
| 201 | 208 | # Check light curve |
| 202 | - self._check_light_curve('cslightcrv_py3.fits', 1) | |
| 209 | + self._check_light_curve('cslightcrv_py3.fits', 1, 1.6e-16) | |
| 203 | 210 | |
| 204 | - # Finally we set-up a binned cslightcrv | |
| 211 | + # Binned cslightcrv | |
| 205 | 212 | lcrv = cscripts.cslightcrv() |
| 206 | 213 | lcrv['inobs'] = self._events |
| 207 | 214 | lcrv['inmodel'] = self._model |
| ... | ... | @@ -212,6 +219,7 @@ class Test(test): |
| 212 | 219 | lcrv['tmin'] = 'MJD 51544.50' |
| 213 | 220 | lcrv['tmax'] = 'MJD 51544.53' |
| 214 | 221 | lcrv['tbins'] = 2 |
| 222 | + lcrv['method'] = '3D' | |
| 215 | 223 | lcrv['emin'] = 0.1 |
| 216 | 224 | lcrv['emax'] = 100.0 |
| 217 | 225 | lcrv['enumbins'] = 10 |
| ... | ... | @@ -230,13 +238,43 @@ class Test(test): |
| 230 | 238 | lcrv.execute() |
| 231 | 239 | |
| 232 | 240 | # Check light curve |
| 233 | - self._check_light_curve('cslightcrv_py4.fits', 2) | |
| 241 | + self._check_light_curve('cslightcrv_py4.fits', 2, 1.6e-16) | |
| 242 | + | |
| 243 | + # cslightcrv with classical analysis | |
| 244 | + lcrv = cscripts.cslightcrv() | |
| 245 | + lcrv['inobs'] = self._offaxis_events | |
| 246 | + lcrv['inmodel'] = self._model_onoff | |
| 247 | + lcrv['srcname'] = 'Crab' | |
| 248 | + lcrv['caldb'] = self._caldb | |
| 249 | + lcrv['irf'] = self._irf | |
| 250 | + lcrv['tbinalg'] = 'LIN' | |
| 251 | + lcrv['tmin'] = 'MJD 58849.0008' | |
| 252 | + lcrv['tmax'] = 'MJD 58849.0112' | |
| 253 | + lcrv['tbins'] = 2 | |
| 254 | + lcrv['method'] = 'ONOFF' | |
| 255 | + lcrv['emin'] = 0.1 | |
| 256 | + lcrv['emax'] = 100.0 | |
| 257 | + lcrv['enumbins'] = 10 | |
| 258 | + lcrv['coordsys'] = 'CEL' | |
| 259 | + lcrv['xref'] = 83.63 | |
| 260 | + lcrv['yref'] = 22.01 | |
| 261 | + lcrv['rad'] = 0.2 | |
| 262 | + lcrv['statistic'] = 'WSTAT' | |
| 263 | + lcrv['outfile'] = 'cslightcrv_py5.fits' | |
| 264 | + lcrv['logfile'] = 'cslightcrv_py5.log' | |
| 265 | + lcrv['chatter'] = 4 | |
| 266 | + | |
| 267 | + # Execute cslightcrv script | |
| 268 | + lcrv.execute() | |
| 269 | + | |
| 270 | + # Check light curve | |
| 271 | + self._check_light_curve('cslightcrv_py5.fits', 2, 6.e-16) | |
| 234 | 272 | |
| 235 | 273 | # Return |
| 236 | 274 | return |
| 237 | 275 | |
| 238 | 276 | # Check light curve result file |
| 239 | - def _check_light_curve(self, filename, bins): | |
| 277 | + def _check_light_curve(self, filename, bins,pref): | |
| 240 | 278 | """ |
| 241 | 279 | Check light curve file |
| 242 | 280 | """ |
| ... | ... | @@ -266,6 +304,13 @@ class Test(test): |
| 266 | 304 | self.test_assert(table.contains(col), |
| 267 | 305 | 'FITS file contains "'+col+'" column') |
| 268 | 306 | |
| 307 | + # Check that table has been filled | |
| 308 | + # Prefactor has right order of magnitude | |
| 309 | + for s in range(table.nrows()): | |
| 310 | + self.test_value(table['Prefactor'][s], pref, 0.2*pref, | |
| 311 | + 'Check prefactor value') | |
| 312 | + | |
| 313 | + | |
| 269 | 314 | # Close FITS file |
| 270 | 315 | fits.close() |
| 271 | 316 | ... | ... |
test/test_csphasecrv.py
| ... | ... | @@ -44,6 +44,8 @@ class Test(test): |
| 44 | 44 | |
| 45 | 45 | # Set test data |
| 46 | 46 | self._phased_events = self._datadir + '/phased_events.fits' |
| 47 | + self._offaxis_events = self._datadir + '/crab_offaxis1.fits' | |
| 48 | + self._model_onoff = self._datadir + '/crab_onoff.xml' | |
| 47 | 49 | |
| 48 | 50 | # Return |
| 49 | 51 | return |
| ... | ... | @@ -75,7 +77,7 @@ class Test(test): |
| 75 | 77 | cmd = csphasecrv+' inobs="'+self._phased_events+'"'+ \ |
| 76 | 78 | ' inmodel="'+self._model+'" srcname="Crab"'+ \ |
| 77 | 79 | ' caldb="'+self._caldb+'" irf="'+self._irf+'"'+ \ |
| 78 | - ' phbinalg="LIN" phbins=5'+ \ | |
| 80 | + ' phbinalg="LIN" phbins=5 method="3D"'+ \ | |
| 79 | 81 | ' enumbins=0 emin=0.1 emax=100.0'+ \ |
| 80 | 82 | ' outfile="csphasecrv_cmd1.fits"'+ \ |
| 81 | 83 | ' logfile="csphasecrv_cmd1.log" chatter=1' |
| ... | ... | @@ -95,7 +97,7 @@ class Test(test): |
| 95 | 97 | cmd = csphasecrv+' inobs="events_that_do_not_exist.fits"'+ \ |
| 96 | 98 | ' inmodel="'+self._model+'" srcname="Crab"'+ \ |
| 97 | 99 | ' caldb="'+self._caldb+'" irf="'+self._irf+'"'+ \ |
| 98 | - ' phbinalg="LIN" phbins=5'+ \ | |
| 100 | + ' phbinalg="LIN" phbins=5 method="3D"'+ \ | |
| 99 | 101 | ' enumbins=0 emin=0.1 emax=100.0'+ \ |
| 100 | 102 | ' outfile="csphasecrv_cmd2.fits"'+ \ |
| 101 | 103 | ' logfile="csphasecrv_cmd2.log" debug=yes chatter=1' |
| ... | ... | @@ -124,6 +126,7 @@ class Test(test): |
| 124 | 126 | pcrv['irf'] = self._irf |
| 125 | 127 | pcrv['phbinalg'] = 'LIN' |
| 126 | 128 | pcrv['phbins'] = 5 |
| 129 | + pcrv['method'] = '3D' | |
| 127 | 130 | pcrv['enumbins'] = 0 |
| 128 | 131 | pcrv['emin'] = 0.1 |
| 129 | 132 | pcrv['emax'] = 100.0 |
| ... | ... | @@ -160,6 +163,7 @@ class Test(test): |
| 160 | 163 | pcrv['irf'] = self._irf |
| 161 | 164 | pcrv['phbinalg'] = 'FILE' |
| 162 | 165 | pcrv['phbinfile'] = 'csphasecrv_py2.dat' |
| 166 | + pcrv['method'] = '3D' | |
| 163 | 167 | pcrv['enumbins'] = 0 |
| 164 | 168 | pcrv['emin'] = 0.1 |
| 165 | 169 | pcrv['emax'] = 100.0 |
| ... | ... | @@ -190,6 +194,7 @@ class Test(test): |
| 190 | 194 | pcrv['irf'] = self._irf |
| 191 | 195 | pcrv['phbinalg'] = 'LIN' |
| 192 | 196 | pcrv['phbins'] = 5 |
| 197 | + pcrv['method'] = '3D' | |
| 193 | 198 | pcrv['enumbins'] = 0 |
| 194 | 199 | pcrv['emin'] = 0.1 |
| 195 | 200 | pcrv['emax'] = 100.0 |
| ... | ... | @@ -204,7 +209,7 @@ class Test(test): |
| 204 | 209 | # Check phase curve |
| 205 | 210 | self._check_phase_curve('csphasecrv_py3.fits', 5) |
| 206 | 211 | |
| 207 | - # Finally we set-up a binned csphasecrv | |
| 212 | + # Binned csphasecrv | |
| 208 | 213 | pcrv = cscripts.csphasecrv() |
| 209 | 214 | pcrv['inobs'] = self._phased_events |
| 210 | 215 | pcrv['inmodel'] = self._model |
| ... | ... | @@ -213,6 +218,7 @@ class Test(test): |
| 213 | 218 | pcrv['irf'] = self._irf |
| 214 | 219 | pcrv['phbinalg'] = 'LIN' |
| 215 | 220 | pcrv['phbins'] = 2 |
| 221 | + pcrv['method'] = '3D' | |
| 216 | 222 | pcrv['emin'] = 0.1 |
| 217 | 223 | pcrv['emax'] = 100.0 |
| 218 | 224 | pcrv['enumbins'] = 10 |
| ... | ... | @@ -234,6 +240,35 @@ class Test(test): |
| 234 | 240 | # Check phase curve |
| 235 | 241 | self._check_phase_curve('csphasecrv_py4.fits', 2) |
| 236 | 242 | |
| 243 | + # On/Off csphasecrv | |
| 244 | + pcrv = cscripts.csphasecrv() | |
| 245 | + pcrv['inobs'] = self._offaxis_events | |
| 246 | + pcrv['inmodel'] = self._model_onoff | |
| 247 | + pcrv['srcname'] = 'Crab' | |
| 248 | + pcrv['caldb'] = self._caldb | |
| 249 | + pcrv['irf'] = self._irf | |
| 250 | + pcrv['phbinalg'] = 'LIN' | |
| 251 | + pcrv['phbins'] = 2 | |
| 252 | + pcrv['method'] = 'ONOFF' | |
| 253 | + pcrv['statistic'] = 'WSTAT' | |
| 254 | + pcrv['emin'] = 0.1 | |
| 255 | + pcrv['emax'] = 100.0 | |
| 256 | + pcrv['enumbins'] = 10 | |
| 257 | + pcrv['coordsys'] = 'CEL' | |
| 258 | + pcrv['xref'] = 83.63 | |
| 259 | + pcrv['yref'] = 22.01 | |
| 260 | + pcrv['rad'] = 0.2 | |
| 261 | + pcrv['outfile'] = 'csphasecrv_py5.fits' | |
| 262 | + pcrv['logfile'] = 'csphasecrv_py5.log' | |
| 263 | + pcrv['chatter'] = 4 | |
| 264 | + | |
| 265 | + # Execute csphasecrv script | |
| 266 | + pcrv.logFileOpen() # Make sure we get a log file | |
| 267 | + pcrv.execute() | |
| 268 | + | |
| 269 | + # Check phase curve | |
| 270 | + self._check_phase_curve('csphasecrv_py5.fits', 2) | |
| 271 | + | |
| 237 | 272 | # Return |
| 238 | 273 | return |
| 239 | 274 | |
| ... | ... | @@ -267,6 +302,12 @@ class Test(test): |
| 267 | 302 | self.test_assert(table.contains(col), |
| 268 | 303 | 'FITS file contains "'+col+'" column') |
| 269 | 304 | |
| 305 | + # Check that table has been filled | |
| 306 | + # Prefactor has right order of magnitude | |
| 307 | + for s in range(table.nrows()): | |
| 308 | + self.test_value(table['Prefactor'][s], 4.e-16, 3.e-16, | |
| 309 | + 'Check prefactor value') | |
| 310 | + | |
| 270 | 311 | # Close FITS file |
| 271 | 312 | fits.close() |
| 272 | 313 | ... | ... |