2828#include " GPUO2InterfaceUtils.h"
2929#include " GPUTPCGMMergedTrackHit.h"
3030
31+ #include < cstdlib>
32+
3133using namespace o2 ::tpc;
3234
3335CalculatedEdx::CalculatedEdx ()
@@ -373,21 +375,26 @@ void CalculatedEdx::gatherRowClusterDataForRow(o2::tpc::TrackTPC& track, const o
373375 row.gain = mCalibCont .getGain (sectorIndex, rowIndex, pad);
374376 row.gainResidual = mCalibCont .getResidualGain (sectorIndex, rowIndex, pad);
375377
376- // number of rows skipped since the previous row in rowOrder
377- row.missingClusters = rowIndex - rowIndexOld - 1 ;
378+ // number of rows skipped between this row and the previous entry in rowOrder
378379 row.sameSectorAsPrevRow = (sectorIndexOld == sectorIndex);
380+ row.missingClusters = (rowIndexOld == 255 ) ? 0 : (std::abs (static_cast <int >(rowIndex) - static_cast <int >(rowIndexOld)) - 1 );
379381
380382 // veto the gap as a subthreshold candidate if any of its missing row(s) would land on a dead channel or off the padrow edge
381383 row.missingClusterGapDeadOrEdge = false ;
382- if (row.missingClusters > 0 && row.missingClusters <= mMaxMissingCl && row. sameSectorAsPrevRow ) {
384+ if (row.missingClusters > 0 && row.missingClusters <= mMaxMissingCl ) {
383385 const o2::gpu::GPUTPCGeometry gpuGeom;
384386 const RowClusterData& prevRow = rowData.back ();
385- const float yPrev = gpuGeom.LinearPad2Y (sectorIndex, prevRow.rowIndex , prevRow.clPad );
386- const float yCur = gpuGeom.LinearPad2Y (sectorIndex, rowIndex, row.clPad );
387+ // bracket the gap by its lower/upper real row, independent of the rowOrder direction
388+ const int rowLo = std::min<int >(rowIndex, rowIndexOld);
389+ const int rowHi = std::max<int >(rowIndex, rowIndexOld);
390+ const float padLo = (rowLo == static_cast <int >(rowIndexOld)) ? prevRow.clPad : row.clPad ;
391+ const float padHi = (rowHi == static_cast <int >(rowIndexOld)) ? prevRow.clPad : row.clPad ;
392+ const float yLo = gpuGeom.LinearPad2Y (sectorIndex, rowLo, padLo);
393+ const float yHi = gpuGeom.LinearPad2Y (sectorIndex, rowHi, padHi);
387394 for (int k = 1 ; k <= row.missingClusters ; ++k) {
388- const unsigned char missingRow = prevRow. rowIndex + k;
395+ const unsigned char missingRow = static_cast < unsigned char >(rowLo + k) ;
389396 const float frac = static_cast <float >(k) / (row.missingClusters + 1 );
390- const float missingPad = gpuGeom.LinearY2Pad (sectorIndex, missingRow, yPrev + (yCur - yPrev ) * frac);
397+ const float missingPad = gpuGeom.LinearY2Pad (sectorIndex, missingRow, yLo + (yHi - yLo ) * frac);
391398 if (missingPad < 0 .f || missingPad >= gpuGeom.NPads (missingRow)) {
392399 row.missingClusterGapDeadOrEdge = true ;
393400 break ;
@@ -442,6 +449,7 @@ void CalculatedEdx::gatherRowClusterData(o2::tpc::TrackTPC& track, const std::ve
442449 const bool isShared = clusterInfos[clusterIdx].isShared ;
443450
444451 gatherRowClusterDataForRow (track, cl, sectorIndex, rowIndex, isCombined, isShared, rowIndexOld, sectorIndexOld, occupancyROC, rowData);
452+ rowData.back ().inputClusterIndices = clusterIndices; // positions in the caller-supplied clusters vector merged into this row
445453
446454 rowIndexOld = rowIndex;
447455 sectorIndexOld = sectorIndex;
@@ -492,7 +500,11 @@ void CalculatedEdx::calculatedEdxFromRowData(const std::vector<RowClusterData>&
492500 occupancyVector.reserve (rowData.size ());
493501 }
494502
495- for (const auto & row : rowData) {
503+ // a gap is not filled as a subthreshold cluster when the row that closes it sits within the outermost min(nRows/2, mSubThreshEdgeRows) rows
504+ const int edgeRowCut = std::min<int >(static_cast <int >(rowData.size ()) / 2 , mSubThreshEdgeRows );
505+
506+ for (size_t iRowData = 0 ; iRowData < rowData.size (); ++iRowData) {
507+ const auto & row = rowData[iRowData];
496508 if (mDebug ) {
497509 occupancyVector.emplace_back (row.occupancy );
498510 }
@@ -550,24 +562,28 @@ void CalculatedEdx::calculatedEdxFromRowData(const std::vector<RowClusterData>&
550562 chargeTot /= effectiveLength;
551563 chargeMax /= effectiveLength;
552564 };
565+
566+ const bool gainFullApplied = (settings.correctionMask & CorrectionFlags::GainFull) == CorrectionFlags::GainFull;
567+ float topoChargeTot = chargeTot;
568+ float topoChargeMax = chargeMax;
569+ if (gainFullApplied) {
570+ gain = row.gain ;
571+ chargeTot /= gain;
572+ chargeMax /= gain;
573+ } else {
574+ topoChargeTot *= row.gain ;
575+ topoChargeMax *= row.gain ;
576+ }
577+
578+ // topology correction
553579 if ((settings.correctionMask & CorrectionFlags::TopologyPol) == CorrectionFlags::TopologyPol) {
554- effectiveLengthTot = getTrackTopologyCorrectionPol (row.trackSnapshot , row.cl , row.region , chargeTot , ChargeType::Tot, row.threshold );
555- effectiveLengthMax = getTrackTopologyCorrectionPol (row.trackSnapshot , row.cl , row.region , chargeMax , ChargeType::Max, row.threshold );
580+ effectiveLengthTot = getTrackTopologyCorrectionPol (row.trackSnapshot , row.cl , row.region , topoChargeTot , ChargeType::Tot, row.threshold );
581+ effectiveLengthMax = getTrackTopologyCorrectionPol (row.trackSnapshot , row.cl , row.region , topoChargeMax , ChargeType::Max, row.threshold );
556582 chargeTot /= effectiveLengthTot;
557583 chargeMax /= effectiveLengthMax;
558584 };
559585
560- // get gain
561- if ((settings.correctionMask & CorrectionFlags::GainFull) == CorrectionFlags::GainFull) {
562- gain = row.gain ;
563- };
564- if ((settings.correctionMask & CorrectionFlags::GainResidual) == CorrectionFlags::GainResidual) {
565- gainResidual = row.gainResidual ;
566- };
567- chargeTot /= gain * gainResidual;
568- chargeMax /= gain * gainResidual;
569-
570- // get dEdx correction on tgl and sector plane
586+ // residual dE/dx correction on tgl and sector plane
571587 if ((settings.correctionMask & CorrectionFlags::dEdxResidual) == CorrectionFlags::dEdxResidual) {
572588 corrTot = mCalibCont .getResidualCorrection (row.stackID , ChargeType::Tot, row.trackSnapshot .getTgl (), row.trackSnapshot .getSnp ());
573589 corrMax = mCalibCont .getResidualCorrection (row.stackID , ChargeType::Max, row.trackSnapshot .getTgl (), row.trackSnapshot .getSnp ());
@@ -579,6 +595,13 @@ void CalculatedEdx::calculatedEdxFromRowData(const std::vector<RowClusterData>&
579595 };
580596 };
581597
598+ // residual gain map
599+ if ((settings.correctionMask & CorrectionFlags::GainResidual) == CorrectionFlags::GainResidual) {
600+ gainResidual = row.gainResidual ;
601+ chargeTot /= gainResidual;
602+ chargeMax /= gainResidual;
603+ };
604+
582605 // space-charge dEdx corrections
583606 const float time = row.clTime - trackTime0; // ToDo: get correct time from ITS-TPC track if possible
584607 if ((settings.correctionMask & CorrectionFlags::dEdxSC) == CorrectionFlags::dEdxSC) {
@@ -630,12 +653,13 @@ void CalculatedEdx::calculatedEdxFromRowData(const std::vector<RowClusterData>&
630653 << " residualCorrMax=" << corrMax
631654 << " scCorr=" << scCorr
632655 << " occupancy=" << row.occupancy
656+ << " inputClusterIndices=" << row.inputClusterIndices
633657 << " \n " ;
634658 };
635659
636660 // find missing clusters
637661 const int missingClusters = row.missingClusters ;
638- if ((missingClusters > 0 ) && (missingClusters <= mMaxMissingCl ) && !row.missingClusterGapDeadOrEdge ) {
662+ if ((missingClusters > 0 ) && (missingClusters <= mMaxMissingCl ) && !row.missingClusterGapDeadOrEdge && ( static_cast < int >(iRowData) >= edgeRowCut) ) {
639663 if ((settings.clusterMask & ClusterFlags::ExcludeSectorBoundaries) == ClusterFlags::ExcludeSectorBoundaries) {
640664 if (row.sameSectorAsPrevRow ) {
641665 if (row.stack == GEMstack::IROCgem) {
@@ -899,8 +923,13 @@ void CalculatedEdx::calculatedEdx(o2::tpc::TrackTPC& track, dEdxInfo& output, Av
899923 trackOrig = track; // pristine track, before refit/propagation mutates it cluster-by-cluster below
900924 }
901925
926+ // a gap is not filled as a subthreshold cluster when the row that closes it sits within the outermost min(nRows/2, mSubThreshEdgeRows) rows
927+ const int edgeRowCut = std::min<int >(static_cast <int >(rowOrder.size ()) / 2 , mSubThreshEdgeRows );
928+ size_t iRowData = 0 ;
929+
902930 // loop over the clusters in the track's true physical row-traversal order (rowOrder)
903931 for (const auto & rowKey : rowOrder) {
932+ const int iRowInTrack = static_cast <int >(iRowData++);
904933 const auto & clusterIndices = clustersByRow.at (rowKey);
905934 const unsigned char rowIndex = rowKey.second ;
906935 int clusterIdx = clusterIndices[0 ];
@@ -1033,24 +1062,29 @@ void CalculatedEdx::calculatedEdx(o2::tpc::TrackTPC& track, dEdxInfo& output, Av
10331062 chargeTot /= effectiveLength;
10341063 chargeMax /= effectiveLength;
10351064 };
1065+
1066+ const float fullGainMapGain = mCalibCont .getGain (sectorIndex, rowIndex, pad);
1067+ const bool gainFullApplied = (correctionMask & CorrectionFlags::GainFull) == CorrectionFlags::GainFull;
1068+ float topoChargeTot = chargeTot;
1069+ float topoChargeMax = chargeMax;
1070+ if (gainFullApplied) {
1071+ gain = fullGainMapGain;
1072+ chargeTot /= gain;
1073+ chargeMax /= gain;
1074+ } else {
1075+ topoChargeTot *= fullGainMapGain;
1076+ topoChargeMax *= fullGainMapGain;
1077+ }
1078+
1079+ // topology correction
10361080 if ((correctionMask & CorrectionFlags::TopologyPol) == CorrectionFlags::TopologyPol) {
1037- effectiveLengthTot = getTrackTopologyCorrectionPol (track, cl, region, chargeTot , ChargeType::Tot, threshold);
1038- effectiveLengthMax = getTrackTopologyCorrectionPol (track, cl, region, chargeMax , ChargeType::Max, threshold);
1081+ effectiveLengthTot = getTrackTopologyCorrectionPol (track, cl, region, topoChargeTot , ChargeType::Tot, threshold);
1082+ effectiveLengthMax = getTrackTopologyCorrectionPol (track, cl, region, topoChargeMax , ChargeType::Max, threshold);
10391083 chargeTot /= effectiveLengthTot;
10401084 chargeMax /= effectiveLengthMax;
10411085 };
10421086
1043- // get gain
1044- if ((correctionMask & CorrectionFlags::GainFull) == CorrectionFlags::GainFull) {
1045- gain = mCalibCont .getGain (sectorIndex, rowIndex, pad);
1046- };
1047- if ((correctionMask & CorrectionFlags::GainResidual) == CorrectionFlags::GainResidual) {
1048- gainResidual = mCalibCont .getResidualGain (sectorIndex, rowIndex, pad);
1049- };
1050- chargeTot /= gain * gainResidual;
1051- chargeMax /= gain * gainResidual;
1052-
1053- // get dEdx correction on tgl and sector plane
1087+ // residual dE/dx correction on tgl and sector plane
10541088 if ((correctionMask & CorrectionFlags::dEdxResidual) == CorrectionFlags::dEdxResidual) {
10551089 corrTot = mCalibCont .getResidualCorrection (stackID, ChargeType::Tot, track.getTgl (), track.getSnp ());
10561090 corrMax = mCalibCont .getResidualCorrection (stackID, ChargeType::Max, track.getTgl (), track.getSnp ());
@@ -1062,6 +1096,13 @@ void CalculatedEdx::calculatedEdx(o2::tpc::TrackTPC& track, dEdxInfo& output, Av
10621096 };
10631097 };
10641098
1099+ // residual gain map
1100+ if ((correctionMask & CorrectionFlags::GainResidual) == CorrectionFlags::GainResidual) {
1101+ gainResidual = mCalibCont .getResidualGain (sectorIndex, rowIndex, pad);
1102+ chargeTot /= gainResidual;
1103+ chargeMax /= gainResidual;
1104+ };
1105+
10651106 // space-charge dEdx corrections
10661107 const float time = clTime - track.getTime0 (); // ToDo: get correct time from ITS-TPC track if possible
10671108 if ((correctionMask & CorrectionFlags::dEdxSC) == CorrectionFlags::dEdxSC) {
@@ -1116,22 +1157,28 @@ void CalculatedEdx::calculatedEdx(o2::tpc::TrackTPC& track, dEdxInfo& output, Av
11161157 << " residualCorrMax=" << corrMax
11171158 << " scCorr=" << scCorr
11181159 << " occupancy=" << occupancy
1160+ << " inputClusterIndices=" << clusterIndices
11191161 << " \n " ;
11201162 };
11211163
11221164 // find missing clusters - deliberately evaluated before (independent of) this row's own excludeCl status
1123- int missingClusters = rowIndex - rowIndexOld - 1 ;
1165+ int missingClusters = (rowIndexOld == 255 ) ? 0 : ( std::abs ( static_cast < int >( rowIndex) - static_cast < int >( rowIndexOld)) - 1 ) ;
11241166
11251167 // veto the gap as a subthreshold candidate if any of its missing row(s) would land on a dead channel or off the padrow edge
11261168 bool missingClusterGapDeadOrEdge = false ;
1127- if (missingClusters > 0 && missingClusters <= mMaxMissingCl && sectorIndexOld == sectorIndex ) {
1169+ if (missingClusters > 0 && missingClusters <= mMaxMissingCl ) {
11281170 const o2::gpu::GPUTPCGeometry gpuGeom;
1129- const float yPrev = gpuGeom.LinearPad2Y (sectorIndex, rowIndexOld, clPadOld);
1130- const float yCur = gpuGeom.LinearPad2Y (sectorIndex, rowIndex, clPad);
1171+ // bracket the gap by its lower/upper real row, independent of the reference-list direction
1172+ const int rowLo = std::min<int >(rowIndex, rowIndexOld);
1173+ const int rowHi = std::max<int >(rowIndex, rowIndexOld);
1174+ const float padLo = (rowLo == static_cast <int >(rowIndexOld)) ? clPadOld : clPad;
1175+ const float padHi = (rowHi == static_cast <int >(rowIndexOld)) ? clPadOld : clPad;
1176+ const float yLo = gpuGeom.LinearPad2Y (sectorIndex, rowLo, padLo);
1177+ const float yHi = gpuGeom.LinearPad2Y (sectorIndex, rowHi, padHi);
11311178 for (int k = 1 ; k <= missingClusters; ++k) {
1132- const unsigned char missingRow = rowIndexOld + k;
1179+ const unsigned char missingRow = static_cast < unsigned char >(rowLo + k) ;
11331180 const float frac = static_cast <float >(k) / (missingClusters + 1 );
1134- const float missingPad = gpuGeom.LinearY2Pad (sectorIndex, missingRow, yPrev + (yCur - yPrev ) * frac);
1181+ const float missingPad = gpuGeom.LinearY2Pad (sectorIndex, missingRow, yLo + (yHi - yLo ) * frac);
11351182 if (missingPad < 0 .f || missingPad >= gpuGeom.NPads (missingRow)) {
11361183 missingClusterGapDeadOrEdge = true ;
11371184 break ;
@@ -1145,7 +1192,7 @@ void CalculatedEdx::calculatedEdx(o2::tpc::TrackTPC& track, dEdxInfo& output, Av
11451192 }
11461193 }
11471194
1148- if ((missingClusters > 0 ) && (missingClusters <= mMaxMissingCl ) && !missingClusterGapDeadOrEdge) {
1195+ if ((missingClusters > 0 ) && (missingClusters <= mMaxMissingCl ) && !missingClusterGapDeadOrEdge && (iRowInTrack >= edgeRowCut) ) {
11491196 if ((clusterMask & ClusterFlags::ExcludeSectorBoundaries) == ClusterFlags::ExcludeSectorBoundaries) {
11501197 if (sectorIndexOld == sectorIndex) {
11511198 if (stack == GEMstack::IROCgem) {
@@ -1341,7 +1388,11 @@ float CalculatedEdx::getTrackTopologyCorrectionPol(const o2::tpc::TrackTPC& trac
13411388{
13421389 const float snp = std::abs (track.getSnp ());
13431390 const float tgl = track.getTgl ();
1344- const float snp2 = snp * snp;
1391+ constexpr float maxSnp2 = 0 .99f ;
1392+ float snp2 = snp * snp;
1393+ if (snp2 > maxSnp2) {
1394+ snp2 = maxSnp2;
1395+ }
13451396 const float tgl2 = tgl * tgl;
13461397 const float sec2 = 1 .f / (1 .f - snp2);
13471398 const float tanTheta = std::sqrt (tgl2 * sec2);
0 commit comments