21 #include "CaloEvent/CaloClusterContainer.h"
22 #include "CaloEvent/CaloCluster.h"
33 #include "CLHEP/Units/SystemOfUnits.h"
35 #include <Eigen/Dense>
56 const std::map<std::string,xAOD::CaloCluster::MomentType> momentNameToEnumMap = {
57 {
"AVG_LAR_Q", AVG_LAR_Q },
58 {
"AVG_TILE_Q", AVG_TILE_Q },
59 {
"BADLARQ_FRAC", BADLARQ_FRAC },
60 {
"BAD_CELLS_CORR_E", BAD_CELLS_CORR_E },
61 {
"CELL_SIGNIFICANCE", CELL_SIGNIFICANCE },
62 {
"CELL_SIG_SAMPLING", CELL_SIG_SAMPLING },
65 {
"CENTER_X", CENTER_X },
66 {
"CENTER_Y", CENTER_Y },
67 {
"CENTER_Z", CENTER_Z },
68 {
"DELTA_ALPHA", DELTA_ALPHA },
69 {
"DELTA_PHI", DELTA_PHI },
70 {
"DELTA_THETA", DELTA_THETA },
71 {
"ENG_BAD_CELLS", ENG_BAD_CELLS },
72 {
"ENG_BAD_HV_CELLS", ENG_BAD_HV_CELLS },
73 {
"ENG_FRAC_CORE", ENG_FRAC_CORE },
74 {
"ENG_FRAC_EM", ENG_FRAC_EM },
75 {
"ENG_FRAC_MAX", ENG_FRAC_MAX },
76 {
"ENG_POS", ENG_POS },
78 {
"FIRST_ETA", FIRST_ETA },
79 {
"FIRST_PHI", FIRST_PHI },
80 {
"ISOLATION", ISOLATION },
81 {
"LATERAL", LATERAL },
82 {
"LONGITUDINAL", LONGITUDINAL },
84 {
"N_BAD_CELLS", N_BAD_CELLS },
85 {
"N_BAD_HV_CELLS", N_BAD_HV_CELLS },
86 {
"N_BAD_CELLS_CORR", N_BAD_CELLS_CORR },
88 {
"SECOND_ENG_DENS", SECOND_ENG_DENS },
91 {
"SECOND_TIME", SECOND_TIME },
92 {
"SIGNIFICANCE", SIGNIFICANCE },
94 {
"NCELL_SAMPLING", NCELL_SAMPLING }
97 const std::map<xAOD::CaloCluster::MomentType,std::string> momentEnumToNameMap = {
98 { AVG_LAR_Q,
"AVG_LAR_Q" },
99 { AVG_TILE_Q,
"AVG_TILE_Q" },
100 { BADLARQ_FRAC,
"BADLARQ_FRAC" },
101 { BAD_CELLS_CORR_E,
"BAD_CELLS_CORR_E" },
102 { CELL_SIGNIFICANCE,
"CELL_SIGNIFICANCE"},
103 { CELL_SIG_SAMPLING,
"CELL_SIG_SAMPLING"},
106 { CENTER_X,
"CENTER_X" },
107 { CENTER_Y,
"CENTER_Y" },
108 { CENTER_Z,
"CENTER_Z" },
109 { DELTA_ALPHA,
"DELTA_ALPHA" },
110 { DELTA_PHI,
"DELTA_PHI" },
111 { DELTA_THETA,
"DELTA_THETA" },
112 { ENG_BAD_CELLS,
"ENG_BAD_CELLS" },
113 { ENG_BAD_HV_CELLS,
"ENG_BAD_HV_CELLS" },
114 { ENG_FRAC_CORE,
"ENG_FRAC_CORE" },
115 { ENG_FRAC_EM,
"ENG_FRAC_EM" },
116 { ENG_FRAC_MAX,
"ENG_FRAC_MAX" },
117 { ENG_POS,
"ENG_POS" },
119 { FIRST_ETA,
"FIRST_ETA" },
120 { FIRST_PHI,
"FIRST_PHI" },
121 { ISOLATION,
"ISOLATION" },
122 { LATERAL,
"LATERAL" },
123 { LONGITUDINAL,
"LONGITUDINAL" },
125 { N_BAD_CELLS,
"N_BAD_CELLS" },
126 { N_BAD_HV_CELLS,
"N_BAD_HV_CELLS" },
127 { N_BAD_CELLS_CORR,
"N_BAD_CELLS_CORR" },
129 { SECOND_ENG_DENS,
"SECOND_ENG_DENS" },
132 { SECOND_TIME,
"SECOND_TIME" },
133 { SIGNIFICANCE,
"SIGNIFICANCE" },
135 { NCELL_SAMPLING,
"NCELL_SAMPLING" }
142 const std::string&
name,
146 m_maxAxisAngle(20*
deg),
148 m_minLLongitudinal(10*
cm),
149 m_minBadLArQuality(4000),
150 m_calculateSignificance(false),
151 m_calculateIsolation(false),
152 m_calculateLArHVFraction(false),
153 m_twoGaussianNoise(false),
154 m_caloDepthTool(
"CaloDepthTool",this),
155 m_larHVFraction(
"LArHVFraction",this),
158 declareInterface<CaloClusterCollectionProcessor> (
this);
188 std::string::size_type nstr(0);
int nmom(0);
192 auto fmap(momentNameToEnumMap.find(
mom));
193 if (fmap != momentNameToEnumMap.end()) {
197 if (fmap->second == SECOND_TIME) {
208 }
else if (fmap->second == NCELL_SAMPLING) {
222 <<
" not calculated in this tool - misconfiguration?");
231 switch (fmap->second) {
233 case CELL_SIGNIFICANCE:
239 case ENG_BAD_HV_CELLS:
249 std::string::size_type lstr(nstr);
251 for (
const auto& fmom : momentNameToEnumMap) {
252 lstr =
std::max(lstr, fmom.first.length());
255 for (
const auto& fmom : momentNameToEnumMap) {
256 sprintf(
buffer,
"moment name: %-*.*s - enumerator: %i", (
int)lstr,
257 (
int)lstr, fmom.first.c_str(), (
int)fmom.second);
260 auto fmom(momentNameToEnumMap.find(
"SECOND_TIME"));
261 sprintf(
buffer,
"moment name: %-*.*s - enumerator: %i", (
int)nstr,
262 (
int)nstr, fmom->first.c_str(), (
int)fmom->second);
264 fmom = momentNameToEnumMap.find(
"NCELL_SAMPLING");
265 sprintf(
buffer,
"moment name: %-*.*s - enumerator: %i", (
int)nstr,
266 (
int)nstr, fmom->first.c_str(), (
int)fmom->second);
268 return StatusCode::FAILURE;
279 ATH_MSG_INFO(
"Construct and save " << nmom <<
" cluster moments: ");
282 sprintf(
buffer,
"moment name: %-*.*s - enumerator: %i", (
int)nstr,
283 (
int)nstr, momentEnumToNameMap.at(menum).c_str(), (
int)menum);
287 auto fmom(momentNameToEnumMap.find(
"SECOND_TIME"));
288 sprintf(
buffer,
"moment name: %-*.*s - enumerator: %i (save only)",
289 (
int)nstr, (
int)nstr, fmom->first.c_str(), (
int)fmom->second);
293 auto fmom(momentNameToEnumMap.find(
"NCELL_SAMPLING"));
294 sprintf(
buffer,
"moment name: %-*.*s - enumerator: %i", (
int)nstr,
295 (
int)nstr, fmom->first.c_str(), (
int)fmom->second);
310 return StatusCode::SUCCESS;
315 return StatusCode::SUCCESS;
349 typedef std::pair<clusterIdx_t, clusterIdx_t> clusterPair_t;
350 std::vector<clusterPair_t> clusterIdx;
371 if (theClusColl->
size() >= noCluster) {
372 msg(MSG::ERROR) <<
"Too many clusters" <<
endmsg;
373 return StatusCode::FAILURE;
378 clusterPair_t(noCluster, noCluster));
385 for(; cellIter != cellIterEnd; cellIter++ ){
391 if ( clusterIdx[(
unsigned int)myHashId].
first != noCluster) {
395 clusterIdx[(
unsigned int)myHashId].
first = iClus;
398 clusterIdx[(
unsigned int)myHashId].
first = iClus;
409 std::vector<CaloClusterMomentsMaker_detail::cellinfo> cellinfo;
414 std::vector<IdentifierHash> theNeighbors;
419 for( ;clusIter!=clusIterEnd;++clusIter,++iClus) {
422 double w(0),xc(0),yc(0),zc(0),
mx(0),
my(0),
mz(0),
mass(0);
423 double eBad(0),ebad_dac(0),ePos(0),eBadLArQ(0),sumSig2(0),maxAbsSig(0);
424 double eLAr2(0),eLAr2Q(0);
425 double eTile2(0),eTile2Q(0);
427 int nbad(0),nbad_dac(0),nBadLArHV(0);
428 unsigned int i,nSigSampl(0);
429 unsigned int theNumOfCells = theCluster->
size();
433 int iCellScndMax(-1);
436 if (cellinfo.capacity() == 0)
437 cellinfo.reserve (theNumOfCells*2);
443 std::fill (myMoments.begin(), myMoments.end(), 0);
444 std::fill (myNorms.begin(), myNorms.end(), 0);
453 for(; cellIter != cellIterEnd; cellIter++ ){
456 const CaloCell* pCell = (*cellIter);
459 double ene = pCell->
e();
471 if ( myCDDE && ! (myCDDE->
is_tile())
473 && !((pCell->
provenance() & 0x0800) == 0x0800)) {
480 if ( myCDDE && myCDDE->
is_tile() ) {
485 if ( ((tq1&0xFF) != 0xFF) && ((tq2&0xFF) != 0xFF) ) {
499 noise->getEffectiveSigma(pCell->
ID(),pCell->
gain(),pCell->
energy()) : \
507 if ( ( std::abs(Sig) > std::abs(maxAbsSig) ) ||
508 ( std::abs(Sig) == std::abs(maxAbsSig) && thisSampl > nSigSampl ) ||
509 ( std::abs(Sig) == std::abs(maxAbsSig) && thisSampl == nSigSampl && Sig > maxAbsSig ) ) {
511 nSigSampl = thisSampl;
516 if ( std::abs(Sig) > std::abs(maxAbsSig) ) {
527 if ( clusterIdx[myHashId].
first == iClus ) {
528 theNeighbors.clear();
530 for (
const auto& nhash: theNeighbors) {
531 clusterPair_t&
idx = clusterIdx[nhash];
534 if (
idx.second == iClus )
continue;
537 if (
idx.first == noCluster ) {
539 }
else if (
idx.first != iClus ) {
547 if ( myCDDE !=
nullptr ) {
550 size_t idx((
size_t)sam);
551 if (
idx >= nCellsSamp.size() ) { nCellsSamp.resize(
idx+1, { 0, 0 } ); }
552 std::get<0>(nCellsSamp[
idx])++;
556 if ( ene > 0. &&
weight > 0) {
563 .eta = myCDDE->
eta(),
564 .phi = myCDDE->
phi(),
567 .volume = myCDDE->
volume(),
578 ci.
energy > cellinfo[iCellMax].energy ||
579 (ci.
energy == cellinfo[iCellMax].energy && ci.
identifier > cellinfo[iCellMax].identifier) ) {
580 iCellScndMax = iCellMax;
581 iCellMax = cellinfo.size()-1;
583 else if (iCellScndMax < 0 ||
584 ci.
energy > cellinfo[iCellScndMax].energy ||
585 (ci.
energy == cellinfo[iCellScndMax].energy && ci.
identifier > cellinfo[iCellScndMax].identifier) )
587 iCellScndMax = cellinfo.size()-1;
591 if (iCellMax < 0 || ci.energy > cellinfo[iCellMax].
energy ) {
592 iCellScndMax = iCellMax;
593 iCellMax = cellinfo.size()-1;
595 else if (iCellScndMax < 0 ||
596 ci.
energy > cellinfo[iCellScndMax].energy )
598 iCellScndMax = cellinfo.size()-1;
606 double dir = ci.
x*ci.
x+ci.
y*ci.
y+ci.
z*ci.
z;
622 eBadLArHV= hvFrac.first;
623 nBadLArHV=hvFrac.second;
657 if ( cellinfo.size() > 2 ) {
660 const double e2 = ci.energy * ci.energy;
662 C(0,0) +=
e2*(ci.x-xc)*(ci.x-xc);
663 C(1,0) +=
e2*(ci.x-xc)*(ci.y-yc);
664 C(2,0) +=
e2*(ci.x-xc)*(ci.z-zc);
666 C(1,1) +=
e2*(ci.y-yc)*(ci.y-yc);
667 C(2,1) +=
e2*(ci.y-yc)*(ci.z-zc);
669 C(2,2) +=
e2*(ci.z-zc)*(ci.z-zc);
674 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eigensolver(
C);
675 if (eigensolver.info() != Eigen::Success) {
676 msg(MSG::WARNING) <<
"Failed to compute Eigenvalues -> Can't determine shower axis" <<
endmsg;
682 const Eigen::Vector3d&
S=eigensolver.eigenvalues();
683 const Eigen::Matrix3d& U=eigensolver.eigenvectors();
685 const double epsilon = 1.E-6;
687 if ( std::abs(
S[0]) >= epsilon && std::abs(
S[1]) >= epsilon && std::abs(
S[2]) >= epsilon ) {
696 double tmpAngle=
Amg::angle(tmpAxis,showerAxis);
698 if ( tmpAngle > 90*
deg ) {
699 tmpAngle = 180*
deg - tmpAngle;
703 if ( iEigen == -1 || tmpAngle <
angle ) {
714 deltaTheta = showerAxis.theta() - prAxis.theta();
723 << prAxis[
Amg::y] <<
", " << prAxis[
Amg::z] <<
") deviates more than "
725 <<
" deg from IP-to-ClusterCenter-axis (" << showerAxis[
Amg::x] <<
", "
726 << showerAxis[
Amg::y] <<
", " << showerAxis[
Amg::z] <<
")");
729 ATH_MSG_DEBUG(
"Eigenvalues close to 0, do not use principal axis");
735 << showerAxis[
Amg::y] <<
", " << showerAxis[
Amg::z] <<
")");
742 for (
auto& ci : cellinfo) {
745 ci.r = ((currentCell-showerCenter).cross(showerAxis)).
mag();
747 ci.lambda = (currentCell-showerCenter).
dot(showerAxis);
753 double commonNorm = 0;
754 double phi0 = cellinfo.size() > 0 ? cellinfo[0].phi : 0;
756 for(
unsigned i=0;
i<cellinfo.size();
i++) {
776 myMoments[iMoment] += ci.
energy*ci.
r*ci.
r;
782 if ( (
int)
i != iCellMax && (
int)
i != iCellScndMax ) {
783 myMoments[iMoment] += ci.
energy*ci.
r*ci.
r;
784 myNorms[iMoment] += ci.
energy*ci.
r*ci.
r;
790 myNorms[iMoment] += rm*rm*ci.
energy;
794 if ( (
int)
i != iCellMax && (
int)
i != iCellScndMax ) {
802 myNorms[iMoment] += lm*lm*ci.
energy;
808 myNorms[iMoment] += ci.
energy;
811 case SECOND_ENG_DENS:
814 myNorms[iMoment] += ci.
energy;
825 myMoments[iMoment] += ci.
energy;
828 if ( (
int)
i == iCellMax )
829 myMoments[iMoment] = ci.
energy;
836 myNorms[iMoment] += ci.
energy;
859 myNorms[iMoment] = commonNorm;
865 myMoments[iMoment] = deltaTheta;
868 myMoments[iMoment] =
angle;
871 myMoments[iMoment] = showerCenter.x();
874 myMoments[iMoment] = showerCenter.y();
877 myMoments[iMoment] = showerCenter.z();
880 myMoments[iMoment] = showerCenter.mag();
890 double r_calo(0),z_calo(0),lambda_c(0);
915 if ( z_calo != 0 && showerAxis.z() != 0 ) {
916 lambda_c = std::abs((z_calo-showerCenter.z())/showerAxis.z());
920 double r_s2 = showerAxis.x()*showerAxis.x()
921 +showerAxis.y()*showerAxis.y();
922 double r_cs = showerAxis.x()*showerCenter.x()
923 +showerAxis.y()*showerCenter.y();
924 double r_cr = showerCenter.x()*showerCenter.x()
925 +showerCenter.y()*showerCenter.y()-r_calo*r_calo;
927 double det = r_cs*r_cs/(r_s2*r_s2) - r_cr/r_s2;
930 double l1(-r_cs/r_s2);
934 if ( std::abs(
l1) < std::abs(
l2) )
935 lambda_c = std::abs(
l1);
937 lambda_c = std::abs(
l2);
941 myMoments[iMoment] = lambda_c;
946 myMoments[iMoment] += maxSampE[
i];
947 myNorms[iMoment] = commonNorm;
956 const double eSample = theCluster->
eSample(
s);
958 int nAll = nbEmpty[
i]+nbNonEmpty[
i];
960 myMoments[iMoment] += (eSample*nbEmpty[
i])/nAll;
961 myNorms[iMoment] += eSample;
969 myMoments[iMoment] = eBad;
972 myMoments[iMoment] = nbad;
974 case N_BAD_CELLS_CORR:
975 myMoments[iMoment] = nbad_dac;
977 case BAD_CELLS_CORR_E:
978 myMoments[iMoment] = ebad_dac;
981 myMoments[iMoment] = eBadLArQ/(theCluster->
e()!=0.?theCluster->
e():1.);
984 myMoments[iMoment] = ePos;
987 myMoments[iMoment] = (sumSig2>0?theCluster->
e()/sqrt(sumSig2):0.);
989 case CELL_SIGNIFICANCE:
990 myMoments[iMoment] = maxAbsSig;
992 case CELL_SIG_SAMPLING:
993 myMoments[iMoment] = nSigSampl;
996 myMoments[iMoment] = eLAr2Q/(eLAr2>0?eLAr2:1);
999 myMoments[iMoment] = eTile2Q/(eTile2>0?eTile2:1);
1001 case ENG_BAD_HV_CELLS:
1002 myMoments[iMoment] = eBadLArHV;
1004 case N_BAD_HV_CELLS:
1005 myMoments[iMoment] = nBadLArHV;
1008 myMoments[iMoment] = sqrt(myMoments[iMoment]);
1011 myMoments[iMoment] =
mass;
1022 for (
size_t iMoment = 0; iMoment !=
size; ++iMoment) {
1024 if ( myNorms[iMoment] != 0 )
1025 myMoments[iMoment] /= myNorms[iMoment];
1026 if ( moment == FIRST_PHI )
1035 for (
size_t isam(0); isam < nCellsSamp.size(); ++isam ) {
1037 if ( isam == (
size_t)
CaloCell_ID::EME2 && std::get<1>(nCellsSamp.at(isam)) > 0 ) {
1045 return StatusCode::SUCCESS;