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