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,7 +536,9 @@ void GCTAOnOffObservation::write(GXmlElement& xml) const
536 * @exception GException::invalid_value 536 * @exception GException::invalid_value
537 * No CTA event list found in CTA observation. 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 void GCTAOnOffObservation::fill(const GCTAObservation& obs) 543 void GCTAOnOffObservation::fill(const GCTAObservation& obs)
542 { 544 {
@@ -1027,14 +1029,20 @@ void GCTAOnOffObservation::free_members(void) @@ -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 * @param[in] obs CTA observation. 1034 * @param[in] obs CTA observation.
1033 * 1035 *
1034 * @exception GException::invalid_value 1036 * @exception GException::invalid_value
1035 * No CTA response found in CTA observation. 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 void GCTAOnOffObservation::compute_alpha(const GCTAObservation& obs) 1047 void GCTAOnOffObservation::compute_alpha(const GCTAObservation& obs)
1040 { 1048 {
@@ -1044,7 +1052,7 @@ void GCTAOnOffObservation::compute_alpha(const GCTAObservation& obs) @@ -1044,7 +1052,7 @@ void GCTAOnOffObservation::compute_alpha(const GCTAObservation& obs)
1044 // Continue only if there are spectral bins 1052 // Continue only if there are spectral bins
1045 int nreco = ereco.size(); 1053 int nreco = ereco.size();
1046 if (nreco > 0) { 1054 if (nreco > 0) {
1047 - 1055 +
1048 // Initialise On/Off exposure ratios 1056 // Initialise On/Off exposure ratios
1049 m_alpha.assign(nreco, 0.0); 1057 m_alpha.assign(nreco, 0.0);
1050 1058
@@ -1061,8 +1069,6 @@ void GCTAOnOffObservation::compute_alpha(const GCTAObservation& obs) @@ -1061,8 +1069,6 @@ void GCTAOnOffObservation::compute_alpha(const GCTAObservation& obs)
1061 // Get CTA observation pointing direction, zenith, and azimuth 1069 // Get CTA observation pointing direction, zenith, and azimuth
1062 GCTAPointing obspnt = obs.pointing(); 1070 GCTAPointing obspnt = obs.pointing();
1063 GSkyDir obsdir = obspnt.dir(); 1071 GSkyDir obsdir = obspnt.dir();
1064 - double zenith = obspnt.zenith();  
1065 - double azimuth = obspnt.azimuth();  
1066 1072
1067 // Loop over reconstructed energies 1073 // Loop over reconstructed energies
1068 for (int i = 0; i < nreco; ++i) { 1074 for (int i = 0; i < nreco; ++i) {
@@ -1071,8 +1077,8 @@ void GCTAOnOffObservation::compute_alpha(const GCTAObservation&amp; obs) @@ -1071,8 +1077,8 @@ void GCTAOnOffObservation::compute_alpha(const GCTAObservation&amp; obs)
1071 double logEreco = ereco.elogmean(i).log10TeV(); 1077 double logEreco = ereco.elogmean(i).log10TeV();
1072 1078
1073 // Initialise effective area totals 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 // Loop over ON sky regions 1083 // Loop over ON sky regions
1078 for (int m = 0; m < m_on_regions.size(); ++m) { 1084 for (int m = 0; m < m_on_regions.size(); ++m) {
@@ -1085,18 +1091,14 @@ void GCTAOnOffObservation::compute_alpha(const GCTAObservation&amp; obs) @@ -1085,18 +1091,14 @@ void GCTAOnOffObservation::compute_alpha(const GCTAObservation&amp; obs)
1085 // Get centre of circular region 1091 // Get centre of circular region
1086 GSkyDir centreg = skyreg->centre(); 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 } // endif: sky region is of type GSkyRegionCircle 1103 } // endif: sky region is of type GSkyRegionCircle
1102 1104
@@ -1113,18 +1115,14 @@ void GCTAOnOffObservation::compute_alpha(const GCTAObservation&amp; obs) @@ -1113,18 +1115,14 @@ void GCTAOnOffObservation::compute_alpha(const GCTAObservation&amp; obs)
1113 // Get centre of circular region 1115 // Get centre of circular region
1114 GSkyDir centreg = skyreg->centre(); 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 } // endif: sky region is of type GSkyRegionCircle 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,7 +252,7 @@ class Test(gammalib.GPythonTestSuite):
252 crab = gammalib.GSkyDir() 252 crab = gammalib.GSkyDir()
253 crab.radec_deg(83.6331, 22.0145) 253 crab.radec_deg(83.6331, 22.0145)
254 on = gammalib.GSkyRegions() 254 on = gammalib.GSkyRegions()
255 - on.append(gammalib.GSkyRegionCircle(crab, 0.5)) 255 + on.append(gammalib.GSkyRegionCircle(crab, 0.2))
256 256
257 # Create Off region 257 # Create Off region
258 crab.radec_deg(83.6331, 23.5145) 258 crab.radec_deg(83.6331, 23.5145)
@@ -291,21 +291,21 @@ class Test(gammalib.GPythonTestSuite): @@ -291,21 +291,21 @@ class Test(gammalib.GPythonTestSuite):
291 # Test On/Off model fitting results 291 # Test On/Off model fitting results
292 sky = outobs.models()['Crab'] 292 sky = outobs.models()['Crab']
293 bgd = outobs.models()['Background'] 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 'Check sky model prefactor value') 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 'Check sky model prefactor error') 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 'Check sky model index value') 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 'Check sky model index error') 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 'Check background model prefactor value') 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 'Check background model prefactor error') 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 'Check background model index value') 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 'Check background model index error') 309 'Check background model index error')
310 310
311 # Save PHA, ARF and RMFs 311 # Save PHA, ARF and RMFs