385 Determine sensitivity for given observations
389 emin : `~gammalib.GEnergy`
390 Minimum energy for fitting and flux computation
391 emax : `~gammalib.GEnergy`
392 Maximum energy for fitting and flux computation
393 test_model : `~gammalib.GModels`
405 ts_thres = self[
'sigma'].real() * self[
'sigma'].real()
406 max_iter = self[
'max_iter'].integer()
407 enumbins = self[
'enumbins'].integer()
408 if not enumbins == 0:
409 npix = self[
'npix'].integer()
410 binsz = self[
'binsz'].real()
417 edisp_orig = self[
'edisp'].boolean()
418 self[
'edisp'] =
False
421 ratio_precision = 0.05
424 self._log_string(gammalib.TERSE,
'')
425 self._log_header2(gammalib.TERSE,
'Energies: '+str(emin)+
' - '+str(emax))
431 e_mean = math.sqrt(emin.TeV()*emax.TeV())
432 loge = math.log10(e_mean)
433 erg_mean = e_mean * tev2erg
434 energy = gammalib.GEnergy(e_mean,
'TeV')
439 if test_model[self.
_srcname].spatial().classname() ==
'GModelSpatialDiffuseCube':
441 if test_model[self.
_srcname].spatial().spectrum().nodes() == 0:
442 test_model[self.
_srcname].spatial().set_mc_cone(gammalib.GSkyDir(),180.0)
447 src_flux = test_model[self.
_srcname].spectral().eval(energy) * \
448 test_model[self.
_srcname].spatial().spectrum().flux(emin, emax)
450 src_flux = test_model[self.
_srcname].spectral().flux(emin, emax)
455 crab_unit = crab_flux/src_flux
458 self._log_header3(gammalib.TERSE,
'Initial parameters')
459 self._log_value(gammalib.TERSE,
'Mapcube model', str(mapcube))
460 self._log_value(gammalib.TERSE,
'Crab flux', str(crab_flux)+
' ph/cm2/s')
461 self._log_value(gammalib.TERSE,
'Source model flux', str(src_flux)+
' ph/cm2/s')
462 self._log_value(gammalib.TERSE,
'Crab unit factor', crab_unit)
474 self._log_header3(gammalib.TERSE,
'Iterations')
486 self._log_header2(gammalib.EXPLICIT,
'Iteration '+str(iterations))
493 sim = obsutils.sim(self.obs(), nbins=enumbins, seed=self.
_seed,
494 binsz=binsz, npix=npix,
496 debug=self[
'debug'].boolean(),
497 edisp=self[
'edisp'].boolean(),
501 nevents = sim.nobserved()
504 self._log_header3(gammalib.EXPLICIT,
'Simulation')
505 self._log_value(gammalib.EXPLICIT,
'Number of simulated events', nevents)
509 fit = ctools.ctlike(sim)
510 fit[
'edisp'] = self[
'edisp'].boolean()
512 fit[
'debug'] = self[
'debug'].boolean()
513 fit[
'chatter'] = self[
'chatter'].integer()
517 logL = fit.opt().value()
518 npred = fit.obs().npred()
519 models = fit.obs().models()
524 prefactor = modutils.normalisation_parameter(source)
525 crab_flux = prefactor.value() / crab_prefactor
530 diff_flux = source.spectral().eval(energy)
535 photon_flux = diff_flux*source.spatial().spectrum().flux(emin, emax)
536 energy_flux = diff_flux*source.spatial().spectrum().eflux(emin, emax)
538 photon_flux = source.spectral().flux(emin, emax)
539 energy_flux = source.spectral().eflux(emin, emax)
548 sensitivity = diff_flux*e_mean*erg_mean*1.0e6
550 sensitivity *= source.spatial().spectrum().eval(energy)
553 name =
'Iteration %d' % iterations
554 value = (
'TS=%10.4f Sim=%9.4f mCrab Fit=%9.4f mCrab '
555 'Sens=%e erg/cm2/s' %
556 (ts, test_crab_flux*1000.0, crab_flux*1000.0, sensitivity))
557 self._log_value(gammalib.TERSE, name, value)
563 if (iterations >= max_iter):
564 self._log_string(gammalib.TERSE,
565 ' Test ended after %d iterations.' % max_iter)
569 test_crab_flux *= 3.0
572 self._log_string(gammalib.EXPLICIT,
573 'Non positive TS, increase test flux and start over.')
579 result = {
'ts': ts,
'crab_flux': crab_flux,
580 'photon_flux': photon_flux,
581 'energy_flux': energy_flux}
582 results.append(result)
588 correct = math.sqrt(ts_thres / ts)
591 pred_crab_flux, regcoeff = self.
_predict_flux(results, ts_thres)
592 correct = pred_crab_flux / crab_flux
594 self._log_value(gammalib.TERSE,
'Skipping failed regression',
595 'Retain simple TS scaling relation')
598 crab_flux = correct * crab_flux
599 photon_flux = correct * photon_flux
600 energy_flux = correct * energy_flux
601 sensitivity = correct * sensitivity
606 if test_crab_flux > 0:
610 ratio = crab_flux/test_crab_flux
614 if ratio > 1.0-ratio_precision
and \
615 ratio < 1.0+ratio_precision:
616 value = (
'TS=%10.4f Sim=%9.4f mCrab '
617 ' Sens=%e erg/cm2/s' %
618 (ts, crab_flux*1000.0, sensitivity))
619 self._log_value(gammalib.TERSE,
'Converged result', value)
620 self._log_value(gammalib.TERSE,
'Converged flux ratio', ratio)
621 self._log_value(gammalib.TERSE,
'Regression coefficient',
627 if edisp_orig
and not self[
'edisp'].boolean():
633 self._log_value(gammalib.TERSE,
'Converged result',
634 'Now use energy dispersion after '
635 'initial convergence without it')
643 self._log_value(gammalib.TERSE,
'Not converged',
'Flux is zero')
647 test_crab_flux = crab_flux
650 if (iterations >= max_iter):
651 self._log_string(gammalib.TERSE,
652 ' Test ended after %d iterations.' % max_iter)
657 self._log_header3(gammalib.TERSE,
'Iterations for source counts cuts')
660 self[
'edisp'] = edisp_orig
664 for iterations
in range(max_iter):
670 n_bck_evts=n_bck_evts)
673 name =
'Iteration %d' % iterations
674 value =
'Fit=%9.4f mCrab Sens=%e erg/cm2/s' % (crab_flux*1000.0, sensitivity)
675 self._log_value(gammalib.TERSE, name, value)
682 correct = 1.0 + ratio_precision
683 crab_flux = correct * crab_flux
684 photon_flux = correct * photon_flux
685 energy_flux = correct * energy_flux
686 sensitivity = correct * sensitivity
692 self._log_header3(gammalib.TERSE,
'Fit results')
693 self._log_value(gammalib.TERSE,
'Photon flux',
694 str(photon_flux)+
' ph/cm2/s')
695 self._log_value(gammalib.TERSE,
'Energy flux',
696 str(energy_flux)+
' erg/cm2/s')
697 self._log_value(gammalib.TERSE,
'Crab flux',
698 str(crab_flux*1000.0)+
' mCrab')
699 self._log_value(gammalib.TERSE,
'Differential sensitivity',
700 str(sensitivity)+
' erg/cm2/s')
701 self._log_value(gammalib.TERSE,
'Number of simulated events', nevents)
702 self._log_header3(gammalib.TERSE,
'Test source model fitting')
703 self._log_value(gammalib.TERSE,
'log likelihood', logL)
704 self._log_value(gammalib.TERSE,
'Number of predicted events', npred)
706 self._log_value(gammalib.TERSE,
'Model', model.name())
708 self._log_string(gammalib.TERSE, str(par))
711 for i, obs
in enumerate(self.obs()):
715 result = {
'loge': loge,
'emin': emin.TeV(),
'emax': emax.TeV(), \
716 'crab_flux': crab_flux,
'photon_flux': photon_flux, \
717 'energy_flux': energy_flux, \
718 'sensitivity': sensitivity,
'regcoeff': regcoeff, \
719 'nevents': nevents,
'npred': npred}
843 Return the number of excess events for the source model, compared
849 Number of bins for the observation simulation
851 Bin size for the observation simulation
853 Pixel size for the observation simulation
855 Number of background counts from previous call
860 Signals that the source passes the minimal excess criteria
862 Number of background counts
869 mincounts = self[
'mincounts'].integer()
870 bkgexcess = self[
'bkgexcess'].real()
871 bkgrad = self[
'bkgrad'].real()
874 if mincounts > 0
or bkgexcess > 0.0:
877 models = self.obs().models()
878 src_model = gammalib.GModels()
879 bck_models = gammalib.GModels()
882 src_model.append(model)
884 bck_models.append(model)
887 src_obs = self.obs().copy()
888 bck_obs = self.obs().copy()
889 src_obs.models(src_model)
890 bck_obs.models(bck_models)
898 if bkgexcess > 0.0
and n_bck_evts ==
None:
902 min_bkg_events = n_bck_evts * bkgexcess
903 has_min_evts = n_src_evts >= mincounts
904 is_above_bck = n_src_evts >= min_bkg_events
905 pass_evt_cut = has_min_evts
and is_above_bck
908 self._log_value(gammalib.EXPLICIT,
'Pass minimum counts cut', has_min_evts)
909 self._log_value(gammalib.EXPLICIT,
'Pass background cut', is_above_bck)
910 self._log_value(gammalib.EXPLICIT,
'Pass event cut', pass_evt_cut)
911 self._log_value(gammalib.EXPLICIT,
'Minimum counts threshold', mincounts)
912 self._log_value(gammalib.EXPLICIT,
'Background threshold', min_bkg_events)
913 self._log_value(gammalib.EXPLICIT,
'Source events', n_src_evts)
914 self._log_value(gammalib.EXPLICIT,
'Background events', n_bck_evts)
917 return pass_evt_cut, n_bck_evts