43 mFollowTrack = &Tracker::followTrackKeepAll;
45 mFollowTrack = &Tracker::followTrackKeepBest;
50 mMaxChi2 = 2. * mSigmaCut * mSigmaCut;
56int Tracker::getFirstNeighbourRPC(
int rpc)
const
59 return (rpc == 0) ? rpc : rpc - 1;
63int Tracker::getLastNeighbourRPC(
int rpc)
const
66 return (rpc == 8) ? rpc : rpc + 1;
70bool Tracker::loadClusters(gsl::span<const Cluster>&
clusters)
77 mClusterIndexes[deId].emplace_back(mClusters.size());
78 const auto& position = mTransformer.
localToGlobal(deId, cl.xCoor, cl.yCoor);
79 mClusters.emplace_back(cl);
80 mClusters.back().xCoor = position.x();
81 mClusters.back().yCoor = position.y();
82 mClusters.back().zCoor = position.z();
95 mTrackROFRecords.clear();
96 mClusterROFRecords.clear();
97 for (
auto& rofRecord : rofRecords) {
98 auto firstTrackEntry = mTracks.size();
99 auto firstClusterEntry = mClusters.size();
100 process(
clusters.subspan(rofRecord.firstEntry, rofRecord.nEntries),
true);
101 auto nTrackEntries = mTracks.size() - firstTrackEntry;
102 mTrackROFRecords.emplace_back(rofRecord, firstTrackEntry, nTrackEntries);
103 auto nClusterEntries = mClusters.size() - firstClusterEntry;
104 mClusterROFRecords.emplace_back(rofRecord, firstClusterEntry, nClusterEntries);
115 for (
auto& clIdx : mClusterIndexes) {
126 mFirstTrackOffset = mTracks.size();
130 mTrackOffset = mTracks.size();
132 processSide(
true,
true);
133 mNTracksStep1 = mTracks.size() - mTrackOffset;
135 processSide(
true,
false);
137 mTrackOffset = mTracks.size();
139 processSide(
false,
true);
140 mNTracksStep1 = mTracks.size() - mTrackOffset;
142 processSide(
false,
false);
143 }
catch (std::exception
const& e) {
144 LOG(error) << e.what() <<
" --> abort";
145 mTracks.erase(mTracks.begin() + mFirstTrackOffset, mTracks.end());
151void Tracker::processSide(
bool isRight,
bool isInward)
154 int firstCh = (isInward) ? 3 : 0;
155 int secondCh = (isInward) ? 2 : 1;
161 for (
int irpc = 0; irpc < 9; ++irpc) {
162 int deId1 = rpcOffset1 + irpc;
163 for (
auto clIdx1 : mClusterIndexes[deId1]) {
165 auto& cl1 = mClusters[clIdx1];
166 int firstRpc = getFirstNeighbourRPC(irpc);
167 int lastRpc = getLastNeighbourRPC(irpc);
168 for (
int irpc2 = firstRpc; irpc2 <= lastRpc; ++irpc2) {
170 int deId2 = rpcOffset2 + irpc2;
171 for (
auto clIdx2 : mClusterIndexes[deId2]) {
173 auto& cl2 = mClusters[clIdx2];
175 if (!makeTrackSeed(track, cl1, cl2)) {
183 std::invoke(mFollowTrack,
this, track, isRight, isInward);
191bool Tracker::makeTrackSeed(Track& track,
const Cluster& cl1,
const Cluster& cl2)
const
196 if (!(cl1.isFired(0) || cl2.isFired(0)) || !(cl1.isFired(1) || cl2.isFired(1))) {
201 double dZ = cl2.zCoor - cl1.zCoor;
202 double dZ2 = dZ * dZ;
203 double nonBendingSlope = (cl2.xCoor - cl1.xCoor) / dZ;
204 double nonBendingImpactParam = std::abs(cl2.xCoor - cl2.zCoor * nonBendingSlope);
205 double nonBendingImpactParamErr = std::sqrt(
206 (cl1.zCoor * cl1.zCoor * cl2.getEX2() + cl2.zCoor * cl2.zCoor * cl1.getEX2()) / dZ2);
207 if ((nonBendingImpactParam - mSigmaCut * nonBendingImpactParamErr) > mImpactParamCut) {
212 track.setPosition(cl2.xCoor, cl2.yCoor, cl2.zCoor);
213 track.setDirection(nonBendingSlope, (cl2.yCoor - cl1.yCoor) / dZ, 1.);
214 track.setCovarianceParameters(cl2.getEX2(),
216 (cl1.getEX2() + cl2.getEX2()) / dZ2,
217 (cl1.getEY2() + cl2.getEY2()) / dZ2,
224 track.resetIncomplete();
225 for (
int cathode = 0; cathode < 2; ++cathode) {
226 if (!cl1.isFired(cathode) || !cl2.isFired(cathode)) {
227 track.setIncomplete(cathode);
235void Tracker::followTrackKeepAll(Track& track,
bool isRight,
bool isInward)
247 std::unordered_set<int> excludedClusters;
252 findAllClusters(track, isRight, 1, 0, 8, 0, excludedClusters,
true);
255 if (skipOneChamber(track)) {
256 findAllClusters(track, isRight, 0, 0, 8, -1, excludedClusters,
true);
259 }
else if (skipOneChamber(track)) {
262 excludeUsedClusters(track, 1, 0, excludedClusters);
265 findAllClusters(track, isRight, 2, 0, 8, -1, excludedClusters,
true);
268 findAllClusters(track, isRight, 3, 0, 8, -1, excludedClusters,
true);
273bool Tracker::findAllClusters(
const Track& track,
bool isRight,
int chamber,
int firstRPC,
int lastRPC,
int nextChamber,
274 std::unordered_set<int>& excludedClusters,
bool excludeClusters)
282 bool clusterFound =
false;
285 for (
int irpc = firstRPC; irpc <= lastRPC; ++irpc) {
286 int deId = rpcOffset + irpc;
287 for (
auto clIdx : mClusterIndexes[deId]) {
290 if (excludeClusters && excludedClusters.count(clIdx) > 0) {
295 if (!tryOneCluster(track, chamber, clIdx, newTrack)) {
301 if (!excludeClusters) {
302 excludedClusters.emplace(clIdx);
307 if (nextChamber < 0 || (!findAllClusters(newTrack, isRight, nextChamber, getFirstNeighbourRPC(irpc),
308 getLastNeighbourRPC(irpc), -1, excludedClusters,
false) &&
309 skipOneChamber(newTrack))) {
311 throw std::length_error(std::string(
"Too many track candidates (") +
312 (mTracks.size() - mFirstTrackOffset) +
")");
314 newTrack.propagateToZ(SMT11Z);
315 mTracks.emplace_back(newTrack);
324void Tracker::followTrackKeepBest(Track& track,
bool isRight,
bool isInward)
338 std::array<int, 2> chamberOrder;
339 chamberOrder[0] = isInward ? 1 : 2;
340 chamberOrder[1] = isInward ? 0 : 3;
345 findNextCluster(track, isRight, isInward, chamberOrder[0], 0, 8, bestTrack);
348 if (bestTrack.getNDF() != 4 && skipOneChamber(track)) {
349 findNextCluster(track, isRight, isInward, chamberOrder[1], 0, 8, bestTrack);
352 if (bestTrack.getNDF() > 0) {
354 bestTrack.propagateToZ(SMT11Z);
357 tryAddTrack(bestTrack);
362void Tracker::findNextCluster(
const Track& track,
bool isRight,
bool isInward,
int chamber,
int firstRPC,
int lastRPC,
363 Track& bestTrack)
const
366 int nextChamber = (isInward) ? chamber - 1 :
chamber + 1;
369 for (
int irpc = firstRPC; irpc <= lastRPC; ++irpc) {
370 int deId = rpcOffset + irpc;
371 for (
auto clIdx : mClusterIndexes[deId]) {
372 if (!tryOneCluster(track, chamber, clIdx, newTrack)) {
375 if (nextChamber >= 0 && nextChamber <= 3) {
378 findNextCluster(newTrack, isRight, isInward, nextChamber,
379 getFirstNeighbourRPC(irpc), getLastNeighbourRPC(irpc), bestTrack);
382 if (!skipOneChamber(newTrack)) {
386 if (newTrack.getNDF() > bestTrack.getNDF() ||
387 (newTrack.getNDF() == bestTrack.getNDF() && newTrack.getChi2() < bestTrack.getChi2())) {
389 bestTrack = newTrack;
396bool Tracker::tryOneCluster(
const Track& track,
int chamber,
int clIdx, Track& newTrack)
const
402 auto& cl = mClusters[clIdx];
403 if ((track.isIncomplete(0) && !cl.isFired(0)) || (track.isIncomplete(1) && !cl.isFired(1))) {
408 newTrack.propagateToZ(cl.zCoor);
410 double diff[2] = {cl.xCoor - newTrack.getPositionX(), cl.yCoor - newTrack.getPositionY()};
413 double chi2 = diff[0] * diff[0] / err2[0] + diff[1] * diff[1] / err2[1];
414 if (chi2 > mMaxChi2) {
418 runKalmanFilter(newTrack, cl);
419 newTrack.setChi2(track.getChi2() + chi2);
420 newTrack.setNDF(track.getNDF() + 2);
421 newTrack.setClusterMatchedUnchecked(chamber, clIdx);
424 for (
int cathode = 0; cathode < 2; ++cathode) {
425 if (!cl.isFired(cathode)) {
426 newTrack.setIncomplete(cathode);
434void Tracker::runKalmanFilter(Track& track,
const Cluster& cluster)
const
438 double pos[2] = {track.getPositionX(), track.getPositionY()};
439 double dir[2] = {track.getDirectionX(), track.getDirectionY()};
440 const std::array<float, 6>& covParams = track.getCovarianceParameters();
441 double clusPos[2] = {cluster.xCoor, cluster.yCoor};
442 double clusterSigma[2] = {cluster.getEX2(), cluster.getEY2()};
444 std::array<float, 6> newCovParams;
445 double newPos[2], newDir[2];
446 for (
int idx = 0;
idx < 2; ++
idx) {
447 int slopeIdx =
idx + 2;
448 int covIdx =
idx + 4;
450 double den = clusterSigma[
idx] + covParams[
idx];
459 newCovParams[
idx] = covParams[
idx] * clusterSigma[
idx] / den;
461 newCovParams[covIdx] = covParams[covIdx] * clusterSigma[
idx] / den;
463 newCovParams[slopeIdx] = covParams[slopeIdx] - covParams[covIdx] * covParams[covIdx] / den;
471 newDir[
idx] = dir[
idx] + diff * covParams[covIdx] / den;
475 track.setPosition(newPos[0], newPos[1], cluster.zCoor);
476 track.setDirection(newDir[0], newDir[1], 1.);
479 track.setCovarianceParameters(newCovParams);
483void Tracker::tryAddTrack(
const Track& track)
495 float chi2Cut = 0.4 * mSigmaCut * mSigmaCut;
496 for (
auto checkTrack = mTracks.begin() + mTrackOffset; checkTrack != mTracks.end(); ++checkTrack) {
497 int nCommonClusters = 0;
498 for (
int ich = 0; ich < 4; ++ich) {
499 if (track.getClusterMatchedUnchecked(ich) == checkTrack->getClusterMatchedUnchecked(ich)) {
503 if (nCommonClusters == 4) {
506 if (nCommonClusters == 3 && track.isCompatible(*checkTrack,
chi2Cut)) {
508 if (track.getNDF() > checkTrack->getNDF() ||
509 (track.getNDF() == checkTrack->getNDF() && track.getChi2() < checkTrack->getChi2())) {
518 mTracks.emplace_back(track);
522void Tracker::excludeUsedClusters(
const Track& track,
int ch1,
int ch2, std::unordered_set<int>& excludedClusters)
const
527 int nTracks = mTrackOffset + mNTracksStep1;
528 for (
int i = mTrackOffset;
i < nTracks; ++
i) {
529 const auto& tr = mTracks[
i];
530 if (track.getClusterMatchedUnchecked(ch1) == tr.getClusterMatchedUnchecked(ch1) &&
531 track.getClusterMatchedUnchecked(ch2) == tr.getClusterMatchedUnchecked(ch2)) {
532 excludedClusters.emplace(tr.getClusterMatchedUnchecked(3 - ch1));
533 excludedClusters.emplace(tr.getClusterMatchedUnchecked(3 - ch2));
539bool Tracker::skipOneChamber(Track& track)
const
545 if (track.isIncomplete(0) || track.isIncomplete(1)) {
549 track.setIncomplete(0);
550 track.setIncomplete(1);
Useful detector parameters for MID.
Configurable parameters for MID tracking.
Track reconstruction algorithm for MID.
static const TrackerParam & Instance()
HMPID cluster implementation.
This class defines the MID track.
@ VarX
Variance on X position.
@ VarY
Variance on Y position.
void setClusterMatchedUnchecked(int chamber, int id)
bool init(bool keepAll=false)
void process(gsl::span< const Cluster > clusters, bool accumulate=false)
Tracker(const GeometryTransformer &geoTrans)
o2::track::TrackParCov Track
std::optional< Chamber > chamber(int chamberId)
int getDEId(bool isRight, int chamber, int rpc)
std::vector< Cluster > clusters
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"