Belle II Software  release-05-02-19
ECLShowerShapeModule.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2016 - Belle II Collaboration *
4  * *
5  * This module calculates shower shape variables. *
6  * *
7  * Author: The Belle II Collaboration *
8  * Contributors: Torben Ferber (ferber@physics.ubc.ca) *
9  * Guglielmo De Nardo (denardo@na.infn.it) *
10  * Alon Hershenhorn (hershen@phas.ubc.ca) *
11  * *
12  * This software is provided "as is" without any warranty. *
13  **************************************************************************/
14 
15 // THIS MODULE
16 #include <ecl/modules/eclShowerShape/ECLShowerShapeModule.h>
17 
18 //BOOST
19 #include <boost/algorithm/string/predicate.hpp>
20 
21 // ROOT
22 #include <TMath.h>
23 
24 // FRAMEWORK
25 #include <framework/datastore/RelationVector.h>
26 #include <framework/logging/Logger.h>
27 #include <framework/geometry/B2Vector3.h>
28 
29 //MVA
30 #include <mva/interface/Expert.h>
31 #include <mva/interface/Weightfile.h>
32 #include <mva/interface/Interface.h>
33 #include <mva/dataobjects/DatabaseRepresentationOfWeightfile.h>
34 
35 // ECL
36 #include <ecl/dataobjects/ECLCalDigit.h>
37 #include <ecl/dataobjects/ECLConnectedRegion.h>
38 #include <ecl/geometry/ECLGeometryPar.h>
39 #include <ecl/dataobjects/ECLShower.h>
40 #include <ecl/geometry/ECLNeighbours.h>
41 #include <ecl/dbobjects/ECLShowerShapeSecondMomentCorrection.h>
42 
43 using namespace Belle2;
44 using namespace ECL;
45 
46 //-----------------------------------------------------------------
47 // Register the Module
48 //-----------------------------------------------------------------
49 REG_MODULE(ECLShowerShape)
50 REG_MODULE(ECLShowerShapePureCsI)
51 
52 //-----------------------------------------------------------------
53 // Implementation
54 //-----------------------------------------------------------------
55 
57  m_eclConnectedRegions(eclConnectedRegionArrayName()),
58  m_secondMomentCorrectionArray("ecl_shower_shape_second_moment_corrections")
59 {
60  // Set description
61  setDescription("ECLShowerShapeModule: Calculate ECL shower shape variables (e.g. E9oE21)");
62  setPropertyFlags(c_ParallelProcessingCertified);
63 
64  addParam("zernike_n1_rho0", m_zernike_n1_rho0,
65  "Scaling factor for radial distances in a plane perpendicular to direction to shower for the n photon hypothesis in Zernike moment calculation.",
66  10.0 * Unit::cm);
67 
68  addParam("zernike_n2_rho0", m_zernike_n2_rho0,
69  "Scaling factor for radial distances in a plane perpendicular to direction to shower for the neutral hadron hypothesis in Zernike moment calculation. ",
70  20.0 * Unit::cm);
71 
72  addParam("zernike_useFarCrystals", m_zernike_useFarCrystals,
73  "Determines if Digits with rho > rho0 are used for the zernike moment calculation. If they are, their radial distance will be set to rho0.",
74  true);
75 
76  addParam("zernike_MVAidentifier_FWD", m_zernike_MVAidentifier_FWD, "The Zernike moment MVA database identifier for forward endcap.",
77  std::string{"ecl_showershape_zernike_mva_fwd"});
78  addParam("zernike_MVAidentifier_BRL", m_zernike_MVAidentifier_BRL, "The Zernike moment MVA database identifier for barrel.",
79  std::string{"ecl_showershape_zernike_mva_brl"});
80  addParam("zernike_MVAidentifier_BWD", m_zernike_MVAidentifier_BWD,
81  "The Zernike moment MVA database identifier for backward endcap.", std::string{"ecl_showershape_zernike_mva_bwd"});
82 
83  addParam("avgCrystalDimension", m_avgCrystalDimension,
84  "Average crystal dimension used in lateral energy calculation.",
85  5.0 * Unit::cm);
86 
87 }
88 
90 {
91 }
92 
93 void ECLShowerShapeModule::initializeMVAweightFiles(const std::string& identifier,
94  std::unique_ptr<DBObjPtr<DatabaseRepresentationOfWeightfile>>& weightFileRepresentation)
95 {
96  if (not(boost::ends_with(identifier, ".root") or boost::ends_with(identifier, ".xml"))) {
97  weightFileRepresentation = std::unique_ptr<DBObjPtr<DatabaseRepresentationOfWeightfile>>(new
99  }
101 }
102 
104 {
105 
106  // Initialize neighbour maps.
107  m_neighbourMap9 = std::unique_ptr<ECL::ECLNeighbours>(new ECL::ECLNeighbours("N", 1));
108  m_neighbourMap21 = std::unique_ptr<ECL::ECLNeighbours>(new ECL::ECLNeighbours("NC", 2));
109 
110  initializeMVAweightFiles(m_zernike_MVAidentifier_FWD, m_weightfile_representation_FWD);
111  initializeMVAweightFiles(m_zernike_MVAidentifier_BRL, m_weightfile_representation_BRL);
112  initializeMVAweightFiles(m_zernike_MVAidentifier_BWD, m_weightfile_representation_BWD);
113 
114 
115  //Add callback to fill m_secondMomentCorrections when m_secondMomentCorrectionArray changes
116  //21-Oct-2016 - The callback doesn't seem to be called at the begining of the run so I commented it out and added a call to prepareSecondMomentCorrectionsCallback in the beginRun
117 // m_secondMomentCorrectionArray.addCallback(this, &ECLShowerShapeModule::prepareSecondMomentCorrectionsCallback);
118 // prepareSecondMomentCorrectionsCallback();
119 
120 }
121 
122 void ECLShowerShapeModule::initializeMVA(const std::string& identifier,
123  std::unique_ptr<DBObjPtr<DatabaseRepresentationOfWeightfile>>& weightFileRepresentation, std::unique_ptr<MVA::Expert>& expert)
124 {
125  MVA::Weightfile weightfile;
126  //Load MVA weight file
127  if (weightFileRepresentation) {
128 
129  //If multiple sources of conditions DB have been configured (the regular case), then the IOV of each payload will be "artificially" set to the current run only.
130  //This is so that in the next run, the payload can be taken from a different DB source.
131  //For example, payload of current run will be taken from central DB and payload of next run will be taken from local DB, if it appears there.
132  //In this case weightFileRepresentation->hasChanged() will be true at the beginning of each run, even though the IOV of the payload is greater than a single run.
133  //This is true as of 2017-06-01, functionality of hasChanged() might be changed in future.
134 
135  if (weightFileRepresentation->hasChanged()) {
136  std::stringstream ss((*weightFileRepresentation)->m_data);
137  weightfile = MVA::Weightfile::loadFromStream(ss);
138  } else
139  return;
140  } else {
141  weightfile = MVA::Weightfile::loadFromFile(identifier);
142  }
143 
144  auto supported_interfaces = MVA::AbstractInterface::getSupportedInterfaces();
145  MVA::GeneralOptions general_options;
146  weightfile.getOptions(general_options);
147 
148  //Check number of variables in weight file
149  if (m_numZernikeMVAvariables != general_options.m_variables.size())
150  B2FATAL("Expecting " << m_numZernikeMVAvariables << " varibales, found " << general_options.m_variables.size());
151 
152  expert = supported_interfaces[general_options.m_method]->getExpert();
153  expert->load(weightfile);
154 
155  //create new dataset, if this is the barrel MVA (assumes FWD and BWD datasets are same size)
156  if (weightFileRepresentation == m_weightfile_representation_BRL) {
157  std::vector<float> dummy(general_options.m_variables.size(), 0);
158  m_dataset = std::unique_ptr<MVA::SingleDataset>(new MVA::SingleDataset(general_options, dummy, 0));
159  }
160 }
161 
163 {
164  initializeMVA(m_zernike_MVAidentifier_FWD, m_weightfile_representation_FWD, m_expert_FWD);
165  initializeMVA(m_zernike_MVAidentifier_BRL, m_weightfile_representation_BRL, m_expert_BRL);
166  initializeMVA(m_zernike_MVAidentifier_BWD, m_weightfile_representation_BWD, m_expert_BWD);
167 
168  //This is a hack because the callback doesn't seem to be called at the begining of the run
169  if (m_secondMomentCorrectionArray.hasChanged()) {
170  if (m_secondMomentCorrectionArray) prepareSecondMomentCorrectionsCallback();
171  else B2ERROR("ECLShowerShapeModule::beginRun - Couldn't find second moment correction for current run");
172  }
173 }
174 
175 
176 void ECLShowerShapeModule::setShowerShapeVariables(ECLShower* eclShower, const bool calculateZernikeMVA) const
177 {
178  //Project the digits on the plane perpendicular to the shower direction
179  std::vector<ProjectedECLDigit> projectedECLDigits = projectECLDigits(*eclShower);
180 
181  const double showerEnergy = eclShower->getEnergy();
182  const double showerTheta = eclShower->getTheta();
183  const double showerPhi = eclShower->getPhi();
184 
185  //sum crystal energies
186  double sumEnergies = 0.0;
187  for (const auto& projectedECLDigit : projectedECLDigits) sumEnergies += projectedECLDigit.energy;
188 
189  //Choose rho0 according to shower hypothesis
190  double rho0 = 0.0;
191  const int hypothesisID = eclShower->getHypothesisId();
192  if (hypothesisID == ECLShower::c_nPhotons) rho0 = m_zernike_n1_rho0;
193  else if (hypothesisID == ECLShower::c_neutralHadron) rho0 = m_zernike_n2_rho0;
194 
195  const double absZernike40 = computeAbsZernikeMoment(projectedECLDigits, sumEnergies, 4, 0, rho0);
196  const double absZernike51 = computeAbsZernikeMoment(projectedECLDigits, sumEnergies, 5, 1, rho0);
197 
198  const double secondMomentCorrection = getSecondMomentCorrection(showerTheta, showerPhi, hypothesisID);
199  B2DEBUG(175, "Second moment angular correction: " << secondMomentCorrection << " (theta(rad)=" << showerTheta << ", phi(rad)=" <<
200  showerPhi << ",hypothesisId=" << hypothesisID <<
201  ")");
202  const double secondMoment = computeSecondMoment(projectedECLDigits, showerEnergy) * secondMomentCorrection;
203  B2DEBUG(175, "Second moment after correction: " << secondMoment);
204 
205  const double LATenergy = computeLateralEnergy(projectedECLDigits, m_avgCrystalDimension);
206 
207  // Set shower shape variables.
208  eclShower->setAbsZernike40(absZernike40);
209  eclShower->setAbsZernike51(absZernike51);
210  eclShower->setSecondMoment(secondMoment);
211  eclShower->setLateralEnergy(LATenergy);
212  eclShower->setE1oE9(computeE1oE9(*eclShower));
213  if (eclShower->getE9oE21() < 1e-9) eclShower->setE9oE21(computeE9oE21(*eclShower));
214 
215  if (calculateZernikeMVA) {
216  //Set Zernike moments that will be used in MVA calculation
217  // m_dataset holds 22 entries, 11 Zernike moments of N2 shower, followed by 11 Zernike moments of N1 shower
218  int indexOffset = 0;//Offset entries depending on hypothesis type
219  if (hypothesisID == ECLShower::c_nPhotons) indexOffset = (m_numZernikeMVAvariables / 2);
220  else if (hypothesisID == ECLShower::c_neutralHadron) indexOffset = 0;
221 
222  m_dataset->m_input[0 + indexOffset] = computeAbsZernikeMoment(projectedECLDigits, sumEnergies, 1, 1, rho0);
223  m_dataset->m_input[1 + indexOffset] = computeAbsZernikeMoment(projectedECLDigits, sumEnergies, 2, 0, rho0);
224  m_dataset->m_input[2 + indexOffset] = computeAbsZernikeMoment(projectedECLDigits, sumEnergies, 2, 2, rho0);
225  m_dataset->m_input[3 + indexOffset] = computeAbsZernikeMoment(projectedECLDigits, sumEnergies, 3, 1, rho0);
226  m_dataset->m_input[4 + indexOffset] = computeAbsZernikeMoment(projectedECLDigits, sumEnergies, 3, 3, rho0);
227  m_dataset->m_input[5 + indexOffset] = absZernike40;
228  m_dataset->m_input[6 + indexOffset] = computeAbsZernikeMoment(projectedECLDigits, sumEnergies, 4, 2, rho0);
229  m_dataset->m_input[7 + indexOffset] = computeAbsZernikeMoment(projectedECLDigits, sumEnergies, 4, 4, rho0);
230  m_dataset->m_input[8 + indexOffset] = absZernike51;
231  m_dataset->m_input[9 + indexOffset] = computeAbsZernikeMoment(projectedECLDigits, sumEnergies, 5, 3, rho0);
232  m_dataset->m_input[10 + indexOffset] = computeAbsZernikeMoment(projectedECLDigits, sumEnergies, 5, 5, rho0);
233  //Set zernikeMVA for N1 showers
234  //This assumes that the N2 zernike moments have already been set in m_dataset!!!!
235  if (hypothesisID == ECLShower::c_nPhotons) {
236  //FWD
237  if (eclShower->getTheta() < m_BRLthetaMin) eclShower->setZernikeMVA(m_expert_FWD->apply(*m_dataset)[0]);
238  //BWD
239  else if (eclShower->getTheta() > m_BRLthetaMax) eclShower->setZernikeMVA(m_expert_BWD->apply(*m_dataset)[0]);
240  //BRL
241  else eclShower->setZernikeMVA(m_expert_BRL->apply(*m_dataset)[0]);
242  }
243  } else eclShower->setZernikeMVA(0.0);
244 }
245 
247 {
248  for (auto& eclCR : m_eclConnectedRegions) {
249 
250  //Start by finding the N2 shower and calculating it's shower shape variables
251  //Assumes that there is only 1 N2 Shower per CR!!!!!!
252  ECLShower* N2shower = nullptr;
253  for (auto& eclShower : eclCR.getRelationsWith<ECLShower>(eclShowerArrayName())) {
254  if (eclShower.getHypothesisId() == ECLShower::c_neutralHadron) {
255  N2shower = &eclShower;
256  setShowerShapeVariables(N2shower, true);
257  break;
258  }
259  }
260 
261  //If couldn't find N2 shower, don't calculate zernikeMVA
262  bool found_N2shower = true;
263  if (N2shower == nullptr) found_N2shower = false;
264 
265  double prodN1zernikeMVAs = 1.0;
266  //Calculate shower shape variables for the rest of the showers
267  for (auto& eclShower : eclCR.getRelationsWith<ECLShower>(eclShowerArrayName())) {
268  if (eclShower.getHypothesisId() == ECLShower::c_neutralHadron)
269  continue; //shower shape variables already calculated for neutral hadrons
270 
271  bool calculateZernikeMVA = true;
272  if (!found_N2shower || eclShower.getHypothesisId() != ECLShower::c_nPhotons) calculateZernikeMVA = false;
273 
274  setShowerShapeVariables(&eclShower, calculateZernikeMVA);
275 
276  if (eclShower.getHypothesisId() == ECLShower::c_nPhotons) prodN1zernikeMVAs *= eclShower.getZernikeMVA();
277  }
278 
279  //Set zernikeMVA for the N2 shower
280  if (N2shower) N2shower->setZernikeMVA(1.0 - prodN1zernikeMVAs);
281  }
282 }
283 
284 std::vector<ECLShowerShapeModule::ProjectedECLDigit> ECLShowerShapeModule::projectECLDigits(const ECLShower& shower) const
285 {
286  std::vector<ProjectedECLDigit> tmpProjectedECLDigits; //Will be returned at the end of the function
287  auto showerDigitRelations = shower.getRelationsTo<ECLCalDigit>(eclCalDigitArrayName());
288 // tmpProjectedECLDigits.resize( showerDigitRelations.size() );
289  //---------------------------------------------------------------------
290  // Get shower parameters.
291  //---------------------------------------------------------------------
292  const double showerR = shower.getR();
293  const double showerTheta = shower.getTheta();
294  const double showerPhi = shower.getPhi();
295 
296  B2Vector3D showerPosition;
297  showerPosition.SetMagThetaPhi(showerR, showerTheta, showerPhi);
298 
299  // Unit vector pointing in shower direction.
300  const B2Vector3D showerDirection = (1.0 / showerPosition.Mag()) * showerPosition;
301 
302  //---------------------------------------------------------------------
303  // Calculate axes that span the perpendicular plane.
304  //---------------------------------------------------------------------
305  //xPrimeDirection = showerdirection.cross(zAxis)
306  B2Vector3D xPrimeDirection = B2Vector3D(showerPosition.y(), -showerPosition.x(), 0.0);
307  xPrimeDirection *= 1.0 / xPrimeDirection.Mag();
308 
309  B2Vector3D yPrimeDirection = xPrimeDirection.Cross(showerDirection);
310  yPrimeDirection *= 1.0 / yPrimeDirection.Mag();
311 
312  //---------------------------------------------------------------------
313  // Loop on CalDigits in shower and calculate the projection.
314  //---------------------------------------------------------------------
315 
317 
318  for (unsigned int iRelation = 0; iRelation < showerDigitRelations.size(); ++iRelation) {
319  const auto calDigit = showerDigitRelations.object(iRelation);
320 
321  ProjectedECLDigit tmpProjectedDigit;
322 
323  //---------------------------------------------------------------------
324  // Projected digit energy.
325  //---------------------------------------------------------------------
326  const auto weight = showerDigitRelations.weight(iRelation);
327  tmpProjectedDigit.energy = weight * calDigit->getEnergy();
328 
329  //---------------------------------------------------------------------
330  // Projected digit radial distance.
331  //---------------------------------------------------------------------
332  const int cellId = calDigit->getCellId();
333  B2Vector3D calDigitPosition = geometry->GetCrystalPos(cellId - 1);
334 
335  // Angle between vector pointing to shower and vector pointing to CalDigit,
336  //where the orgin is the detector origin (implicitly assuming IP = detector origin)
337  const double angleDigitShower = calDigitPosition.Angle(showerPosition);
338  tmpProjectedDigit.rho = showerR * TMath::Tan(angleDigitShower);
339 
340  //---------------------------------------------------------------------
341  // Projected digit polar angle
342  //---------------------------------------------------------------------
343  // Vector perpendicular to the vector pointing to the shower position, pointing to the CalDigit.
344  // It's length is not rho. Not normalized!!! We only care about the angle between in and xPrime.
345  B2Vector3D projectedDigitDirection = calDigitPosition - calDigitPosition.Dot(showerDirection) * showerDirection;
346  tmpProjectedDigit.alpha = projectedDigitDirection.Angle(xPrimeDirection);
347 
348  // adjust so that alpha spans 0..2pi
349  if (projectedDigitDirection.Angle(yPrimeDirection) > TMath::Pi() / 2.0)
350  tmpProjectedDigit.alpha = 2.0 * TMath::Pi() - tmpProjectedDigit.alpha;
351  tmpProjectedECLDigits.push_back(tmpProjectedDigit);
352  }
353 
354  return tmpProjectedECLDigits;
355 }
356 
358 {
359 }
360 
362 {
363 
364 }
365 
366 double ECLShowerShapeModule::computeLateralEnergy(const std::vector<ProjectedECLDigit>& projectedDigits,
367  const double avgCrystalDimension) const
368 {
369 
370 // auto relatedDigitsPairs = shower.getRelationsTo<ECLCalDigit>();
371  if (projectedDigits.size() < 3.0) return 0;
372 
373  // Find the two projected digits with the maximum energy.
374  double maxEnergy(0), secondMaxEnergy(0);
375  unsigned int iMax(0), iSecondMax(0);
376 
377  for (unsigned int iProjecteDigit = 0; iProjecteDigit < projectedDigits.size(); iProjecteDigit++) {
378  if (projectedDigits[iProjecteDigit].energy > maxEnergy) {
379  secondMaxEnergy = maxEnergy;
380  iSecondMax = iMax;
381  maxEnergy = projectedDigits[iProjecteDigit].energy;
382  iMax = iProjecteDigit;
383  } else if (projectedDigits[iProjecteDigit].energy > secondMaxEnergy) {
384  secondMaxEnergy = projectedDigits[iProjecteDigit].energy;
385  iSecondMax = iProjecteDigit;
386  }
387  }
388 
389  //Calculate lateral energy
390  double sumE = 0;
391  for (unsigned int iProjecteDigit = 0; iProjecteDigit < projectedDigits.size(); iProjecteDigit++) {
392 
393  //2 highest energies are considered differently than the rest
394  if (iProjecteDigit == iMax || iProjecteDigit == iSecondMax) continue;
395 
396  double rho = projectedDigits[iProjecteDigit].rho;
397  double rho2 = rho * rho;
398  double energy = projectedDigits[iProjecteDigit].energy;
399  sumE += energy * rho2;
400 
401  }
402 
403  const double r0sq = avgCrystalDimension * avgCrystalDimension; // average crystal dimension squared.
404  return sumE / (sumE + r0sq * (maxEnergy + secondMaxEnergy));
405 }
406 
407 double ECLShowerShapeModule::Rnm(const int n, const int m, const double rho) const
408 {
409  // Some explicit polynomials.
410  if (n == 1 && m == 1) return rho;
411  if (n == 2 && m == 0) return 2.0 * rho * rho - 1.0;
412  if (n == 2 && m == 2) return rho * rho;
413  if (n == 3 && m == 1) return 3.0 * rho * rho * rho - 2.0 * rho;
414  if (n == 3 && m == 3) return rho * rho * rho;
415  if (n == 4 && m == 0) return 6.0 * rho * rho * rho * rho - 6.0 * rho * rho + 1.0;
416  if (n == 4 && m == 2) return 4.0 * rho * rho * rho * rho - 3.0 * rho * rho;
417  if (n == 4 && m == 4) return rho * rho * rho * rho;
418  if (n == 5 && m == 1) return 10.0 * rho * rho * rho * rho * rho - 12.0 * rho * rho * rho + 3.0 * rho;
419  if (n == 5 && m == 3) return 5.0 * rho * rho * rho * rho * rho - 4.0 * rho * rho * rho;
420  if (n == 5 && m == 5) return rho * rho * rho * rho * rho;
421 
422  // Otherwise compute explicitely.
423  double returnVal = 0;
424  for (int idx = 0; idx <= (n - std::abs(m)) / 2; ++idx)
425  returnVal += std::pow(-1, idx) * TMath::Factorial(n - idx) / TMath::Factorial(idx)
426  / TMath::Factorial((n + std::abs(m)) / 2 - idx) / TMath::Factorial((n - std::abs(m)) / 2 - idx) * std::pow(rho, n - 2 * idx);
427 
428  return returnVal;
429 }
430 
431 std::complex<double> ECLShowerShapeModule::zernikeValue(const double rho, const double alpha, const int n, const int m) const
432 {
433  // Zernike moment defined only on the unit cercile (rho < 1).
434  if (rho > 1.0) return std::complex<double>(0, 0);
435 
436  std::complex<double> i(0, 1);
437  std::complex<double> exponent = std::exp(i * std::complex<double>(m * alpha, 0));
438  return std::complex<double>(Rnm(n, m, rho), 0) * exponent;
439 }
440 
441 
442 double ECLShowerShapeModule::computeAbsZernikeMoment(const std::vector<ProjectedECLDigit>& projectedDigits,
443  const double totalEnergy, const int n, const int m, const double rho0) const
444 {
445  if (totalEnergy <= 0.0) return 0.0;
446 
447  // Make sure n,m are valid
448  if (n < 0 || m < 0) return 0.0;
449  if (m > n) return 0.0;
450 
451  std::complex<double> sum(0.0, 0.0);
452 
453  for (const auto projectedDigit : projectedDigits) {
454  double normalizedRho = projectedDigit.rho / rho0; // Normalize radial distance according to rho0.
455  //Ignore crystals with rho > rho0, if requested
456  if (normalizedRho > 1.0) {
457  if (!m_zernike_useFarCrystals) continue;
458  else normalizedRho = 1.0; //crystals with rho > rho0 are scaled to rho0 instead of discarded
459  }
460 
461  sum += projectedDigit.energy * std::conj(zernikeValue(normalizedRho, projectedDigit.alpha, n, m));
462  }
463  return (n + 1.0) / TMath::Pi() * std::abs(sum) / totalEnergy;
464 }
465 
466 double ECLShowerShapeModule::computeSecondMoment(const std::vector<ProjectedECLDigit>& projectedDigits,
467  const double totalEnergy) const
468 {
469  if (totalEnergy <= 0.0) return 0.0;
470 
471  double sum = 0.0;
472 
473  for (const auto projectedDigit : projectedDigits) sum += projectedDigit.energy * projectedDigit.rho * projectedDigit.rho;
474 
475  return sum / totalEnergy;
476 }
477 
478 
480 {
481 
482  // get central id
483  const int centralCellId = shower.getCentralCellId();
484  if (centralCellId == 0) return 0.0; //cell id starts at 1
485 
486  // get list of 9 neighbour ids
487  const std::vector< short int > n9 = m_neighbourMap9->getNeighbours(centralCellId);
488 
489  double energy1 = 0.0; // to check: 'highest energy' data member may not always be the right one
490  double energy9 = 0.0;
491 
492  auto relatedDigitsPairs = shower.getRelationsTo<ECLCalDigit>(eclCalDigitArrayName());
493 
494  for (unsigned int iRel = 0; iRel < relatedDigitsPairs.size(); iRel++) {
495  const auto caldigit = relatedDigitsPairs.object(iRel);
496  const auto weight = relatedDigitsPairs.weight(iRel);
497  const auto energy = caldigit->getEnergy();
498  const int cellid = caldigit->getCellId();
499 
500  // get central cell id energy
501  if (cellid == centralCellId) {
502  energy1 = weight * energy;
503  }
504 
505  // check if this is contained in the 9 neighbours
506  const auto it9 = std::find(n9.begin(), n9.end(), cellid);
507  if (it9 != n9.end()) {
508  energy9 += weight * energy;
509  }
510 
511  }
512 
513  if (energy9 > 1e-9) return energy1 / energy9;
514  else return 0.0;
515 }
516 
518 {
519  // get central id
520  const int centralCellId = shower.getCentralCellId();
521  if (centralCellId == 0) return 0.0; //cell id starts at 1
522 
523  // get list of 9 and 21 neighbour ids
524  const std::vector< short int > n9 = m_neighbourMap9->getNeighbours(centralCellId);
525  const std::vector< short int > n21 = m_neighbourMap21->getNeighbours(centralCellId);
526 
527  double energy9 = 0.0;
528  double energy21 = 0.0;
529 
530  auto relatedDigitsPairs = shower.getRelationsTo<ECLCalDigit>(eclCalDigitArrayName());
531 
532  for (unsigned int iRel = 0; iRel < relatedDigitsPairs.size(); iRel++) {
533  const auto caldigit = relatedDigitsPairs.object(iRel);
534  const auto weight = relatedDigitsPairs.weight(iRel);
535  const auto energy = caldigit->getEnergy();
536  const int cellid = caldigit->getCellId();
537 
538  // check if this is contained in the 9 neighbours
539  const auto it9 = std::find(n9.begin(), n9.end(), cellid);
540  if (it9 != n9.end()) {
541  energy9 += weight * energy;
542  }
543 
544  // check if this is contained in the 21 neighbours
545  const auto it21 = std::find(n21.begin(), n21.end(), cellid);
546  if (it21 != n21.end()) {
547  energy21 += weight * energy;
548  }
549 
550  }
551 
552  if (energy21 > 1e-9) return energy9 / energy21;
553  else return 0.0;
554 
555 }
556 
558 {
559  //Clear m_secondMomentCorrections array
560  for (auto iType = 0; iType < 2; ++iType)
561  for (auto iHypothesis = 0; iHypothesis < 10; ++iHypothesis)
562  m_secondMomentCorrections[iType][iHypothesis] = TGraph();
563 
564  // Read all corrections.
565  for (const ECLShowerShapeSecondMomentCorrection& correction : m_secondMomentCorrectionArray) {
566  const int type = correction.getType();
567  const int hypothesis = correction.getHypothesisId();
568  if (type < 0 or type > 1 or hypothesis < 1 or hypothesis > 9) {
569  B2FATAL("Invalid type or hypothesis for second moment corrections.");
570  }
571 
572  m_secondMomentCorrections[type][hypothesis] = correction.getCorrection();
573  }
574 
575  // Check that all corrections are there
576  if (m_secondMomentCorrections[c_thetaType][ECLShower::c_nPhotons].GetN() == 0 or
577  m_secondMomentCorrections[c_phiType][ECLShower::c_nPhotons].GetN() == 0 or
578  m_secondMomentCorrections[c_thetaType][ECLShower::c_neutralHadron].GetN() == 0 or
579  m_secondMomentCorrections[c_phiType][ECLShower::c_neutralHadron].GetN() == 0) {
580  B2FATAL("Missing corrections for second moments..");
581  }
582 }
583 
584 double ECLShowerShapeModule::getSecondMomentCorrection(const double theta, const double phi, const int hypothesis) const
585 {
586  // convert to deg.
587  double thetadeg = theta * TMath::RadToDeg();
588 
589  // protect angular range.
590  if (thetadeg < 0.1) thetadeg = 0.1;
591  else if (thetadeg > 179.9) thetadeg = 179.9;
592 
593  //Convert phi
594  double phideg = phi * TMath::RadToDeg();
595 
596  //Protect phi
597  if (phideg < -179.9) phideg = -179.9;
598  else if (phideg > 179.9) phideg = 179.9;
599 
600 
601  // protect hypothesis.
602  if (hypothesis < 1 or hypothesis > 10) {
603  B2FATAL("Invalid hypothesis for second moment corrections.");
604  }
605 
606  const double thetaCorrection = m_secondMomentCorrections[c_thetaType][hypothesis].Eval(thetadeg);
607  const double phiCorrection = m_secondMomentCorrections[c_phiType][hypothesis].Eval(phideg);
608 
609  B2DEBUG(175, "Second momen theta crrection = " << thetaCorrection << ", phi correction = " << phiCorrection);
610 
611  return thetaCorrection * phiCorrection;
612 }
Belle2::ECLShower::getHypothesisId
int getHypothesisId() const
Get Hypothesis Id.
Definition: ECLShower.h:276
Belle2::Unit::cm
static const double cm
Standard units with the value = 1.
Definition: Unit.h:57
Belle2::ECLShowerShapeModule::zernikeValue
std::complex< double > zernikeValue(const double rho, const double alpha, const int n, const int m) const
Return the complex value of the Zernike polynomial of rank n,m.
Definition: ECLShowerShapeModule.cc:431
Belle2::ECLShowerShapeModule::ProjectedECLDigit::rho
double rho
radial distance
Definition: ECLShowerShapeModule.h:106
Belle2::MVA::AbstractInterface::getSupportedInterfaces
static std::map< std::string, AbstractInterface * > getSupportedInterfaces()
Returns interfaces supported by the MVA Interface.
Definition: Interface.h:55
Belle2::ECLCalDigit
Class to store calibrated ECLDigits: ECLCalDigits.
Definition: ECLCalDigit.h:38
Belle2::ECLShowerShapeModule::ProjectedECLDigit
Struct used to hold information of the digits projected to a plane perpendicular to the shower direct...
Definition: ECLShowerShapeModule.h:100
Belle2::MVA::Weightfile::getOptions
void getOptions(Options &options) const
Fills an Option object from the xml tree.
Definition: Weightfile.cc:76
Belle2::ECLShowerShapeModule::computeSecondMoment
double computeSecondMoment(const std::vector< ProjectedECLDigit > &shower, const double totalEnergy) const
Compute the second moment in the plane perpendicular to the direction of the shower.
Definition: ECLShowerShapeModule.cc:466
Belle2::ECLShower::getTheta
double getTheta() const
Get Theta.
Definition: ECLShower.h:296
Belle2::ECLShower::getE9oE21
double getE9oE21() const
Get energy ratio E9oE21.
Definition: ECLShower.h:401
Belle2::ECLShowerShapeModule::endRun
virtual void endRun() override
End run.
Definition: ECLShowerShapeModule.cc:357
REG_MODULE
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:652
Belle2::ECLShowerShapeModule::initialize
virtual void initialize() override
Initialize.
Definition: ECLShowerShapeModule.cc:103
Belle2::B2Vector3::x
DataType x() const
access variable X (= .at(0) without boundary check)
Definition: B2Vector3.h:424
Belle2::ECLShowerShapeModule::event
virtual void event() override
Event.
Definition: ECLShowerShapeModule.cc:246
Belle2::B2Vector3::Angle
DataType Angle(const B2Vector3< DataType > &q) const
The angle w.r.t.
Definition: B2Vector3.h:301
Belle2::MVA::Weightfile
The Weightfile class serializes all information about a training into an xml tree.
Definition: Weightfile.h:40
Belle2::ECLShowerShapeModule::setShowerShapeVariables
void setShowerShapeVariables(ECLShower *eclShower, const bool calculateZernikeMVA) const
Set showr shape variables.
Definition: ECLShowerShapeModule.cc:176
Belle2::ECLShowerShapeModule::computeE1oE9
double computeE1oE9(const ECLShower &) const
Shower shape variable: E1oE9 The energy ratio is calculated taking the weighted central (=1) and the ...
Definition: ECLShowerShapeModule.cc:479
Belle2::ECLShowerShapeModule::initializeMVA
void initializeMVA(const std::string &identifier, std::unique_ptr< DBObjPtr< DatabaseRepresentationOfWeightfile >> &weightFileRepresentation, std::unique_ptr< MVA::Expert > &expert)
Load MVA weight file and set pointer of expert.
Definition: ECLShowerShapeModule.cc:122
Belle2::B2Vector3::Cross
B2Vector3< DataType > Cross(const B2Vector3< DataType > &p) const
Cross product.
Definition: B2Vector3.h:295
Belle2::ECLShowerShapeModule::beginRun
virtual void beginRun() override
Begin run.
Definition: ECLShowerShapeModule.cc:162
Belle2::ECLShower::setLateralEnergy
void setLateralEnergy(double lateralEnergy)
Set Lateral Energy.
Definition: ECLShower.h:186
Belle2::ECLShower::setAbsZernike40
void setAbsZernike40(double absZernike40)
Set absolute value of Zernike moment 40.
Definition: ECLShower.h:206
Belle2::ECLShower::getCentralCellId
int getCentralCellId() const
Get central cell Id.
Definition: ECLShower.h:281
Belle2::ECLShower::c_neutralHadron
@ c_neutralHadron
CR is reconstructed as a neutral hadron (N2)
Definition: ECLShower.h:56
Belle2::RelationsInterface::getRelationsTo
RelationVector< TO > getRelationsTo(const std::string &name="", const std::string &namedRelation="") const
Get the relations that point from this object to another store array.
Definition: RelationsObject.h:199
Belle2::ECLShowerShapeModule::prepareSecondMomentCorrectionsCallback
void prepareSecondMomentCorrectionsCallback()
Prepare corrections for second moment Will be called whenever the m_secondMomentCorrectionArray get u...
Definition: ECLShowerShapeModule.cc:557
Belle2::DBObjPtr
Class for accessing objects in the database.
Definition: DBObjPtr.h:31
Belle2::B2Vector3< double >
Belle2::ECLShowerShapeModule::ProjectedECLDigit::energy
double energy
weighted energy
Definition: ECLShowerShapeModule.h:103
Belle2::ECLShowerShapeModule::initializeMVAweightFiles
void initializeMVAweightFiles(const std::string &identifier, std::unique_ptr< DBObjPtr< DatabaseRepresentationOfWeightfile >> &weightFileRepresentation)
initialize MVA weight files from DB
Definition: ECLShowerShapeModule.cc:93
Belle2::Module
Base class for Modules.
Definition: Module.h:74
Belle2::ECLShowerShapeModule
Class to perform the shower correction.
Definition: ECLShowerShapeModule.h:65
Belle2::ECL::ECLGeometryPar::Instance
static ECLGeometryPar * Instance()
Static method to get a reference to the ECLGeometryPar instance.
Definition: ECLGeometryPar.cc:151
Belle2::ECLShower::getPhi
double getPhi() const
Get Phi.
Definition: ECLShower.h:301
Belle2::B2Vector3::Dot
DataType Dot(const B2Vector3< DataType > &p) const
Scalar product.
Definition: B2Vector3.h:289
Belle2::ECLShowerShapeModule::~ECLShowerShapeModule
~ECLShowerShapeModule()
Destructor.
Definition: ECLShowerShapeModule.cc:89
Belle2::ECL::ECLNeighbours
Class to get the neighbours for a given cell id.
Definition: ECLNeighbours.h:38
Belle2::ECLShowerShapeModule::computeE9oE21
double computeE9oE21(const ECLShower &) const
Shower shape variable: E9oE21 The energy ratio is calculated taking the weighted 3x3 (=9) and the wei...
Definition: ECLShowerShapeModule.cc:517
Belle2::B2Vector3D
B2Vector3< double > B2Vector3D
typedef for common usage with double
Definition: B2Vector3.h:507
Belle2::ECLShower::setE9oE21
void setE9oE21(double E9oE21)
Set energy ration E9 over E21.
Definition: ECLShower.h:226
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::ECLShower::getEnergy
double getEnergy() const
Get Energy.
Definition: ECLShower.h:286
Belle2::ECLShowerShapeModule::computeLateralEnergy
double computeLateralEnergy(const std::vector< ProjectedECLDigit > &projectedDigits, const double avgCrystalDimension) const
Shower shape variable: Lateral energy.
Definition: ECLShowerShapeModule.cc:366
Belle2::ECLShowerShapeSecondMomentCorrection
Corrections to the second moment shower shape.
Definition: ECLShowerShapeSecondMomentCorrection.h:38
Belle2::MVA::Weightfile::loadFromFile
static Weightfile loadFromFile(const std::string &filename)
Static function which loads a Weightfile from a file.
Definition: Weightfile.cc:215
Belle2::ECLShower::setZernikeMVA
void setZernikeMVA(double zernikeMVA)
SetZernike MVA value.
Definition: ECLShower.h:214
Belle2::ECLShower::setSecondMoment
void setSecondMoment(double secondMoment)
Set second moment.
Definition: ECLShower.h:218
Belle2::ECLShower::setE1oE9
void setE1oE9(double E1oE9)
Set energy ration E1 over E9.
Definition: ECLShower.h:222
Belle2::MVA::GeneralOptions
General options which are shared by all MVA trainings.
Definition: Options.h:64
Belle2::ECLShowerShapeModule::computeAbsZernikeMoment
double computeAbsZernikeMoment(const std::vector< ProjectedECLDigit > &projectedDigits, const double totalEnergy, const int n, const int m, const double rho) const
Compute the absolute value of the complex Zernike moment Znm.
Definition: ECLShowerShapeModule.cc:442
Belle2::B2Vector3::y
DataType y() const
access variable Y (= .at(1) without boundary check)
Definition: B2Vector3.h:426
Belle2::MVA::AbstractInterface::initSupportedInterfaces
static void initSupportedInterfaces()
Static function which initliazes all supported interfaces, has to be called once before getSupportedI...
Definition: Interface.cc:55
Belle2::MVA::SingleDataset
Wraps the data of a single event into a Dataset.
Definition: Dataset.h:136
Belle2::ECLShower::c_nPhotons
@ c_nPhotons
CR is split into n photons (N1)
Definition: ECLShower.h:54
Belle2::B2Vector3::SetMagThetaPhi
void SetMagThetaPhi(DataType mag, DataType theta, DataType phi)
setter with mag, theta, phi
Definition: B2Vector3.h:258
Belle2::ECLShowerShapeModule::projectECLDigits
std::vector< ProjectedECLDigit > projectECLDigits(const ECLShower &shower) const
Compute projections of the ECLCalDigits to the perpendicular plane.
Definition: ECLShowerShapeModule.cc:284
Belle2::MVA::Weightfile::loadFromStream
static Weightfile loadFromStream(std::istream &stream)
Static function which deserializes a Weightfile from a stream.
Definition: Weightfile.cc:260
Belle2::ECLShowerShapeModule::getSecondMomentCorrection
double getSecondMomentCorrection(const double theta, const double phi, const int hypothesis) const
Get corrections for second moment.
Definition: ECLShowerShapeModule.cc:584
Belle2::ECLShowerShapeModule::terminate
virtual void terminate() override
Terminate.
Definition: ECLShowerShapeModule.cc:361
Belle2::ECL::ECLGeometryPar
The Class for ECL Geometry Parameters.
Definition: ECLGeometryPar.h:45
Belle2::ECLShowerShapeModule::ProjectedECLDigit::alpha
double alpha
polar angel
Definition: ECLShowerShapeModule.h:109
Belle2::ECLShower::setAbsZernike51
void setAbsZernike51(double absZernike51)
Set absolute value of Zernike moment 51.
Definition: ECLShower.h:210
Belle2::ECLShower::getR
double getR() const
Get R.
Definition: ECLShower.h:306
Belle2::ECLShowerShapeModule::Rnm
double Rnm(const int n, const int m, const double rho) const
The radial part of the Zernike polynomial n,m - Zernike polynomial rank rho - radial distance
Definition: ECLShowerShapeModule.cc:407
Belle2::B2Vector3::Mag
DataType Mag() const
The magnitude (rho in spherical coordinate system).
Definition: B2Vector3.h:158
Belle2::ECLShower
Class to store ECL Showers.
Definition: ECLShower.h:42