21#include "GaudiKernel/ITHistSvc.h"
24#include <onnxruntime_cxx_api.h>
43 coerceToIntRange(
double v){
44 constexpr double minint = std::numeric_limits<int>::min();
45 constexpr double maxint = std::numeric_limits<int>::max();
46 auto d = std::clamp(v, minint, maxint);
48 return {
static_cast<int>(
d), d != v};
52 constexpr double unsetPos = -100.;
55 constexpr double legacyPhiPitch = 0.05;
60 const std::array<std::regex, NnClusterizationFactory::kNNetworkTypes>
62 std::regex(
"^NumberParticles(|/|_.*)$"),
63 std::regex(
"^ImpactPoints([0-9])P(|/|_.*)$"),
64 std::regex(
"^ImpactPointErrorsX([0-9])(|/|_.*)$"),
65 std::regex(
"^ImpactPointErrorsY([0-9])(|/|_.*)$"),
69 const std::string& n,
const IInterface* p)
71 declareInterface<NnClusterizationFactory>(
this);
89 std::smatch match_result;
90 for(
const std::string &nn_name :
m_nnOrder) {
92 for (
unsigned int network_i=0; network_i<
kNNetworkTypes; ++network_i) {
93 if (std::regex_match( nn_name, match_result,
m_nnNames[network_i])) {
99 ATH_MSG_ERROR(
"Regex and match group of particle multiplicity do not coincide (groups=" << match_result.size()
101 <<
"; type=" << network_i <<
")");
104 if (n_particles<=0 or
static_cast<unsigned int>(n_particles)>
m_maxSubClusters) {
107 return StatusCode::FAILURE;
109 if (
static_cast<unsigned int>(n_particles)>=
m_NNId[network_i-1].
size()) {
110 m_NNId[network_i-1].resize( n_particles );
112 m_NNId[network_i-1][n_particles-1] = nn_id;
115 m_NNId[network_i-1].resize(1);
117 m_NNId[network_i-1][0] = nn_id;
126 ATH_MSG_ERROR(
"No NN specified to estimate the number of particles.");
127 return StatusCode::FAILURE;
131 unsigned int type_i=0;
132 for (std::vector<unsigned int> &nn_id :
m_NNId) {
136 return StatusCode::FAILURE;
140 return StatusCode::FAILURE;
142 unsigned int n_particles=0;
143 for (
unsigned int &a_nn_id : nn_id ) {
145 if ((a_nn_id==0) or (a_nn_id>
m_nnOrder.size())) {
147 return StatusCode::FAILURE;
156 ATH_MSG_FATAL(
"useXPitches=True is only supported with the ONNX backend "
157 "(useONNX=True): the lwtnn VariableOrder and the "
158 "TTrainedNetwork inputs do not include the X pitches.");
159 return StatusCode::FAILURE;
165 return StatusCode::SUCCESS;
172 const auto invalidValue{std::numeric_limits<double>::quiet_NaN()};
173 std::vector<double> inputData(vectorSize, invalidValue);
174 size_t vectorIndex{0};
175 for (
unsigned int u=0;u<
m_sizeX;u++){
176 for (
unsigned int s=0;s<
m_sizeY;s++){
177 inputData[vectorIndex++] = input.matrixOfToT[u][s];
180 for (
unsigned int s=0;s<
m_sizeY;s++){
181 inputData[vectorIndex++] = input.vectorOfPitchesY[s];
183 inputData[vectorIndex++] = input.ClusterPixLayer;
184 inputData[vectorIndex++] = input.ClusterPixBarrelEC;
185 inputData[vectorIndex++] = input.phi;
186 inputData[vectorIndex++] = input.theta;
187 if (not input.useTrackInfo) inputData[vectorIndex] = input.etaModule;
194 const auto invalidValue{std::numeric_limits<double>::quiet_NaN()};
195 std::vector<double> inputData(vectorSize, invalidValue);
196 size_t vectorIndex{0};
197 for (
unsigned int u=0;u<
m_sizeX;u++){
198 for (
unsigned int s=0;s<
m_sizeY;s++){
200 inputData[vectorIndex++] =
norm_rawToT(input.matrixOfToT[u][s]);
202 inputData[vectorIndex++] =
norm_ToT(input.matrixOfToT[u][s]);
206 for (
unsigned int s=0;s<
m_sizeY;s++){
207 const double rawPitch(input.vectorOfPitchesY[s]);
209 if (std::isnan(normPitch)){
212 inputData[vectorIndex++] = normPitch;
215 inputData[vectorIndex++] =
norm_layerType(input.ClusterPixBarrelEC);
216 if (input.useTrackInfo){
217 inputData[vectorIndex++] =
norm_phi(input.phi);
218 inputData[vectorIndex] =
norm_theta(input.theta);
220 inputData[vectorIndex++] =
norm_phiBS(input.phi);
234 const bool appendEtaModule{!
m_useONNX && !input.useTrackInfo};
238 Eigen::VectorXd valuesVector( vecSize );
244 for (
const auto & xvec: input.matrixOfToT){
245 for (
const auto & xyElement : xvec){
246 valuesVector[location++] = xyElement;
249 for (
const auto & pitch : input.vectorOfPitchesY) {
250 valuesVector[location++] = pitch;
253 for (
const auto & pitch : input.vectorOfPitchesX) {
254 valuesVector[location++] = pitch;
257 valuesVector[location] = input.ClusterPixLayer;
259 valuesVector[location] = input.ClusterPixBarrelEC;
261 valuesVector[location] = input.phi;
263 valuesVector[location] = input.theta;
265 if (appendEtaModule) {
266 valuesVector[location] = input.etaModule;
271 std::vector<Eigen::VectorXd> vectorOfEigen;
272 vectorOfEigen.push_back(std::move(valuesVector));
273 return vectorOfEigen;
281 if (!input)
return {};
287 if (!nn_collection.
isValid()) {
309 if (!input)
return {};
316 if (!nn_collection.
isValid()) {
332 const std::vector<double>& inputData)
const{
334 std::vector<double> resultNN_TTN{};
341 ATH_MSG_FATAL(
"NnClusterizationFactory::estimateNumberOfParticlesTTN: nullptr returned for TrainedNetwork");
346 ATH_MSG_VERBOSE(
" TTN Prob of n. particles (1): " << resultNN_TTN[0] <<
347 " (2): " << resultNN_TTN[1] <<
348 " (3): " << resultNN_TTN[2]);
355 std::vector<double> result(3,0.0);
357 if (!lwtnn_collection.
isValid()) {
361 if (lwtnn_collection->empty()){
368 Eigen::VectorXd discriminant = lwtnn_collection->at(0)->compute(input);
369 const double & num0 = discriminant[0];
370 const double & num1 = discriminant[1];
371 const double & num2 = discriminant[2];
373 const auto inverseSum = 1./(num0+num1+num2);
374 result[0] = num0 * inverseSum;
375 result[1] = num1 * inverseSum;
376 result[2] = num2 * inverseSum;
378 " (2): " << result[1] <<
379 " (3): " << result[2]);
384 std::vector<Amg::Vector2D>
387 std::vector<Amg::MatrixX> & errors,
388 int numberSubClusters)
const{
400 if (!nn_collection.
isValid()) {
405 return estimatePositionsTTN(**nn_collection, inputData,input,pCluster,numberSubClusters,errors);
416 std::vector<Amg::Vector2D>
420 std::vector<Amg::MatrixX> & errors,
421 int numberSubClusters)
const{
426 if (!input)
return {};
433 if (!nn_collection.
isValid()) {
437 return estimatePositionsTTN(**nn_collection, inputData,input,pCluster,numberSubClusters,errors);
447 std::vector<Amg::Vector2D>
449 const std::vector<double>& inputData,
452 int numberSubClusters,
453 std::vector<Amg::MatrixX> & errors)
const{
455 std::vector<Amg::Vector2D> allPositions{};
456 const auto endNnIdx = nn_collection.size();
457 if (numberSubClusters>0 and
static_cast<unsigned int>(numberSubClusters) <
m_maxSubClusters) {
458 const auto subClusterIndex = numberSubClusters-1;
463 if (not(networkIndex < endNnIdx)){
464 ATH_MSG_FATAL(
"estimatePositionsTTN: Requested collection index, "<< networkIndex <<
" is out of range.");
467 auto *
const pNetwork = nn_collection[networkIndex].get();
470 assert( position1P.size() % 2 == 0);
471 for (
unsigned int i=0; i<position1P.size()/2 ; ++i) {
472 ATH_MSG_DEBUG(
" Original RAW Estimated positions (" << i <<
") x: " <<
back_posX(position1P[0+i*2],applyRecentering) <<
" y: " <<
back_posY(position1P[1+i*2]));
475 const std::size_t nPositions{
static_cast<std::size_t
>(numberSubClusters*2)};
476 assert( nPositions <= position1P.size() );
478 std::vector<double> inputDataNew;
479 inputDataNew.reserve( inputDataNew.size() + nPositions);
480 inputDataNew.insert(inputDataNew.end(), inputData.begin(), inputData.end());
481 inputDataNew.insert(inputDataNew.end(), position1P.begin(), position1P.begin() + nPositions);
487 if ((not (xNetworkIndex < endNnIdx)) or (not (yNetworkIndex < endNnIdx))){
488 ATH_MSG_FATAL(
"estimatePositionsTTN: A requested collection index, "<< xNetworkIndex <<
" or "<< yNetworkIndex <<
"is out of range.");
491 auto *pxNetwork = nn_collection.at(xNetworkIndex).get();
492 auto *pyNetwork = nn_collection.at(yNetworkIndex).get();
497 std::vector<Amg::MatrixX> errorMatrices1;
499 allPositions.reserve( allPositions.size() + myPosition1.size());
500 errors.reserve( errors.size() + myPosition1.size());
501 for (
unsigned int i=0;i<myPosition1.size();i++){
502 allPositions.push_back(myPosition1[i]);
503 errors.push_back(errorMatrices1[i]);
510 std::vector<Amg::Vector2D>
514 int numberSubClusters,
515 std::vector<Amg::MatrixX> & errors)
const {
517 if (not lwtnn_collection.
isValid()) {
521 if (lwtnn_collection->empty()){
527 std::vector<double> positionValues{};
528 std::vector<Amg::MatrixX> errorMatrices;
529 errorMatrices.reserve(numberSubClusters);
530 positionValues.reserve(numberSubClusters * 2);
531 std::size_t outputNode(0);
532 for (
int cluster = 1; cluster < numberSubClusters+1; cluster++) {
535 const auto pNetwork = lwtnn_collection->find(numberSubClusters);
536 const bool validGraph = (pNetwork != lwtnn_collection->end()) and (pNetwork->second !=
nullptr);
537 if (not validGraph) {
538 std::string infoMsg =
"Acceptable numbers of subclusters for the lwtnn collection:\n ";
539 for (
const auto &
pair: **lwtnn_collection){
540 infoMsg += std::to_string(
pair.first) +
"\n ";
542 infoMsg +=
"\nNumber of subclusters requested : "+ std::to_string(numberSubClusters);
544 ATH_MSG_FATAL(
"estimatePositionsLWTNN: No lwtnn network found for the number of clusters.\n"
545 <<
" If you are outside the valid range for an lwtnn-based configuration, please run with useNNTTrainedNetworks instead.\n Key = "
549 if(numberSubClusters==1) {
551 }
else if(numberSubClusters==2) {
553 }
else if(numberSubClusters==3) {
556 ATH_MSG_FATAL(
"Cannot evaluate LWTNN networks with " << numberSubClusters <<
" numberSubClusters" );
563 Eigen::VectorXd position = lwtnn_collection->at(numberSubClusters)->compute(input, {}, outputNode);
564 ATH_MSG_DEBUG(
"Testing for numberSubClusters " << numberSubClusters <<
" and cluster " << cluster);
565 for (
int i=0; i<position.rows(); i++) {
568 positionValues.push_back(position[1]);
569 positionValues.push_back(position[2]);
572 const float rawRmsX = std::sqrt(1.0/position[3]);
573 const float rawRmsY = std::sqrt(1.0/position[4]);
577 const double rmsX = rawRmsX * legacyPhiPitch;
579 ATH_MSG_DEBUG(
" Estimated RMS errors (1) x: " << rmsX <<
", y: " << rmsY);
585 errorMatrices.push_back(std::move(erm));
589 errors=std::move(errorMatrices);
595 const std::vector<float>& pitches,
596 unsigned int size)
const{
600 double p = posPixels + (
size - 1) * 0.5;
601 double p_pos = unsetPos;
602 double p_center = unsetPos;
604 for (
unsigned int i = 0; i <
size; i++) {
605 if (p >= i and p <= (i + 1)) p_pos = p_actual + (p - i + 0.5) * pitches.at(i);
606 if (i == (
size - 1) / 2) p_center = p_actual + 0.5 * pitches.at(i);
607 p_actual += pitches.at(i);
609 return std::abs(p_pos - p_center);
614 std::vector<double>& outputY,
615 std::vector<Amg::MatrixX>& errorMatrix,
616 int nParticles)
const{
617 int sizeOutputX=outputX.size()/nParticles;
618 int sizeOutputY=outputY.size()/nParticles;
625 errorMatrix.reserve( errorMatrix.size() + nParticles);
626 for (
int i=0;i<nParticles;i++){
628 for (
int u=0;u<sizeOutputX;u++){
629 sumValuesX+=outputX[i*sizeOutputX+u];
632 for (
int u=0;u<sizeOutputY;u++){
633 sumValuesY+=outputY[i*sizeOutputY+u];
635 ATH_MSG_VERBOSE(
" minimumX: " << minimumX <<
" maximumX: " << maximumX <<
" sizeOutputX " << sizeOutputX);
636 ATH_MSG_VERBOSE(
" minimumY: " << minimumY <<
" maximumY: " << maximumY <<
" sizeOutputY " << sizeOutputY);
638 for (
int u=0;u<sizeOutputX;u++){
639 RMSx+=outputX[i*sizeOutputX+u]/sumValuesX*std::pow(minimumX+(maximumX-minimumX)/(
double)(sizeOutputX-2)*(u-1./2.),2);
641 RMSx=std::sqrt(RMSx);
643 double intervalErrorX=3*RMSx;
645 int minBinX=(int)(1+(-intervalErrorX-minimumX)/(maximumX-minimumX)*(
double)(sizeOutputX-2));
646 int maxBinX=(int)(1+(intervalErrorX-minimumX)/(maximumX-minimumX)*(
double)(sizeOutputX-2));
647 if (maxBinX>sizeOutputX-1) maxBinX=sizeOutputX-1;
648 if (minBinX<0) minBinX=0;
651 for (
int u=minBinX;u<maxBinX+1;u++){
652 RMSx+=outputX[i*sizeOutputX+u]/sumValuesX*std::pow(minimumX+(maximumX-minimumX)/(
double)(sizeOutputX-2)*(u-1./2.),2);
654 RMSx=std::sqrt(RMSx);
656 for (
int u=0;u<sizeOutputY;u++){
657 RMSy+=outputY[i*sizeOutputY+u]/sumValuesY*std::pow(minimumY+(maximumY-minimumY)/(
double)(sizeOutputY-2)*(u-1./2.),2);
659 RMSy=std::sqrt(RMSy);
661 double intervalErrorY=3*RMSy;
663 int minBinY=(int)(1+(-intervalErrorY-minimumY)/(maximumY-minimumY)*(
double)(sizeOutputY-2));
664 int maxBinY=(int)(1+(intervalErrorY-minimumY)/(maximumY-minimumY)*(
double)(sizeOutputY-2));
665 if (maxBinY>sizeOutputY-1) maxBinY=sizeOutputY-1;
666 if (minBinY<0) minBinY=0;
669 for (
int u=minBinY;u<maxBinY+1;u++){
670 RMSy+=outputY[i*sizeOutputY+u]/sumValuesY*std::pow(minimumY+(maximumY-minimumY)/(
double)(sizeOutputY-2)*(u-1./2.),2);
672 RMSy=std::sqrt(RMSy);
673 ATH_MSG_VERBOSE(
"Computed error, sigma(X) " << RMSx <<
" sigma(Y) " << RMSy );
678 errorMatrix.push_back(std::move(erm));
683 std::vector<Amg::Vector2D>
692 ATH_MSG_ERROR(
"Dynamic cast failed at line "<<__LINE__<<
" of NnClusterizationFactory.cxx.");
695 int numParticles=output.size()/2;
696 int columnWeightedPosition=input.columnWeightedPosition;
697 int rowWeightedPosition=input.rowWeightedPosition;
698 ATH_MSG_VERBOSE(
" REF POS columnWeightedPos: " << columnWeightedPosition <<
" rowWeightedPos: " << rowWeightedPosition );
699 bool applyRecentering=
false;
701 applyRecentering=
true;
704 applyRecentering=
true;
706 std::vector<Amg::Vector2D> positions;
707 for (
int u=0;u<numParticles;u++){
711 posXid=
back_posX(output[2*u],applyRecentering)+rowWeightedPosition;
712 posYid=
back_posY(output[2*u+1])+columnWeightedPosition;
714 posXid=output[2*u]+rowWeightedPosition;
715 posYid=output[2*u+1]+columnWeightedPosition;
717 ATH_MSG_VERBOSE(
" N. particle: " << u <<
" idx posX " << posXid <<
" posY " << posYid );
719 const auto & [posXid_int, coercedX]=coerceToIntRange(posXid+0.5);
720 const auto & [posYid_int, coercedY]=coerceToIntRange(posYid+0.5);
721 if (coercedX or coercedY){
722 ATH_MSG_WARNING(
"X or Y position value has been limited in range; original values are (" << posXid<<
", "<<posYid<<
")");
725 ATH_MSG_VERBOSE(
" N. particle: " << u <<
" TO INTEGER idx posX " << posXid_int <<
" posY " << posYid_int );
728 if ( not cellIdOfPositionDiscrete.
isValid()){
729 ATH_MSG_WARNING(
" Cell is outside validity region with index Y: " << posYid_int <<
" and index X: " << posXid_int <<
". Not foreseen... " );
732 double pitchY = diodeParameters.
width().
xEta();
733 double pitchX = diodeParameters.
width().
xPhi();
735 <<
" Translated weighted position : " << siLocalPositionDiscrete.
xEta() );
738 ATH_MSG_VERBOSE(
" Translated weighted position +1col +1row phi: " << siLocalPositionDiscreteOneRowMoreOneColumnMore.
xPhi()
739 <<
" Translated weighted position +1col +1row eta: " << siLocalPositionDiscreteOneRowMoreOneColumnMore.
xEta() );
742 pitchX*(posXid-(
double)posXid_int));
744 if (input.ClusterPixBarrelEC == 0){
745 if (not input.useTrackInfo){
753 siLocalPosition(siLocalPositionDiscrete.
xEta()+pitchY*(posYid-(
double)posYid_int),
754 siLocalPositionDiscrete.
xPhi()+pitchX*(posXid-(
double)posXid_int)+lorentzShift);
755 ATH_MSG_VERBOSE(
" Translated final position phi: " << siLocalPosition.
xPhi() <<
" eta: " << siLocalPosition.
xEta() );
756 const auto halfWidth{design->
width()*0.5};
757 if (siLocalPositionDiscrete.
xPhi() > halfWidth){
760 ATH_MSG_WARNING(
" Corrected out of boundary cluster from x(phi): " << siLocalPositionDiscrete.
xPhi()+pitchX*(posXid-(
double)posXid_int)
761 <<
" to: " << halfWidth-1e-6);
762 }
else if (siLocalPositionDiscrete.
xPhi() < -halfWidth) {
765 ATH_MSG_WARNING(
" Corrected out of boundary cluster from x(phi): " << siLocalPositionDiscrete.
xPhi()+pitchX*(posXid-(
double)posXid_int)
766 <<
" to: " << -halfWidth+1e-6);
768 positions.emplace_back(siLocalPosition);
778 const double tanl)
const {
779 input.useTrackInfo=
true;
782 localIntersection *= 0.250/cos(localIntersection.theta());
783 float trackDeltaX = (float)localIntersection.x();
784 float trackDeltaY = (float)localIntersection.y();
785 input.theta=std::atan2(trackDeltaY,0.250);
786 input.phi=std::atan2(trackDeltaX,0.250);
788 input.phi=std::atan(std::tan(input.phi)-tanl);
789 ATH_MSG_VERBOSE(
" From track: angle phi: " << input.phi <<
" theta: " << input.theta );
796 double & tanl)
const{
815 const PixelID& pixelID = *pixelIDp;
819 ATH_MSG_ERROR(
"Dynamic cast failed at line "<<__LINE__<<
" of NnClusterizationFactory.cxx.");
824 const std::vector<Identifier>& rdos = pCluster.
rdoList();
825 const size_t rdoSize = rdos.size();
827 const std::vector<float>& chList = pCluster.
chargeList();
828 const std::vector<int>& totList = pCluster.
totList();
829 std::vector<float> chListRecreated{};
830 chListRecreated.reserve(rdoSize);
832 std::vector<int>::const_iterator tot = totList.begin();
833 std::vector<Identifier>::const_iterator rdosBegin = rdos.begin();
834 std::vector<Identifier>::const_iterator rdosEnd = rdos.end();
835 std::vector<int> totListRecreated{};
836 totListRecreated.reserve(rdoSize);
837 std::vector<int>::const_iterator totRecreated = totListRecreated.begin();
842 for ( ; rdosBegin!= rdosEnd and tot != totList.end(); ++tot, ++rdosBegin, ++totRecreated ){
848 std::array<InDetDD::PixelDiodeTree::CellIndexType,2> diode_idx
852 std::uint32_t feValue = design->
getFE(si_param);
859 float charge = calibData->
getCharge(diode_type, moduleHash, feValue, tot0);
860 chListRecreated.push_back(
charge);
861 totListRecreated.push_back(tot0);
864 rdosBegin = rdos.begin();
865 rdosEnd = rdos.end();
867 tot = totList.begin();
868 totRecreated = totListRecreated.begin();
870 std::vector<float>::const_iterator
charge = chListRecreated.begin();
871 std::vector<float>::const_iterator chargeEnd = chListRecreated.end();
872 tot = totListRecreated.begin();
873 std::vector<int>::const_iterator totEnd = totListRecreated.end();
880 for (; (rdosBegin!= rdosEnd) and (
charge != chargeEnd) and (tot != totEnd); ++rdosBegin, ++
charge, ++tot){
886 sumOfWeightedPositions += (*charge)*siLocalPosition;
887 sumOfTot += (*charge);
889 sumOfWeightedPositions += ((double)(*tot))*siLocalPosition;
890 sumOfTot += (double)(*tot);
892 rowMin = std::min(row, rowMin);
893 rowMax = std::max(row, rowMax);
894 colMin = std::min(col, colMin);
895 colMax = std::max(col, colMax);
898 sumOfWeightedPositions /= sumOfTot;
903 if (!cellIdWeightedPosition.
isValid()){
906 int columnWeightedPosition=cellIdWeightedPosition.
etaIndex();
907 int rowWeightedPosition=cellIdWeightedPosition.
phiIndex();
908 ATH_MSG_VERBOSE(
" weighted pos row: " << rowWeightedPosition <<
" col: " << columnWeightedPosition );
909 int centralIndexX=(
m_sizeX-1)/2;
910 int centralIndexY=(
m_sizeY-1)/2;
911 if (std::abs(rowWeightedPosition-rowMin)>centralIndexX or
912 std::abs(rowWeightedPosition-rowMax)>centralIndexX){
913 ATH_MSG_VERBOSE(
" Cluster too large rowMin" << rowMin <<
" rowMax " << rowMax <<
" centralX " << centralIndexX);
916 if (std::abs(columnWeightedPosition-colMin)>centralIndexY or
917 std::abs(columnWeightedPosition-colMax)>centralIndexY){
918 ATH_MSG_VERBOSE(
" Cluster too large colMin" << colMin <<
" colMax " << colMax <<
" centralY " << centralIndexY);
921 input.matrixOfToT.reserve(
m_sizeX);
923 input.matrixOfToT.emplace_back(
m_sizeY, 0.0);
932 input.vectorOfPitchesY.assign(
m_sizeY, 0.4);
934 rdosBegin = rdos.begin();
935 charge = chListRecreated.begin();
936 chargeEnd = chListRecreated.end();
937 tot = totListRecreated.begin();
938 ATH_MSG_VERBOSE(
" Putting together the n. " << rdos.size() <<
" rdos into a matrix." );
940 input.etaModule=(int)pixelID.
eta_module(pixidentif);
941 input.ClusterPixLayer=(int)pixelID.
layer_disk(pixidentif);
942 input.ClusterPixBarrelEC=(int)pixelID.
barrel_ec(pixidentif);
943 for (;(
charge != chargeEnd) and (rdosBegin!= rdosEnd); ++rdosBegin, ++
charge, ++tot){
945 unsigned int absrow = pixelID.
phi_index(rId)-rowWeightedPosition+centralIndexX;
946 unsigned int abscol = pixelID.
eta_index(rId)-columnWeightedPosition+centralIndexY;
957 double pitchY = diodeParameters.
width().
xEta();
958 double pitchX = diodeParameters.
width().
xPhi();
960 input.matrixOfToT[absrow][abscol]=*
charge;
962 input.matrixOfToT[absrow][abscol]=(double)(*tot);
965 if (
m_addIBL and (input.ClusterPixLayer==0) and (input.ClusterPixBarrelEC==0)){
966 input.matrixOfToT[absrow][abscol]*=3;
970 if ( (input.ClusterPixLayer==0) and (input.ClusterPixBarrelEC==0)){
971 input.matrixOfToT[absrow][abscol]*=3;
977 input.vectorOfPitchesY[abscol]=pitchY;
978 input.vectorOfPitchesX[absrow]=pitchX;
979 }
else if (std::abs(pitchY-0.4)>1e-5){
981 input.vectorOfPitchesY[abscol]=pitchY;
985 ATH_MSG_VERBOSE(
" Layer number: " << input.ClusterPixLayer <<
" Barrel / endcap: " << input.ClusterPixBarrelEC );
986 input.useTrackInfo=
false;
994 float trkphicomp = my_track.dot(my_phiax);
995 float trketacomp = my_track.dot(my_etaax);
996 float trknormcomp = my_track.dot(my_normal);
997 double bowphi = std::atan2(trkphicomp,trknormcomp);
998 double boweta = std::atan2(trketacomp,trknormcomp);
1000 if(bowphi > M_PI_2) bowphi -=
M_PI;
1001 if(bowphi < -M_PI_2) bowphi +=
M_PI;
1003 double angle = std::atan(std::tan(bowphi)-readoutside*tanl);
1006 if (boweta>M_PI_2) boweta-=
M_PI;
1007 if (boweta<-M_PI_2) boweta+=
M_PI;
1010 input.rowWeightedPosition=rowWeightedPosition;
1011 input.columnWeightedPosition=columnWeightedPosition;
1012 ATH_MSG_VERBOSE(
" RowWeightedPosition: " << rowWeightedPosition <<
" ColWeightedPosition: " << columnWeightedPosition );
1027 const Eigen::VectorXd& input)
const {
1029 std::vector<double> result(3, 0.0);
1031 if (!onnxCollection.
isValid()) {
1035 Ort::Session& session = *onnxCollection->numberNetwork;
1038 auto inputTypeInfo = session.GetInputTypeInfo(0);
1039 auto tensorInfo = inputTypeInfo.GetTensorTypeAndShapeInfo();
1040 const int64_t expectedDim = tensorInfo.GetShape()[1];
1043 if (
static_cast<int64_t
>(input.size()) != expectedDim) {
1044 ATH_MSG_FATAL(
"ONNX number network expects input dimension " << expectedDim
1045 <<
" but got " << input.size() <<
" — check model/configuration");
1048 std::vector<float> inputData(expectedDim);
1049 for (
int i = 0; i < expectedDim; ++i) {
1050 inputData[i] =
static_cast<float>(input[i]);
1054 Ort::MemoryInfo memInfo = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
1055 std::vector<int64_t> inputShape = {1, expectedDim};
1056 Ort::Value inputTensor = Ort::Value::CreateTensor<float>(
1057 memInfo, inputData.data(), inputData.size(),
1058 inputShape.data(), inputShape.size());
1059 Ort::AllocatorWithDefaultOptions allocator;
1060 auto inputName = session.GetInputNameAllocated(0, allocator);
1061 auto outputName = session.GetOutputNameAllocated(0, allocator);
1062 const char* inputNames[] = {inputName.get()};
1063 const char* outputNames[] = {outputName.get()};
1066 auto outputTensors = session.Run(
1067 Ort::RunOptions{
nullptr},
1068 inputNames, &inputTensor, 1,
1072 const float* outputData = outputTensors[0].GetTensorData<
float>();
1073 double num0 = outputData[0];
1074 double num1 = outputData[1];
1075 double num2 = outputData[2];
1078 const double sum = num0 + num1 + num2;
1080 ATH_MSG_WARNING(
"ONNX number network output sum is non-positive: " << sum);
1083 const double inverseSum = 1.0 / sum;
1084 result[0] = num0 * inverseSum;
1085 result[1] = num1 * inverseSum;
1086 result[2] = num2 * inverseSum;
1089 <<
" (2): " << result[1]
1090 <<
" (3): " << result[2]);
1094 std::vector<Amg::Vector2D>
1096 const Eigen::VectorXd& input,
1099 int numberSubClusters,
1100 std::vector<Amg::MatrixX>& errors)
const {
1102 std::vector<Amg::Vector2D> allPositions;
1103 if (numberSubClusters < 1 || numberSubClusters >
static_cast<int>(
m_maxSubClusters)) {
1104 return allPositions;
1108 if (!onnxCollection.
isValid()) {
1110 return allPositions;
1112 Ort::Session* posNet =
nullptr;
1113 if (numberSubClusters == 1) posNet = onnxCollection->positionNetwork1.get();
1114 else if (numberSubClusters == 2) posNet = onnxCollection->positionNetwork2.get();
1115 else if (numberSubClusters == 3) posNet = onnxCollection->positionNetwork3.get();
1118 ATH_MSG_FATAL(
"ONNX position network for " << numberSubClusters
1119 <<
" sub-clusters not found in collection");
1120 return allPositions;
1123 Ort::Session& session = *posNet;
1126 auto inputTypeInfo = session.GetInputTypeInfo(0);
1127 auto tensorInfo = inputTypeInfo.GetTensorTypeAndShapeInfo();
1128 const int64_t expectedDim = tensorInfo.GetShape()[1];
1131 if (
static_cast<int64_t
>(input.size()) != expectedDim) {
1132 ATH_MSG_FATAL(
"ONNX position network (" << numberSubClusters
1133 <<
" sub-clusters) expects input dimension " << expectedDim
1134 <<
" but got " << input.size() <<
" — check model/configuration");
1135 return allPositions;
1137 std::vector<float> inputData(expectedDim);
1138 for (
int i = 0; i < expectedDim; ++i) {
1139 inputData[i] =
static_cast<float>(input[i]);
1143 Ort::MemoryInfo memInfo = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
1144 std::vector<int64_t> inputShape = {1, expectedDim};
1145 Ort::Value inputTensor = Ort::Value::CreateTensor<float>(
1146 memInfo, inputData.data(), inputData.size(),
1147 inputShape.data(), inputShape.size());
1148 Ort::AllocatorWithDefaultOptions allocator;
1149 auto inputName = session.GetInputNameAllocated(0, allocator);
1150 auto outputName = session.GetOutputNameAllocated(0, allocator);
1151 const char* inputNames[] = {inputName.get()};
1152 const char* outputNames[] = {outputName.get()};
1155 auto outputTensors = session.Run(
1156 Ort::RunOptions{
nullptr},
1157 inputNames, &inputTensor, 1,
1162 const float* outputData = outputTensors[0].GetTensorData<
float>();
1164 std::vector<double> positionValues;
1165 positionValues.reserve(numberSubClusters * 2);
1167 for (
int iSub = 0; iSub < numberSubClusters; ++iSub) {
1168 const int offset = iSub * 5;
1170 const double mean_x = outputData[offset + 1];
1171 const double mean_y = outputData[offset + 2];
1172 const double prec_x = outputData[offset + 3];
1173 const double prec_y = outputData[offset + 4];
1175 positionValues.push_back(mean_x);
1176 positionValues.push_back(mean_y);
1179 if (prec_x <= 0 || prec_y <= 0) {
1180 ATH_MSG_WARNING(
"ONNX position network returned non-positive precision for sub-cluster "
1181 << iSub <<
" (prec_x=" << prec_x <<
", prec_y=" << prec_y
1182 <<
"); using fallback RMS of 0.01");
1184 const float rawRmsX = (prec_x > 0) ? std::sqrt(1.0f / prec_x) : 0.01f;
1185 const float rawRmsY = (prec_y > 0) ? std::sqrt(1.0f / prec_y) : 0.01f;
1191 erm(0, 0) = rmsX * rmsX;
1192 erm(1, 1) = rmsY * rmsY;
1193 errors.push_back(std::move(erm));
1198 return allPositions;
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
double charge(const T &p)
This file defines the class for a collection of AttributeLists where each one is associated with a ch...
double norm_rawToT(const double input)
double norm_pitch(const double input, bool addIBL=false)
double errorHalfIntervalY(const int nParticles)
double norm_layerNumber(const double input)
double norm_thetaBS(const double input)
double norm_layerType(const double input)
double norm_ToT(const double input)
double back_posX(const double input, const bool recenter=false)
double back_posY(const double input)
double norm_phi(const double input)
double norm_phiBS(const double input)
double norm_theta(const double input)
double norm_etaModule(const double input)
double errorHalfIntervalX(const int nParticles)
This is an Identifier helper class for the Pixel subdetector.
size_t size() const
Number of registered mappings.
double angle(const GeoTrf::Vector2D &a, const GeoTrf::Vector2D &b)
static const Attributes_t empty
This class provides an interface to generate or decode an identifier for the upper levels of the dete...
virtual HelperType helper() const
Type of helper, defaulted to 'Unimplemented'.
This is a "hash" representation of an Identifier.
int readoutSide() const
ReadoutSide.
static constexpr std::array< PixelDiodeTree::CellIndexType, 2 > makeCellIndex(T local_x_idx, T local_y_idx)
Create a 2D cell index from the indices in local-x (phi, row) and local-y (eta, column) direction.
Class used to describe the design of a module (diode segmentation and readout scheme).
virtual SiDiodesParameters parameters(const SiCellId &cellId) const
readout or diode id -> position, size
virtual int numberOfConnectedCells(const SiReadoutCellId &readoutId) const
readout id -> id of connected diodes
PixelReadoutTechnology getReadoutTechnology() const
PixelDiodeTree::DiodeProxy diodeProxyFromIdx(const std::array< PixelDiodeTree::IndexType, 2 > &idx) const
SiLocalPosition positionFromColumnRow(const int column, const int row) const
Given row and column index of a diode, return position of diode center ALTERNATIVE/PREFERED way is to...
virtual SiReadoutCellId readoutIdOfCell(const SiCellId &cellId) const
diode id -> readout id
static InDetDD::PixelDiodeType getDiodeType(const PixelDiodeTree::DiodeProxy &diode_proxy)
virtual SiCellId cellIdOfPosition(const SiLocalPosition &localPos) const
position -> id
virtual double width() const
Method to calculate average width of a module.
virtual double etaPitch() const
Pitch in eta direction.
static unsigned int getFE(const PixelDiodeTree::DiodeProxy &diode_proxy)
virtual double phiPitch() const
Pitch in phi direction.
Identifier for the strip or pixel cell.
int phiIndex() const
Get phi index. Equivalent to strip().
bool isValid() const
Test if its in a valid state.
int etaIndex() const
Get eta index.
Class to hold geometrical description of a silicon detector element.
virtual SiCellId cellIdFromIdentifier(const Identifier &identifier) const override final
SiCellId from Identifier.
virtual const SiDetectorDesign & design() const override final
access to the local description (inline):
Class to handle the position of the centre and the width of a diode or a cluster of diodes Version 1....
const SiLocalPosition & width() const
width of the diodes:
Class to represent a position in the natural frame of a silicon sensor, for Pixel and SCT For Pixel: ...
double xPhi() const
position along phi direction:
double xEta() const
position along eta direction:
const Amg::Vector3D & etaAxis() const
virtual const Amg::Vector3D & normal() const override final
Get reconstruction local normal axes in global frame.
virtual IdentifierHash identifyHash() const override final
identifier hash (inline)
HepGeom::Point3D< double > globalPosition(const HepGeom::Point3D< double > &localPos) const
transform a reconstruction local position into a global position (inline):
const Amg::Vector3D & phiAxis() const
const AtlasDetectorID * getIdHelper() const
Returns the id helper (inline).
std::vector< double > assembleInputRunII(NNinput &input) const
void addTrackInfoToInput(NNinput &input, const Trk::Surface &pixelSurface, const Trk::TrackParameters &trackParsAtSurface, const double tanl) const
Gaudi::Property< unsigned int > m_maxSubClusters
SG::ReadCondHandleKey< PixelChargeCalibCondData > m_chargeDataKey
std::vector< double > estimateNumberOfParticlesLWTNN(NnClusterizationFactory::InputVector &input) const
double correctedRMS(double posPixels, const std::vector< float > &pitches, unsigned int size) const
std::vector< Amg::Vector2D > estimatePositionsONNX(const Eigen::VectorXd &input, NNinput &rawInput, const InDet::PixelCluster &pCluster, int numberSubClusters, std::vector< Amg::MatrixX > &errors) const
Gaudi::Property< unsigned int > m_sizeX
ReturnType(::TTrainedNetwork::* m_calculateOutput)(const InputType &input) const
NNinput createInput(const InDet::PixelCluster &pCluster, Amg::Vector3D &beamSpotPosition, double &tanl) const
Gaudi::Property< bool > m_useONNX
virtual StatusCode initialize() override
Gaudi::Property< double > m_correctLorShiftBarrelWithoutTracks
Gaudi::Property< std::size_t > m_outputNodesPos1
Gaudi::Property< std::vector< std::size_t > > m_outputNodesPos2
ToolHandle< ISiLorentzAngleTool > m_pixelLorentzAngleTool
Gaudi::Property< bool > m_useToT
Gaudi::Property< std::vector< std::size_t > > m_outputNodesPos3
std::vector< Amg::Vector2D > estimatePositionsLWTNN(NnClusterizationFactory::InputVector &input, NNinput &rawInput, const InDet::PixelCluster &pCluster, int numberSubClusters, std::vector< Amg::MatrixX > &errors) const
SG::ReadCondHandleKey< OnnxNNCollection > m_readKeyONNX
std::vector< double > assembleInputRunI(NNinput &input) const
SG::ReadCondHandleKey< LWTNNCollection > m_readKeyJSON
std::vector< Amg::Vector2D > estimatePositions(const InDet::PixelCluster &pCluster, Amg::Vector3D &beamSpotPosition, std::vector< Amg::MatrixX > &errors, int numberSubClusters) const
Gaudi::Property< std::vector< std::string > > m_nnOrder
Gaudi::Property< double > m_correctLorShiftBarrelWithTracks
Gaudi::Property< bool > m_useTTrainedNetworks
std::vector< double > estimateNumberOfParticlesTTN(const TTrainedNetworkCollection &nn_collection, const std::vector< double > &inputData) const
static constexpr std::array< unsigned int, kNNetworkTypes > m_nParticleGroup
unsigned int m_nParticleNNId
Gaudi::Property< bool > m_useXPitches
SG::ReadCondHandleKey< TTrainedNetworkCollection > m_readKeyWithoutTrack
std::vector< double >(InDet::NnClusterizationFactory::* m_assembleInput)(NNinput &input) const
std::vector< Eigen::VectorXd > InputVector
NnClusterizationFactory(const std::string &name, const std::string &n, const IInterface *p)
std::vector< Amg::Vector2D > estimatePositionsTTN(const TTrainedNetworkCollection &nn_collection, const std::vector< double > &inputData, const NNinput &input, const InDet::PixelCluster &pCluster, int numberSubClusters, std::vector< Amg::MatrixX > &errors) const
Gaudi::Property< bool > m_doRunI
static const std::array< std::regex, kNNetworkTypes > m_nnNames
Gaudi::Property< bool > m_useRecenteringNNWithouTracks
static constexpr std::array< std::string_view, kNNetworkTypes > s_nnTypeNames
InputVector eigenInput(NNinput &input) const
void getErrorMatrixFromOutput(std::vector< double > &outputX, std::vector< double > &outputY, std::vector< Amg::MatrixX > &errorMatrix, int nParticles) const
Gaudi::Property< bool > m_useRecenteringNNWithTracks
std::vector< std::vector< unsigned int > > m_NNId
std::vector< Amg::Vector2D > getPositionsFromOutput(std::vector< double > &output, const NNinput &input, const InDet::PixelCluster &pCluster) const
size_t calculateVectorDimension(const bool useTrackInfo) const
Gaudi::Property< unsigned int > m_sizeY
Gaudi::Property< bool > m_addIBL
SG::ReadCondHandleKey< TTrainedNetworkCollection > m_readKeyWithTrack
std::vector< double > estimateNumberOfParticlesONNX(const Eigen::VectorXd &input) const
std::vector< double > estimateNumberOfParticles(const InDet::PixelCluster &pCluster, Amg::Vector3D &beamSpotPosition) const
const std::vector< int > & totList() const
const std::vector< float > & chargeList() const
virtual const InDetDD::SiDetectorElement * detectorElement() const override final
return the detector element corresponding to this PRD The pointer will be zero if the det el is not d...
float getCharge(InDetDD::PixelDiodeType type, unsigned int moduleHash, unsigned int FE, float ToT) const
This is an Identifier helper class for the Pixel subdetector.
int eta_index(const Identifier &id) const
int layer_disk(const Identifier &id) const
Identifier wafer_id(int barrel_ec, int layer_disk, int phi_module, int eta_module) const
For a single crystal.
int barrel_ec(const Identifier &id) const
Values of different levels (failure returns 0).
IdentifierHash wafer_hash(Identifier wafer_id) const
wafer hash from id
int eta_module(const Identifier &id) const
int phi_index(const Identifier &id) const
std::vector< Double_t > calculateOutputValues(std::vector< Double_t > &input) const
DVec calculateNormalized(const DVec &input) const
const Amg::Vector3D & momentum() const
Access method for the momentum.
const Amg::Vector2D & localPosition() const
return the local position reference
Identifier identify() const
return the identifier
const std::vector< Identifier > & rdoList() const
return the List of rdo identifiers (pointers)
Abstract Base Class for tracking surfaces.
const Amg::Transform3D & transform() const
Returns HepGeom::Transform3D by reference.
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > MatrixX
Dynamic Matrix - dynamic allocation.
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
ParametersBase< TrackParametersDim, Charged > TrackParameters
Helper class to access parameters of a diode.