Belle II Software development
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
37using namespace Belle2;
38using namespace ECL;
39
40//-----------------------------------------------------------------
41// Register the Module
42//-----------------------------------------------------------------
43REG_MODULE(ECLShowerShape);
44REG_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
87void 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{
101 eclCalDigits.isRequired();
103 eclShowers.isRequired();
104 m_eclConnectedRegions.requireRelationTo(eclCalDigits);
105 eclShowers.requireRelationTo(eclCalDigits);
106
107 // Initialize neighbour maps.
108 m_neighbourMap9 = std::unique_ptr<ECL::ECLNeighbours>(new ECL::ECLNeighbours("N", 1));
109 m_neighbourMap21 = std::unique_ptr<ECL::ECLNeighbours>(new ECL::ECLNeighbours("NC", 2));
110
114
115
116 //Add callback to fill m_secondMomentCorrections when m_secondMomentCorrectionArray changes
117 //21-Oct-2016 - The callback doesn't seem to be called at the beginning of the run so I commented it out and added a call to prepareSecondMomentCorrectionsCallback in the beginRun
118// m_secondMomentCorrectionArray.addCallback(this, &ECLShowerShapeModule::prepareSecondMomentCorrectionsCallback);
119// prepareSecondMomentCorrectionsCallback();
120
121}
122
123void ECLShowerShapeModule::initializeMVA(const std::string& identifier,
124 std::unique_ptr<DBObjPtr<DatabaseRepresentationOfWeightfile>>& weightFileRepresentation, std::unique_ptr<MVA::Expert>& expert)
125{
126 MVA::Weightfile weightfile;
127 //Load MVA weight file
128 if (weightFileRepresentation) {
129
130 //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.
131 //This is so that in the next run, the payload can be taken from a different DB source.
132 //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.
133 //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.
134 //This is true as of 2017-06-01, functionality of hasChanged() might be changed in future.
135
136 if (weightFileRepresentation->hasChanged()) {
137 std::stringstream ss((*weightFileRepresentation)->m_data);
138 weightfile = MVA::Weightfile::loadFromStream(ss);
139 } else
140 return;
141 } else {
142 weightfile = MVA::Weightfile::loadFromFile(identifier);
143 }
144
145 auto supported_interfaces = MVA::AbstractInterface::getSupportedInterfaces();
146 MVA::GeneralOptions general_options;
147 weightfile.getOptions(general_options);
148
149 //Check number of variables in weight file
150 if (m_numZernikeMVAvariables != general_options.m_variables.size())
151 B2FATAL("Expecting " << m_numZernikeMVAvariables << " variables, found " << general_options.m_variables.size());
152
153 expert = supported_interfaces[general_options.m_method]->getExpert();
154 expert->load(weightfile);
155
156 //create new dataset, if this is the barrel MVA (assumes FWD and BWD datasets are same size)
157 if (weightFileRepresentation == m_weightfile_representation_BRL) {
158 std::vector<float> dummy(general_options.m_variables.size(), 0);
159 m_dataset = std::unique_ptr<MVA::SingleDataset>(new MVA::SingleDataset(general_options, dummy, 0));
160 }
161}
162
164{
168
169 //This is a hack because the callback doesn't seem to be called at the beginning of the run
170 if (m_secondMomentCorrectionArray.hasChanged()) {
172 else B2ERROR("ECLShowerShapeModule::beginRun - Couldn't find second moment correction for current run");
173 }
174}
175
176
177void ECLShowerShapeModule::setShowerShapeVariables(ECLShower* eclShower, const bool calculateZernikeMVA) const
178{
179 //Project the digits on the plane perpendicular to the shower direction
180 std::vector<ProjectedECLDigit> projectedECLDigits = projectECLDigits(*eclShower);
181
182 const double showerEnergy = eclShower->getEnergy();
183 const double showerTheta = eclShower->getTheta();
184 const double showerPhi = eclShower->getPhi();
185
186 //sum crystal energies
187 double sumEnergies = 0.0;
188 for (const auto& projectedECLDigit : projectedECLDigits) sumEnergies += projectedECLDigit.energy;
189
190 //Choose rho0 according to shower hypothesis
191 double rho0 = 0.0;
192 const int hypothesisID = eclShower->getHypothesisId();
193 if (hypothesisID == ECLShower::c_nPhotons) rho0 = m_zernike_n1_rho0;
194 else if (hypothesisID == ECLShower::c_neutralHadron) rho0 = m_zernike_n2_rho0;
195
196 const double secondMomentCorrection = getSecondMomentCorrection(showerTheta, showerPhi, hypothesisID);
197 B2DEBUG(175, "Second moment angular correction: " << secondMomentCorrection << " (theta(rad)=" << showerTheta << ", phi(rad)=" <<
198 showerPhi << ",hypothesisId=" << hypothesisID <<
199 ")");
200 const double secondMoment = computeSecondMoment(projectedECLDigits, showerEnergy) * secondMomentCorrection;
201 B2DEBUG(175, "Second moment after correction: " << secondMoment);
202
203 const double LATenergy = computeLateralEnergy(projectedECLDigits, m_avgCrystalDimension);
204
205 // Set shower shape variables.
206 eclShower->setSecondMoment(secondMoment);
207 eclShower->setLateralEnergy(LATenergy);
208 eclShower->setE1oE9(computeE1oE9(*eclShower));
209 if (eclShower->getE9oE21() < 1e-9) eclShower->setE9oE21(computeE9oE21(*eclShower));
210 for (unsigned int n = 1; n <= 5; n++) {
211 for (unsigned int m = 0; m <= n; m++) {
212 eclShower->setAbsZernikeMoment(n, m, computeAbsZernikeMoment(projectedECLDigits, sumEnergies, n, m, rho0));
213 }
214 }
215
216 if (calculateZernikeMVA) {
217 //Set Zernike moments that will be used in MVA calculation
218 // m_dataset holds 22 entries, 11 Zernike moments of N2 shower, followed by 11 Zernike moments of N1 shower
219 int indexOffset = 0;//Offset entries depending on hypothesis type
220 if (hypothesisID == ECLShower::c_nPhotons) indexOffset = (m_numZernikeMVAvariables / 2);
221 else if (hypothesisID == ECLShower::c_neutralHadron) indexOffset = 0;
222
223 m_dataset->m_input[0 + indexOffset] = eclShower->getAbsZernikeMoment(1, 1);
224 m_dataset->m_input[1 + indexOffset] = eclShower->getAbsZernikeMoment(2, 0);
225 m_dataset->m_input[2 + indexOffset] = eclShower->getAbsZernikeMoment(2, 2);
226 m_dataset->m_input[3 + indexOffset] = eclShower->getAbsZernikeMoment(3, 1);
227 m_dataset->m_input[4 + indexOffset] = eclShower->getAbsZernikeMoment(3, 3);
228 m_dataset->m_input[5 + indexOffset] = eclShower->getAbsZernikeMoment(4, 0);
229 m_dataset->m_input[6 + indexOffset] = eclShower->getAbsZernikeMoment(4, 2);
230 m_dataset->m_input[7 + indexOffset] = eclShower->getAbsZernikeMoment(4, 4);
231 m_dataset->m_input[8 + indexOffset] = eclShower->getAbsZernikeMoment(5, 1);
232 m_dataset->m_input[9 + indexOffset] = eclShower->getAbsZernikeMoment(5, 3);
233 m_dataset->m_input[10 + indexOffset] = eclShower->getAbsZernikeMoment(5, 5);
234 //Set zernikeMVA for N1 showers
235 //This assumes that the N2 zernike moments have already been set in m_dataset!!!!
236 if (hypothesisID == ECLShower::c_nPhotons) {
237 //FWD
238 if (eclShower->getTheta() < m_BRLthetaMin) eclShower->setZernikeMVA(m_expert_FWD->apply(*m_dataset)[0]);
239 //BWD
240 else if (eclShower->getTheta() > m_BRLthetaMax) eclShower->setZernikeMVA(m_expert_BWD->apply(*m_dataset)[0]);
241 //BRL
242 else eclShower->setZernikeMVA(m_expert_BRL->apply(*m_dataset)[0]);
243 }
244 } else eclShower->setZernikeMVA(0.0);
245}
246
248{
249 for (auto& eclCR : m_eclConnectedRegions) {
250
251 //Start by finding the N2 shower and calculating it's shower shape variables
252 //Assumes that there is only 1 N2 Shower per CR!!!!!!
253 ECLShower* N2shower = nullptr;
254 for (auto& eclShower : eclCR.getRelationsWith<ECLShower>(eclShowerArrayName())) {
255 if (eclShower.getHypothesisId() == ECLShower::c_neutralHadron) {
256 N2shower = &eclShower;
257 setShowerShapeVariables(N2shower, true);
258 break;
259 }
260 }
261
262 //If couldn't find N2 shower, don't calculate zernikeMVA
263 bool found_N2shower = true;
264 if (N2shower == nullptr) found_N2shower = false;
265
266 double prodN1zernikeMVAs = 1.0;
267 //Calculate shower shape variables for the rest of the showers
268 for (auto& eclShower : eclCR.getRelationsWith<ECLShower>(eclShowerArrayName())) {
269 if (eclShower.getHypothesisId() == ECLShower::c_neutralHadron)
270 continue; //shower shape variables already calculated for neutral hadrons
271
272 bool calculateZernikeMVA = true;
273 if (!found_N2shower || eclShower.getHypothesisId() != ECLShower::c_nPhotons) calculateZernikeMVA = false;
274
275 setShowerShapeVariables(&eclShower, calculateZernikeMVA);
276
277 if (eclShower.getHypothesisId() == ECLShower::c_nPhotons) prodN1zernikeMVAs *= eclShower.getZernikeMVA();
278 }
279
280 //Set zernikeMVA for the N2 shower
281 if (N2shower) N2shower->setZernikeMVA(1.0 - prodN1zernikeMVAs);
282 }
283}
284
285std::vector<ECLShowerShapeModule::ProjectedECLDigit> ECLShowerShapeModule::projectECLDigits(const ECLShower& shower) const
286{
287 std::vector<ProjectedECLDigit> tmpProjectedECLDigits; //Will be returned at the end of the function
288 auto showerDigitRelations = shower.getRelationsTo<ECLCalDigit>(eclCalDigitArrayName());
289// tmpProjectedECLDigits.resize( showerDigitRelations.size() );
290 //---------------------------------------------------------------------
291 // Get shower parameters.
292 //---------------------------------------------------------------------
293 const double showerR = shower.getR();
294 const double showerTheta = shower.getTheta();
295 const double showerPhi = shower.getPhi();
296
297 B2Vector3D showerPosition;
298 showerPosition.SetMagThetaPhi(showerR, showerTheta, showerPhi);
299
300 // Unit vector pointing in shower direction.
301 const B2Vector3D showerDirection = (1.0 / showerPosition.Mag()) * showerPosition;
302
303 //---------------------------------------------------------------------
304 // Calculate axes that span the perpendicular plane.
305 //---------------------------------------------------------------------
306 //xPrimeDirection = showerdirection.cross(zAxis)
307 B2Vector3D xPrimeDirection = B2Vector3D(showerPosition.Y(), -showerPosition.X(), 0.0);
308 xPrimeDirection *= 1.0 / xPrimeDirection.Mag();
309
310 B2Vector3D yPrimeDirection = xPrimeDirection.Cross(showerDirection);
311 yPrimeDirection *= 1.0 / yPrimeDirection.Mag();
312
313 //---------------------------------------------------------------------
314 // Loop on CalDigits in shower and calculate the projection.
315 //---------------------------------------------------------------------
316
318
319 for (unsigned int iRelation = 0; iRelation < showerDigitRelations.size(); ++iRelation) {
320 const auto calDigit = showerDigitRelations.object(iRelation);
321
322 ProjectedECLDigit tmpProjectedDigit;
323
324 //---------------------------------------------------------------------
325 // Projected digit energy.
326 //---------------------------------------------------------------------
327 const auto weight = showerDigitRelations.weight(iRelation);
328 tmpProjectedDigit.energy = weight * calDigit->getEnergy();
329
330 //---------------------------------------------------------------------
331 // Projected digit radial distance.
332 //---------------------------------------------------------------------
333 const int cellId = calDigit->getCellId();
334 B2Vector3D calDigitPosition = geometry->GetCrystalPos(cellId - 1);
335
336 // Angle between vector pointing to shower and vector pointing to CalDigit,
337 //where the origin is the detector origin (implicitly assuming IP = detector origin)
338 const double angleDigitShower = calDigitPosition.Angle(showerPosition);
339 tmpProjectedDigit.rho = showerR * TMath::Tan(angleDigitShower);
340
341 //---------------------------------------------------------------------
342 // Projected digit polar angle
343 //---------------------------------------------------------------------
344 // Vector perpendicular to the vector pointing to the shower position, pointing to the CalDigit.
345 // It's length is not rho. Not normalized!!! We only care about the angle between in and xPrime.
346 B2Vector3D projectedDigitDirection = calDigitPosition - calDigitPosition.Dot(showerDirection) * showerDirection;
347 tmpProjectedDigit.alpha = projectedDigitDirection.Angle(xPrimeDirection);
348
349 // adjust so that alpha spans 0..2pi
350 if (projectedDigitDirection.Angle(yPrimeDirection) > TMath::Pi() / 2.0)
351 tmpProjectedDigit.alpha = 2.0 * TMath::Pi() - tmpProjectedDigit.alpha;
352 tmpProjectedECLDigits.push_back(tmpProjectedDigit);
353 }
354
355 return tmpProjectedECLDigits;
356}
357
359{
360}
361
363{
364
365}
366
367double ECLShowerShapeModule::computeLateralEnergy(const std::vector<ProjectedECLDigit>& projectedDigits,
368 const double avgCrystalDimension) const
369{
370
371// auto relatedDigitsPairs = shower.getRelationsTo<ECLCalDigit>();
372 if (projectedDigits.size() < 3.0) return 0;
373
374 // Find the two projected digits with the maximum energy.
375 double maxEnergy(0), secondMaxEnergy(0);
376 unsigned int iMax(0), iSecondMax(0);
377
378 for (unsigned int iProjecteDigit = 0; iProjecteDigit < projectedDigits.size(); iProjecteDigit++) {
379 if (projectedDigits[iProjecteDigit].energy > maxEnergy) {
380 secondMaxEnergy = maxEnergy;
381 iSecondMax = iMax;
382 maxEnergy = projectedDigits[iProjecteDigit].energy;
383 iMax = iProjecteDigit;
384 } else if (projectedDigits[iProjecteDigit].energy > secondMaxEnergy) {
385 secondMaxEnergy = projectedDigits[iProjecteDigit].energy;
386 iSecondMax = iProjecteDigit;
387 }
388 }
389
390 //Calculate lateral energy
391 double sumE = 0;
392 for (unsigned int iProjecteDigit = 0; iProjecteDigit < projectedDigits.size(); iProjecteDigit++) {
393
394 //2 highest energies are considered differently than the rest
395 if (iProjecteDigit == iMax || iProjecteDigit == iSecondMax) continue;
396
397 double rho = projectedDigits[iProjecteDigit].rho;
398 double rho2 = rho * rho;
399 double energy = projectedDigits[iProjecteDigit].energy;
400 sumE += energy * rho2;
401
402 }
403
404 const double r0sq = avgCrystalDimension * avgCrystalDimension; // average crystal dimension squared.
405 return sumE / (sumE + r0sq * (maxEnergy + secondMaxEnergy));
406}
407
408double ECLShowerShapeModule::Rnm(const int n, const int m, const double rho) const
409{
410 // Some explicit polynomials.
411 if (n == 1 && m == 1) return rho;
412 if (n == 2 && m == 0) return 2.0 * rho * rho - 1.0;
413 if (n == 2 && m == 2) return rho * rho;
414 if (n == 3 && m == 1) return 3.0 * rho * rho * rho - 2.0 * rho;
415 if (n == 3 && m == 3) return rho * rho * rho;
416 if (n == 4 && m == 0) return 6.0 * rho * rho * rho * rho - 6.0 * rho * rho + 1.0;
417 if (n == 4 && m == 2) return 4.0 * rho * rho * rho * rho - 3.0 * rho * rho;
418 if (n == 4 && m == 4) return rho * rho * rho * rho;
419 if (n == 5 && m == 1) return 10.0 * rho * rho * rho * rho * rho - 12.0 * rho * rho * rho + 3.0 * rho;
420 if (n == 5 && m == 3) return 5.0 * rho * rho * rho * rho * rho - 4.0 * rho * rho * rho;
421 if (n == 5 && m == 5) return rho * rho * rho * rho * rho;
422
423 // Otherwise compute explicitly.
424 double returnVal = 0;
425 for (int idx = 0; idx <= (n - std::abs(m)) / 2; ++idx)
426 returnVal += std::pow(-1, idx) * TMath::Factorial(n - idx) / TMath::Factorial(idx)
427 / TMath::Factorial((n + std::abs(m)) / 2 - idx) / TMath::Factorial((n - std::abs(m)) / 2 - idx) * std::pow(rho, n - 2 * idx);
428
429 return returnVal;
430}
431
432std::complex<double> ECLShowerShapeModule::zernikeValue(const double rho, const double alpha, const int n, const int m) const
433{
434 // Zernike moment defined only on the unit cercile (rho < 1).
435 if (rho > 1.0) return std::complex<double>(0, 0);
436
437 std::complex<double> i(0, 1);
438 std::complex<double> exponent = std::exp(i * std::complex<double>(m * alpha, 0));
439 return std::complex<double>(Rnm(n, m, rho), 0) * exponent;
440}
441
442
443double ECLShowerShapeModule::computeAbsZernikeMoment(const std::vector<ProjectedECLDigit>& projectedDigits,
444 const double totalEnergy, const int n, const int m, const double rho0) const
445{
446 if (totalEnergy <= 0.0) return 0.0;
447
448 // Make sure n,m are valid
449 if (n < 0 || m < 0) return 0.0;
450 if (m > n) return 0.0;
451
452 std::complex<double> sum(0.0, 0.0);
453
454 for (const auto projectedDigit : projectedDigits) {
455 double normalizedRho = projectedDigit.rho / rho0; // Normalize radial distance according to rho0.
456 //Ignore crystals with rho > rho0, if requested
457 if (normalizedRho > 1.0) {
458 if (!m_zernike_useFarCrystals) continue;
459 else normalizedRho = 1.0; //crystals with rho > rho0 are scaled to rho0 instead of discarded
460 }
461
462 sum += projectedDigit.energy * std::conj(zernikeValue(normalizedRho, projectedDigit.alpha, n, m));
463 }
464 return (n + 1.0) / TMath::Pi() * std::abs(sum) / totalEnergy;
465}
466
467double ECLShowerShapeModule::computeSecondMoment(const std::vector<ProjectedECLDigit>& projectedDigits,
468 const double totalEnergy) const
469{
470 if (totalEnergy <= 0.0) return 0.0;
471
472 double sum = 0.0;
473
474 for (const auto projectedDigit : projectedDigits) sum += projectedDigit.energy * projectedDigit.rho * projectedDigit.rho;
475
476 return sum / totalEnergy;
477}
478
479
481{
482
483 // get central id
484 const int centralCellId = shower.getCentralCellId();
485 if (centralCellId == 0) return 0.0; //cell id starts at 1
486
487 // get list of 9 neighbour ids
488 const std::vector< short int > n9 = m_neighbourMap9->getNeighbours(centralCellId);
489
490 double energy1 = 0.0; // to check: 'highest energy' data member may not always be the right one
491 double energy9 = 0.0;
492
493 auto relatedDigitsPairs = shower.getRelationsTo<ECLCalDigit>(eclCalDigitArrayName());
494
495 for (unsigned int iRel = 0; iRel < relatedDigitsPairs.size(); iRel++) {
496 const auto caldigit = relatedDigitsPairs.object(iRel);
497 const auto weight = relatedDigitsPairs.weight(iRel);
498 const auto energy = caldigit->getEnergy();
499 const int cellid = caldigit->getCellId();
500
501 // get central cell id energy
502 if (cellid == centralCellId) {
503 energy1 = weight * energy;
504 }
505
506 // check if this is contained in the 9 neighbours
507 const auto it9 = std::find(n9.begin(), n9.end(), cellid);
508 if (it9 != n9.end()) {
509 energy9 += weight * energy;
510 }
511
512 }
513
514 if (energy9 > 1e-9) return energy1 / energy9;
515 else return 0.0;
516}
517
519{
520 // get central id
521 const int centralCellId = shower.getCentralCellId();
522 if (centralCellId == 0) return 0.0; //cell id starts at 1
523
524 // get list of 9 and 21 neighbour ids
525 const std::vector< short int > n9 = m_neighbourMap9->getNeighbours(centralCellId);
526 const std::vector< short int > n21 = m_neighbourMap21->getNeighbours(centralCellId);
527
528 double energy9 = 0.0;
529 double energy21 = 0.0;
530
531 auto relatedDigitsPairs = shower.getRelationsTo<ECLCalDigit>(eclCalDigitArrayName());
532
533 for (unsigned int iRel = 0; iRel < relatedDigitsPairs.size(); iRel++) {
534 const auto caldigit = relatedDigitsPairs.object(iRel);
535 const auto weight = relatedDigitsPairs.weight(iRel);
536 const auto energy = caldigit->getEnergy();
537 const int cellid = caldigit->getCellId();
538
539 // check if this is contained in the 9 neighbours
540 const auto it9 = std::find(n9.begin(), n9.end(), cellid);
541 if (it9 != n9.end()) {
542 energy9 += weight * energy;
543 }
544
545 // check if this is contained in the 21 neighbours
546 const auto it21 = std::find(n21.begin(), n21.end(), cellid);
547 if (it21 != n21.end()) {
548 energy21 += weight * energy;
549 }
550
551 }
552
553 if (energy21 > 1e-9) return energy9 / energy21;
554 else return 0.0;
555
556}
557
559{
560 //Clear m_secondMomentCorrections array
561 for (auto iType = 0; iType < 2; ++iType)
562 for (auto iHypothesis = 0; iHypothesis < 10; ++iHypothesis)
563 m_secondMomentCorrections[iType][iHypothesis] = TGraph();
564
565 // Read all corrections.
567 const int type = correction.getType();
568 const int hypothesis = correction.getHypothesisId();
569 if (type < 0 or type > 1 or hypothesis < 1 or hypothesis > 9) {
570 B2FATAL("Invalid type or hypothesis for second moment corrections.");
571 }
572
573 m_secondMomentCorrections[type][hypothesis] = correction.getCorrection();
574 }
575
576 // Check that all corrections are there
581 B2FATAL("Missing corrections for second moments..");
582 }
583}
584
585double ECLShowerShapeModule::getSecondMomentCorrection(const double theta, const double phi, const int hypothesis) const
586{
587 // convert to deg.
588 double thetadeg = theta * TMath::RadToDeg();
589
590 // protect angular range.
591 if (thetadeg < 0.1) thetadeg = 0.1;
592 else if (thetadeg > 179.9) thetadeg = 179.9;
593
594 //Convert phi
595 double phideg = phi * TMath::RadToDeg();
596
597 //Protect phi
598 if (phideg < -179.9) phideg = -179.9;
599 else if (phideg > 179.9) phideg = 179.9;
600
601
602 // protect hypothesis.
603 if (hypothesis < 1 or hypothesis > 10) {
604 B2FATAL("Invalid hypothesis for second moment corrections.");
605 }
606
607 const double thetaCorrection = m_secondMomentCorrections[c_thetaType][hypothesis].Eval(thetadeg);
608 const double phiCorrection = m_secondMomentCorrections[c_phiType][hypothesis].Eval(phideg);
609
610 B2DEBUG(175, "Second momen theta crrection = " << thetaCorrection << ", phi correction = " << phiCorrection);
611
612 return thetaCorrection * phiCorrection;
613}
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.
virtual const char * eclShowerArrayName() const
We need names for the data objects to differentiate between PureCsI and default.
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 void endRun() override
End run.
std::vector< ProjectedECLDigit > projectECLDigits(const ECLShower &shower) const
Compute projections of the ECLCalDigits to the perpendicular plane.
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.
void initializeMVAweightFiles(const std::string &identifier, std::unique_ptr< DBObjPtr< DatabaseRepresentationOfWeightfile > > &weightFileRepresentation)
initialize MVA weight files from DB
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.
@ c_phiType
type of phi identifier
@ c_thetaType
type of theta identifier
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.
virtual const char * eclConnectedRegionArrayName() const
Default name ECLConnectedRegions.
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].
virtual const char * eclCalDigitArrayName() const
Default name ECLCalDigits.
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.
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...
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 void initSupportedInterfaces()
Static function which initliazes all supported interfaces, has to be called once before getSupportedI...
Definition: Interface.cc:45
static std::map< std::string, AbstractInterface * > getSupportedInterfaces()
Returns interfaces supported by the MVA Interface.
Definition: Interface.h:53
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.
bool isRequired(const std::string &name="")
Ensure this array/object has been registered previously.
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
bool requireRelationTo(const StoreArray< TO > &toArray, DataStore::EDurability durability=DataStore::c_Event, const std::string &namedRelation="") const
Produce error if no relation from this array to 'toArray' has been registered.
Definition: StoreArray.h:155
static const double cm
Standard units with the value = 1.
Definition: Unit.h:47
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
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
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...