21 #include "GaudiKernel/ITHistSvc.h"
42 coerceToIntRange(
double v){
45 auto d = std::clamp(
v, minint, maxint);
47 return {
static_cast<int>(
d),
d !=
v};
53 const std::array<std::regex, NnClusterizationFactory::kNNetworkTypes>
57 std::regex(
"^ImpactPointErrorsX([0-9])(|/|_.*)$"),
58 std::regex(
"^ImpactPointErrorsY([0-9])(|/|_.*)$"),
62 const std::string&
n,
const IInterface*
p)
64 declareInterface<NnClusterizationFactory>(
this);
83 std::smatch match_result;
84 for(
const std::string &nn_name :
m_nnOrder) {
86 for (
unsigned int network_i=0; network_i<
kNNetworkTypes; ++network_i) {
87 if (std::regex_match( nn_name, match_result,
m_nnNames[network_i])) {
93 ATH_MSG_ERROR(
"Regex and match group of particle multiplicity do not coincide (groups=" << match_result.size()
95 <<
"; type=" << network_i <<
")");
98 if (n_particles<=0 or
static_cast<unsigned int>(n_particles)>
m_maxSubClusters) {
101 return StatusCode::FAILURE;
103 if (
static_cast<unsigned int>(n_particles)>=
m_NNId[network_i-1].
size()) {
104 m_NNId[network_i-1].resize( n_particles );
106 m_NNId[network_i-1][n_particles-1] = nn_id;
109 m_NNId[network_i-1].resize(1);
111 m_NNId[network_i-1][0] = nn_id;
120 ATH_MSG_ERROR(
"No NN specified to estimate the number of particles.");
121 return StatusCode::FAILURE;
125 unsigned int type_i=0;
126 for (std::vector<unsigned int> &nn_id :
m_NNId) {
130 return StatusCode::FAILURE;
134 return StatusCode::FAILURE;
136 unsigned int n_particles=0;
137 for (
unsigned int &a_nn_id : nn_id ) {
139 if ((a_nn_id==0) or (a_nn_id>
m_nnOrder.size())) {
141 return StatusCode::FAILURE;
150 return StatusCode::SUCCESS;
157 const auto invalidValue{std::numeric_limits<double>::quiet_NaN()};
158 std::vector<double> inputData(vectorSize, invalidValue);
159 size_t vectorIndex{0};
162 inputData[vectorIndex++] =
input.matrixOfToT[
u][
s];
166 inputData[vectorIndex++] =
input.vectorOfPitchesY[
s];
168 inputData[vectorIndex++] =
input.ClusterPixLayer;
169 inputData[vectorIndex++] =
input.ClusterPixBarrelEC;
170 inputData[vectorIndex++] =
input.phi;
171 inputData[vectorIndex++] =
input.theta;
172 if (not
input.useTrackInfo) inputData[vectorIndex] =
input.etaModule;
179 const auto invalidValue{std::numeric_limits<double>::quiet_NaN()};
180 std::vector<double> inputData(vectorSize, invalidValue);
181 size_t vectorIndex{0};
192 const double rawPitch(
input.vectorOfPitchesY[
s]);
194 if (std::isnan(normPitch)){
197 inputData[vectorIndex++] = normPitch;
201 if (
input.useTrackInfo){
221 Eigen::VectorXd valuesVector( vecSize );
227 for (
const auto & xvec:
input.matrixOfToT){
228 for (
const auto & xyElement : xvec){
229 valuesVector[location++] = xyElement;
232 for (
const auto & pitch :
input.vectorOfPitchesY) {
233 valuesVector[location++] = pitch;
235 valuesVector[location] =
input.ClusterPixLayer;
237 valuesVector[location] =
input.ClusterPixBarrelEC;
239 valuesVector[location] =
input.phi;
241 valuesVector[location] =
input.theta;
243 if (!
input.useTrackInfo) {
244 valuesVector[location] =
input.etaModule;
249 std::vector<Eigen::VectorXd> vectorOfEigen;
250 vectorOfEigen.push_back(valuesVector);
251 return vectorOfEigen;
259 if (!
input)
return {};
265 if (!nn_collection.
isValid()) {
284 if (!
input)
return {};
291 if (!nn_collection.
isValid()) {
304 const std::vector<double>& inputData)
const{
306 std::vector<double> resultNN_TTN{};
313 ATH_MSG_FATAL(
"NnClusterizationFactory::estimateNumberOfParticlesTTN: nullptr returned for TrainedNetwork");
318 ATH_MSG_VERBOSE(
" TTN Prob of n. particles (1): " << resultNN_TTN[0] <<
319 " (2): " << resultNN_TTN[1] <<
320 " (3): " << resultNN_TTN[2]);
327 std::vector<double>
result(3,0.0);
329 if (!lwtnn_collection.
isValid()) {
333 if (lwtnn_collection->empty()){
345 const auto inverseSum = 1./(num0+num1+num2);
346 result[0] = num0 * inverseSum;
347 result[1] = num1 * inverseSum;
348 result[2] = num2 * inverseSum;
356 std::vector<Amg::Vector2D>
359 std::vector<Amg::MatrixX> &
errors,
360 int numberSubClusters)
const{
372 if (!nn_collection.
isValid()) {
385 std::vector<Amg::Vector2D>
389 std::vector<Amg::MatrixX> &
errors,
390 int numberSubClusters)
const{
395 if (!
input)
return {};
402 if (!nn_collection.
isValid()) {
413 std::vector<Amg::Vector2D>
415 const std::vector<double>& inputData,
418 int numberSubClusters,
419 std::vector<Amg::MatrixX> &
errors)
const{
421 std::vector<Amg::Vector2D> allPositions{};
422 const auto endNnIdx = nn_collection.size();
423 if (numberSubClusters>0 and
static_cast<unsigned int>(numberSubClusters) <
m_maxSubClusters) {
424 const auto subClusterIndex = numberSubClusters-1;
429 if (not(networkIndex < endNnIdx)){
430 ATH_MSG_FATAL(
"estimatePositionsTTN: Requested collection index, "<< networkIndex <<
" is out of range.");
433 auto *
const pNetwork = nn_collection[networkIndex].get();
436 assert( position1P.size() % 2 == 0);
437 for (
unsigned int i=0;
i<position1P.size()/2 ; ++
i) {
441 std::vector<double> inputDataNew=inputData;
442 inputDataNew.reserve( inputDataNew.size() + numberSubClusters*2);
443 assert(
static_cast<unsigned int>(numberSubClusters*2) <= position1P.size() );
444 for (
unsigned int i=0; i<static_cast<unsigned int>(numberSubClusters*2); ++
i) {
445 inputDataNew.push_back(position1P[
i]);
451 if ((not (xNetworkIndex < endNnIdx)) or (not (yNetworkIndex < endNnIdx))){
452 ATH_MSG_FATAL(
"estimatePositionsTTN: A requested collection index, "<< xNetworkIndex <<
" or "<< yNetworkIndex <<
"is out of range.");
455 auto *pxNetwork = nn_collection.at(xNetworkIndex).get();
456 auto *pyNetwork = nn_collection.at(yNetworkIndex).get();
461 std::vector<Amg::MatrixX> errorMatrices1;
463 allPositions.reserve( allPositions.size() + myPosition1.size());
465 for (
unsigned int i=0;
i<myPosition1.size();
i++){
466 allPositions.push_back(myPosition1[
i]);
467 errors.push_back(errorMatrices1[
i]);
474 std::vector<Amg::Vector2D>
478 int numberSubClusters,
479 std::vector<Amg::MatrixX> &
errors)
const {
481 if (not lwtnn_collection.
isValid()) {
485 if (lwtnn_collection->empty()){
491 std::vector<double> positionValues{};
492 std::vector<Amg::MatrixX> errorMatrices;
493 errorMatrices.reserve(numberSubClusters);
494 positionValues.reserve(numberSubClusters * 2);
495 std::size_t outputNode(0);
496 for (
int cluster = 1; cluster < numberSubClusters+1; cluster++) {
499 const auto pNetwork = lwtnn_collection->find(numberSubClusters);
500 const bool validGraph = (pNetwork != lwtnn_collection->end()) and (pNetwork->second !=
nullptr);
501 if (not validGraph) {
502 std::string infoMsg =
"Acceptable numbers of subclusters for the lwtnn collection:\n ";
503 for (
const auto & pair: **lwtnn_collection){
506 infoMsg +=
"\nNumber of subclusters requested : "+
std::to_string(numberSubClusters);
508 ATH_MSG_FATAL(
"estimatePositionsLWTNN: No lwtnn network found for the number of clusters.\n"
509 <<
" If you are outside the valid range for an lwtnn-based configuration, please run with useNNTTrainedNetworks instead.\n Key = "
513 if(numberSubClusters==1) {
515 }
else if(numberSubClusters==2) {
517 }
else if(numberSubClusters==3) {
520 ATH_MSG_FATAL(
"Cannot evaluate LWTNN networks with " << numberSubClusters <<
" numberSubClusters" );
527 Eigen::VectorXd position = lwtnn_collection->at(numberSubClusters)->compute(
input, {}, outputNode);
528 ATH_MSG_DEBUG(
"Testing for numberSubClusters " << numberSubClusters <<
" and cluster " << cluster);
529 for (
int i=0;
i<position.rows();
i++) {
532 positionValues.push_back(position[1]);
533 positionValues.push_back(position[2]);
536 const float rawRmsX = std::sqrt(1.0/position[3]);
537 const float rawRmsY = std::sqrt(1.0/position[4]);
541 ATH_MSG_DEBUG(
" Estimated RMS errors (1) x: " << rmsX <<
", y: " << rmsY);
547 errorMatrices.push_back(erm);
551 errors=std::move(errorMatrices);
558 constexpr
double pitch = 0.05;
559 const double corrected = posPixels * pitch;
565 std::vector<float>& pitches)
const{
566 double p = posPixels + (
m_sizeY - 1) * 0.5;
568 double p_center = -100;
571 if (
p >=
i and
p <= (
i + 1)) p_Y = p_actual + (
p -
i + 0.5) * pitches.at(
i);
572 if (
i == (
m_sizeY - 1) / 2) p_center = p_actual + 0.5 * pitches.at(
i);
573 p_actual += pitches.at(
i);
575 return std::abs(p_Y - p_center);
580 std::vector<double>& outputY,
581 std::vector<Amg::MatrixX>& errorMatrix,
582 int nParticles)
const{
583 int sizeOutputX=outputX.size()/nParticles;
584 int sizeOutputY=outputY.size()/nParticles;
591 errorMatrix.reserve( errorMatrix.size() + nParticles);
592 for (
int i=0;
i<nParticles;
i++){
594 for (
int u=0;
u<sizeOutputX;
u++){
595 sumValuesX+=outputX[
i*sizeOutputX+
u];
598 for (
int u=0;
u<sizeOutputY;
u++){
599 sumValuesY+=outputY[
i*sizeOutputY+
u];
601 ATH_MSG_VERBOSE(
" minimumX: " << minimumX <<
" maximumX: " << maximumX <<
" sizeOutputX " << sizeOutputX);
602 ATH_MSG_VERBOSE(
" minimumY: " << minimumY <<
" maximumY: " << maximumY <<
" sizeOutputY " << sizeOutputY);
604 for (
int u=0;
u<sizeOutputX;
u++){
605 RMSx+=outputX[
i*sizeOutputX+
u]/sumValuesX*
std::pow(minimumX+(maximumX-minimumX)/(
double)(sizeOutputX-2)*(
u-1./2.),2);
607 RMSx=std::sqrt(RMSx);
609 double intervalErrorX=3*RMSx;
611 int minBinX=(
int)(1+(-intervalErrorX-minimumX)/(maximumX-minimumX)*(
double)(sizeOutputX-2));
612 int maxBinX=(
int)(1+(intervalErrorX-minimumX)/(maximumX-minimumX)*(
double)(sizeOutputX-2));
613 if (maxBinX>sizeOutputX-1) maxBinX=sizeOutputX-1;
614 if (minBinX<0) minBinX=0;
617 for (
int u=minBinX;
u<maxBinX+1;
u++){
618 RMSx+=outputX[
i*sizeOutputX+
u]/sumValuesX*
std::pow(minimumX+(maximumX-minimumX)/(
double)(sizeOutputX-2)*(
u-1./2.),2);
620 RMSx=std::sqrt(RMSx);
622 for (
int u=0;
u<sizeOutputY;
u++){
623 RMSy+=outputY[
i*sizeOutputY+
u]/sumValuesY*
std::pow(minimumY+(maximumY-minimumY)/(
double)(sizeOutputY-2)*(
u-1./2.),2);
625 RMSy=std::sqrt(RMSy);
627 double intervalErrorY=3*RMSy;
629 int minBinY=(
int)(1+(-intervalErrorY-minimumY)/(maximumY-minimumY)*(
double)(sizeOutputY-2));
630 int maxBinY=(
int)(1+(intervalErrorY-minimumY)/(maximumY-minimumY)*(
double)(sizeOutputY-2));
631 if (maxBinY>sizeOutputY-1) maxBinY=sizeOutputY-1;
632 if (minBinY<0) minBinY=0;
635 for (
int u=minBinY;
u<maxBinY+1;
u++){
636 RMSy+=outputY[
i*sizeOutputY+
u]/sumValuesY*
std::pow(minimumY+(maximumY-minimumY)/(
double)(sizeOutputY-2)*(
u-1./2.),2);
638 RMSy=std::sqrt(RMSy);
639 ATH_MSG_VERBOSE(
"Computed error, sigma(X) " << RMSx <<
" sigma(Y) " << RMSy );
644 errorMatrix.push_back(erm);
649 std::vector<Amg::Vector2D>
658 ATH_MSG_ERROR(
"Dynamic cast failed at line "<<__LINE__<<
" of NnClusterizationFactory.cxx.");
661 int numParticles=
output.size()/2;
662 int columnWeightedPosition=
input.columnWeightedPosition;
663 int rowWeightedPosition=
input.rowWeightedPosition;
664 ATH_MSG_VERBOSE(
" REF POS columnWeightedPos: " << columnWeightedPosition <<
" rowWeightedPos: " << rowWeightedPosition );
665 bool applyRecentering=
false;
667 applyRecentering=
true;
670 applyRecentering=
true;
672 std::vector<Amg::Vector2D> positions;
673 for (
int u=0;
u<numParticles;
u++){
680 posXid=
output[2*
u]+rowWeightedPosition;
681 posYid=
output[2*
u+1]+columnWeightedPosition;
683 ATH_MSG_VERBOSE(
" N. particle: " <<
u <<
" idx posX " << posXid <<
" posY " << posYid );
685 const auto & [posXid_int, coercedX]=coerceToIntRange(posXid+0.5);
686 const auto & [posYid_int, coercedY]=coerceToIntRange(posYid+0.5);
687 if (coercedX or coercedY){
688 ATH_MSG_WARNING(
"X or Y position value has been limited in range; original values are (" << posXid<<
", "<<posYid<<
")");
691 ATH_MSG_VERBOSE(
" N. particle: " <<
u <<
" TO INTEGER idx posX " << posXid_int <<
" posY " << posYid_int );
693 InDetDD::SiCellId cellIdOfPositionDiscrete=design->cellIdOfPosition(siLocalPositionDiscrete);
694 if ( not cellIdOfPositionDiscrete.
isValid()){
695 ATH_MSG_WARNING(
" Cell is outside validity region with index Y: " << posYid_int <<
" and index X: " << posXid_int <<
". Not foreseen... " );
698 double pitchY = diodeParameters.
width().
xEta();
699 double pitchX = diodeParameters.
width().
xPhi();
701 <<
" Translated weighted position : " << siLocalPositionDiscrete.
xEta() );
703 InDetDD::SiLocalPosition siLocalPositionDiscreteOneRowMoreOneColumnMore(design->positionFromColumnRow(posYid_int+1,posXid_int+1));
704 ATH_MSG_VERBOSE(
" Translated weighted position +1col +1row phi: " << siLocalPositionDiscreteOneRowMoreOneColumnMore.
xPhi()
705 <<
" Translated weighted position +1col +1row eta: " << siLocalPositionDiscreteOneRowMoreOneColumnMore.
xEta() );
708 pitchX*(posXid-(
double)posXid_int));
710 if (
input.ClusterPixBarrelEC == 0){
711 if (not
input.useTrackInfo){
719 siLocalPosition(siLocalPositionDiscrete.
xEta()+pitchY*(posYid-(
double)posYid_int),
720 siLocalPositionDiscrete.
xPhi()+pitchX*(posXid-(
double)posXid_int)+lorentzShift);
721 ATH_MSG_VERBOSE(
" Translated final position phi: " << siLocalPosition.
xPhi() <<
" eta: " << siLocalPosition.
xEta() );
722 const auto halfWidth{design->width()*0.5};
723 if (siLocalPositionDiscrete.
xPhi() > halfWidth){
726 ATH_MSG_WARNING(
" Corrected out of boundary cluster from x(phi): " << siLocalPositionDiscrete.
xPhi()+pitchX*(posXid-(
double)posXid_int)
727 <<
" to: " << halfWidth-1
e-6);
728 }
else if (siLocalPositionDiscrete.
xPhi() < -halfWidth) {
731 ATH_MSG_WARNING(
" Corrected out of boundary cluster from x(phi): " << siLocalPositionDiscrete.
xPhi()+pitchX*(posXid-(
double)posXid_int)
732 <<
" to: " << -halfWidth+1
e-6);
734 positions.emplace_back(siLocalPosition);
744 const double tanl)
const {
745 input.useTrackInfo=
true;
748 localIntersection *= 0.250/
cos(localIntersection.theta());
749 float trackDeltaX = (
float)localIntersection.x();
750 float trackDeltaY = (
float)localIntersection.y();
751 input.theta=std::atan2(trackDeltaY,0.250);
752 input.phi=std::atan2(trackDeltaX,0.250);
762 double & tanl)
const{
781 const PixelID& pixelID = *pixelIDp;
785 ATH_MSG_ERROR(
"Dynamic cast failed at line "<<__LINE__<<
" of NnClusterizationFactory.cxx.");
790 const std::vector<Identifier>& rdos = pCluster.
rdoList();
791 const size_t rdoSize = rdos.size();
793 const std::vector<float>& chList = pCluster.
chargeList();
794 const std::vector<int>& totList = pCluster.
totList();
795 std::vector<float> chListRecreated{};
796 chListRecreated.reserve(rdoSize);
798 std::vector<int>::const_iterator tot = totList.begin();
799 std::vector<Identifier>::const_iterator rdosBegin = rdos.begin();
800 std::vector<Identifier>::const_iterator rdosEnd = rdos.end();
801 std::vector<int> totListRecreated{};
802 totListRecreated.reserve(rdoSize);
803 std::vector<int>::const_iterator totRecreated = totListRecreated.begin();
806 for ( ; rdosBegin!= rdosEnd and tot != totList.end(); ++tot, ++rdosBegin, ++totRecreated ){
815 chListRecreated.push_back(
charge);
816 totListRecreated.push_back(tot0);
819 rdosBegin = rdos.begin();
820 rdosEnd = rdos.end();
822 tot = totList.begin();
823 totRecreated = totListRecreated.begin();
825 std::vector<float>::const_iterator
charge = chListRecreated.begin();
826 std::vector<float>::const_iterator chargeEnd = chListRecreated.end();
827 tot = totListRecreated.begin();
828 std::vector<int>::const_iterator totEnd = totListRecreated.end();
835 for (; (rdosBegin!= rdosEnd) and (
charge != chargeEnd) and (tot != totEnd); ++rdosBegin, ++
charge, ++tot){
841 sumOfWeightedPositions += (*charge)*siLocalPosition;
842 sumOfTot += (*charge);
844 sumOfWeightedPositions += ((
double)(*tot))*siLocalPosition;
845 sumOfTot += (
double)(*tot);
853 sumOfWeightedPositions /= sumOfTot;
856 InDetDD::SiCellId cellIdWeightedPosition=design->cellIdOfPosition(sumOfWeightedPositions);
858 if (!cellIdWeightedPosition.
isValid()){
861 int columnWeightedPosition=cellIdWeightedPosition.
etaIndex();
862 int rowWeightedPosition=cellIdWeightedPosition.
phiIndex();
863 ATH_MSG_VERBOSE(
" weighted pos row: " << rowWeightedPosition <<
" col: " << columnWeightedPosition );
864 int centralIndexX=(
m_sizeX-1)/2;
865 int centralIndexY=(
m_sizeY-1)/2;
866 if (std::abs(rowWeightedPosition-rowMin)>centralIndexX or
867 std::abs(rowWeightedPosition-rowMax)>centralIndexX){
868 ATH_MSG_VERBOSE(
" Cluster too large rowMin" << rowMin <<
" rowMax " << rowMax <<
" centralX " << centralIndexX);
871 if (std::abs(columnWeightedPosition-colMin)>centralIndexY or
872 std::abs(columnWeightedPosition-colMax)>centralIndexY){
873 ATH_MSG_VERBOSE(
" Cluster too large colMin" << colMin <<
" colMax " << colMax <<
" centralY " << centralIndexY);
881 rdosBegin = rdos.begin();
882 charge = chListRecreated.begin();
883 chargeEnd = chListRecreated.end();
884 tot = totListRecreated.begin();
885 ATH_MSG_VERBOSE(
" Putting together the n. " << rdos.size() <<
" rdos into a matrix." );
890 for (;(
charge != chargeEnd) and (rdosBegin!= rdosEnd); ++rdosBegin, ++
charge, ++tot){
892 unsigned int absrow = pixelID.
phi_index(rId)-rowWeightedPosition+centralIndexX;
893 unsigned int abscol = pixelID.
eta_index(rId)-columnWeightedPosition+centralIndexY;
904 double pitchY = diodeParameters.
width().
xEta();
912 input.matrixOfToT[absrow][abscol]*=3;
916 if ( (
input.ClusterPixLayer==0) and (
input.ClusterPixBarrelEC==0)){
917 input.matrixOfToT[absrow][abscol]*=3;
922 if (std::abs(pitchY-0.4)>1
e-5){
923 input.vectorOfPitchesY[abscol]=pitchY;
928 input.useTrackInfo=
false;
936 float trkphicomp = my_track.dot(my_phiax);
937 float trketacomp = my_track.dot(my_etaax);
938 float trknormcomp = my_track.dot(my_normal);
939 double bowphi = std::atan2(trkphicomp,trknormcomp);
940 double boweta = std::atan2(trketacomp,trknormcomp);
942 if(bowphi > M_PI_2) bowphi -=
M_PI;
943 if(bowphi < -M_PI_2) bowphi +=
M_PI;
944 int readoutside = design->readoutSide();
948 if (boweta>M_PI_2) boweta-=
M_PI;
949 if (boweta<-M_PI_2) boweta+=
M_PI;
952 input.rowWeightedPosition=rowWeightedPosition;
953 input.columnWeightedPosition=columnWeightedPosition;
954 ATH_MSG_VERBOSE(
" RowWeightedPosition: " << rowWeightedPosition <<
" ColWeightedPosition: " << columnWeightedPosition );