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;
337 if (useGPUCriteria) {
365 typedef std::pair<clusterIdx_t, clusterIdx_t> clusterPair_t;
366 std::vector<clusterPair_t> clusterIdx;
387 if (theClusColl->
size() >= noCluster) {
388 msg(MSG::ERROR) <<
"Too many clusters" <<
endmsg;
389 return StatusCode::FAILURE;
394 clusterPair_t(noCluster, noCluster));
401 for(; cellIter != cellIterEnd; cellIter++ ){
407 if ( clusterIdx[(
unsigned int)myHashId].
first != noCluster) {
411 clusterIdx[(
unsigned int)myHashId].
first = iClus;
414 clusterIdx[(
unsigned int)myHashId].
first = iClus;
425 std::vector<CaloClusterMomentsMaker_detail::cellinfo> cellinfo;
430 std::vector<IdentifierHash> theNeighbors;
435 for( ;clusIter!=clusIterEnd;++clusIter,++iClus) {
438 double w(0),xc(0),yc(0),zc(0),
mx(0),
my(0),
mz(0),
mass(0);
439 double eBad(0),ebad_dac(0),ePos(0),eBadLArQ(0),sumSig2(0),maxAbsSig(0);
440 double eLAr2(0),eLAr2Q(0);
441 double eTile2(0),eTile2Q(0);
443 int nbad(0),nbad_dac(0),nBadLArHV(0);
444 unsigned int ncell(0),
i,nSigSampl(0);
445 unsigned int theNumOfCells = theCluster->
size();
449 int iCellScndMax(-1);
451 if (cellinfo.capacity() == 0)
452 cellinfo.reserve (theNumOfCells*2);
459 std::fill (myMoments.begin(), myMoments.end(), 0);
460 std::fill (myNorms.begin(), myNorms.end(), 0);
469 for(; cellIter != cellIterEnd; cellIter++ ){
472 const CaloCell* pCell = (*cellIter);
475 double ene = pCell->
e();
487 if ( myCDDE && ! (myCDDE->
is_tile())
489 && !((pCell->
provenance() & 0x0800) == 0x0800)) {
496 if ( myCDDE && myCDDE->
is_tile() ) {
501 if ( ((tq1&0xFF) != 0xFF) && ((tq2&0xFF) != 0xFF) ) {
515 noise->getEffectiveSigma(pCell->
ID(),pCell->
gain(),pCell->
energy()) : \
523 if ( ( std::abs(Sig) > std::abs(maxAbsSig) ) ||
524 ( std::abs(Sig) == std::abs(maxAbsSig) && thisSampl > nSigSampl ) ||
525 ( std::abs(Sig) == std::abs(maxAbsSig) && thisSampl == nSigSampl && Sig > maxAbsSig ) ) {
527 nSigSampl = thisSampl;
532 if ( std::abs(Sig) > std::abs(maxAbsSig) ) {
543 if ( clusterIdx[myHashId].
first == iClus ) {
544 theNeighbors.clear();
546 for (
const auto& nhash: theNeighbors) {
547 clusterPair_t&
idx = clusterIdx[nhash];
550 if (
idx.second == iClus )
continue;
553 if (
idx.first == noCluster ) {
555 }
else if (
idx.first != iClus ) {
563 if ( myCDDE !=
nullptr ) {
566 size_t idx((
size_t)sam);
567 if (
idx >= nCellsSamp.size() ) { nCellsSamp.resize(
idx+1, { 0, 0 } ); }
568 std::get<0>(nCellsSamp[
idx])++;
572 if ( ene > 0. &&
weight > 0) {
590 ci.
energy > cellinfo[iCellMax].energy ||
591 (ci.
energy == cellinfo[iCellMax].energy && ci.
identifier > cellinfo[iCellMax].identifier) ) {
592 iCellScndMax = iCellMax;
595 else if (iCellScndMax < 0 ||
596 ci.
energy > cellinfo[iCellScndMax].energy ||
597 (ci.
energy == cellinfo[iCellScndMax].energy && ci.
identifier > cellinfo[iCellScndMax].identifier) )
599 iCellScndMax =
ncell;
603 if (iCellMax < 0 || ci.energy > cellinfo[iCellMax].
energy ) {
604 iCellScndMax = iCellMax;
607 else if (iCellScndMax < 0 ||
608 ci.
energy > cellinfo[iCellScndMax].energy )
610 iCellScndMax =
ncell;
618 double dir = ci.
x*ci.
x+ci.
y*ci.
y+ci.
z*ci.
z;
636 eBadLArHV= hvFrac.first;
637 nBadLArHV=hvFrac.second;
677 C(0,0) +=
e2*(ci.
x-xc)*(ci.
x-xc);
678 C(1,0) +=
e2*(ci.
x-xc)*(ci.
y-yc);
679 C(2,0) +=
e2*(ci.
x-xc)*(ci.
z-zc);
681 C(1,1) +=
e2*(ci.
y-yc)*(ci.
y-yc);
682 C(2,1) +=
e2*(ci.
y-yc)*(ci.
z-zc);
684 C(2,2) +=
e2*(ci.
z-zc)*(ci.
z-zc);
689 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eigensolver(
C);
690 if (eigensolver.info() != Eigen::Success) {
691 msg(MSG::WARNING) <<
"Failed to compute Eigenvalues -> Can't determine shower axis" <<
endmsg;
697 const Eigen::Vector3d&
S=eigensolver.eigenvalues();
698 const Eigen::Matrix3d& U=eigensolver.eigenvectors();
700 const double epsilon = 1.E-6;
702 if ( std::abs(
S[0]) >= epsilon && std::abs(
S[1]) >= epsilon && std::abs(
S[2]) >= epsilon ) {
711 double tmpAngle=
Amg::angle(tmpAxis,showerAxis);
713 if ( tmpAngle > 90*
deg ) {
714 tmpAngle = 180*
deg - tmpAngle;
718 if ( iEigen == -1 || tmpAngle <
angle ) {
729 deltaTheta = showerAxis.theta() - prAxis.theta();
738 << prAxis[
Amg::y] <<
", " << prAxis[
Amg::z] <<
") deviates more than "
740 <<
" deg from IP-to-ClusterCenter-axis (" << showerAxis[
Amg::x] <<
", "
741 << showerAxis[
Amg::y] <<
", " << showerAxis[
Amg::z] <<
")");
744 ATH_MSG_DEBUG(
"Eigenvalues close to 0, do not use principal axis");
750 << showerAxis[
Amg::y] <<
", " << showerAxis[
Amg::z] <<
")");
757 for (
auto& ci : cellinfo) {
760 ci.r = ((currentCell-showerCenter).cross(showerAxis)).
mag();
762 ci.lambda = (currentCell-showerCenter).
dot(showerAxis);
768 double commonNorm = 0;
769 double phi0 =
ncell > 0 ? cellinfo[0].phi : 0;
791 myMoments[iMoment] += ci.
energy*ci.
r*ci.
r;
797 if ( (
int)
i != iCellMax && (
int)
i != iCellScndMax ) {
798 myMoments[iMoment] += ci.
energy*ci.
r*ci.
r;
799 myNorms[iMoment] += ci.
energy*ci.
r*ci.
r;
805 myNorms[iMoment] += rm*rm*ci.
energy;
809 if ( (
int)
i != iCellMax && (
int)
i != iCellScndMax ) {
817 myNorms[iMoment] += lm*lm*ci.
energy;
823 myNorms[iMoment] += ci.
energy;
826 case SECOND_ENG_DENS:
829 myNorms[iMoment] += ci.
energy;
840 myMoments[iMoment] += ci.
energy;
843 if ( (
int)
i == iCellMax )
844 myMoments[iMoment] = ci.
energy;
851 myNorms[iMoment] += ci.
energy;
874 myNorms[iMoment] = commonNorm;
880 myMoments[iMoment] = deltaTheta;
883 myMoments[iMoment] =
angle;
886 myMoments[iMoment] = showerCenter.x();
889 myMoments[iMoment] = showerCenter.y();
892 myMoments[iMoment] = showerCenter.z();
895 myMoments[iMoment] = showerCenter.mag();
905 double r_calo(0),z_calo(0),lambda_c(0);
930 if ( z_calo != 0 && showerAxis.z() != 0 ) {
931 lambda_c = std::abs((z_calo-showerCenter.z())/showerAxis.z());
935 double r_s2 = showerAxis.x()*showerAxis.x()
936 +showerAxis.y()*showerAxis.y();
937 double r_cs = showerAxis.x()*showerCenter.x()
938 +showerAxis.y()*showerCenter.y();
939 double r_cr = showerCenter.x()*showerCenter.x()
940 +showerCenter.y()*showerCenter.y()-r_calo*r_calo;
942 double det = r_cs*r_cs/(r_s2*r_s2) - r_cr/r_s2;
945 double l1(-r_cs/r_s2);
949 if ( std::abs(
l1) < std::abs(
l2) )
950 lambda_c = std::abs(
l1);
952 lambda_c = std::abs(
l2);
956 myMoments[iMoment] = lambda_c;
961 myMoments[iMoment] += maxSampE[
i];
962 myNorms[iMoment] = commonNorm;
971 const double eSample = theCluster->
eSample(
s);
973 int nAll = nbEmpty[
i]+nbNonEmpty[
i];
975 myMoments[iMoment] += (eSample*nbEmpty[
i])/nAll;
976 myNorms[iMoment] += eSample;
984 myMoments[iMoment] = eBad;
987 myMoments[iMoment] = nbad;
989 case N_BAD_CELLS_CORR:
990 myMoments[iMoment] = nbad_dac;
992 case BAD_CELLS_CORR_E:
993 myMoments[iMoment] = ebad_dac;
996 myMoments[iMoment] = eBadLArQ/(theCluster->
e()!=0.?theCluster->
e():1.);
999 myMoments[iMoment] = ePos;
1002 myMoments[iMoment] = (sumSig2>0?theCluster->
e()/sqrt(sumSig2):0.);
1004 case CELL_SIGNIFICANCE:
1005 myMoments[iMoment] = maxAbsSig;
1007 case CELL_SIG_SAMPLING:
1008 myMoments[iMoment] = nSigSampl;
1011 myMoments[iMoment] = eLAr2Q/(eLAr2>0?eLAr2:1);
1014 myMoments[iMoment] = eTile2Q/(eTile2>0?eTile2:1);
1016 case ENG_BAD_HV_CELLS:
1017 myMoments[iMoment] = eBadLArHV;
1019 case N_BAD_HV_CELLS:
1020 myMoments[iMoment] = nBadLArHV;
1023 myMoments[iMoment] = sqrt(myMoments[iMoment]);
1026 myMoments[iMoment] =
mass;
1037 for (
size_t iMoment = 0; iMoment !=
size; ++iMoment) {
1039 if ( myNorms[iMoment] != 0 )
1040 myMoments[iMoment] /= myNorms[iMoment];
1041 if ( moment == FIRST_PHI )
1050 for (
size_t isam(0); isam < nCellsSamp.size(); ++isam ) {
1052 if ( isam == (
size_t)
CaloCell_ID::EME2 && std::get<1>(nCellsSamp.at(isam)) > 0 ) {
1060 return StatusCode::SUCCESS;