@@ -76,7 +76,7 @@ void CalculatedEdx::fillMissingClusters(int missingClusters[4], float minChargeT
7676 }
7777}
7878
79- void CalculatedEdx::handleSameRowClusters (o2::tpc::TrackTPC& track, std::map<std::pair<unsigned char , unsigned char >, std::vector<int >>& clustersByRow, std::map<std::pair<unsigned char , unsigned char >, o2::tpc::ClusterNative>& combinedClustersByRow, std::map<int , std::tuple<unsigned char , unsigned char , unsigned int >>& clusterReferencesByIndex)
79+ void CalculatedEdx::handleSameRowClusters (o2::tpc::TrackTPC& track, std::vector<std::pair< unsigned char , unsigned char >>& rowOrder, std:: map<std::pair<unsigned char , unsigned char >, std::vector<int >>& clustersByRow, std::map<std::pair<unsigned char , unsigned char >, o2::tpc::ClusterNative>& combinedClustersByRow, std::map<int , std::tuple<unsigned char , unsigned char , unsigned int >>& clusterReferencesByIndex)
8080{
8181 // get number of clusters
8282 const int nClusters = track.getNClusterReferences ();
@@ -91,8 +91,13 @@ void CalculatedEdx::handleSameRowClusters(o2::tpc::TrackTPC& track, std::map<std
9191
9292 track.getClusterReference (*mTPCTrackClIdxVecInput , iCl, sectorIndex, rowIndex, clusterIndexNumb);
9393
94+ const auto rowKey = std::make_pair (sectorIndex, rowIndex);
95+ if (clustersByRow.find (rowKey) == clustersByRow.end ()) {
96+ rowOrder.emplace_back (rowKey);
97+ }
98+
9499 // add the cluster index to the corresponding (sector, row) key in clustersByRow
95- clustersByRow[{sectorIndex, rowIndex} ].emplace_back (iCl);
100+ clustersByRow[rowKey ].emplace_back (iCl);
96101
97102 // store the reference data in clusterReferencesByIndex
98103 clusterReferencesByIndex[iCl] = std::make_tuple (sectorIndex, rowIndex, clusterIndexNumb);
@@ -180,11 +185,12 @@ void CalculatedEdx::calculatedEdx(o2::tpc::TrackTPC& track, dEdxInfo& output, Av
180185 float scCorr = 1 .0f ;
181186
182187 // handle same (sector, row) clusters
188+ std::vector<std::pair<unsigned char , unsigned char >> rowOrder;
183189 std::map<std::pair<unsigned char , unsigned char >, std::vector<int >> clustersByRow;
184190 std::map<std::pair<unsigned char , unsigned char >, o2::tpc::ClusterNative> combinedClustersByRow;
185191 std::map<int , std::tuple<unsigned char , unsigned char , unsigned int >> clusterReferencesByIndex;
186192
187- handleSameRowClusters (track, clustersByRow, combinedClustersByRow, clusterReferencesByIndex);
193+ handleSameRowClusters (track, rowOrder, clustersByRow, combinedClustersByRow, clusterReferencesByIndex);
188194
189195 o2::utils::TreeStreamRedirector* debugStreamer = nullptr ;
190196 o2::tpc::TrackTPC trackOrig;
@@ -195,8 +201,9 @@ void CalculatedEdx::calculatedEdx(o2::tpc::TrackTPC& track, dEdxInfo& output, Av
195201 trackOrig = track; // pristine track, before refit/propagation mutates it cluster-by-cluster below
196202 }
197203
198- // loop over the clusters
199- for (const auto & [rowKey, clusterIndices] : clustersByRow) {
204+ // loop over the clusters in the track's true physical row-traversal order (rowOrder)
205+ for (const auto & rowKey : rowOrder) {
206+ const auto & clusterIndices = clustersByRow.at (rowKey);
200207 const unsigned char rowIndex = rowKey.second ;
201208 int clusterIdx = clusterIndices[0 ];
202209 const o2::tpc::ClusterNative& clConst = track.getCluster (*mTPCTrackClIdxVecInput , clusterIdx, *mClusterIndex );
@@ -280,12 +287,27 @@ void CalculatedEdx::calculatedEdx(o2::tpc::TrackTPC& track, dEdxInfo& output, Av
280287 check = (mRefit ->RefitTrackAsGPU (track, false , true ) < 0 ) ? false : true ;
281288 } else if (mPropagateTrack ) {
282289 // propagate this track to the plane X=xk (cm) in the field "b" (kG)
283- track.rotate (o2::math_utils::detail::sector2Angle<float >(sectorIndex));
284- check = o2::base::Propagator::Instance ()->PropagateToXBxByBz (track, xPosition, 0 .999f , 2 ., o2::base::Propagator::MatCorrType::USEMatCorrLUT);
290+ // snapshot the fit state first and roll it back on failure
291+ // rotate() rejecting the frame change, or PropagateToXBxByBz failing mid-step e.g. its material-LUT lookup driving the state into an unphysical regime for a difficult trajectory
292+ // so that a single bad row doesn't leave the track corrupted for every subsequent row's propagation attempt
293+ const o2::track::TrackParCov trackBackup = track;
294+ check = track.rotate (o2::math_utils::detail::sector2Angle<float >(sectorIndex));
295+ if (check) {
296+ check = o2::base::Propagator::Instance ()->PropagateToXBxByBz (track, xPosition, 0 .999f , 0 .5f , o2::base::Propagator::MatCorrType::USEMatCorrLUT);
297+ }
298+ if (!check) {
299+ static_cast <o2::track::TrackParCov&>(track) = trackBackup;
300+ }
285301 } else if (mPropagateParams ) {
286- // propagate the params of the track instead of full propagation
287- track.rotateParam (o2::math_utils::detail::sector2Angle<float >(sectorIndex));
288- check = track.propagateParamTo (xPosition, mFieldNominalGPUBz );
302+ // propagate the params of the track instead of full propagation; same rollback rationale as mPropagateTrack above
303+ const o2::track::TrackParCov trackBackup = track;
304+ check = track.rotateParam (o2::math_utils::detail::sector2Angle<float >(sectorIndex));
305+ if (check) {
306+ check = track.propagateParamTo (xPosition, mFieldNominalGPUBz );
307+ }
308+ if (!check) {
309+ static_cast <o2::track::TrackParCov&>(track) = trackBackup;
310+ }
289311 }
290312
291313 if (!check || std::isnan (track.getParam (1 ))) {
0 commit comments