338 using clusterIdx_t = std::uint16_t;
339 typedef std::pair<clusterIdx_t, clusterIdx_t> clusterPair_t;
340 std::vector<clusterPair_t> clusterIdx;
341 const clusterIdx_t noCluster = std::numeric_limits<clusterIdx_t>::max();
353 int nbEmpty[CaloCell_ID::Unknown];
354 int nbNonEmpty[CaloCell_ID::Unknown];
361 if (theClusColl->
size() >= noCluster) {
362 msg(MSG::ERROR) <<
"Too many clusters" <<
endmsg;
363 return StatusCode::FAILURE;
367 clusterIdx.resize(
m_calo_id->calo_cell_hash_max(),
368 clusterPair_t(noCluster, noCluster));
375 for(; cellIter != cellIterEnd; cellIter++ ){
383 if(hashid >= (signalCells)->
size())
continue;
385 pCell = (*signalCells).findCell(hashid);
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_DigiHSTruth_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();
431 double theClusterEnergy = 0;
432 double theClusterAbsEnergy = 0;
433 double theClusterEta = 0;
434 double theClusterPhi = 0;
435 double theNewSecondTime = 0;
440 int iCellScndMax(-1);
443 if (cellinfo.capacity() == 0)
444 cellinfo.reserve (theNumOfCells*2);
446 double phi0 = theCluster->
phi();
448 for(i=0;i<(
unsigned int)CaloCell_ID::Unknown;i++)
452 std::fill (myMoments.begin(), myMoments.end(), 0);
453 std::fill (myNorms.begin(), myNorms.end(), 0);
455 std::fill_n(nbNonEmpty, CaloCell_ID::Unknown, 0);
456 std::fill_n(nbEmpty, CaloCell_ID::Unknown, 0);
462 for(; cellIter != cellIterEnd; cellIter++ ){
465 const CaloCell* pCell = (*cellIter);
471 if(hashid >= (signalCells)->
size())
continue;
472 pCell = (*signalCells).findCell(hashid);
479 return StatusCode::FAILURE;
481 double ene = pCell->
e();
483 double weight = cellIter.
weight();
485 double cellPhi = myCDDE->
phi();
486 double thePhi =
proxim (cellPhi, phi0);
488 theClusterEnergy += weight * ene;
489 theClusterAbsEnergy += weight*std::abs(ene);
490 theClusterEta += weight*std::abs(ene)*pCell->
eta();
491 theClusterPhi += weight*std::abs(ene)* thePhi;
497 ebad_dac+=ene*weight;
504 && !((pCell->
provenance() & 0x0800) == 0x0800)) {
506 eBadLArQ += ene*weight;
508 eLAr2 += ene*weight*ene*weight;
509 eLAr2Q += ene*weight*ene*weight*pCell->
quality();
512 uint16_t tq = pCell->
quality();
513 uint8_t tq1 = (0xFF00&tq)>>8;
514 uint8_t tq2 = (0xFF&tq);
516 if ( ((tq1&0xFF) != 0xFF) && ((tq2&0xFF) != 0xFF) ) {
517 eTile2 += ene*weight*ene*weight;
520 eTile2Q += ene*weight*ene*weight*(tq1>tq2?tq1:tq2);
533 noise->getEffectiveSigma(pCell->
ID(),pCell->
gain(),pCell->
energy()) : \
534 noise->getNoise(pCell->
ID(),pCell->
gain());
536 sumSig2 += sigma*sigma;
538 double Sig = (sigma>0?ene*weight/sigma:0);
541 if ( ( std::abs(Sig) > std::abs(maxAbsSig) ) ||
542 ( std::abs(Sig) == std::abs(maxAbsSig) && thisSampl > nSigSampl ) ||
543 ( std::abs(Sig) == std::abs(maxAbsSig) && thisSampl == nSigSampl && Sig > maxAbsSig ) ) {
545 nSigSampl = thisSampl;
550 if ( std::abs(Sig) > std::abs(maxAbsSig) ) {
561 if ( clusterIdx[myHashId].first == iClus ) {
562 theNeighbors.clear();
564 for (
const auto& nhash: theNeighbors) {
565 clusterPair_t& idx = clusterIdx[nhash];
568 if ( idx.second == iClus )
continue;
571 if ( idx.first == noCluster ) {
572 ++ nbEmpty[
m_calo_id->calo_sample(nhash)];
573 }
else if ( idx.first != iClus ) {
574 ++ nbNonEmpty[
m_calo_id->calo_sample(nhash)];
582 if (sam != CaloSampling::PreSamplerB &&
583 sam != CaloSampling::PreSamplerE){
584 unsigned int pmask = myCDDE->
is_tile() ? 0x8080 : 0x2000;
588 double theTimeNorm = std::abs(weight) * weight * ene * ene;
589 theNewSecondTime += theTimeNorm * pCell->
time() * pCell->
time();
590 timeNorm += theTimeNorm;
596 if ( ene > 0. && weight > 0) {
602 .energy = ene*weight,
603 .eta = myCDDE->
eta(),
604 .phi = myCDDE->
phi(),
607 .volume = myCDDE->
volume(),
609 .identifier = cellIter.
index()
622 ci.
energy > cellinfo[iCellMax].energy ||
623 (ci.
energy == cellinfo[iCellMax].energy && ci.
identifier > cellinfo[iCellMax].identifier) ) {
624 iCellScndMax = iCellMax;
625 iCellMax = cellinfo.size()-1;
627 else if (iCellScndMax < 0 ||
628 ci.
energy > cellinfo[iCellScndMax].energy ||
629 (ci.
energy == cellinfo[iCellScndMax].energy && ci.
identifier > cellinfo[iCellScndMax].identifier) )
631 iCellScndMax = cellinfo.size()-1;
635 if (iCellMax < 0 || ci.energy > cellinfo[iCellMax].energy ) {
636 iCellScndMax = iCellMax;
637 iCellMax = cellinfo.size()-1;
639 else if (iCellScndMax < 0 ||
640 ci.
energy > cellinfo[iCellScndMax].energy )
642 iCellScndMax = cellinfo.size()-1;
650 double dir = ci.
x*ci.
x+ci.
y*ci.
y+ci.
z*ci.
z;
665 eBadLArHV= hvFrac.first;
666 nBadLArHV=hvFrac.second;
670 mass = w*w - mx*mx - my*my - mz*mz;
704 if ( cellinfo.size() > 2 ) {
705 Eigen::Matrix3d
C=Eigen::Matrix3d::Zero();
707 const double e2 = ci.energy * ci.energy;
709 C(0,0) += e2*(ci.x-xc)*(ci.x-xc);
710 C(1,0) += e2*(ci.x-xc)*(ci.y-yc);
711 C(2,0) += e2*(ci.x-xc)*(ci.z-zc);
713 C(1,1) += e2*(ci.y-yc)*(ci.y-yc);
714 C(2,1) += e2*(ci.y-yc)*(ci.z-zc);
716 C(2,2) += e2*(ci.z-zc)*(ci.z-zc);
719 C/=(w != 0 ? w : 1.0);
721 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eigensolver(
C);
722 if (eigensolver.info() != Eigen::Success) {
723 msg(MSG::WARNING) <<
"Failed to compute Eigenvalues -> Can't determine shower axis" <<
endmsg;
729 const Eigen::Vector3d& S=eigensolver.eigenvalues();
730 const Eigen::Matrix3d& U=eigensolver.eigenvectors();
732 const double epsilon = 1.E-6;
734 if ( std::abs(S[0]) >= epsilon && std::abs(S[1]) >= epsilon && std::abs(S[2]) >= epsilon ) {
743 double tmpAngle=
Amg::angle(tmpAxis,showerAxis);
745 if ( tmpAngle > 90*
deg ) {
746 tmpAngle = 180*
deg - tmpAngle;
750 if ( iEigen == -1 || tmpAngle <
angle ) {
761 deltaTheta = showerAxis.theta() - prAxis.theta();
770 << prAxis[
Amg::y] <<
", " << prAxis[
Amg::z] <<
") deviates more than "
772 <<
" deg from IP-to-ClusterCenter-axis (" << showerAxis[
Amg::x] <<
", "
773 << showerAxis[
Amg::y] <<
", " << showerAxis[
Amg::z] <<
")");
776 ATH_MSG_DEBUG(
"Eigenvalues close to 0, do not use principal axis");
782 << showerAxis[
Amg::y] <<
", " << showerAxis[
Amg::z] <<
")");
789 for (
auto& ci : cellinfo) {
792 ci.r = ((currentCell-showerCenter).cross(showerAxis)).mag();
794 ci.lambda = (currentCell-showerCenter).
dot(showerAxis);
800 double commonNorm = 0;
801 double phi0 = cellinfo.size() > 0 ? cellinfo[0].phi : 0;
803 for(
unsigned i=0;i<cellinfo.size();i++) {
813 case FIRST_ETA_DigiHSTruth:
816 case FIRST_PHI_DigiHSTruth:
822 case SECOND_R_DigiHSTruth:
823 myMoments[iMoment] += ci.
energy*ci.
r*ci.
r;
825 case SECOND_LAMBDA_DigiHSTruth:
828 case LATERAL_DigiHSTruth:
829 if ( (
int)i != iCellMax && (
int)i != iCellScndMax ) {
830 myMoments[iMoment] += ci.
energy*ci.
r*ci.
r;
831 myNorms[iMoment] += ci.
energy*ci.
r*ci.
r;
837 myNorms[iMoment] += rm*rm*ci.
energy;
840 case LONGITUDINAL_DigiHSTruth:
841 if ( (
int)i != iCellMax && (
int)i != iCellScndMax ) {
849 myNorms[iMoment] += lm*lm*ci.
energy;
852 case FIRST_ENG_DENS_DigiHSTruth:
855 myNorms[iMoment] += ci.
energy;
858 case SECOND_ENG_DENS_DigiHSTruth:
861 myNorms[iMoment] += ci.
energy;
864 case ENG_FRAC_EM_DigiHSTruth:
865 if ( ci.
sample == CaloCell_ID::EMB1
866 || ci.
sample == CaloCell_ID::EMB2
867 || ci.
sample == CaloCell_ID::EMB3
868 || ci.
sample == CaloCell_ID::EME1
869 || ci.
sample == CaloCell_ID::EME2
870 || ci.
sample == CaloCell_ID::EME3
871 || ci.
sample == CaloCell_ID::FCAL0 )
872 myMoments[iMoment] += ci.
energy;
874 case ENG_FRAC_MAX_DigiHSTruth:
875 if ( (
int)i == iCellMax )
876 myMoments[iMoment] = ci.
energy;
878 case PTD_DigiHSTruth:
883 myNorms[iMoment] += ci.
energy;
899 case FIRST_ETA_DigiHSTruth:
900 case FIRST_PHI_DigiHSTruth:
901 case SECOND_R_DigiHSTruth:
902 case SECOND_LAMBDA_DigiHSTruth:
903 case ENG_FRAC_EM_DigiHSTruth:
904 case ENG_FRAC_MAX_DigiHSTruth:
905 myNorms[iMoment] = commonNorm;
907 case DELTA_PHI_DigiHSTruth:
910 case DELTA_THETA_DigiHSTruth:
911 myMoments[iMoment] = deltaTheta;
913 case DELTA_ALPHA_DigiHSTruth:
914 myMoments[iMoment] =
angle;
916 case CENTER_X_DigiHSTruth:
917 myMoments[iMoment] = showerCenter.x();
919 case CENTER_Y_DigiHSTruth:
920 myMoments[iMoment] = showerCenter.y();
922 case CENTER_Z_DigiHSTruth:
923 myMoments[iMoment] = showerCenter.z();
925 case CENTER_MAG_DigiHSTruth:
926 myMoments[iMoment] = showerCenter.mag();
928 case CENTER_LAMBDA_DigiHSTruth:
936 double r_calo(0),z_calo(0),lambda_c(0);
961 if ( z_calo != 0 && showerAxis.z() != 0 ) {
962 lambda_c = std::abs((z_calo-showerCenter.z())/showerAxis.z());
966 double r_s2 = showerAxis.x()*showerAxis.x()
967 +showerAxis.y()*showerAxis.y();
968 double r_cs = showerAxis.x()*showerCenter.x()
969 +showerAxis.y()*showerCenter.y();
970 double r_cr = showerCenter.x()*showerCenter.x()
971 +showerCenter.y()*showerCenter.y()-r_calo*r_calo;
973 double det = r_cs*r_cs/(r_s2*r_s2) - r_cr/r_s2;
976 double l1(-r_cs/r_s2);
980 if ( std::abs(l1) < std::abs(l2) )
981 lambda_c = std::abs(l1);
983 lambda_c = std::abs(l2);
987 myMoments[iMoment] = lambda_c;
990 case ENG_FRAC_CORE_DigiHSTruth:
991 for(i=0;i<(int)CaloCell_ID::Unknown;i++)
992 myMoments[iMoment] += maxSampE[i];
993 myNorms[iMoment] = commonNorm;
995 case ISOLATION_DigiHSTruth:
999 for(
unsigned int i=0; i != CaloSampling::Unknown; ++ i) {
1002 const double eSample = theCluster->
eSample(s);
1004 int nAll = nbEmpty[i]+nbNonEmpty[i];
1006 myMoments[iMoment] += (eSample*nbEmpty[i])/nAll;
1007 myNorms[iMoment] += eSample;
1014 case ENG_BAD_CELLS_DigiHSTruth:
1015 myMoments[iMoment] = eBad;
1017 case N_BAD_CELLS_DigiHSTruth:
1018 myMoments[iMoment] = nbad;
1020 case N_BAD_CELLS_CORR_DigiHSTruth:
1021 myMoments[iMoment] = nbad_dac;
1023 case BAD_CELLS_CORR_E_DigiHSTruth:
1024 myMoments[iMoment] = ebad_dac;
1026 case BADLARQ_FRAC_DigiHSTruth:
1027 myMoments[iMoment] = eBadLArQ/(theCluster->
e()!=0.?theCluster->
e():1.);
1029 case ENG_POS_DigiHSTruth:
1030 myMoments[iMoment] = ePos;
1032 case SIGNIFICANCE_DigiHSTruth:
1033 myMoments[iMoment] = (sumSig2>0?theCluster->
e()/sqrt(sumSig2):0.);
1035 case CELL_SIGNIFICANCE_DigiHSTruth:
1036 myMoments[iMoment] = maxAbsSig;
1038 case CELL_SIG_SAMPLING_DigiHSTruth:
1039 myMoments[iMoment] = nSigSampl;
1041 case AVG_LAR_Q_DigiHSTruth:
1042 myMoments[iMoment] = eLAr2Q/(eLAr2>0?eLAr2:1);
1044 case AVG_TILE_Q_DigiHSTruth:
1045 myMoments[iMoment] = eTile2Q/(eTile2>0?eTile2:1);
1047 case ENG_BAD_HV_CELLS_DigiHSTruth:
1048 myMoments[iMoment] = eBadLArHV;
1050 case N_BAD_HV_CELLS_DigiHSTruth:
1051 myMoments[iMoment] = nBadLArHV;
1053 case PTD_DigiHSTruth:
1054 myMoments[iMoment] = sqrt(myMoments[iMoment]);
1056 case MASS_DigiHSTruth:
1057 myMoments[iMoment] = mass;
1059 case ENERGY_DigiHSTruth:
1060 myMoments[iMoment] = theClusterEnergy;
1062 case ETA_DigiHSTruth:
1063 if(theClusterAbsEnergy > 0)
1064 myMoments[iMoment] = theClusterEta / theClusterAbsEnergy;
1066 myMoments[iMoment] = 0;
1069 case PHI_DigiHSTruth:
1070 if(theClusterAbsEnergy > 0)
1073 myMoments[iMoment] = 0;
1085 for (
size_t iMoment = 0; iMoment !=
size; ++iMoment) {
1087 if ( myNorms[iMoment] != 0 )
1088 myMoments[iMoment] /= myNorms[iMoment];
1089 if ( moment == FIRST_PHI_DigiHSTruth )
1096 double secondTime(0.0);
1098 secondTime = theNewSecondTime/timeNorm-theCluster->
time()*theCluster->
time();
1105 return StatusCode::SUCCESS;