Belle II Software release-09-00-00
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{
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
116void 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
170void 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
278std::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
360double 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
401double 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
425std::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
436double 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
460double 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
578double 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.
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.
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.
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...