Commit df53f488232c9d156bd6ba97e3e6e6e999ca6d0c

Authored by Jürgen Knödlseder
1 parent fb713040

Correct computation of alpha in On/Off observations.

inst/cta/src/GCTAOnOffObservation.cpp
... ... @@ -536,7 +536,9 @@ void GCTAOnOffObservation::write(GXmlElement& xml) const
536 536 * @exception GException::invalid_value
537 537 * No CTA event list found in CTA observation.
538 538 *
539   - * @todo Set the PHA spectra to zero before filling.
  539 + * Fills events from an observation into the On and Off spectra and cumulates
  540 + * their livetime. This method adds to any existing content in the On and
  541 + * Off spectra.
540 542 ***************************************************************************/
541 543 void GCTAOnOffObservation::fill(const GCTAObservation& obs)
542 544 {
... ... @@ -1027,14 +1029,20 @@ void GCTAOnOffObservation::free_members(void)
1027 1029  
1028 1030  
1029 1031 /***********************************************************************//**
1030   - * @brief Compute alpha parameter (ratio of On to Off effective areas)
  1032 + * @brief Compute vector of alpha parameters
1031 1033 *
1032 1034 * @param[in] obs CTA observation.
1033 1035 *
1034 1036 * @exception GException::invalid_value
1035 1037 * No CTA response found in CTA observation.
1036 1038 *
1037   - * @todo What about the livetime? What about the solid angle of the regions?
  1039 + * Compute the alpha parameters for all energy bins. The alpha parameter
  1040 + * gives the ratio between the On and Off region background acceptance
  1041 + * multiplied by the ratio between On and Off region solid angles.
  1042 + *
  1043 + * @todo Implement for general sky regions, not only circles
  1044 + * @todo Integrate over the sky region instead of taking the values at the
  1045 + * sky region centre
1038 1046 ***************************************************************************/
1039 1047 void GCTAOnOffObservation::compute_alpha(const GCTAObservation& obs)
1040 1048 {
... ... @@ -1044,7 +1052,7 @@ void GCTAOnOffObservation::compute_alpha(const GCTAObservation& obs)
1044 1052 // Continue only if there are spectral bins
1045 1053 int nreco = ereco.size();
1046 1054 if (nreco > 0) {
1047   -
  1055 +
1048 1056 // Initialise On/Off exposure ratios
1049 1057 m_alpha.assign(nreco, 0.0);
1050 1058  
... ... @@ -1061,8 +1069,6 @@ void GCTAOnOffObservation::compute_alpha(const GCTAObservation& obs)
1061 1069 // Get CTA observation pointing direction, zenith, and azimuth
1062 1070 GCTAPointing obspnt = obs.pointing();
1063 1071 GSkyDir obsdir = obspnt.dir();
1064   - double zenith = obspnt.zenith();
1065   - double azimuth = obspnt.azimuth();
1066 1072  
1067 1073 // Loop over reconstructed energies
1068 1074 for (int i = 0; i < nreco; ++i) {
... ... @@ -1071,8 +1077,8 @@ void GCTAOnOffObservation::compute_alpha(const GCTAObservation&amp; obs)
1071 1077 double logEreco = ereco.elogmean(i).log10TeV();
1072 1078  
1073 1079 // Initialise effective area totals
1074   - double aon = 0.0;
1075   - double aoff = 0.0;
  1080 + double aon(0.0);
  1081 + double aoff(0.0);
1076 1082  
1077 1083 // Loop over ON sky regions
1078 1084 for (int m = 0; m < m_on_regions.size(); ++m) {
... ... @@ -1085,18 +1091,14 @@ void GCTAOnOffObservation::compute_alpha(const GCTAObservation&amp; obs)
1085 1091 // Get centre of circular region
1086 1092 GSkyDir centreg = skyreg->centre();
1087 1093  
1088   - // Compute position of region centre in instrument
1089   - // coordinates (should be replaced by proper method to
1090   - // yield theta and phi)
1091   - double theta = obsdir.dist(centreg);
1092   - double phi = obsdir.posang(centreg);
1093   -
1094   - // Add up effective area
1095   - aon += response->aeff(theta,
1096   - phi,
1097   - zenith,
1098   - azimuth,
1099   - logEreco);
  1094 + // Compute instrument direction from region centre
  1095 + GCTAInstDir instdir(obspnt.instdir(centreg));
  1096 +
  1097 + // Add up acceptance
  1098 + aon += (*response->background())(logEreco,
  1099 + instdir.detx(),
  1100 + instdir.dety()) *
  1101 + skyreg->solidangle();
1100 1102  
1101 1103 } // endif: sky region is of type GSkyRegionCircle
1102 1104  
... ... @@ -1113,18 +1115,14 @@ void GCTAOnOffObservation::compute_alpha(const GCTAObservation&amp; obs)
1113 1115 // Get centre of circular region
1114 1116 GSkyDir centreg = skyreg->centre();
1115 1117  
1116   - // Compute position of region centre in instrument
1117   - // coordinates (should be replaced by proper method to
1118   - // yield theta and phi)
1119   - double theta = obsdir.dist(centreg);
1120   - double phi = obsdir.posang(centreg);
1121   -
1122   - // Add up effective area
1123   - aoff += response->aeff(theta,
1124   - phi,
1125   - zenith,
1126   - azimuth,
1127   - logEreco);
  1118 + // Compute instrument direction from region centre
  1119 + GCTAInstDir instdir(obspnt.instdir(centreg));
  1120 +
  1121 + // Add up acceptance
  1122 + aoff += (*response->background())(logEreco,
  1123 + instdir.detx(),
  1124 + instdir.dety()) *
  1125 + skyreg->solidangle();
1128 1126  
1129 1127 } // endif: sky region is of type GSkyRegionCircle
1130 1128  
... ...
inst/cta/test/test_CTA.py
... ... @@ -252,7 +252,7 @@ class Test(gammalib.GPythonTestSuite):
252 252 crab = gammalib.GSkyDir()
253 253 crab.radec_deg(83.6331, 22.0145)
254 254 on = gammalib.GSkyRegions()
255   - on.append(gammalib.GSkyRegionCircle(crab, 0.5))
  255 + on.append(gammalib.GSkyRegionCircle(crab, 0.2))
256 256  
257 257 # Create Off region
258 258 crab.radec_deg(83.6331, 23.5145)
... ... @@ -291,21 +291,21 @@ class Test(gammalib.GPythonTestSuite):
291 291 # Test On/Off model fitting results
292 292 sky = outobs.models()['Crab']
293 293 bgd = outobs.models()['Background']
294   - self.test_value(sky['Prefactor'].value(), 6.15281e-16, 1.0e-20,
  294 + self.test_value(sky['Prefactor'].value(), 5.95777e-16, 1.0e-20,
295 295 'Check sky model prefactor value')
296   - self.test_value(sky['Prefactor'].error(), 2.35727e-17, 1.0e-20,
  296 + self.test_value(sky['Prefactor'].error(), 2.02034e-17, 1.0e-20,
297 297 'Check sky model prefactor error')
298   - self.test_value(sky['Index'].value(), -2.51599, 1.0e-4,
  298 + self.test_value(sky['Index'].value(), -2.50932, 1.0e-4,
299 299 'Check sky model index value')
300   - self.test_value(sky['Index'].error(), 0.037628, 1.0e-4,
  300 + self.test_value(sky['Index'].error(), 0.0304839, 1.0e-4,
301 301 'Check sky model index error')
302   - self.test_value(bgd['Prefactor'].value(), 1.04038, 1.0e-4,
  302 + self.test_value(bgd['Prefactor'].value(), 1.09509, 1.0e-4,
303 303 'Check background model prefactor value')
304   - self.test_value(bgd['Prefactor'].error(), 0.130852, 1.0e-4,
  304 + self.test_value(bgd['Prefactor'].error(), 0.140468, 1.0e-4,
305 305 'Check background model prefactor error')
306   - self.test_value(bgd['Index'].value(), 0.539376, 1.0e-4,
  306 + self.test_value(bgd['Index'].value(), 0.54909, 1.0e-4,
307 307 'Check background model index value')
308   - self.test_value(bgd['Index'].error(), 0.0855112, 1.0e-4,
  308 + self.test_value(bgd['Index'].error(), 0.0872644, 1.0e-4,
309 309 'Check background model index error')
310 310  
311 311 # Save PHA, ARF and RMFs
... ...