349 using clusterIdx_t = std::uint16_t;
350 typedef std::pair<clusterIdx_t, clusterIdx_t> clusterPair_t;
351 std::vector<clusterPair_t> clusterIdx;
352 const clusterIdx_t noCluster = std::numeric_limits<clusterIdx_t>::max();
364 int nbEmpty[CaloCell_ID::Unknown];
365 int nbNonEmpty[CaloCell_ID::Unknown];
372 if (theClusColl->
size() >= noCluster) {
373 msg(MSG::ERROR) <<
"Too many clusters" <<
endmsg;
374 return StatusCode::FAILURE;
378 clusterIdx.resize(
m_calo_id->calo_cell_hash_max(),
379 clusterPair_t(noCluster, noCluster));
386 for(; cellIter != cellIterEnd; cellIter++ ){
392 if ( clusterIdx[(
unsigned int)myHashId].first != noCluster) {
394 double weight = cellIter.
weight();
396 clusterIdx[(
unsigned int)myHashId].first = iClus;
399 clusterIdx[(
unsigned int)myHashId].first = iClus;
410 std::vector<CaloClusterMomentsMaker_detail::cellinfo> cellinfo;
411 std::vector<double> maxSampE (CaloCell_ID::Unknown);
414 std::vector<std::tuple<int,int> > nCellsSamp; nCellsSamp.reserve(CaloCell_ID::Unknown);
415 std::vector<IdentifierHash> theNeighbors;
420 for( ;clusIter!=clusIterEnd;++clusIter,++iClus) {
423 double w(0),xc(0),yc(0),zc(0),mx(0),my(0),mz(0),mass(0);
424 double eBad(0),ebad_dac(0),ePos(0),eBadLArQ(0),sumSig2(0),maxAbsSig(0);
425 double eLAr2(0),eLAr2Q(0);
426 double eTile2(0),eTile2Q(0);
428 int nbad(0),nbad_dac(0),nBadLArHV(0);
429 unsigned int i,nSigSampl(0);
430 unsigned int theNumOfCells = theCluster->
size();
434 int iCellScndMax(-1);
437 if (cellinfo.capacity() == 0)
438 cellinfo.reserve (theNumOfCells*2);
440 for(i=0;i<(
unsigned int)CaloCell_ID::Unknown;i++)
444 std::fill (myMoments.begin(), myMoments.end(), 0);
445 std::fill (myNorms.begin(), myNorms.end(), 0);
447 std::fill_n(nbNonEmpty, CaloCell_ID::Unknown, 0);
448 std::fill_n(nbEmpty, CaloCell_ID::Unknown, 0);
454 for(; cellIter != cellIterEnd; cellIter++ ){
457 const CaloCell* pCell = (*cellIter);
460 double ene = pCell->
e();
462 double weight = cellIter.
weight();
467 ebad_dac+=ene*weight;
472 if ( myCDDE && ! (myCDDE->
is_tile())
474 && !((pCell->
provenance() & 0x0800) == 0x0800)) {
476 eBadLArQ += ene*weight;
478 eLAr2 += ene*weight*ene*weight;
479 eLAr2Q += ene*weight*ene*weight*pCell->
quality();
481 if ( myCDDE && myCDDE->
is_tile() ) {
482 uint16_t tq = pCell->
quality();
483 uint8_t tq1 = (0xFF00&tq)>>8;
484 uint8_t tq2 = (0xFF&tq);
486 if ( ((tq1&0xFF) != 0xFF) && ((tq2&0xFF) != 0xFF) ) {
487 eTile2 += ene*weight*ene*weight;
490 eTile2Q += ene*weight*ene*weight*(tq1>tq2?tq1:tq2);
503 noise->getEffectiveSigma(pCell->
ID(),pCell->
gain(),pCell->
energy()) : \
504 noise->getNoise(pCell->
ID(),pCell->
gain());
506 sumSig2 += sigma*sigma;
508 double Sig = (sigma>0?ene*weight/sigma:0);
511 if ( ( std::abs(Sig) > std::abs(maxAbsSig) ) ||
512 ( std::abs(Sig) == std::abs(maxAbsSig) && thisSampl > nSigSampl ) ||
513 ( std::abs(Sig) == std::abs(maxAbsSig) && thisSampl == nSigSampl && Sig > maxAbsSig ) ) {
515 nSigSampl = thisSampl;
520 if ( std::abs(Sig) > std::abs(maxAbsSig) ) {
531 if ( clusterIdx[myHashId].first == iClus ) {
532 theNeighbors.clear();
534 for (
const auto& nhash: theNeighbors) {
535 clusterPair_t& idx = clusterIdx[nhash];
538 if ( idx.second == iClus )
continue;
541 if ( idx.first == noCluster ) {
542 ++ nbEmpty[
m_calo_id->calo_sample(nhash)];
543 }
else if ( idx.first != iClus ) {
544 ++ nbNonEmpty[
m_calo_id->calo_sample(nhash)];
551 if ( myCDDE !=
nullptr ) {
554 size_t idx((
size_t)sam);
555 if ( idx >= nCellsSamp.size() ) { nCellsSamp.resize(idx+1, { 0, 0 } ); }
556 std::get<0>(nCellsSamp[idx])++;
558 if ( sam == CaloCell_ID::EME2 && std::abs(myCDDE->
eta()) >
m_etaInnerWheel ) { std::get<1>(nCellsSamp[idx])++; }
560 if ( ene > 0. && weight > 0) {
566 .energy = ene*weight,
567 .eta = myCDDE->
eta(),
568 .phi = myCDDE->
phi(),
571 .volume = myCDDE->
volume(),
573 .identifier = cellIter.
index()
586 ci.
energy > cellinfo[iCellMax].energy ||
587 (ci.
energy == cellinfo[iCellMax].energy && ci.
identifier > cellinfo[iCellMax].identifier) ) {
588 iCellScndMax = iCellMax;
589 iCellMax = cellinfo.size()-1;
591 else if (iCellScndMax < 0 ||
592 ci.
energy > cellinfo[iCellScndMax].energy ||
593 (ci.
energy == cellinfo[iCellScndMax].energy && ci.
identifier > cellinfo[iCellScndMax].identifier) )
595 iCellScndMax = cellinfo.size()-1;
599 if (iCellMax < 0 || ci.energy > cellinfo[iCellMax].energy ) {
600 iCellScndMax = iCellMax;
601 iCellMax = cellinfo.size()-1;
603 else if (iCellScndMax < 0 ||
604 ci.
energy > cellinfo[iCellScndMax].energy )
606 iCellScndMax = cellinfo.size()-1;
614 double dir = ci.
x*ci.
x+ci.
y*ci.
y+ci.
z*ci.
z;
630 eBadLArHV= hvFrac.first;
631 nBadLArHV=hvFrac.second;
635 mass = w*w - mx*mx - my*my - mz*mz;
669 if ( cellinfo.size() > 2 ) {
670 Eigen::Matrix3d
C=Eigen::Matrix3d::Zero();
672 const double e2 = ci.energy * ci.energy;
674 C(0,0) += e2*(ci.x-xc)*(ci.x-xc);
675 C(1,0) += e2*(ci.x-xc)*(ci.y-yc);
676 C(2,0) += e2*(ci.x-xc)*(ci.z-zc);
678 C(1,1) += e2*(ci.y-yc)*(ci.y-yc);
679 C(2,1) += e2*(ci.y-yc)*(ci.z-zc);
681 C(2,2) += e2*(ci.z-zc)*(ci.z-zc);
684 C/=(w != 0 ? w : 1.0);
686 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eigensolver(
C);
687 if (eigensolver.info() != Eigen::Success) {
688 msg(MSG::WARNING) <<
"Failed to compute Eigenvalues -> Can't determine shower axis" <<
endmsg;
694 const Eigen::Vector3d& S=eigensolver.eigenvalues();
695 const Eigen::Matrix3d& U=eigensolver.eigenvectors();
697 const double epsilon = 1.E-6;
699 if ( std::abs(S[0]) >= epsilon && std::abs(S[1]) >= epsilon && std::abs(S[2]) >= epsilon ) {
708 double tmpAngle=
Amg::angle(tmpAxis,showerAxis);
710 if ( tmpAngle > 90*
deg ) {
711 tmpAngle = 180*
deg - tmpAngle;
715 if ( iEigen == -1 || tmpAngle <
angle ) {
726 deltaTheta = showerAxis.theta() - prAxis.theta();
735 << prAxis[
Amg::y] <<
", " << prAxis[
Amg::z] <<
") deviates more than "
737 <<
" deg from IP-to-ClusterCenter-axis (" << showerAxis[
Amg::x] <<
", "
738 << showerAxis[
Amg::y] <<
", " << showerAxis[
Amg::z] <<
")");
741 ATH_MSG_DEBUG(
"Eigenvalues close to 0, do not use principal axis");
747 << showerAxis[
Amg::y] <<
", " << showerAxis[
Amg::z] <<
")");
754 for (
auto& ci : cellinfo) {
757 ci.r = ((currentCell-showerCenter).cross(showerAxis)).mag();
759 ci.lambda = (currentCell-showerCenter).
dot(showerAxis);
765 double commonNorm = 0;
766 double phi0 = cellinfo.size() > 0 ? cellinfo[0].phi : 0;
768 for(
unsigned i=0;i<cellinfo.size();i++) {
788 myMoments[iMoment] += ci.
energy*ci.
r*ci.
r;
794 if ( (
int)i != iCellMax && (
int)i != iCellScndMax ) {
795 myMoments[iMoment] += ci.
energy*ci.
r*ci.
r;
796 myNorms[iMoment] += ci.
energy*ci.
r*ci.
r;
802 myNorms[iMoment] += rm*rm*ci.
energy;
806 if ( (
int)i != iCellMax && (
int)i != iCellScndMax ) {
814 myNorms[iMoment] += lm*lm*ci.
energy;
820 myNorms[iMoment] += ci.
energy;
823 case SECOND_ENG_DENS:
826 myNorms[iMoment] += ci.
energy;
830 if ( ci.
sample == CaloCell_ID::EMB1
831 || ci.
sample == CaloCell_ID::EMB2
832 || ci.
sample == CaloCell_ID::EMB3
833 || ci.
sample == CaloCell_ID::EME1
834 || ci.
sample == CaloCell_ID::EME2
835 || ci.
sample == CaloCell_ID::EME3
836 || ci.
sample == CaloCell_ID::FCAL0 )
837 myMoments[iMoment] += ci.
energy;
840 if ( (
int)i == iCellMax )
841 myMoments[iMoment] = ci.
energy;
848 myNorms[iMoment] += ci.
energy;
871 myNorms[iMoment] = commonNorm;
877 myMoments[iMoment] = deltaTheta;
880 myMoments[iMoment] =
angle;
883 myMoments[iMoment] = showerCenter.x();
886 myMoments[iMoment] = showerCenter.y();
889 myMoments[iMoment] = showerCenter.z();
892 myMoments[iMoment] = showerCenter.mag();
902 double r_calo(0),z_calo(0),lambda_c(0);
927 if ( z_calo != 0 && showerAxis.z() != 0 ) {
928 lambda_c = std::abs((z_calo-showerCenter.z())/showerAxis.z());
932 double r_s2 = showerAxis.x()*showerAxis.x()
933 +showerAxis.y()*showerAxis.y();
934 double r_cs = showerAxis.x()*showerCenter.x()
935 +showerAxis.y()*showerCenter.y();
936 double r_cr = showerCenter.x()*showerCenter.x()
937 +showerCenter.y()*showerCenter.y()-r_calo*r_calo;
939 double det = r_cs*r_cs/(r_s2*r_s2) - r_cr/r_s2;
942 double l1(-r_cs/r_s2);
946 if ( std::abs(l1) < std::abs(l2) )
947 lambda_c = std::abs(l1);
949 lambda_c = std::abs(l2);
953 myMoments[iMoment] = lambda_c;
957 for(i=0;i<(int)CaloCell_ID::Unknown;i++)
958 myMoments[iMoment] += maxSampE[i];
959 myNorms[iMoment] = commonNorm;
965 for(
unsigned int i=0; i != CaloSampling::Unknown; ++ i) {
968 const double eSample = theCluster->
eSample(s);
970 int nAll = nbEmpty[i]+nbNonEmpty[i];
972 myMoments[iMoment] += (eSample*nbEmpty[i])/nAll;
973 myNorms[iMoment] += eSample;
981 myMoments[iMoment] = eBad;
984 myMoments[iMoment] = nbad;
986 case N_BAD_CELLS_CORR:
987 myMoments[iMoment] = nbad_dac;
989 case BAD_CELLS_CORR_E:
990 myMoments[iMoment] = ebad_dac;
993 myMoments[iMoment] = eBadLArQ/(theCluster->
e()!=0.?theCluster->
e():1.);
996 myMoments[iMoment] = ePos;
999 myMoments[iMoment] = (sumSig2>0?theCluster->
e()/sqrt(sumSig2):0.);
1001 case CELL_SIGNIFICANCE:
1002 myMoments[iMoment] = maxAbsSig;
1004 case CELL_SIG_SAMPLING:
1005 myMoments[iMoment] = nSigSampl;
1008 myMoments[iMoment] = eLAr2Q/(eLAr2>0?eLAr2:1);
1011 myMoments[iMoment] = eTile2Q/(eTile2>0?eTile2:1);
1013 case ENG_BAD_HV_CELLS:
1014 myMoments[iMoment] = eBadLArHV;
1016 case N_BAD_HV_CELLS:
1017 myMoments[iMoment] = nBadLArHV;
1020 myMoments[iMoment] = sqrt(myMoments[iMoment]);
1023 myMoments[iMoment] = mass;
1034 for (
size_t iMoment = 0; iMoment !=
size; ++iMoment) {
1036 if ( myNorms[iMoment] != 0 )
1037 myMoments[iMoment] /= myNorms[iMoment];
1038 if ( moment == FIRST_PHI )
1047 for (
size_t isam(0); isam < nCellsSamp.size(); ++isam ) {
1049 if ( isam == (
size_t)CaloCell_ID::EME2 && std::get<1>(nCellsSamp.at(isam)) > 0 ) {
1057 return StatusCode::SUCCESS;