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};
54 const std::array<std::regex, NnClusterizationFactory::kNNetworkTypes>
56 std::regex(
"^NumberParticles(|/|_.*)$"),
57 std::regex(
"^ImpactPoints([0-9])P(|/|_.*)$"),
58 std::regex(
"^ImpactPointErrorsX([0-9])(|/|_.*)$"),
59 std::regex(
"^ImpactPointErrorsY([0-9])(|/|_.*)$"),
63 const std::string& n,
const IInterface* p)
65 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;
151 return StatusCode::SUCCESS;
158 const auto invalidValue{std::numeric_limits<double>::quiet_NaN()};
159 std::vector<double> inputData(vectorSize, invalidValue);
160 size_t vectorIndex{0};
161 for (
unsigned int u=0;u<
m_sizeX;u++){
162 for (
unsigned int s=0;s<
m_sizeY;s++){
163 inputData[vectorIndex++] = input.matrixOfToT[u][s];
166 for (
unsigned int s=0;s<
m_sizeY;s++){
167 inputData[vectorIndex++] = input.vectorOfPitchesY[s];
169 inputData[vectorIndex++] = input.ClusterPixLayer;
170 inputData[vectorIndex++] = input.ClusterPixBarrelEC;
171 inputData[vectorIndex++] = input.phi;
172 inputData[vectorIndex++] = input.theta;
173 if (not input.useTrackInfo) inputData[vectorIndex] = input.etaModule;
180 const auto invalidValue{std::numeric_limits<double>::quiet_NaN()};
181 std::vector<double> inputData(vectorSize, invalidValue);
182 size_t vectorIndex{0};
183 for (
unsigned int u=0;u<
m_sizeX;u++){
184 for (
unsigned int s=0;s<
m_sizeY;s++){
186 inputData[vectorIndex++] =
norm_rawToT(input.matrixOfToT[u][s]);
188 inputData[vectorIndex++] =
norm_ToT(input.matrixOfToT[u][s]);
192 for (
unsigned int s=0;s<
m_sizeY;s++){
193 const double rawPitch(input.vectorOfPitchesY[s]);
195 if (std::isnan(normPitch)){
198 inputData[vectorIndex++] = normPitch;
201 inputData[vectorIndex++] =
norm_layerType(input.ClusterPixBarrelEC);
202 if (input.useTrackInfo){
203 inputData[vectorIndex++] =
norm_phi(input.phi);
204 inputData[vectorIndex] =
norm_theta(input.theta);
206 inputData[vectorIndex++] =
norm_phiBS(input.phi);
222 Eigen::VectorXd valuesVector( vecSize );
228 for (
const auto & xvec: input.matrixOfToT){
229 for (
const auto & xyElement : xvec){
230 valuesVector[location++] = xyElement;
233 for (
const auto & pitch : input.vectorOfPitchesY) {
234 valuesVector[location++] = pitch;
236 valuesVector[location] = input.ClusterPixLayer;
238 valuesVector[location] = input.ClusterPixBarrelEC;
240 valuesVector[location] = input.phi;
242 valuesVector[location] = input.theta;
244 if (!input.useTrackInfo) {
245 valuesVector[location] = input.etaModule;
250 std::vector<Eigen::VectorXd> vectorOfEigen;
251 vectorOfEigen.push_back(valuesVector);
252 return vectorOfEigen;
260 if (!input)
return {};
266 if (!nn_collection.
isValid()) {
288 if (!input)
return {};
295 if (!nn_collection.
isValid()) {
311 const std::vector<double>& inputData)
const{
313 std::vector<double> resultNN_TTN{};
320 ATH_MSG_FATAL(
"NnClusterizationFactory::estimateNumberOfParticlesTTN: nullptr returned for TrainedNetwork");
325 ATH_MSG_VERBOSE(
" TTN Prob of n. particles (1): " << resultNN_TTN[0] <<
326 " (2): " << resultNN_TTN[1] <<
327 " (3): " << resultNN_TTN[2]);
334 std::vector<double> result(3,0.0);
336 if (!lwtnn_collection.
isValid()) {
340 if (lwtnn_collection->empty()){
347 Eigen::VectorXd discriminant = lwtnn_collection->at(0)->compute(input);
348 const double & num0 = discriminant[0];
349 const double & num1 = discriminant[1];
350 const double & num2 = discriminant[2];
352 const auto inverseSum = 1./(num0+num1+num2);
353 result[0] = num0 * inverseSum;
354 result[1] = num1 * inverseSum;
355 result[2] = num2 * inverseSum;
357 " (2): " << result[1] <<
358 " (3): " << result[2]);
363 std::vector<Amg::Vector2D>
366 std::vector<Amg::MatrixX> & errors,
367 int numberSubClusters)
const{
379 if (!nn_collection.
isValid()) {
384 return estimatePositionsTTN(**nn_collection, inputData,input,pCluster,numberSubClusters,errors);
395 std::vector<Amg::Vector2D>
399 std::vector<Amg::MatrixX> & errors,
400 int numberSubClusters)
const{
405 if (!input)
return {};
412 if (!nn_collection.
isValid()) {
416 return estimatePositionsTTN(**nn_collection, inputData,input,pCluster,numberSubClusters,errors);
426 std::vector<Amg::Vector2D>
428 const std::vector<double>& inputData,
431 int numberSubClusters,
432 std::vector<Amg::MatrixX> & errors)
const{
434 std::vector<Amg::Vector2D> allPositions{};
435 const auto endNnIdx = nn_collection.size();
436 if (numberSubClusters>0 and
static_cast<unsigned int>(numberSubClusters) <
m_maxSubClusters) {
437 const auto subClusterIndex = numberSubClusters-1;
442 if (not(networkIndex < endNnIdx)){
443 ATH_MSG_FATAL(
"estimatePositionsTTN: Requested collection index, "<< networkIndex <<
" is out of range.");
446 auto *
const pNetwork = nn_collection[networkIndex].get();
449 assert( position1P.size() % 2 == 0);
450 for (
unsigned int i=0; i<position1P.size()/2 ; ++i) {
451 ATH_MSG_DEBUG(
" Original RAW Estimated positions (" << i <<
") x: " <<
back_posX(position1P[0+i*2],applyRecentering) <<
" y: " <<
back_posY(position1P[1+i*2]));
454 std::vector<double> inputDataNew=inputData;
455 inputDataNew.reserve( inputDataNew.size() + numberSubClusters*2);
456 assert(
static_cast<unsigned int>(numberSubClusters*2) <= position1P.size() );
457 for (
unsigned int i=0; i<static_cast<unsigned int>(numberSubClusters*2); ++i) {
458 inputDataNew.push_back(position1P[i]);
464 if ((not (xNetworkIndex < endNnIdx)) or (not (yNetworkIndex < endNnIdx))){
465 ATH_MSG_FATAL(
"estimatePositionsTTN: A requested collection index, "<< xNetworkIndex <<
" or "<< yNetworkIndex <<
"is out of range.");
468 auto *pxNetwork = nn_collection.at(xNetworkIndex).get();
469 auto *pyNetwork = nn_collection.at(yNetworkIndex).get();
474 std::vector<Amg::MatrixX> errorMatrices1;
476 allPositions.reserve( allPositions.size() + myPosition1.size());
477 errors.reserve( errors.size() + myPosition1.size());
478 for (
unsigned int i=0;i<myPosition1.size();i++){
479 allPositions.push_back(myPosition1[i]);
480 errors.push_back(errorMatrices1[i]);
487 std::vector<Amg::Vector2D>
491 int numberSubClusters,
492 std::vector<Amg::MatrixX> & errors)
const {
494 if (not lwtnn_collection.
isValid()) {
498 if (lwtnn_collection->empty()){
504 std::vector<double> positionValues{};
505 std::vector<Amg::MatrixX> errorMatrices;
506 errorMatrices.reserve(numberSubClusters);
507 positionValues.reserve(numberSubClusters * 2);
508 std::size_t outputNode(0);
509 for (
int cluster = 1; cluster < numberSubClusters+1; cluster++) {
512 const auto pNetwork = lwtnn_collection->find(numberSubClusters);
513 const bool validGraph = (pNetwork != lwtnn_collection->end()) and (pNetwork->second !=
nullptr);
514 if (not validGraph) {
515 std::string infoMsg =
"Acceptable numbers of subclusters for the lwtnn collection:\n ";
516 for (
const auto &
pair: **lwtnn_collection){
517 infoMsg += std::to_string(
pair.first) +
"\n ";
519 infoMsg +=
"\nNumber of subclusters requested : "+ std::to_string(numberSubClusters);
521 ATH_MSG_FATAL(
"estimatePositionsLWTNN: No lwtnn network found for the number of clusters.\n"
522 <<
" If you are outside the valid range for an lwtnn-based configuration, please run with useNNTTrainedNetworks instead.\n Key = "
526 if(numberSubClusters==1) {
528 }
else if(numberSubClusters==2) {
530 }
else if(numberSubClusters==3) {
533 ATH_MSG_FATAL(
"Cannot evaluate LWTNN networks with " << numberSubClusters <<
" numberSubClusters" );
540 Eigen::VectorXd position = lwtnn_collection->at(numberSubClusters)->compute(input, {}, outputNode);
541 ATH_MSG_DEBUG(
"Testing for numberSubClusters " << numberSubClusters <<
" and cluster " << cluster);
542 for (
int i=0; i<position.rows(); i++) {
545 positionValues.push_back(position[1]);
546 positionValues.push_back(position[2]);
549 const float rawRmsX = std::sqrt(1.0/position[3]);
550 const float rawRmsY = std::sqrt(1.0/position[4]);
554 ATH_MSG_DEBUG(
" Estimated RMS errors (1) x: " << rmsX <<
", y: " << rmsY);
560 errorMatrices.push_back(erm);
564 errors=std::move(errorMatrices);
571 constexpr double pitch = 0.05;
572 const double corrected = posPixels * pitch;
578 std::vector<float>& pitches)
const{
579 double p = posPixels + (
m_sizeY - 1) * 0.5;
581 double p_center = -100;
583 for (
unsigned int i = 0; i <
m_sizeY; i++) {
584 if (p >= i and p <= (i + 1)) p_Y = p_actual + (p - i + 0.5) * pitches.at(i);
585 if (i == (
m_sizeY - 1) / 2) p_center = p_actual + 0.5 * pitches.at(i);
586 p_actual += pitches.at(i);
588 return std::abs(p_Y - p_center);
593 std::vector<double>& outputY,
594 std::vector<Amg::MatrixX>& errorMatrix,
595 int nParticles)
const{
596 int sizeOutputX=outputX.size()/nParticles;
597 int sizeOutputY=outputY.size()/nParticles;
604 errorMatrix.reserve( errorMatrix.size() + nParticles);
605 for (
int i=0;i<nParticles;i++){
607 for (
int u=0;u<sizeOutputX;u++){
608 sumValuesX+=outputX[i*sizeOutputX+u];
611 for (
int u=0;u<sizeOutputY;u++){
612 sumValuesY+=outputY[i*sizeOutputY+u];
614 ATH_MSG_VERBOSE(
" minimumX: " << minimumX <<
" maximumX: " << maximumX <<
" sizeOutputX " << sizeOutputX);
615 ATH_MSG_VERBOSE(
" minimumY: " << minimumY <<
" maximumY: " << maximumY <<
" sizeOutputY " << sizeOutputY);
617 for (
int u=0;u<sizeOutputX;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 double intervalErrorX=3*RMSx;
624 int minBinX=(int)(1+(-intervalErrorX-minimumX)/(maximumX-minimumX)*(
double)(sizeOutputX-2));
625 int maxBinX=(int)(1+(intervalErrorX-minimumX)/(maximumX-minimumX)*(
double)(sizeOutputX-2));
626 if (maxBinX>sizeOutputX-1) maxBinX=sizeOutputX-1;
627 if (minBinX<0) minBinX=0;
630 for (
int u=minBinX;u<maxBinX+1;u++){
631 RMSx+=outputX[i*sizeOutputX+u]/sumValuesX*std::pow(minimumX+(maximumX-minimumX)/(
double)(sizeOutputX-2)*(u-1./2.),2);
633 RMSx=std::sqrt(RMSx);
635 for (
int u=0;u<sizeOutputY;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);
640 double intervalErrorY=3*RMSy;
642 int minBinY=(int)(1+(-intervalErrorY-minimumY)/(maximumY-minimumY)*(
double)(sizeOutputY-2));
643 int maxBinY=(int)(1+(intervalErrorY-minimumY)/(maximumY-minimumY)*(
double)(sizeOutputY-2));
644 if (maxBinY>sizeOutputY-1) maxBinY=sizeOutputY-1;
645 if (minBinY<0) minBinY=0;
648 for (
int u=minBinY;u<maxBinY+1;u++){
649 RMSy+=outputY[i*sizeOutputY+u]/sumValuesY*std::pow(minimumY+(maximumY-minimumY)/(
double)(sizeOutputY-2)*(u-1./2.),2);
651 RMSy=std::sqrt(RMSy);
652 ATH_MSG_VERBOSE(
"Computed error, sigma(X) " << RMSx <<
" sigma(Y) " << RMSy );
657 errorMatrix.push_back(erm);
662 std::vector<Amg::Vector2D>
671 ATH_MSG_ERROR(
"Dynamic cast failed at line "<<__LINE__<<
" of NnClusterizationFactory.cxx.");
674 int numParticles=output.size()/2;
675 int columnWeightedPosition=input.columnWeightedPosition;
676 int rowWeightedPosition=input.rowWeightedPosition;
677 ATH_MSG_VERBOSE(
" REF POS columnWeightedPos: " << columnWeightedPosition <<
" rowWeightedPos: " << rowWeightedPosition );
678 bool applyRecentering=
false;
680 applyRecentering=
true;
683 applyRecentering=
true;
685 std::vector<Amg::Vector2D> positions;
686 for (
int u=0;u<numParticles;u++){
690 posXid=
back_posX(output[2*u],applyRecentering)+rowWeightedPosition;
691 posYid=
back_posY(output[2*u+1])+columnWeightedPosition;
693 posXid=output[2*u]+rowWeightedPosition;
694 posYid=output[2*u+1]+columnWeightedPosition;
696 ATH_MSG_VERBOSE(
" N. particle: " << u <<
" idx posX " << posXid <<
" posY " << posYid );
698 const auto & [posXid_int, coercedX]=coerceToIntRange(posXid+0.5);
699 const auto & [posYid_int, coercedY]=coerceToIntRange(posYid+0.5);
700 if (coercedX or coercedY){
701 ATH_MSG_WARNING(
"X or Y position value has been limited in range; original values are (" << posXid<<
", "<<posYid<<
")");
704 ATH_MSG_VERBOSE(
" N. particle: " << u <<
" TO INTEGER idx posX " << posXid_int <<
" posY " << posYid_int );
707 if ( not cellIdOfPositionDiscrete.
isValid()){
708 ATH_MSG_WARNING(
" Cell is outside validity region with index Y: " << posYid_int <<
" and index X: " << posXid_int <<
". Not foreseen... " );
711 double pitchY = diodeParameters.
width().
xEta();
712 double pitchX = diodeParameters.
width().
xPhi();
714 <<
" Translated weighted position : " << siLocalPositionDiscrete.
xEta() );
717 ATH_MSG_VERBOSE(
" Translated weighted position +1col +1row phi: " << siLocalPositionDiscreteOneRowMoreOneColumnMore.
xPhi()
718 <<
" Translated weighted position +1col +1row eta: " << siLocalPositionDiscreteOneRowMoreOneColumnMore.
xEta() );
721 pitchX*(posXid-(
double)posXid_int));
723 if (input.ClusterPixBarrelEC == 0){
724 if (not input.useTrackInfo){
732 siLocalPosition(siLocalPositionDiscrete.
xEta()+pitchY*(posYid-(
double)posYid_int),
733 siLocalPositionDiscrete.
xPhi()+pitchX*(posXid-(
double)posXid_int)+lorentzShift);
734 ATH_MSG_VERBOSE(
" Translated final position phi: " << siLocalPosition.
xPhi() <<
" eta: " << siLocalPosition.
xEta() );
735 const auto halfWidth{design->
width()*0.5};
736 if (siLocalPositionDiscrete.
xPhi() > halfWidth){
739 ATH_MSG_WARNING(
" Corrected out of boundary cluster from x(phi): " << siLocalPositionDiscrete.
xPhi()+pitchX*(posXid-(
double)posXid_int)
740 <<
" to: " << halfWidth-1e-6);
741 }
else if (siLocalPositionDiscrete.
xPhi() < -halfWidth) {
744 ATH_MSG_WARNING(
" Corrected out of boundary cluster from x(phi): " << siLocalPositionDiscrete.
xPhi()+pitchX*(posXid-(
double)posXid_int)
745 <<
" to: " << -halfWidth+1e-6);
747 positions.emplace_back(siLocalPosition);
757 const double tanl)
const {
758 input.useTrackInfo=
true;
761 localIntersection *= 0.250/cos(localIntersection.theta());
762 float trackDeltaX = (float)localIntersection.x();
763 float trackDeltaY = (float)localIntersection.y();
764 input.theta=std::atan2(trackDeltaY,0.250);
765 input.phi=std::atan2(trackDeltaX,0.250);
767 input.phi=std::atan(std::tan(input.phi)-tanl);
768 ATH_MSG_VERBOSE(
" From track: angle phi: " << input.phi <<
" theta: " << input.theta );
775 double & tanl)
const{
794 const PixelID& pixelID = *pixelIDp;
798 ATH_MSG_ERROR(
"Dynamic cast failed at line "<<__LINE__<<
" of NnClusterizationFactory.cxx.");
803 const std::vector<Identifier>& rdos = pCluster.
rdoList();
804 const size_t rdoSize = rdos.size();
806 const std::vector<float>& chList = pCluster.
chargeList();
807 const std::vector<int>& totList = pCluster.
totList();
808 std::vector<float> chListRecreated{};
809 chListRecreated.reserve(rdoSize);
811 std::vector<int>::const_iterator tot = totList.begin();
812 std::vector<Identifier>::const_iterator rdosBegin = rdos.begin();
813 std::vector<Identifier>::const_iterator rdosEnd = rdos.end();
814 std::vector<int> totListRecreated{};
815 totListRecreated.reserve(rdoSize);
816 std::vector<int>::const_iterator totRecreated = totListRecreated.begin();
821 for ( ; rdosBegin!= rdosEnd and tot != totList.end(); ++tot, ++rdosBegin, ++totRecreated ){
827 std::array<InDetDD::PixelDiodeTree::CellIndexType,2> diode_idx
831 std::uint32_t feValue = design->
getFE(si_param);
838 float charge = calibData->
getCharge(diode_type, moduleHash, feValue, tot0);
839 chListRecreated.push_back(
charge);
840 totListRecreated.push_back(tot0);
843 rdosBegin = rdos.begin();
844 rdosEnd = rdos.end();
846 tot = totList.begin();
847 totRecreated = totListRecreated.begin();
849 std::vector<float>::const_iterator
charge = chListRecreated.begin();
850 std::vector<float>::const_iterator chargeEnd = chListRecreated.end();
851 tot = totListRecreated.begin();
852 std::vector<int>::const_iterator totEnd = totListRecreated.end();
859 for (; (rdosBegin!= rdosEnd) and (
charge != chargeEnd) and (tot != totEnd); ++rdosBegin, ++
charge, ++tot){
865 sumOfWeightedPositions += (*charge)*siLocalPosition;
866 sumOfTot += (*charge);
868 sumOfWeightedPositions += ((double)(*tot))*siLocalPosition;
869 sumOfTot += (double)(*tot);
871 rowMin = std::min(row, rowMin);
872 rowMax = std::max(row, rowMax);
873 colMin = std::min(col, colMin);
874 colMax = std::max(col, colMax);
877 sumOfWeightedPositions /= sumOfTot;
882 if (!cellIdWeightedPosition.
isValid()){
885 int columnWeightedPosition=cellIdWeightedPosition.
etaIndex();
886 int rowWeightedPosition=cellIdWeightedPosition.
phiIndex();
887 ATH_MSG_VERBOSE(
" weighted pos row: " << rowWeightedPosition <<
" col: " << columnWeightedPosition );
888 int centralIndexX=(
m_sizeX-1)/2;
889 int centralIndexY=(
m_sizeY-1)/2;
890 if (std::abs(rowWeightedPosition-rowMin)>centralIndexX or
891 std::abs(rowWeightedPosition-rowMax)>centralIndexX){
892 ATH_MSG_VERBOSE(
" Cluster too large rowMin" << rowMin <<
" rowMax " << rowMax <<
" centralX " << centralIndexX);
895 if (std::abs(columnWeightedPosition-colMin)>centralIndexY or
896 std::abs(columnWeightedPosition-colMax)>centralIndexY){
897 ATH_MSG_VERBOSE(
" Cluster too large colMin" << colMin <<
" colMax " << colMax <<
" centralY " << centralIndexY);
900 input.matrixOfToT.reserve(
m_sizeX);
902 input.matrixOfToT.emplace_back(
m_sizeY, 0.0);
904 input.vectorOfPitchesY.assign(
m_sizeY, 0.4);
905 rdosBegin = rdos.begin();
906 charge = chListRecreated.begin();
907 chargeEnd = chListRecreated.end();
908 tot = totListRecreated.begin();
909 ATH_MSG_VERBOSE(
" Putting together the n. " << rdos.size() <<
" rdos into a matrix." );
911 input.etaModule=(int)pixelID.
eta_module(pixidentif);
912 input.ClusterPixLayer=(int)pixelID.
layer_disk(pixidentif);
913 input.ClusterPixBarrelEC=(int)pixelID.
barrel_ec(pixidentif);
914 for (;(
charge != chargeEnd) and (rdosBegin!= rdosEnd); ++rdosBegin, ++
charge, ++tot){
916 unsigned int absrow = pixelID.
phi_index(rId)-rowWeightedPosition+centralIndexX;
917 unsigned int abscol = pixelID.
eta_index(rId)-columnWeightedPosition+centralIndexY;
928 double pitchY = diodeParameters.
width().
xEta();
930 input.matrixOfToT[absrow][abscol]=*
charge;
932 input.matrixOfToT[absrow][abscol]=(double)(*tot);
935 if (
m_addIBL and (input.ClusterPixLayer==0) and (input.ClusterPixBarrelEC==0)){
936 input.matrixOfToT[absrow][abscol]*=3;
940 if ( (input.ClusterPixLayer==0) and (input.ClusterPixBarrelEC==0)){
941 input.matrixOfToT[absrow][abscol]*=3;
946 if (std::abs(pitchY-0.4)>1e-5){
947 input.vectorOfPitchesY[abscol]=pitchY;
951 ATH_MSG_VERBOSE(
" Layer number: " << input.ClusterPixLayer <<
" Barrel / endcap: " << input.ClusterPixBarrelEC );
952 input.useTrackInfo=
false;
960 float trkphicomp = my_track.dot(my_phiax);
961 float trketacomp = my_track.dot(my_etaax);
962 float trknormcomp = my_track.dot(my_normal);
963 double bowphi = std::atan2(trkphicomp,trknormcomp);
964 double boweta = std::atan2(trketacomp,trknormcomp);
966 if(bowphi > M_PI_2) bowphi -=
M_PI;
967 if(bowphi < -M_PI_2) bowphi +=
M_PI;
969 double angle = std::atan(std::tan(bowphi)-readoutside*tanl);
972 if (boweta>M_PI_2) boweta-=
M_PI;
973 if (boweta<-M_PI_2) boweta+=
M_PI;
976 input.rowWeightedPosition=rowWeightedPosition;
977 input.columnWeightedPosition=columnWeightedPosition;
978 ATH_MSG_VERBOSE(
" RowWeightedPosition: " << rowWeightedPosition <<
" ColWeightedPosition: " << columnWeightedPosition );
993 const Eigen::VectorXd& input)
const {
995 std::vector<double> result(3, 0.0);
997 if (!onnxCollection.
isValid()) {
1001 Ort::Session& session = *onnxCollection->numberNetwork;
1004 auto inputTypeInfo = session.GetInputTypeInfo(0);
1005 auto tensorInfo = inputTypeInfo.GetTensorTypeAndShapeInfo();
1006 const int64_t expectedDim = tensorInfo.GetShape()[1];
1009 if (
static_cast<int64_t
>(input.size()) != expectedDim) {
1010 ATH_MSG_FATAL(
"ONNX number network expects input dimension " << expectedDim
1011 <<
" but got " << input.size() <<
" — check model/configuration");
1014 std::vector<float> inputData(expectedDim);
1015 for (
int i = 0; i < expectedDim; ++i) {
1016 inputData[i] =
static_cast<float>(input[i]);
1020 Ort::MemoryInfo memInfo = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
1021 std::vector<int64_t> inputShape = {1, expectedDim};
1022 Ort::Value inputTensor = Ort::Value::CreateTensor<float>(
1023 memInfo, inputData.data(), inputData.size(),
1024 inputShape.data(), inputShape.size());
1025 Ort::AllocatorWithDefaultOptions allocator;
1026 auto inputName = session.GetInputNameAllocated(0, allocator);
1027 auto outputName = session.GetOutputNameAllocated(0, allocator);
1028 const char* inputNames[] = {inputName.get()};
1029 const char* outputNames[] = {outputName.get()};
1032 auto outputTensors = session.Run(
1033 Ort::RunOptions{
nullptr},
1034 inputNames, &inputTensor, 1,
1038 const float* outputData = outputTensors[0].GetTensorData<
float>();
1039 double num0 = outputData[0];
1040 double num1 = outputData[1];
1041 double num2 = outputData[2];
1044 const double sum = num0 + num1 + num2;
1046 ATH_MSG_WARNING(
"ONNX number network output sum is non-positive: " << sum);
1049 const double inverseSum = 1.0 / sum;
1050 result[0] = num0 * inverseSum;
1051 result[1] = num1 * inverseSum;
1052 result[2] = num2 * inverseSum;
1055 <<
" (2): " << result[1]
1056 <<
" (3): " << result[2]);
1060 std::vector<Amg::Vector2D>
1062 const Eigen::VectorXd& input,
1065 int numberSubClusters,
1066 std::vector<Amg::MatrixX>& errors)
const {
1068 std::vector<Amg::Vector2D> allPositions;
1069 if (numberSubClusters < 1 || numberSubClusters >
static_cast<int>(
m_maxSubClusters)) {
1070 return allPositions;
1074 if (!onnxCollection.
isValid()) {
1076 return allPositions;
1078 Ort::Session* posNet =
nullptr;
1079 if (numberSubClusters == 1) posNet = onnxCollection->positionNetwork1.get();
1080 else if (numberSubClusters == 2) posNet = onnxCollection->positionNetwork2.get();
1081 else if (numberSubClusters == 3) posNet = onnxCollection->positionNetwork3.get();
1084 ATH_MSG_FATAL(
"ONNX position network for " << numberSubClusters
1085 <<
" sub-clusters not found in collection");
1086 return allPositions;
1089 Ort::Session& session = *posNet;
1092 auto inputTypeInfo = session.GetInputTypeInfo(0);
1093 auto tensorInfo = inputTypeInfo.GetTensorTypeAndShapeInfo();
1094 const int64_t expectedDim = tensorInfo.GetShape()[1];
1097 if (
static_cast<int64_t
>(input.size()) != expectedDim) {
1098 ATH_MSG_FATAL(
"ONNX position network (" << numberSubClusters
1099 <<
" sub-clusters) expects input dimension " << expectedDim
1100 <<
" but got " << input.size() <<
" — check model/configuration");
1101 return allPositions;
1103 std::vector<float> inputData(expectedDim);
1104 for (
int i = 0; i < expectedDim; ++i) {
1105 inputData[i] =
static_cast<float>(input[i]);
1109 Ort::MemoryInfo memInfo = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
1110 std::vector<int64_t> inputShape = {1, expectedDim};
1111 Ort::Value inputTensor = Ort::Value::CreateTensor<float>(
1112 memInfo, inputData.data(), inputData.size(),
1113 inputShape.data(), inputShape.size());
1114 Ort::AllocatorWithDefaultOptions allocator;
1115 auto inputName = session.GetInputNameAllocated(0, allocator);
1116 auto outputName = session.GetOutputNameAllocated(0, allocator);
1117 const char* inputNames[] = {inputName.get()};
1118 const char* outputNames[] = {outputName.get()};
1121 auto outputTensors = session.Run(
1122 Ort::RunOptions{
nullptr},
1123 inputNames, &inputTensor, 1,
1128 const float* outputData = outputTensors[0].GetTensorData<
float>();
1130 std::vector<double> positionValues;
1131 positionValues.reserve(numberSubClusters * 2);
1133 for (
int iSub = 0; iSub < numberSubClusters; ++iSub) {
1134 const int offset = iSub * 5;
1136 const double mean_x = outputData[offset + 1];
1137 const double mean_y = outputData[offset + 2];
1138 const double prec_x = outputData[offset + 3];
1139 const double prec_y = outputData[offset + 4];
1141 positionValues.push_back(mean_x);
1142 positionValues.push_back(mean_y);
1145 if (prec_x <= 0 || prec_y <= 0) {
1146 ATH_MSG_WARNING(
"ONNX position network returned non-positive precision for sub-cluster "
1147 << iSub <<
" (prec_x=" << prec_x <<
", prec_y=" << prec_y
1148 <<
"); using fallback RMS of 0.01");
1150 const float rawRmsX = (prec_x > 0) ? std::sqrt(1.0f / prec_x) : 0.01f;
1151 const float rawRmsY = (prec_y > 0) ? std::sqrt(1.0f / prec_y) : 0.01f;
1157 erm(0, 0) = rmsX * rmsX;
1158 erm(1, 1) = rmsY * rmsY;
1159 errors.push_back(erm);
1164 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.
static unsigned int getFE(const PixelDiodeTree::DiodeProxy &diode_proxy)
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
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
double correctedRMSY(double posPixels, std::vector< float > &pitches) const
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
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
static double correctedRMSX(double posPixels)
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.