Commit 2f2afb6330b79c6e70b3c264e848fef177bceb32

Authored by Jürgen Knödlseder
2 parents a0d4125d d5430cfa

Merge branch 'integration' into devel

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
... ... @@ -104,6 +104,7 @@ protected:
104 104  
105 105 // Protected methods that query user parameters
106 106 bool is_stacked(void);
  107 + bool is_onoff(void);
107 108  
108 109 // Protected methods for logging
109 110 void log_observations(const GChatter& chatter,
... ...
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
... ... @@ -455,6 +455,9 @@ class Test(test):
455 455 # Test is_stacked() method
456 456 # TODO: implement
457 457  
  458 + # Test is_onoff() method
  459 + # TODO: implement
  460 +
458 461 # Test set_response() method
459 462 # TODO: implement
460 463  
... ...
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  
... ...