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(inputData);
479 inputDataNew.reserve( inputData.size() + nPositions);
480 inputDataNew.insert(inputDataNew.end(), position1P.begin(), position1P.begin() + nPositions);
486 if ((not (xNetworkIndex < endNnIdx)) or (not (yNetworkIndex < endNnIdx))){
487 ATH_MSG_FATAL(
"estimatePositionsTTN: A requested collection index, "<< xNetworkIndex <<
" or "<< yNetworkIndex <<
"is out of range.");
490 auto *pxNetwork = nn_collection.at(xNetworkIndex).get();
491 auto *pyNetwork = nn_collection.at(yNetworkIndex).get();
496 std::vector<Amg::MatrixX> errorMatrices1;
498 allPositions.reserve( allPositions.size() + myPosition1.size());
499 errors.reserve( errors.size() + myPosition1.size());
500 for (
unsigned int i=0;i<myPosition1.size();i++){
501 allPositions.push_back(myPosition1[i]);
502 errors.push_back(errorMatrices1[i]);
509 std::vector<Amg::Vector2D>
513 int numberSubClusters,
514 std::vector<Amg::MatrixX> & errors)
const {
516 if (not lwtnn_collection.
isValid()) {
520 if (lwtnn_collection->empty()){
526 std::vector<double> positionValues{};
527 std::vector<Amg::MatrixX> errorMatrices;
528 errorMatrices.reserve(numberSubClusters);
529 positionValues.reserve(numberSubClusters * 2);
530 std::size_t outputNode(0);
531 for (
int cluster = 1; cluster < numberSubClusters+1; cluster++) {
534 const auto pNetwork = lwtnn_collection->find(numberSubClusters);
535 const bool validGraph = (pNetwork != lwtnn_collection->end()) and (pNetwork->second !=
nullptr);
536 if (not validGraph) {
537 std::string infoMsg =
"Acceptable numbers of subclusters for the lwtnn collection:\n ";
538 for (
const auto &
pair: **lwtnn_collection){
539 infoMsg += std::to_string(
pair.first) +
"\n ";
541 infoMsg +=
"\nNumber of subclusters requested : "+ std::to_string(numberSubClusters);
543 ATH_MSG_FATAL(
"estimatePositionsLWTNN: No lwtnn network found for the number of clusters.\n"
544 <<
" If you are outside the valid range for an lwtnn-based configuration, please run with useNNTTrainedNetworks instead.\n Key = "
548 if(numberSubClusters==1) {
550 }
else if(numberSubClusters==2) {
552 }
else if(numberSubClusters==3) {
555 ATH_MSG_FATAL(
"Cannot evaluate LWTNN networks with " << numberSubClusters <<
" numberSubClusters" );
562 Eigen::VectorXd position = lwtnn_collection->at(numberSubClusters)->compute(input, {}, outputNode);
563 ATH_MSG_DEBUG(
"Testing for numberSubClusters " << numberSubClusters <<
" and cluster " << cluster);
564 for (
int i=0; i<position.rows(); i++) {
567 positionValues.push_back(position[1]);
568 positionValues.push_back(position[2]);
571 const float rawRmsX = std::sqrt(1.0/position[3]);
572 const float rawRmsY = std::sqrt(1.0/position[4]);
576 const double rmsX = rawRmsX * legacyPhiPitch;
578 ATH_MSG_DEBUG(
" Estimated RMS errors (1) x: " << rmsX <<
", y: " << rmsY);
584 errorMatrices.push_back(std::move(erm));
588 errors=std::move(errorMatrices);
594 const std::vector<float>& pitches,
595 unsigned int size)
const{
599 double p = posPixels + (
size - 1) * 0.5;
600 double p_pos = unsetPos;
601 double p_center = unsetPos;
603 for (
unsigned int i = 0; i <
size; i++) {
604 if (p >= i and p <= (i + 1)) p_pos = p_actual + (p - i + 0.5) * pitches.at(i);
605 if (i == (
size - 1) / 2) p_center = p_actual + 0.5 * pitches.at(i);
606 p_actual += pitches.at(i);
608 return std::abs(p_pos - p_center);
613 std::vector<double>& outputY,
614 std::vector<Amg::MatrixX>& errorMatrix,
615 int nParticles)
const{
616 int sizeOutputX=outputX.size()/nParticles;
617 int sizeOutputY=outputY.size()/nParticles;
624 errorMatrix.reserve( errorMatrix.size() + nParticles);
625 for (
int i=0;i<nParticles;i++){
627 for (
int u=0;u<sizeOutputX;u++){
628 sumValuesX+=outputX[i*sizeOutputX+u];
631 for (
int u=0;u<sizeOutputY;u++){
632 sumValuesY+=outputY[i*sizeOutputY+u];
634 ATH_MSG_VERBOSE(
" minimumX: " << minimumX <<
" maximumX: " << maximumX <<
" sizeOutputX " << sizeOutputX);
635 ATH_MSG_VERBOSE(
" minimumY: " << minimumY <<
" maximumY: " << maximumY <<
" sizeOutputY " << sizeOutputY);
637 for (
int u=0;u<sizeOutputX;u++){
638 RMSx+=outputX[i*sizeOutputX+u]/sumValuesX*std::pow(minimumX+(maximumX-minimumX)/(
double)(sizeOutputX-2)*(u-1./2.),2);
640 RMSx=std::sqrt(RMSx);
642 double intervalErrorX=3*RMSx;
644 int minBinX=(int)(1+(-intervalErrorX-minimumX)/(maximumX-minimumX)*(
double)(sizeOutputX-2));
645 int maxBinX=(int)(1+(intervalErrorX-minimumX)/(maximumX-minimumX)*(
double)(sizeOutputX-2));
646 if (maxBinX>sizeOutputX-1) maxBinX=sizeOutputX-1;
647 if (minBinX<0) minBinX=0;
650 for (
int u=minBinX;u<maxBinX+1;u++){
651 RMSx+=outputX[i*sizeOutputX+u]/sumValuesX*std::pow(minimumX+(maximumX-minimumX)/(
double)(sizeOutputX-2)*(u-1./2.),2);
653 RMSx=std::sqrt(RMSx);
655 for (
int u=0;u<sizeOutputY;u++){
656 RMSy+=outputY[i*sizeOutputY+u]/sumValuesY*std::pow(minimumY+(maximumY-minimumY)/(
double)(sizeOutputY-2)*(u-1./2.),2);
658 RMSy=std::sqrt(RMSy);
660 double intervalErrorY=3*RMSy;
662 int minBinY=(int)(1+(-intervalErrorY-minimumY)/(maximumY-minimumY)*(
double)(sizeOutputY-2));
663 int maxBinY=(int)(1+(intervalErrorY-minimumY)/(maximumY-minimumY)*(
double)(sizeOutputY-2));
664 if (maxBinY>sizeOutputY-1) maxBinY=sizeOutputY-1;
665 if (minBinY<0) minBinY=0;
668 for (
int u=minBinY;u<maxBinY+1;u++){
669 RMSy+=outputY[i*sizeOutputY+u]/sumValuesY*std::pow(minimumY+(maximumY-minimumY)/(
double)(sizeOutputY-2)*(u-1./2.),2);
671 RMSy=std::sqrt(RMSy);
672 ATH_MSG_VERBOSE(
"Computed error, sigma(X) " << RMSx <<
" sigma(Y) " << RMSy );
677 errorMatrix.push_back(std::move(erm));
682 std::vector<Amg::Vector2D>
691 ATH_MSG_ERROR(
"Dynamic cast failed at line "<<__LINE__<<
" of NnClusterizationFactory.cxx.");
694 int numParticles=output.size()/2;
695 int columnWeightedPosition=input.columnWeightedPosition;
696 int rowWeightedPosition=input.rowWeightedPosition;
697 ATH_MSG_VERBOSE(
" REF POS columnWeightedPos: " << columnWeightedPosition <<
" rowWeightedPos: " << rowWeightedPosition );
698 bool applyRecentering=
false;
700 applyRecentering=
true;
703 applyRecentering=
true;
705 std::vector<Amg::Vector2D> positions;
706 for (
int u=0;u<numParticles;u++){
710 posXid=
back_posX(output[2*u],applyRecentering)+rowWeightedPosition;
711 posYid=
back_posY(output[2*u+1])+columnWeightedPosition;
713 posXid=output[2*u]+rowWeightedPosition;
714 posYid=output[2*u+1]+columnWeightedPosition;
716 ATH_MSG_VERBOSE(
" N. particle: " << u <<
" idx posX " << posXid <<
" posY " << posYid );
718 const auto & [posXid_int, coercedX]=coerceToIntRange(posXid+0.5);
719 const auto & [posYid_int, coercedY]=coerceToIntRange(posYid+0.5);
720 if (coercedX or coercedY){
721 ATH_MSG_WARNING(
"X or Y position value has been limited in range; original values are (" << posXid<<
", "<<posYid<<
")");
724 ATH_MSG_VERBOSE(
" N. particle: " << u <<
" TO INTEGER idx posX " << posXid_int <<
" posY " << posYid_int );
727 if ( not cellIdOfPositionDiscrete.
isValid()){
728 ATH_MSG_WARNING(
" Cell is outside validity region with index Y: " << posYid_int <<
" and index X: " << posXid_int <<
". Not foreseen... " );
731 double pitchY = diodeParameters.
width().
xEta();
732 double pitchX = diodeParameters.
width().
xPhi();
734 <<
" Translated weighted position : " << siLocalPositionDiscrete.
xEta() );
737 ATH_MSG_VERBOSE(
" Translated weighted position +1col +1row phi: " << siLocalPositionDiscreteOneRowMoreOneColumnMore.
xPhi()
738 <<
" Translated weighted position +1col +1row eta: " << siLocalPositionDiscreteOneRowMoreOneColumnMore.
xEta() );
741 pitchX*(posXid-(
double)posXid_int));
743 if (input.ClusterPixBarrelEC == 0){
744 if (not input.useTrackInfo){
752 siLocalPosition(siLocalPositionDiscrete.
xEta()+pitchY*(posYid-(
double)posYid_int),
753 siLocalPositionDiscrete.
xPhi()+pitchX*(posXid-(
double)posXid_int)+lorentzShift);
754 ATH_MSG_VERBOSE(
" Translated final position phi: " << siLocalPosition.
xPhi() <<
" eta: " << siLocalPosition.
xEta() );
755 const auto halfWidth{design->
width()*0.5};
756 if (siLocalPositionDiscrete.
xPhi() > halfWidth){
759 ATH_MSG_WARNING(
" Corrected out of boundary cluster from x(phi): " << siLocalPositionDiscrete.
xPhi()+pitchX*(posXid-(
double)posXid_int)
760 <<
" to: " << halfWidth-1e-6);
761 }
else if (siLocalPositionDiscrete.
xPhi() < -halfWidth) {
764 ATH_MSG_WARNING(
" Corrected out of boundary cluster from x(phi): " << siLocalPositionDiscrete.
xPhi()+pitchX*(posXid-(
double)posXid_int)
765 <<
" to: " << -halfWidth+1e-6);
767 positions.emplace_back(siLocalPosition);
777 const double tanl)
const {
778 input.useTrackInfo=
true;
781 localIntersection *= 0.250/cos(localIntersection.theta());
782 float trackDeltaX = (float)localIntersection.x();
783 float trackDeltaY = (float)localIntersection.y();
784 input.theta=std::atan2(trackDeltaY,0.250);
785 input.phi=std::atan2(trackDeltaX,0.250);
787 input.phi=std::atan(std::tan(input.phi)-tanl);
788 ATH_MSG_VERBOSE(
" From track: angle phi: " << input.phi <<
" theta: " << input.theta );
795 double & tanl)
const{
814 const PixelID& pixelID = *pixelIDp;
818 ATH_MSG_ERROR(
"Dynamic cast failed at line "<<__LINE__<<
" of NnClusterizationFactory.cxx.");
823 const std::vector<Identifier>& rdos = pCluster.
rdoList();
824 const size_t rdoSize = rdos.size();
826 const std::vector<float>& chList = pCluster.
chargeList();
827 const std::vector<int>& totList = pCluster.
totList();
828 std::vector<float> chListRecreated{};
829 chListRecreated.reserve(rdoSize);
831 std::vector<int>::const_iterator tot = totList.begin();
832 std::vector<Identifier>::const_iterator rdosBegin = rdos.begin();
833 std::vector<Identifier>::const_iterator rdosEnd = rdos.end();
834 std::vector<int> totListRecreated{};
835 totListRecreated.reserve(rdoSize);
836 std::vector<int>::const_iterator totRecreated = totListRecreated.begin();
841 for ( ; rdosBegin!= rdosEnd and tot != totList.end(); ++tot, ++rdosBegin, ++totRecreated ){
847 std::array<InDetDD::PixelDiodeTree::CellIndexType,2> diode_idx
851 std::uint32_t feValue = design->
getFE(si_param);
858 float charge = calibData->
getCharge(diode_type, moduleHash, feValue, tot0);
859 chListRecreated.push_back(
charge);
860 totListRecreated.push_back(tot0);
863 rdosBegin = rdos.begin();
864 rdosEnd = rdos.end();
866 tot = totList.begin();
867 totRecreated = totListRecreated.begin();
869 std::vector<float>::const_iterator
charge = chListRecreated.begin();
870 std::vector<float>::const_iterator chargeEnd = chListRecreated.end();
871 tot = totListRecreated.begin();
872 std::vector<int>::const_iterator totEnd = totListRecreated.end();
879 for (; (rdosBegin!= rdosEnd) and (
charge != chargeEnd) and (tot != totEnd); ++rdosBegin, ++
charge, ++tot){
885 sumOfWeightedPositions += (*charge)*siLocalPosition;
886 sumOfTot += (*charge);
888 sumOfWeightedPositions += ((double)(*tot))*siLocalPosition;
889 sumOfTot += (double)(*tot);
891 rowMin = std::min(row, rowMin);
892 rowMax = std::max(row, rowMax);
893 colMin = std::min(col, colMin);
894 colMax = std::max(col, colMax);
897 sumOfWeightedPositions /= sumOfTot;
902 if (!cellIdWeightedPosition.
isValid()){
905 int columnWeightedPosition=cellIdWeightedPosition.
etaIndex();
906 int rowWeightedPosition=cellIdWeightedPosition.
phiIndex();
907 ATH_MSG_VERBOSE(
" weighted pos row: " << rowWeightedPosition <<
" col: " << columnWeightedPosition );
908 int centralIndexX=(
m_sizeX-1)/2;
909 int centralIndexY=(
m_sizeY-1)/2;
910 if (std::abs(rowWeightedPosition-rowMin)>centralIndexX or
911 std::abs(rowWeightedPosition-rowMax)>centralIndexX){
912 ATH_MSG_VERBOSE(
" Cluster too large rowMin" << rowMin <<
" rowMax " << rowMax <<
" centralX " << centralIndexX);
915 if (std::abs(columnWeightedPosition-colMin)>centralIndexY or
916 std::abs(columnWeightedPosition-colMax)>centralIndexY){
917 ATH_MSG_VERBOSE(
" Cluster too large colMin" << colMin <<
" colMax " << colMax <<
" centralY " << centralIndexY);
920 input.matrixOfToT.reserve(
m_sizeX);
922 input.matrixOfToT.emplace_back(
m_sizeY, 0.0);
931 input.vectorOfPitchesY.assign(
m_sizeY, 0.4);
933 rdosBegin = rdos.begin();
934 charge = chListRecreated.begin();
935 chargeEnd = chListRecreated.end();
936 tot = totListRecreated.begin();
937 ATH_MSG_VERBOSE(
" Putting together the n. " << rdos.size() <<
" rdos into a matrix." );
939 input.etaModule=(int)pixelID.
eta_module(pixidentif);
940 input.ClusterPixLayer=(int)pixelID.
layer_disk(pixidentif);
941 input.ClusterPixBarrelEC=(int)pixelID.
barrel_ec(pixidentif);
942 for (;(
charge != chargeEnd) and (rdosBegin!= rdosEnd); ++rdosBegin, ++
charge, ++tot){
944 unsigned int absrow = pixelID.
phi_index(rId)-rowWeightedPosition+centralIndexX;
945 unsigned int abscol = pixelID.
eta_index(rId)-columnWeightedPosition+centralIndexY;
956 double pitchY = diodeParameters.
width().
xEta();
957 double pitchX = diodeParameters.
width().
xPhi();
959 input.matrixOfToT[absrow][abscol]=*
charge;
961 input.matrixOfToT[absrow][abscol]=(double)(*tot);
964 if (
m_addIBL and (input.ClusterPixLayer==0) and (input.ClusterPixBarrelEC==0)){
965 input.matrixOfToT[absrow][abscol]*=3;
969 if ( (input.ClusterPixLayer==0) and (input.ClusterPixBarrelEC==0)){
970 input.matrixOfToT[absrow][abscol]*=3;
976 input.vectorOfPitchesY[abscol]=pitchY;
977 input.vectorOfPitchesX[absrow]=pitchX;
978 }
else if (std::abs(pitchY-0.4)>1e-5){
980 input.vectorOfPitchesY[abscol]=pitchY;
984 ATH_MSG_VERBOSE(
" Layer number: " << input.ClusterPixLayer <<
" Barrel / endcap: " << input.ClusterPixBarrelEC );
985 input.useTrackInfo=
false;
993 float trkphicomp = my_track.dot(my_phiax);
994 float trketacomp = my_track.dot(my_etaax);
995 float trknormcomp = my_track.dot(my_normal);
996 double bowphi = std::atan2(trkphicomp,trknormcomp);
997 double boweta = std::atan2(trketacomp,trknormcomp);
999 if(bowphi > M_PI_2) bowphi -=
M_PI;
1000 if(bowphi < -M_PI_2) bowphi +=
M_PI;
1002 double angle = std::atan(std::tan(bowphi)-readoutside*tanl);
1005 if (boweta>M_PI_2) boweta-=
M_PI;
1006 if (boweta<-M_PI_2) boweta+=
M_PI;
1009 input.rowWeightedPosition=rowWeightedPosition;
1010 input.columnWeightedPosition=columnWeightedPosition;
1011 ATH_MSG_VERBOSE(
" RowWeightedPosition: " << rowWeightedPosition <<
" ColWeightedPosition: " << columnWeightedPosition );
1026 const Eigen::VectorXd& input)
const {
1028 std::vector<double> result(3, 0.0);
1030 if (!onnxCollection.
isValid()) {
1034 Ort::Session& session = *onnxCollection->numberNetwork;
1037 auto inputTypeInfo = session.GetInputTypeInfo(0);
1038 auto tensorInfo = inputTypeInfo.GetTensorTypeAndShapeInfo();
1039 const int64_t expectedDim = tensorInfo.GetShape()[1];
1042 if (
static_cast<int64_t
>(input.size()) != expectedDim) {
1043 ATH_MSG_FATAL(
"ONNX number network expects input dimension " << expectedDim
1044 <<
" but got " << input.size() <<
" — check model/configuration");
1047 std::vector<float> inputData(expectedDim);
1048 for (
int i = 0; i < expectedDim; ++i) {
1049 inputData[i] =
static_cast<float>(input[i]);
1053 Ort::MemoryInfo memInfo = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
1054 std::vector<int64_t> inputShape = {1, expectedDim};
1055 Ort::Value inputTensor = Ort::Value::CreateTensor<float>(
1056 memInfo, inputData.data(), inputData.size(),
1057 inputShape.data(), inputShape.size());
1058 Ort::AllocatorWithDefaultOptions allocator;
1059 auto inputName = session.GetInputNameAllocated(0, allocator);
1060 auto outputName = session.GetOutputNameAllocated(0, allocator);
1061 const char* inputNames[] = {inputName.get()};
1062 const char* outputNames[] = {outputName.get()};
1065 auto outputTensors = session.Run(
1066 Ort::RunOptions{
nullptr},
1067 inputNames, &inputTensor, 1,
1071 const float* outputData = outputTensors[0].GetTensorData<
float>();
1072 double num0 = outputData[0];
1073 double num1 = outputData[1];
1074 double num2 = outputData[2];
1077 const double sum = num0 + num1 + num2;
1079 ATH_MSG_WARNING(
"ONNX number network output sum is non-positive: " << sum);
1082 const double inverseSum = 1.0 / sum;
1083 result[0] = num0 * inverseSum;
1084 result[1] = num1 * inverseSum;
1085 result[2] = num2 * inverseSum;
1088 <<
" (2): " << result[1]
1089 <<
" (3): " << result[2]);
1093 std::vector<Amg::Vector2D>
1095 const Eigen::VectorXd& input,
1098 int numberSubClusters,
1099 std::vector<Amg::MatrixX>& errors)
const {
1101 std::vector<Amg::Vector2D> allPositions;
1102 if (numberSubClusters < 1 || numberSubClusters >
static_cast<int>(
m_maxSubClusters)) {
1103 return allPositions;
1107 if (!onnxCollection.
isValid()) {
1109 return allPositions;
1111 Ort::Session* posNet =
nullptr;
1112 if (numberSubClusters == 1) posNet = onnxCollection->positionNetwork1.get();
1113 else if (numberSubClusters == 2) posNet = onnxCollection->positionNetwork2.get();
1114 else if (numberSubClusters == 3) posNet = onnxCollection->positionNetwork3.get();
1117 ATH_MSG_FATAL(
"ONNX position network for " << numberSubClusters
1118 <<
" sub-clusters not found in collection");
1119 return allPositions;
1122 Ort::Session& session = *posNet;
1125 auto inputTypeInfo = session.GetInputTypeInfo(0);
1126 auto tensorInfo = inputTypeInfo.GetTensorTypeAndShapeInfo();
1127 const int64_t expectedDim = tensorInfo.GetShape()[1];
1130 if (
static_cast<int64_t
>(input.size()) != expectedDim) {
1131 ATH_MSG_FATAL(
"ONNX position network (" << numberSubClusters
1132 <<
" sub-clusters) expects input dimension " << expectedDim
1133 <<
" but got " << input.size() <<
" — check model/configuration");
1134 return allPositions;
1136 std::vector<float> inputData(expectedDim);
1137 for (
int i = 0; i < expectedDim; ++i) {
1138 inputData[i] =
static_cast<float>(input[i]);
1142 Ort::MemoryInfo memInfo = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
1143 std::vector<int64_t> inputShape = {1, expectedDim};
1144 Ort::Value inputTensor = Ort::Value::CreateTensor<float>(
1145 memInfo, inputData.data(), inputData.size(),
1146 inputShape.data(), inputShape.size());
1147 Ort::AllocatorWithDefaultOptions allocator;
1148 auto inputName = session.GetInputNameAllocated(0, allocator);
1149 auto outputName = session.GetOutputNameAllocated(0, allocator);
1150 const char* inputNames[] = {inputName.get()};
1151 const char* outputNames[] = {outputName.get()};
1154 auto outputTensors = session.Run(
1155 Ort::RunOptions{
nullptr},
1156 inputNames, &inputTensor, 1,
1161 const float* outputData = outputTensors[0].GetTensorData<
float>();
1163 std::vector<double> positionValues;
1164 positionValues.reserve(numberSubClusters * 2);
1166 for (
int iSub = 0; iSub < numberSubClusters; ++iSub) {
1167 const int offset = iSub * 5;
1169 const double mean_x = outputData[offset + 1];
1170 const double mean_y = outputData[offset + 2];
1171 const double prec_x = outputData[offset + 3];
1172 const double prec_y = outputData[offset + 4];
1174 positionValues.push_back(mean_x);
1175 positionValues.push_back(mean_y);
1178 if (prec_x <= 0 || prec_y <= 0) {
1179 ATH_MSG_WARNING(
"ONNX position network returned non-positive precision for sub-cluster "
1180 << iSub <<
" (prec_x=" << prec_x <<
", prec_y=" << prec_y
1181 <<
"); using fallback RMS of 0.01");
1183 const float rawRmsX = (prec_x > 0) ? std::sqrt(1.0f / prec_x) : 0.01f;
1184 const float rawRmsY = (prec_y > 0) ? std::sqrt(1.0f / prec_y) : 0.01f;
1190 erm(0, 0) = rmsX * rmsX;
1191 erm(1, 1) = rmsY * rmsY;
1192 errors.push_back(std::move(erm));
1197 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.