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