Commit 955940f1ca82363890ca1052dea055ff17021612

Authored by Jürgen Knödlseder
1 parent e8f4b286

Refactor code, change names of new parameters and adapt code to coding conventions (#3668)

cscripts/cssens.par
... ... @@ -28,23 +28,23 @@ outfile, f, a, sensitivity.fits,,, "Output sensitivity FITS file"
28 28 #
29 29 # Script parameters
30 30 #==================
31   -offset, r, h, 0.0,,, "Source offset angle (deg)"
32   -duration, r, a, 180000.0,,, "Effective exposure time (s)"
33   -rad, r, a, 5.0,,, "Radius of ROI (deg)"
34   -emin, r, a, 0.03163,,, "Lower energy limit (TeV)"
35   -emax, r, a, 125.8925,,, "Upper energy limit (TeV)"
36   -bins, i, a, 18,,, "Number of energy bins for sensitivity computation"
37   -enumbins, i, h, 0,,, "Number of energy bins for binned analysis (0=unbinned)"
38   -npix, i, h, 200,,, "Number of pixels for binned analysis"
39   -binsz, r, h, 0.05,,, "Pixel size for binned analysis (deg/pixel)"
40   -type, s, h, Differential,Differential|Integral,, "Sensitivity type"
41   -sigma, r, h, 5.0,,, "Significance threshold (Gaussian sigma)"
42   -max_iter, i, h, 50,,, "Maximum number of iterations"
43   -statistic, s, h, DEFAULT,DEFAULT|CSTAT|WSTAT|CHI2,, "Optimization statistic"
44   -min_src_events, i, h, -1,,, "minimal number of source counts"
45   -non_source_uncert_frac, r, h, -1,,, "fraction of no-source counts serving as minimal threshold for source counts"
46   -non_source_uncert_rad, r, h, 0.33,,, "radius for circular region in which to integrate no-source counts for threshold"
47   -seed, i, h, 0,,, "optional seed parameter for generating events"
  31 +offset, r, h, 0.0,,, "Source offset angle (deg)"
  32 +duration, r, a, 180000.0,,, "Effective exposure time (s)"
  33 +rad, r, a, 5.0,,, "Radius of ROI (deg)"
  34 +emin, r, a, 0.03163,,, "Lower energy limit (TeV)"
  35 +emax, r, a, 125.8925,,, "Upper energy limit (TeV)"
  36 +bins, i, a, 18,,, "Number of energy bins for sensitivity computation"
  37 +enumbins, i, h, 0,,, "Number of energy bins for binned analysis (0=unbinned)"
  38 +npix, i, h, 200,,, "Number of pixels for binned analysis"
  39 +binsz, r, h, 0.05,,, "Pixel size for binned analysis (deg/pixel)"
  40 +type, s, h, Differential,Differential|Integral,, "Sensitivity type"
  41 +sigma, r, h, 5.0,,, "Significance threshold (Gaussian sigma)"
  42 +max_iter, i, h, 50,,, "Maximum number of iterations"
  43 +statistic, s, h, DEFAULT,DEFAULT|CSTAT|WSTAT|CHI2,, "Optimization statistic"
  44 +mincounts, i, h, 0,,, "Minimal number of source counts"
  45 +bkgcut, r, h, 0.0,,, "Background uncertainty fraction"
  46 +bkgrad, r, h, 0.33,,, "Background radius (deg)"
  47 +seed, i, h, 1,,, "Initial random number generator seed"
48 48  
49 49 #
50 50 # Standard parameters
... ...
cscripts/cssens.py
... ... @@ -20,7 +20,6 @@
20 20 # ==========================================================================
21 21 import sys
22 22 import math
23   -import statistics
24 23 import gammalib
25 24 import ctools
26 25 from cscripts import obsutils
... ... @@ -61,6 +60,7 @@ class cssens(ctools.csobservation):
61 60 self._dec = None
62 61 self._log_clients = False
63 62 self._models = gammalib.GModels()
  63 + self._seed = 1
64 64 self._nthreads = 0
65 65  
66 66 # Return
... ... @@ -86,6 +86,7 @@ class cssens(ctools.csobservation):
86 86 'dec' : self._dec,
87 87 'log_clients' : self._log_clients,
88 88 'models' : self._models,
  89 + 'seed' : self._seed,
89 90 'nthreads' : self._nthreads}
90 91  
91 92 # Return pickled dictionary
... ... @@ -109,6 +110,7 @@ class cssens(ctools.csobservation):
109 110 self._dec = state['dec']
110 111 self._log_clients = state['log_clients']
111 112 self._models = state['models']
  113 + self._seed = state['seed']
112 114 self._nthreads = state['nthreads']
113 115  
114 116 # Return
... ... @@ -151,6 +153,10 @@ class cssens(ctools.csobservation):
151 153 self['type'].string()
152 154 self['edisp'].boolean()
153 155 self['debug'].boolean()
  156 + self['mincounts'].integer()
  157 +
  158 + # Read seed
  159 + self._seed = self['seed'].integer()
154 160  
155 161 # Derive some parameters
156 162 self._ebounds = gammalib.GEbounds(bins,
... ... @@ -170,6 +176,41 @@ class cssens(ctools.csobservation):
170 176 # Return
171 177 return
172 178  
  179 + def _median(self, array):
  180 + """
  181 + Compute median value for an array
  182 +
  183 + Parameters
  184 + ----------
  185 + array : list of floats
  186 + Array
  187 +
  188 + Returns
  189 + -------
  190 + median : float
  191 + Median value of array
  192 + """
  193 + # Initialise median
  194 + median = 0.0
  195 +
  196 + # Get number of elements in array
  197 + n = len(array)
  198 +
  199 + # Continue only if there are elements in the array
  200 + if n > 0:
  201 +
  202 + # Sort the array
  203 + wrk_array = sorted(array)
  204 +
  205 + # Get median
  206 + if n % 2 != 0:
  207 + median = wrk_array[int(n/2)]
  208 + else:
  209 + median = (wrk_array[int((n-1)/2)] + wrk_array[int(n/2)]) / 2.0
  210 +
  211 + # Return median
  212 + return median
  213 +
173 214 def _set_source(self):
174 215 """
175 216 Set source name and position
... ... @@ -371,12 +412,12 @@ class cssens(ctools.csobservation):
371 412 npix = 200
372 413 binsz = 0.05
373 414  
374   - # keep track of the original value of edisp
375   - edisp_orig = self['edisp'].boolean()
376   - # set edisp off for the first iterations
  415 + # Keep track of the original value of edisp and switch-off energy
  416 + # dispersion for the first iterations to speed-up the computations
  417 + edisp_orig = self['edisp'].boolean()
377 418 self['edisp'] = False
378 419  
379   - # optional seed parameter for generating events
  420 + # Get seed parameter for generating events
380 421 seed = self['seed'].integer()
381 422  
382 423 # Set flux ratio precision required for convergence to 5%
... ... @@ -431,18 +472,15 @@ class cssens(ctools.csobservation):
431 472  
432 473 # Simulate events for the models. "sim" holds an observation
433 474 # container with observations containing the simulated events.
434   - sim = obsutils.sim(self.obs(), nbins=enumbins, seed=(iterations + seed),
  475 + sim = obsutils.sim(self.obs(), nbins=enumbins, seed=(iterations+seed),
435 476 binsz=binsz, npix=npix,
436 477 log=self._log_clients,
437 478 debug=self['debug'].boolean(),
438 479 edisp=self['edisp'].boolean(),
439 480 nthreads=1)
440 481  
441   - # Determine number of events in simulation by summing the events
442   - # over all observations in the observation container
443   - nevents = 0.0
444   - for run in sim:
445   - nevents += run.events().number()
  482 + # Determine number of events in simulation
  483 + nevents = sim.nobserved()
446 484  
447 485 # Write simulation results into logger
448 486 self._log_header3(gammalib.EXPLICIT, 'Simulation')
... ... @@ -513,7 +551,7 @@ class cssens(ctools.csobservation):
513 551  
514 552 # Predict Crab flux at threshold TS using a linear regression of
515 553 # the log(TS) and log(crab_flux) values that have so far been
516   - # computed. If not enough results are available than use a simple
  554 + # computed. If not enough results are available then use a simple
517 555 # TS scaling relation.
518 556 correct = math.sqrt(ts_thres / ts)
519 557 if len(results) > 1:
... ... @@ -521,8 +559,9 @@ class cssens(ctools.csobservation):
521 559 pred_crab_flux, regcoeff = self._predict_flux(results, ts_thres)
522 560 correct = pred_crab_flux / crab_flux
523 561 except Exception as e:
524   - # if the regression fails, retain the simple scaling with ts_thres
525   - self._log_value(gammalib.TERSE, 'skipping failed regression with error:', e)
  562 + # If the regression fails, retain the simple scaling with
  563 + # ts_thres
  564 + self._log_value(gammalib.TERSE, 'Skipping failed regression', e)
526 565  
527 566 # Compute extrapolated fluxes based on the flux correction factor
528 567 crab_flux = correct * crab_flux
... ... @@ -551,17 +590,24 @@ class cssens(ctools.csobservation):
551 590 self._log_value(gammalib.TERSE, 'Regression coefficient',
552 591 regcoeff)
553 592  
554   - # if the flux has converged, check if the original value of
555   - # edisp was set, and is not what has fo far been used
  593 + # If the flux has converged then check if the original
  594 + # value of edisp was set, and is not what has fo far
  595 + # been used
556 596 if edisp_orig and not self['edisp'].boolean():
557   - # set edisp on and continue the calculation
  597 +
  598 + # Set edisp on and continue the calculation
558 599 self['edisp'] = True
559 600  
560   - value = 'set edisp on after initial convergence withouth it'
561   - self._log_value(gammalib.TERSE, 'Converged result', value)
  601 + # Log action
  602 + self._log_value(gammalib.TERSE, 'Converged result',
  603 + 'Now use energy dispersion after '
  604 + 'initial convergence without it')
  605 +
  606 + # ... otherwise finish the calculation after convergence
562 607 else:
563   - # finish the calculation after convergence
564 608 break
  609 +
  610 + # ... otherwise break with a zero flux
565 611 else:
566 612 self._log_value(gammalib.TERSE, 'Not converged', 'Flux is zero')
567 613 break
... ... @@ -575,35 +621,42 @@ class cssens(ctools.csobservation):
575 621 ' Test ended after %d iterations.' % max_iter)
576 622 break
577 623  
578   - # make sure edisp is set correctly before the count cuts
579   - if edisp_orig and not self['edisp'].boolean():
580   - self['edisp'] = True
  624 + # Write header for iterations for terse chatter level
  625 + if self._logTerse():
  626 + self._log_header3(gammalib.TERSE, 'Iterations for source counts cuts')
  627 +
  628 + # Recover original energy dispersion setting
  629 + self['edisp'] = edisp_orig
581 630  
  631 + # Take into account the excess event cuts
582 632 n_bck_evts = None
583 633 for iterations in range(max_iter):
584   - pass_evt_cut, n_bck_evts = self._sim_evt_excess(
585   - enumbins=enumbins,
586   - binsz=binsz,
587   - npix=npix,
588   - n_bck_evts=n_bck_evts,
589   - )
  634 +
  635 + # Simulate event excess
  636 + pass_evt_cut, n_bck_evts = self._sim_evt_excess(enumbins=enumbins,
  637 + binsz=binsz,
  638 + npix=npix,
  639 + n_bck_evts=n_bck_evts)
  640 +
  641 + # Write results into logger
  642 + name = 'Iteration %d' % iterations
  643 + value = 'Fit=%9.4f mCrab Sens=%e erg/cm2/s' % (crab_flux*1000.0, sensitivity)
  644 + self._log_value(gammalib.TERSE, name, value)
  645 +
  646 + # If event excess cuts are passed then break now
590 647 if pass_evt_cut:
591 648 break
592 649  
593   - # increase the test flux if the cuts failed
  650 + # ... otherwise increase the test flux
594 651 correct = 1 + ratio_precision
595 652 crab_flux = correct * crab_flux
596 653 photon_flux = correct * photon_flux
597 654 energy_flux = correct * energy_flux
598 655 sensitivity = correct * sensitivity
599 656  
  657 + # ...
600 658 _ = self._set_src_prefactor(test_model, crab_unit, crab_flux)
601 659  
602   - # Write results into logger
603   - name = 'Iteration %d of source count check' % iterations
604   - value = 'Fit=%9.4f mCrab Sens=%e erg/cm2/s' % (crab_flux*1000.0, sensitivity)
605   - self._log_value(gammalib.TERSE, name, value)
606   -
607 660 # Write fit results into logger
608 661 self._log_header3(gammalib.TERSE, 'Fit results')
609 662 self._log_value(gammalib.TERSE, 'Photon flux',
... ... @@ -656,37 +709,111 @@ class cssens(ctools.csobservation):
656 709 crab_prefactor : float
657 710 the prefactor that corresponds to a flux of 1 Crab.
658 711 """
659   -
  712 + # Initialise variables
660 713 models = test_model.copy()
661 714 prefactor = modutils.normalisation_parameter(models[self._srcname])
662 715 crab_prefactor = prefactor.value() * crab_unit
  716 + val_margin = 0.01
  717 + min_pref = prefactor.min() * (1.0 + val_margin)
  718 + max_pref = prefactor.max() * (1.0 - val_margin)
  719 + val_now = crab_prefactor * test_crab_flux
663 720  
664   - val_margin = 0.01
665   - min_pref = prefactor.min() * (1 + val_margin)
666   - max_pref = prefactor.max() * (1 - val_margin)
667   -
668   - val_now = crab_prefactor * test_crab_flux
669   -
  721 + # Check whether prefactor is in valid range
670 722 if val_now < min_pref or val_now > max_pref:
671   - log_name = 'test prefactor beyond limits'
672   - log_value = (
673   - 'test prefactor is too low/high, having value '
674   - + str(val_now) + ' compared to limits: ['
675   - + str(prefactor.min()) + ' , ' + str(prefactor.max()) + ']'
676   - )
677   - self._log_value(gammalib.TERSE, log_name, log_value)
678   -
679   - val_now = max(val_now, min_pref)
680   - val_now = min(val_now, max_pref)
681   -
  723 +
  724 + # Store old prefactor value for logging
  725 + val_old = val_now
  726 +
  727 + # Set new prefactor value
  728 + val_now = max(val_now, min_pref)
  729 + val_now = min(val_now, max_pref)
682 730 crab_prefactor = val_now / test_crab_flux
683 731  
  732 + # Log prefactor modification
  733 + self._log_value(gammalib.EXPLICIT, 'Prefactor range',
  734 + '['+str(min_pref)+','+str(max_pref)+']')
  735 + self._log_value(gammalib.EXPLICIT, 'Initial Prefactor', val_old)
  736 + self._log_value(gammalib.EXPLICIT, 'Updated Prefactor', val_now)
  737 +
  738 + # Store prefactor value
684 739 prefactor.value(val_now)
685 740  
  741 + # Update the models
686 742 self.obs().models(models)
687 743  
  744 + # Return Prefactor
688 745 return crab_prefactor
689 746  
  747 + def _simulate_events(self, obs, rad, seed, enumbins, binsz, npix):
  748 + """
  749 + Simulate events
  750 +
  751 + Parameters
  752 + ----------
  753 + obs : `~gammalib.GObservations`
  754 + Observation container
  755 + rad : float
  756 + Simulation selection radius (degrees)
  757 + seed : integer
  758 + Random number generator seed
  759 + enumbins : integer
  760 + Number of energy bins
  761 + binsz : float
  762 + Pixel size
  763 + npix : integer
  764 + Number of pixels
  765 + """
  766 + # Initialise list of number of simulated events
  767 + n_sim_evts = []
  768 +
  769 + # Simulate events
  770 + for n_sim in range(15):
  771 +
  772 + # Increment the seed
  773 + seed += n_sim
  774 +
  775 + # Simulate observations
  776 + sim = obsutils.sim(obs,
  777 + nbins=enumbins,
  778 + seed=seed,
  779 + binsz=binsz,
  780 + npix=npix,
  781 + log=self._log_clients,
  782 + debug=self['debug'].boolean(),
  783 + edisp=self['edisp'].boolean(),
  784 + nthreads=1)
  785 +
  786 + # If a selection radius is given then select only the events within
  787 + # that selection radius
  788 + if rad > 0.0:
  789 +
  790 + # Run event selection tool
  791 + select = ctools.ctselect(sim)
  792 + select['rad'] = rad
  793 + select['emin'] = 'INDEF'
  794 + select['tmin'] = 'INDEF'
  795 + select.run()
  796 +
  797 + # Store number of events
  798 + n_sim_evts.append(select.obs().nobserved())
  799 +
  800 + # ... otherwise we simply store the number of simulated events
  801 + else:
  802 + n_sim_evts.append(sim.nobserved())
  803 +
  804 + # Determine median number of events
  805 + median = self._median(n_sim_evts)
  806 +
  807 + # Log results
  808 + if rad > 0.0:
  809 + name = 'Median source events'
  810 + else:
  811 + name = 'Median background events'
  812 + self._log_value(gammalib.EXPLICIT, name, median)
  813 +
  814 + # Return
  815 + return median
  816 +
690 817 def _sim_evt_excess(self, enumbins, binsz, npix, n_bck_evts):
691 818 """
692 819 Return the number of excess events for the source model, compared
... ... @@ -695,134 +822,77 @@ class cssens(ctools.csobservation):
695 822 Parameters
696 823 ----------
697 824 enumbins : int
698   - number of bins for the observation simulation
  825 + Number of bins for the observation simulation
699 826 binsz : float
700   - bin size for the observation simulation
  827 + Bin size for the observation simulation
701 828 npix : int
702   - pixel size for the observation simulation
  829 + Pixel size for the observation simulation
703 830 n_bck_evts : int
704   - number of non-source counts (given to avoid computing the same quantity multiple times)
  831 + Number of background counts from previous call
705 832  
706 833 Returns
707 834 -------
708 835 pass_evt_cut : bool
709   - does the source pass the minimal excess criteria
  836 + Signals that the source passes the minimal excess criteria
710 837 n_bck_evts : int
711   - number of non-source counts
  838 + Number of background counts
712 839 """
713   -
714   - # number of times to simulate the observation
715   - n_sims = 15
716   -
717   - # radius of integration for hte non-source background (not necessarily the
718   - # same as self['rad'], to match the current standard for non-ctools analyses)
719   - rad_deg = self['non_source_uncert_rad'].real()
720   -
721   - # minimal number of events for the source
722   - min_src_events = self['min_src_events'].integer()
723   - # threshold by fraction of non-source counts (5 times the assumed uncertainty
724   - # on the background, which is taken as 1% of the non-source counts)
725   - non_source_uncert_frac = self['non_source_uncert_frac'].real()
726   -
727   - # optional seed parameter for generating events
728   - seed = self['seed'].integer()
729   -
730   - # end here if no cuts have been spesified
731   - if min_src_events <= 0 and non_source_uncert_frac <= 0:
732   - return True
733   -
734   - models = self.obs().models()
735   -
736   - src_model = gammalib.GModels()
737   - bck_models = gammalib.GModels()
738   - for s in range(models.size()):
739   - model = models[s]
740   - if model.name() == self._srcname:
741   - src_model.append(model)
742   - else:
743   - bck_models.append(model)
744   -
745   - src_obs = self.obs().copy()
746   - src_obs.models(src_model)
747   -
748   - bck_obs = self.obs().copy()
749   - bck_obs.models(bck_models)
750   -
751   - n_src_evts = 0
752   - for is_src in [True, False]:
753   - if not is_src:
754   - # if the non-source fraction cut is not applied, no need
755   - # to calculate the background rate.
756   - # n_bck_evts will be None onlu in the firs iteration, where
757   - # we only need to compute the non-source counts once, since the
758   - # models dont change with the itterations.
759   - if non_source_uncert_frac <= 0 or n_bck_evts is not None:
760   - continue
761   -
762   - obs_now = src_obs if is_src else bck_obs
763   -
764   - n_sim_evts = []
765   - for n_sim in range(n_sims):
766   - seed = n_sim + seed
767   -
768   - sim_now = obsutils.sim(
769   - obs_now,
770   - nbins=enumbins,
771   - seed=seed,
772   - binsz=binsz,
773   - npix=npix,
774   - log=self._log_clients,
775   - debug=self['debug'].boolean(),
776   - edisp=self['edisp'].boolean(),
777   - nthreads=1
778   - )
779   -
780   - # consider all events in the entire RoI for the minimal cource count cut
781   - if is_src:
782   - n_sim_evts += [len(sim_now[0].events())]
783   - # consider only background within the thetaSqr cut for the systematic
784   - # check, in accordance with the current CTA convention for Li&Ma calculations
  840 + # Initialise results
  841 + pass_evt_cut = True
  842 + n_bck_evts = 0
  843 +
  844 + # Get user parameters
  845 + mincounts = self['mincounts'].integer()
  846 + bkgcut = self['bkgcut'].real()
  847 + bkgrad = self['bkgrad'].real()
  848 +
  849 + # Continue only if cuts were specified
  850 + if mincounts > 0 or bkgcut > 0.0:
  851 +
  852 + # Get seed parameter for generating events
  853 + seed = self['seed'].integer()
  854 +
  855 + # Get models and split them into source and background
  856 + models = self.obs().models()
  857 + src_model = gammalib.GModels()
  858 + bck_models = gammalib.GModels()
  859 + for model in models:
  860 + if model.name() == self._srcname:
  861 + src_model.append(model)
785 862 else:
786   - select = ctools.ctselect(sim_now)
787   - select['rad'] = rad_deg
788   - select['emin'] = 'INDEF'
789   - select['tmin'] = 'INDEF'
790   - select.run()
791   -
792   - obs = select.obs()
793   - n_sim_evts += [len(obs[0].events())]
794   -
795   - if is_src:
796   - n_src_evts = statistics.median(n_sim_evts)
797   - else:
798   - n_bck_evts = statistics.median(n_sim_evts)
799   -
800   - name = 'number of ' + ('source' if is_src else 'non-source') + ' events'
801   - value = (
802   - ','.join([str(i) for i in n_sim_evts])
803   - + ' --> median is: ' + str(n_src_evts if is_src else n_bck_evts)
804   - )
805   - self._log_value(gammalib.TERSE, name, value)
806   -
807   - if n_bck_evts is None:
808   - n_bck_evts = 0
809   -
810   - has_min_evts = n_src_evts >= min_src_events
811   - is_above_bck = n_src_evts >= n_bck_evts * non_source_uncert_frac
812   - pass_evt_cut = has_min_evts and is_above_bck
813   -
814   - name = 'minimal excess threshold'
815   - value = (
816   - 'has counts above \"min source counts('
817   - + str(min_src_events) + ' events)\": ' + str(has_min_evts)
818   - + ' ; pass background uncertainty threshold('
819   - + str(max(non_source_uncert_frac, 0) * 100) + '% == '
820   - + str(n_bck_evts * non_source_uncert_frac)
821   - + ' events): ' + str(is_above_bck)
822   - + ' --> pass selection: ' + str(pass_evt_cut)
823   - )
824   - self._log_value(gammalib.TERSE, name, value)
825   -
  863 + bck_models.append(model)
  864 +
  865 + # Create observations for source and background
  866 + src_obs = self.obs().copy()
  867 + bck_obs = self.obs().copy()
  868 + src_obs.models(src_model)
  869 + bck_obs.models(bck_models)
  870 +
  871 + # Simulate source events
  872 + n_src_evts = self._simulate_events(src_obs, 0.0, seed, enumbins, binsz, npix)
  873 +
  874 + # Simulate background events in case that a background fraction cut
  875 + # is applied and if the number of background events was not yet
  876 + # estimated
  877 + if bkgcut > 0.0 and n_bck_evts == None:
  878 + n_bck_evts = self._simulate_events(bck_obs, bkgrad, seed, enumbins, binsz, npix)
  879 +
  880 + # Set cut results
  881 + min_bkg_events = n_bck_evts * bkgcut
  882 + has_min_evts = n_src_evts >= mincounts
  883 + is_above_bck = n_src_evts >= min_bkg_events
  884 + pass_evt_cut = has_min_evts and is_above_bck
  885 +
  886 + # Log results
  887 + self._log_value(gammalib.EXPLICIT, 'Pass minimum counts cut', has_min_evts)
  888 + self._log_value(gammalib.EXPLICIT, 'Pass background cut', is_above_bck)
  889 + self._log_value(gammalib.EXPLICIT, 'Pass event cut', pass_evt_cut)
  890 + self._log_value(gammalib.EXPLICIT, 'Minimum counts threshold', mincounts)
  891 + self._log_value(gammalib.EXPLICIT, 'Background threshold', min_bkg_events)
  892 + self._log_value(gammalib.EXPLICIT, 'Source events', n_src_evts)
  893 + self._log_value(gammalib.EXPLICIT, 'Background events', n_bck_evts)
  894 +
  895 + # Return passing flag and number of background events
826 896 return pass_evt_cut, n_bck_evts
827 897  
828 898 def _predict_flux(self, results, ts):
... ... @@ -868,14 +938,13 @@ class cssens(ctools.csobservation):
868 938 mean_xx *= norm
869 939 mean_yy *= norm
870 940  
  941 + # Compute regression coefficient
871 942 rxy_norm = (mean_xx - mean_x * mean_x) * (mean_yy - mean_y * mean_y)
872 943 if rxy_norm < 1e-10:
873 944 rxy_norm = 1
874 945 else:
875 946 rxy_norm = math.sqrt(rxy_norm)
876   -
877   - rxy = (mean_xy - mean_x * mean_y) / rxy_norm
878   -
  947 + rxy = (mean_xy - mean_x * mean_y) / rxy_norm
879 948 regcoeff = rxy*rxy
880 949  
881 950 # Compute regression line slope
... ... @@ -1122,4 +1191,4 @@ if __name__ == &#39;__main__&#39;:
1122 1191 app = cssens(sys.argv)
1123 1192  
1124 1193 # Run application
1125   - app.execute()
1126 1194 \ No newline at end of file
  1195 + app.execute()
... ...