10 #include <ecl/modules/eclShowerShape/ECLShowerShapeModule.h>
13 #include <boost/algorithm/string/predicate.hpp>
19 #include <framework/datastore/RelationVector.h>
20 #include <framework/logging/Logger.h>
21 #include <framework/geometry/B2Vector3.h>
24 #include <mva/interface/Expert.h>
25 #include <mva/interface/Weightfile.h>
26 #include <mva/interface/Interface.h>
27 #include <mva/dataobjects/DatabaseRepresentationOfWeightfile.h>
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>
51 m_eclConnectedRegions(eclConnectedRegionArrayName()),
52 m_secondMomentCorrectionArray(
"ecl_shower_shape_second_moment_corrections")
55 setDescription(
"ECLShowerShapeModule: Calculate ECL shower shape variables (e.g. E9oE21)");
59 "Scaling factor for radial distances in a plane perpendicular to direction to shower for the n photon hypothesis in Zernike moment calculation.",
63 "Scaling factor for radial distances in a plane perpendicular to direction to shower for the neutral hadron hypothesis in Zernike moment calculation. ",
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.",
71 std::string{
"ecl_showershape_zernike_mva_fwd"});
73 std::string{
"ecl_showershape_zernike_mva_brl"});
75 "The Zernike moment MVA database identifier for backward endcap.", std::string{
"ecl_showershape_zernike_mva_bwd"});
78 "Average crystal dimension used in lateral energy calculation.",
90 if (not(boost::ends_with(identifier,
".root") or boost::ends_with(identifier,
".xml"))) {
91 weightFileRepresentation = std::unique_ptr<DBObjPtr<DatabaseRepresentationOfWeightfile>>(
new
121 if (weightFileRepresentation) {
129 if (weightFileRepresentation->hasChanged()) {
130 std::stringstream ss((*weightFileRepresentation)->m_data);
146 expert = supported_interfaces[general_options.m_method]->getExpert();
147 expert->load(weightfile);
151 std::vector<float> dummy(general_options.m_variables.size(), 0);
165 else B2ERROR(
"ECLShowerShapeModule::beginRun - Couldn't find second moment correction for current run");
173 std::vector<ProjectedECLDigit> projectedECLDigits =
projectECLDigits(*eclShower);
175 const double showerEnergy = eclShower->
getEnergy();
176 const double showerTheta = eclShower->
getTheta();
177 const double showerPhi = eclShower->
getPhi();
180 double sumEnergies = 0.0;
181 for (
const auto& projectedECLDigit : projectedECLDigits) sumEnergies += projectedECLDigit.energy;
190 B2DEBUG(175,
"Second moment angular correction: " << secondMomentCorrection <<
" (theta(rad)=" << showerTheta <<
", phi(rad)=" <<
191 showerPhi <<
",hypothesisId=" << hypothesisID <<
193 const double secondMoment =
computeSecondMoment(projectedECLDigits, showerEnergy) * secondMomentCorrection;
194 B2DEBUG(175,
"Second moment after correction: " << secondMoment);
203 for (
unsigned int n = 1; n <= 5; n++) {
204 for (
unsigned int m = 0; m <= n; m++) {
209 if (calculateZernikeMVA) {
249 N2shower = &eclShower;
256 bool found_N2shower =
true;
257 if (N2shower ==
nullptr) found_N2shower =
false;
259 double prodN1zernikeMVAs = 1.0;
265 bool calculateZernikeMVA =
true;
266 if (!found_N2shower || eclShower.getHypothesisId() !=
ECLShower::c_nPhotons) calculateZernikeMVA =
false;
270 if (eclShower.getHypothesisId() ==
ECLShower::c_nPhotons) prodN1zernikeMVAs *= eclShower.getZernikeMVA();
274 if (N2shower) N2shower->
setZernikeMVA(1.0 - prodN1zernikeMVAs);
280 std::vector<ProjectedECLDigit> tmpProjectedECLDigits;
286 const double showerR = shower.
getR();
287 const double showerTheta = shower.
getTheta();
288 const double showerPhi = shower.
getPhi();
294 const B2Vector3D showerDirection = (1.0 / showerPosition.
Mag()) * showerPosition;
301 xPrimeDirection *= 1.0 / xPrimeDirection.
Mag();
304 yPrimeDirection *= 1.0 / yPrimeDirection.
Mag();
312 for (
unsigned int iRelation = 0; iRelation < showerDigitRelations.size(); ++iRelation) {
313 const auto calDigit = showerDigitRelations.object(iRelation);
320 const auto weight = showerDigitRelations.weight(iRelation);
321 tmpProjectedDigit.
energy = weight * calDigit->getEnergy();
326 const int cellId = calDigit->getCellId();
327 B2Vector3D calDigitPosition = geometry->GetCrystalPos(cellId - 1);
331 const double angleDigitShower = calDigitPosition.
Angle(showerPosition);
332 tmpProjectedDigit.
rho = showerR * TMath::Tan(angleDigitShower);
339 B2Vector3D projectedDigitDirection = calDigitPosition - calDigitPosition.
Dot(showerDirection) * showerDirection;
340 tmpProjectedDigit.
alpha = projectedDigitDirection.
Angle(xPrimeDirection);
343 if (projectedDigitDirection.
Angle(yPrimeDirection) > TMath::Pi() / 2.0)
344 tmpProjectedDigit.
alpha = 2.0 * TMath::Pi() - tmpProjectedDigit.
alpha;
345 tmpProjectedECLDigits.push_back(tmpProjectedDigit);
348 return tmpProjectedECLDigits;
361 const double avgCrystalDimension)
const
365 if (projectedDigits.size() < 3.0)
return 0;
368 double maxEnergy(0), secondMaxEnergy(0);
369 unsigned int iMax(0), iSecondMax(0);
371 for (
unsigned int iProjecteDigit = 0; iProjecteDigit < projectedDigits.size(); iProjecteDigit++) {
372 if (projectedDigits[iProjecteDigit].energy > maxEnergy) {
373 secondMaxEnergy = maxEnergy;
375 maxEnergy = projectedDigits[iProjecteDigit].energy;
376 iMax = iProjecteDigit;
377 }
else if (projectedDigits[iProjecteDigit].energy > secondMaxEnergy) {
378 secondMaxEnergy = projectedDigits[iProjecteDigit].energy;
379 iSecondMax = iProjecteDigit;
385 for (
unsigned int iProjecteDigit = 0; iProjecteDigit < projectedDigits.size(); iProjecteDigit++) {
388 if (iProjecteDigit == iMax || iProjecteDigit == iSecondMax)
continue;
390 double rho = projectedDigits[iProjecteDigit].rho;
391 double rho2 = rho * rho;
392 double energy = projectedDigits[iProjecteDigit].energy;
393 sumE += energy * rho2;
397 const double r0sq = avgCrystalDimension * avgCrystalDimension;
398 return sumE / (sumE + r0sq * (maxEnergy + secondMaxEnergy));
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;
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);
428 if (rho > 1.0)
return std::complex<double>(0, 0);
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;
437 const double totalEnergy,
const int n,
const int m,
const double rho0)
const
439 if (totalEnergy <= 0.0)
return 0.0;
442 if (n < 0 || m < 0)
return 0.0;
443 if (m > n)
return 0.0;
445 std::complex<double> sum(0.0, 0.0);
447 for (
const auto projectedDigit : projectedDigits) {
448 double normalizedRho = projectedDigit.rho / rho0;
450 if (normalizedRho > 1.0) {
452 else normalizedRho = 1.0;
455 sum += projectedDigit.energy * std::conj(
zernikeValue(normalizedRho, projectedDigit.alpha, n, m));
457 return (n + 1.0) / TMath::Pi() * std::abs(sum) / totalEnergy;
461 const double totalEnergy)
const
463 if (totalEnergy <= 0.0)
return 0.0;
467 for (
const auto projectedDigit : projectedDigits) sum += projectedDigit.energy * projectedDigit.rho * projectedDigit.rho;
469 return sum / totalEnergy;
478 if (centralCellId == 0)
return 0.0;
481 const std::vector< short int > n9 =
m_neighbourMap9->getNeighbours(centralCellId);
483 double energy1 = 0.0;
484 double energy9 = 0.0;
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();
495 if (cellid == centralCellId) {
496 energy1 = weight * energy;
500 const auto it9 = std::find(n9.begin(), n9.end(), cellid);
501 if (it9 != n9.end()) {
502 energy9 += weight * energy;
507 if (energy9 > 1e-9)
return energy1 / energy9;
515 if (centralCellId == 0)
return 0.0;
518 const std::vector< short int > n9 =
m_neighbourMap9->getNeighbours(centralCellId);
519 const std::vector< short int > n21 =
m_neighbourMap21->getNeighbours(centralCellId);
521 double energy9 = 0.0;
522 double energy21 = 0.0;
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();
533 const auto it9 = std::find(n9.begin(), n9.end(), cellid);
534 if (it9 != n9.end()) {
535 energy9 += weight * energy;
539 const auto it21 = std::find(n21.begin(), n21.end(), cellid);
540 if (it21 != n21.end()) {
541 energy21 += weight * energy;
546 if (energy21 > 1e-9)
return energy9 / energy21;
554 for (
auto iType = 0; iType < 2; ++iType)
555 for (
auto iHypothesis = 0; iHypothesis < 10; ++iHypothesis)
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.");
574 B2FATAL(
"Missing corrections for second moments..");
581 double thetadeg = theta * TMath::RadToDeg();
584 if (thetadeg < 0.1) thetadeg = 0.1;
585 else if (thetadeg > 179.9) thetadeg = 179.9;
588 double phideg = phi * TMath::RadToDeg();
591 if (phideg < -179.9) phideg = -179.9;
592 else if (phideg > 179.9) phideg = 179.9;
596 if (hypothesis < 1 or hypothesis > 10) {
597 B2FATAL(
"Invalid hypothesis for second moment corrections.");
603 B2DEBUG(175,
"Second momen theta crrection = " << thetaCorrection <<
", phi correction = " << phiCorrection);
605 return thetaCorrection * phiCorrection;
B2Vector3< DataType > Cross(const B2Vector3< DataType > &p) const
Cross product.
void SetMagThetaPhi(DataType mag, DataType theta, DataType phi)
setter with mag, theta, phi
DataType X() const
access variable X (= .at(0) without boundary check)
DataType Y() const
access variable Y (= .at(1) without boundary check)
DataType Mag() const
The magnitude (rho in spherical coordinate system).
DataType Dot(const B2Vector3< DataType > &p) const
Scalar product.
DataType Angle(const B2Vector3< DataType > &q) const
The angle w.r.t.
Class for accessing objects in the database.
Class to store calibrated ECLDigits: ECLCalDigits.
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.
~ECLShowerShapeModule()
Destructor.
DBArray< ECLShowerShapeSecondMomentCorrection > m_secondMomentCorrectionArray
Shower shape corrections from DB.
std::string m_zernike_MVAidentifier_FWD
Zernike moment MVA - FWD endcap weight-file.
std::unique_ptr< MVA::Expert > m_expert_BRL
Pointer to the current MVA Expert for BRL.
StoreArray< ECLConnectedRegion > m_eclConnectedRegions
StoreArray ECLConnectedRegion.
std::unique_ptr< MVA::SingleDataset > m_dataset
Pointer to the current dataset.
virtual void initialize() override
Initialize.
double computeE1oE9(const ECLShower &) const
Shower shape variable: E1oE9 The energy ratio is calculated taking the weighted central (=1) and the ...
std::unique_ptr< DBObjPtr< DatabaseRepresentationOfWeightfile > > m_weightfile_representation_BRL
Database pointer to the Database representation of the Zernike moment MVA weightfile for BRL.
virtual void event() override
Event.
std::unique_ptr< ECL::ECLNeighbours > m_neighbourMap9
Neighbour map 9 neighbours, for E9oE21 and E1oE9.
double getSecondMomentCorrection(const double theta, const double phi, const int hypothesis) const
Get corrections for second moment.
bool m_zernike_useFarCrystals
Determines if to include or ignore crystals with rho > rho0 in perpendicular plane,...
virtual const char * eclShowerArrayName() const
We need names for the data objects to differentiate between PureCsI and default.
virtual void endRun() override
End run.
std::vector< ProjectedECLDigit > projectECLDigits(const ECLShower &shower) const
Compute projections of the ECLCalDigits to the perpendicular plane.
void initializeMVAweightFiles(const std::string &identifier, std::unique_ptr< DBObjPtr< DatabaseRepresentationOfWeightfile >> &weightFileRepresentation)
initialize MVA weight files from DB
virtual void terminate() override
Terminate.
ECLShowerShapeModule()
Constructor.
std::unique_ptr< MVA::Expert > m_expert_FWD
Pointer to the current MVA Expert for FWD.
const double m_BRLthetaMax
Maximum theta of barrel used for choosing which Zernike MVA to apply.
const unsigned int m_numZernikeMVAvariables
number of variables expected in the Zernike MVA weightfile
std::unique_ptr< DBObjPtr< DatabaseRepresentationOfWeightfile > > m_weightfile_representation_FWD
Database pointer to the Database representation of the Zernike moment MVA weightfile for FWD.
double computeSecondMoment(const std::vector< ProjectedECLDigit > &shower, const double totalEnergy) const
Compute the second moment in the plane perpendicular to the direction of the shower.
virtual void beginRun() override
Begin run.
std::complex< double > zernikeValue(const double rho, const double alpha, const int n, const int m) const
Return the complex value of the Zernike polynomial of rank n,m.
TGraph m_secondMomentCorrections[2][10]
TGraphs that hold the corrections.
std::unique_ptr< ECL::ECLNeighbours > m_neighbourMap21
Neighbour map 21 neighbours, for E9oE21.
double Rnm(const int n, const int m, const double rho) const
The radial part of the Zernike polynomial n,m - Zernike polynomial rank rho - radial distance
double m_zernike_n1_rho0
Scaling factor for radial distances in perpendicular plane, used in Zernike moment calculation for N1...
void prepareSecondMomentCorrectionsCallback()
Prepare corrections for second moment Will be called whenever the m_secondMomentCorrectionArray get u...
void setShowerShapeVariables(ECLShower *eclShower, const bool calculateZernikeMVA) const
Set showr shape variables.
double m_zernike_n2_rho0
Scaling factor for radial distances in perpendicular plane, used in Zernike moment calculation for N2...
std::string m_zernike_MVAidentifier_BRL
Zernike moment MVA - Barrel weight-file.
double m_avgCrystalDimension
Average crystal dimension [cm].
std::string m_zernike_MVAidentifier_BWD
Zernike moment MVA - BWD endcap weight-file.
double computeLateralEnergy(const std::vector< ProjectedECLDigit > &projectedDigits, const double avgCrystalDimension) const
Shower shape variable: Lateral energy.
virtual const char * eclCalDigitArrayName() const
Default name ECLCalDigits.
std::unique_ptr< MVA::Expert > m_expert_BWD
Pointer to the current MVA Expert for BWD.
double computeE9oE21(const ECLShower &) const
Shower shape variable: E9oE21 The energy ratio is calculated taking the weighted 3x3 (=9) and the wei...
@ c_phiType
type of phi identifier
@ c_thetaType
type of theta identifier
void initializeMVA(const std::string &identifier, std::unique_ptr< DBObjPtr< DatabaseRepresentationOfWeightfile >> &weightFileRepresentation, std::unique_ptr< MVA::Expert > &expert)
Load MVA weight file and set pointer of expert.
Corrections to the second moment shower shape.
Class to store ECL Showers.
void setE9oE21(double E9oE21)
Set energy ration E9 over E21.
void setLateralEnergy(double lateralEnergy)
Set Lateral Energy.
double getAbsZernikeMoment(unsigned int n, unsigned int m) const
Get absolute value of Zernike Moment nm.
int getHypothesisId() const
Get Hypothesis Id.
double getPhi() const
Get Phi.
double getEnergy() const
Get Energy.
void setSecondMoment(double secondMoment)
Set second moment.
double getR() const
Get R.
double getE9oE21() const
Get energy ratio E9oE21.
void setAbsZernikeMoment(unsigned int n, unsigned int m, double absZernikeMoment)
Set absolute value of Zernike Moment nm, for nm between 10 and 55.
@ c_neutralHadron
CR is reconstructed as a neutral hadron (N2)
@ c_nPhotons
CR is split into n photons (N1)
int getCentralCellId() const
Get central cell Id.
void setE1oE9(double E1oE9)
Set energy ration E1 over E9.
void setZernikeMVA(double zernikeMVA)
SetZernike MVA value.
double getTheta() const
Get Theta.
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 std::map< std::string, AbstractInterface * > getSupportedInterfaces()
Returns interfaces supported by the MVA Interface.
static void initSupportedInterfaces()
Static function which initliazes all supported interfaces, has to be called once before getSupportedI...
General options which are shared by all MVA trainings.
Wraps the data of a single event into a Dataset.
The Weightfile class serializes all information about a training into an xml tree.
static Weightfile loadFromStream(std::istream &stream)
Static function which deserializes a Weightfile from a stream.
void getOptions(Options &options) const
Fills an Option object from the xml tree.
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.
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
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.
REG_MODULE(arichBtest)
Register the Module.
void addParam(const std::string &name, T ¶mVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
B2Vector3< double > B2Vector3D
typedef for common usage with double
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...
double energy
weighted energy
double rho
radial distance