348 using clusterIdx_t = std::uint16_t;
349 typedef std::pair<clusterIdx_t, clusterIdx_t> clusterPair_t;
350 std::vector<clusterPair_t> clusterIdx;
351 const clusterIdx_t noCluster = std::numeric_limits<clusterIdx_t>::max();
363 int nbEmpty[CaloCell_ID::Unknown];
364 int nbNonEmpty[CaloCell_ID::Unknown];
371 if (theClusColl->
size() >= noCluster) {
372 msg(MSG::ERROR) <<
"Too many clusters" <<
endmsg;
373 return StatusCode::FAILURE;
377 clusterIdx.resize(
m_calo_id->calo_cell_hash_max(),
378 clusterPair_t(noCluster, noCluster));
385 for(; cellIter != cellIterEnd; cellIter++ ){
391 if ( clusterIdx[(
unsigned int)myHashId].first != noCluster) {
393 double weight = cellIter.
weight();
395 clusterIdx[(
unsigned int)myHashId].first = iClus;
398 clusterIdx[(
unsigned int)myHashId].first = iClus;
409 std::vector<CaloClusterMomentsMaker_detail::cellinfo> cellinfo;
410 std::vector<double> maxSampE (CaloCell_ID::Unknown);
413 std::vector<std::tuple<int,int> > nCellsSamp; nCellsSamp.reserve(CaloCell_ID::Unknown);
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);
439 for(i=0;i<(
unsigned int)CaloCell_ID::Unknown;i++)
443 std::fill (myMoments.begin(), myMoments.end(), 0);
444 std::fill (myNorms.begin(), myNorms.end(), 0);
446 std::fill_n(nbNonEmpty, CaloCell_ID::Unknown, 0);
447 std::fill_n(nbEmpty, CaloCell_ID::Unknown, 0);
453 for(; cellIter != cellIterEnd; cellIter++ ){
456 const CaloCell* pCell = (*cellIter);
459 double ene = pCell->
e();
461 double weight = cellIter.
weight();
466 ebad_dac+=ene*weight;
471 if ( myCDDE && ! (myCDDE->
is_tile())
473 && !((pCell->
provenance() & 0x0800) == 0x0800)) {
475 eBadLArQ += ene*weight;
477 eLAr2 += ene*weight*ene*weight;
478 eLAr2Q += ene*weight*ene*weight*pCell->
quality();
480 if ( myCDDE && myCDDE->
is_tile() ) {
481 uint16_t tq = pCell->
quality();
482 uint8_t tq1 = (0xFF00&tq)>>8;
483 uint8_t tq2 = (0xFF&tq);
485 if ( ((tq1&0xFF) != 0xFF) && ((tq2&0xFF) != 0xFF) ) {
486 eTile2 += ene*weight*ene*weight;
489 eTile2Q += ene*weight*ene*weight*(tq1>tq2?tq1:tq2);
499 noise->getEffectiveSigma(pCell->
ID(),pCell->
gain(),pCell->
energy()) : \
500 noise->getNoise(pCell->
ID(),pCell->
gain());
502 sumSig2 += sigma*sigma;
504 double Sig = (sigma>0?ene*weight/sigma:0);
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 ) {
538 ++ nbEmpty[
m_calo_id->calo_sample(nhash)];
539 }
else if ( idx.first != iClus ) {
540 ++ nbNonEmpty[
m_calo_id->calo_sample(nhash)];
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])++;
554 if ( sam == CaloCell_ID::EME2 && std::abs(myCDDE->
eta()) >
m_etaInnerWheel ) { std::get<1>(nCellsSamp[idx])++; }
556 if ( ene > 0. && weight > 0) {
562 .energy = ene*weight,
563 .eta = myCDDE->
eta(),
564 .phi = myCDDE->
phi(),
567 .volume = myCDDE->
volume(),
569 .identifier = cellIter.
index()
582 ci.
energy > cellinfo[iCellMax].energy ||
583 (ci.
energy == cellinfo[iCellMax].energy && ci.
identifier > cellinfo[iCellMax].identifier) ) {
584 iCellScndMax = iCellMax;
585 iCellMax = cellinfo.size()-1;
587 else if (iCellScndMax < 0 ||
588 ci.
energy > cellinfo[iCellScndMax].energy ||
589 (ci.
energy == cellinfo[iCellScndMax].energy && ci.
identifier > cellinfo[iCellScndMax].identifier) )
591 iCellScndMax = cellinfo.size()-1;
595 if (iCellMax < 0 || ci.energy > cellinfo[iCellMax].energy ) {
596 iCellScndMax = iCellMax;
597 iCellMax = cellinfo.size()-1;
599 else if (iCellScndMax < 0 ||
600 ci.
energy > cellinfo[iCellScndMax].energy )
602 iCellScndMax = cellinfo.size()-1;
610 double dir = ci.
x*ci.
x+ci.
y*ci.
y+ci.
z*ci.
z;
626 eBadLArHV= hvFrac.first;
627 nBadLArHV=hvFrac.second;
631 mass = w*w - mx*mx - my*my - mz*mz;
665 if ( cellinfo.size() > 2 ) {
666 Eigen::Matrix3d
C=Eigen::Matrix3d::Zero();
668 const double e2 = ci.energy * ci.energy;
670 C(0,0) += e2*(ci.x-xc)*(ci.x-xc);
671 C(1,0) += e2*(ci.x-xc)*(ci.y-yc);
672 C(2,0) += e2*(ci.x-xc)*(ci.z-zc);
674 C(1,1) += e2*(ci.y-yc)*(ci.y-yc);
675 C(2,1) += e2*(ci.y-yc)*(ci.z-zc);
677 C(2,2) += e2*(ci.z-zc)*(ci.z-zc);
680 C/=(w != 0 ? w : 1.0);
682 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eigensolver(
C);
683 if (eigensolver.info() != Eigen::Success) {
684 msg(MSG::WARNING) <<
"Failed to compute Eigenvalues -> Can't determine shower axis" <<
endmsg;
690 const Eigen::Vector3d& S=eigensolver.eigenvalues();
691 const Eigen::Matrix3d& U=eigensolver.eigenvectors();
693 const double epsilon = 1.E-6;
695 if ( std::abs(S[0]) >= epsilon && std::abs(S[1]) >= epsilon && std::abs(S[2]) >= epsilon ) {
704 double tmpAngle=
Amg::angle(tmpAxis,showerAxis);
706 if ( tmpAngle > 90*
deg ) {
707 tmpAngle = 180*
deg - tmpAngle;
711 if ( iEigen == -1 || tmpAngle <
angle ) {
722 deltaTheta = showerAxis.theta() - prAxis.theta();
731 << prAxis[
Amg::y] <<
", " << prAxis[
Amg::z] <<
") deviates more than "
733 <<
" deg from IP-to-ClusterCenter-axis (" << showerAxis[
Amg::x] <<
", "
734 << showerAxis[
Amg::y] <<
", " << showerAxis[
Amg::z] <<
")");
737 ATH_MSG_DEBUG(
"Eigenvalues close to 0, do not use principal axis");
743 << showerAxis[
Amg::y] <<
", " << showerAxis[
Amg::z] <<
")");
750 for (
auto& ci : cellinfo) {
753 ci.r = ((currentCell-showerCenter).cross(showerAxis)).mag();
755 ci.lambda = (currentCell-showerCenter).
dot(showerAxis);
761 double commonNorm = 0;
762 double phi0 = cellinfo.size() > 0 ? cellinfo[0].phi : 0;
764 for(
unsigned i=0;i<cellinfo.size();i++) {
784 myMoments[iMoment] += ci.
energy*ci.
r*ci.
r;
790 if ( (
int)i != iCellMax && (
int)i != iCellScndMax ) {
791 myMoments[iMoment] += ci.
energy*ci.
r*ci.
r;
792 myNorms[iMoment] += ci.
energy*ci.
r*ci.
r;
798 myNorms[iMoment] += rm*rm*ci.
energy;
802 if ( (
int)i != iCellMax && (
int)i != iCellScndMax ) {
810 myNorms[iMoment] += lm*lm*ci.
energy;
816 myNorms[iMoment] += ci.
energy;
819 case SECOND_ENG_DENS:
822 myNorms[iMoment] += ci.
energy;
826 if ( ci.
sample == CaloCell_ID::EMB1
827 || ci.
sample == CaloCell_ID::EMB2
828 || ci.
sample == CaloCell_ID::EMB3
829 || ci.
sample == CaloCell_ID::EME1
830 || ci.
sample == CaloCell_ID::EME2
831 || ci.
sample == CaloCell_ID::EME3
832 || ci.
sample == CaloCell_ID::FCAL0 )
833 myMoments[iMoment] += ci.
energy;
836 if ( (
int)i == iCellMax )
837 myMoments[iMoment] = ci.
energy;
844 myNorms[iMoment] += ci.
energy;
867 myNorms[iMoment] = commonNorm;
873 myMoments[iMoment] = deltaTheta;
876 myMoments[iMoment] =
angle;
879 myMoments[iMoment] = showerCenter.x();
882 myMoments[iMoment] = showerCenter.y();
885 myMoments[iMoment] = showerCenter.z();
888 myMoments[iMoment] = showerCenter.mag();
898 double r_calo(0),z_calo(0),lambda_c(0);
923 if ( z_calo != 0 && showerAxis.z() != 0 ) {
924 lambda_c = std::abs((z_calo-showerCenter.z())/showerAxis.z());
928 double r_s2 = showerAxis.x()*showerAxis.x()
929 +showerAxis.y()*showerAxis.y();
930 double r_cs = showerAxis.x()*showerCenter.x()
931 +showerAxis.y()*showerCenter.y();
932 double r_cr = showerCenter.x()*showerCenter.x()
933 +showerCenter.y()*showerCenter.y()-r_calo*r_calo;
935 double det = r_cs*r_cs/(r_s2*r_s2) - r_cr/r_s2;
938 double l1(-r_cs/r_s2);
942 if ( std::abs(l1) < std::abs(l2) )
943 lambda_c = std::abs(l1);
945 lambda_c = std::abs(l2);
949 myMoments[iMoment] = lambda_c;
953 for(i=0;i<(int)CaloCell_ID::Unknown;i++)
954 myMoments[iMoment] += maxSampE[i];
955 myNorms[iMoment] = commonNorm;
961 for(
unsigned int i=0; i != CaloSampling::Unknown; ++ i) {
964 const double eSample = theCluster->
eSample(s);
966 int nAll = nbEmpty[i]+nbNonEmpty[i];
968 myMoments[iMoment] += (eSample*nbEmpty[i])/nAll;
969 myNorms[iMoment] += eSample;
977 myMoments[iMoment] = eBad;
980 myMoments[iMoment] = nbad;
982 case N_BAD_CELLS_CORR:
983 myMoments[iMoment] = nbad_dac;
985 case BAD_CELLS_CORR_E:
986 myMoments[iMoment] = ebad_dac;
989 myMoments[iMoment] = eBadLArQ/(theCluster->
e()!=0.?theCluster->
e():1.);
992 myMoments[iMoment] = ePos;
995 myMoments[iMoment] = (sumSig2>0?theCluster->
e()/sqrt(sumSig2):0.);
997 case CELL_SIGNIFICANCE:
998 myMoments[iMoment] = maxAbsSig;
1000 case CELL_SIG_SAMPLING:
1001 myMoments[iMoment] = nSigSampl;
1004 myMoments[iMoment] = eLAr2Q/(eLAr2>0?eLAr2:1);
1007 myMoments[iMoment] = eTile2Q/(eTile2>0?eTile2:1);
1009 case ENG_BAD_HV_CELLS:
1010 myMoments[iMoment] = eBadLArHV;
1012 case N_BAD_HV_CELLS:
1013 myMoments[iMoment] = nBadLArHV;
1016 myMoments[iMoment] = sqrt(myMoments[iMoment]);
1019 myMoments[iMoment] = mass;
1030 for (
size_t iMoment = 0; iMoment != size; ++iMoment) {
1032 if ( myNorms[iMoment] != 0 )
1033 myMoments[iMoment] /= myNorms[iMoment];
1034 if ( moment == FIRST_PHI )
1043 for (
size_t isam(0); isam < nCellsSamp.size(); ++isam ) {
1045 if ( isam == (
size_t)CaloCell_ID::EME2 && std::get<1>(nCellsSamp.at(isam)) > 0 ) {
1053 return StatusCode::SUCCESS;