Project
Loading...
Searching...
No Matches
MatchGlobalFwd.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
13#include "MathUtils/Utils.h"
14#include <queue>
15
16using namespace o2::globaltracking;
17
18//_________________________________________________________
20{
21
22 LOG(info) << "Initializing Global Forward Matcher";
23
24 auto& matchingParam = GlobalFwdMatchingParam::Instance();
25
26 setMFTRadLength(matchingParam.MFTRadLength);
27 LOG(info) << "MFT Radiation Length = " << mMFTDiskThicknessInX0 * 5.;
28
29 setAlignResiduals(matchingParam.alignResidual);
30 LOG(info) << "MFT Align residuals = " << mAlignResidual;
31
32 mMatchingPlaneZ = matchingParam.matchPlaneZ;
33 LOG(info) << "MFTMCH matchingPlaneZ = " << mMatchingPlaneZ;
34
35 auto& matchingFcnStr = matchingParam.matchFcn;
36 LOG(info) << "Match function string = " << matchingFcnStr;
37
38 if (matchingParam.isMatchUpstream()) {
39 LOG(info) << " ==> Setting Upstream matching.";
40 mMatchingType = MATCHINGUPSTREAM;
41 } else if (matchingParam.matchingExternalFunction()) {
42 loadExternalMatchingFunction();
43 mMatchingType = MATCHINGFUNC;
44 } else {
45 if (mMatchingFunctionMap.find(matchingFcnStr) != mMatchingFunctionMap.end()) {
46 mMatchFunc = mMatchingFunctionMap[matchingFcnStr];
47 mMatchingType = MATCHINGFUNC;
48 LOG(info) << " Found built-in matching function " << matchingFcnStr;
49 } else {
50 throw std::invalid_argument("Invalid matching function! Aborting...");
51 }
52 }
53
54 auto& cutFcnStr = matchingParam.cutFcn;
55 LOG(info) << "MFTMCH pair candidate cut function string = " << cutFcnStr;
56
57 if (matchingParam.cutExternalFunction()) {
58 loadExternalCutFunction();
59 } else if (mCutFunctionMap.find(cutFcnStr) != mCutFunctionMap.end()) {
60 mCutFunc = mCutFunctionMap[cutFcnStr];
61 LOG(info) << " Found built-in cut function " << cutFcnStr;
62 } else {
63 throw std::invalid_argument("Invalid cut function! Aborting...");
64 }
65
66 mUseMIDMCHMatch = matchingParam.useMIDMatch;
67 LOG(info) << "UseMIDMCH Matching = " << (mUseMIDMCHMatch ? "true" : "false");
68
69 mUseTrackTime = matchingParam.useTrackTime;
70 LOG(info) << "Use track time = " << (mUseTrackTime ? "true" : "false");
71
72 mSaveMode = matchingParam.saveMode;
73 LOG(info) << "Save mode MFTMCH candidates = " << mSaveMode;
74
75 mNCandidates = matchingParam.nCandidates;
76}
77
78//_________________________________________________________
80{
81
82 auto& matchingParam = GlobalFwdMatchingParam::Instance();
83
84 mRecoCont = &inp;
85 mStartIR = inp.startIR;
86
87 clear();
88
89 if (!prepareMFTData() || !prepareMCHData() || !processMCHMIDMatches()) {
90 return;
91 }
92
93 if (matchingParam.MCMatching) { // MC Label matching
94 mMCTruthON ? doMCMatching() : throw std::runtime_error("Label matching requries MC Labels!");
95 } else {
96 switch (mMatchingType) {
97 case MATCHINGFUNC:
98 switch (mSaveMode) {
99 case kBestMatch:
100 doMatching<kBestMatch>();
101 break;
102 case kSaveAll:
103 doMatching<kSaveAll>();
104 break;
106 doMatching<kSaveTrainingData>();
107 break;
108 case kSaveNCandidates:
109 doMatching<kSaveNCandidates>();
110 break;
111 default:
112 LOG(fatal) << "Invalid MFTMCH save mode";
113 }
114 break;
115 case MATCHINGUPSTREAM:
116 loadMatches();
117 break;
118 default:
119 LOG(fatal) << "Invalid MFTMCH matching mode";
120 }
121 }
122
123 fitTracks();
124 finalize();
125}
126
127//_________________________________________________________
129{
130 LOG(info) << " Finalizing GlobalForwardMatch. Pushing " << mMatchedTracks.size() << " matched tracks";
131}
132
133//_________________________________________________________
135{
136 mMCHROFTimes.clear();
137 mMCHWork.clear();
138 mMFTROFTimes.clear();
139 mMFTWork.clear();
140 mMFTClusters.clear();
141 mMatchedTracks.clear();
142 mMatchLabels.clear();
143 mMFTTrackROFContMapping.clear();
144 mMatchingInfo.clear();
145 mCandidates.clear();
146}
147
148//_________________________________________________________
149bool MatchGlobalFwd::prepareMCHData()
150{
151 const auto& inp = *mRecoCont;
152
153 // Load MCH tracks
154 mMCHTracks = inp.getMCHTracks();
155 mMCHTrackROFRec = inp.getMCHTracksROFRecords();
156 if (mMCTruthON) {
157 mMCHTrkLabels = inp.getMCHTracksMCLabels();
158 }
159 int nROFs = mMCHTrackROFRec.size();
160 LOG(info) << "Loaded " << mMCHTracks.size() << " MCH Tracks in " << nROFs << " ROFs";
161 if (mMCHTracks.empty()) {
162 return false;
163 }
164 mMCHWork.reserve(mMCHTracks.size());
165 mMCHID2Work.clear();
166 mMCHID2Work.resize(mMCHTracks.size(), -1);
167 static int BCDiffErrCount = 0;
168 constexpr int MAXBCDiffErrCount = 2;
169
170 for (int irof = 0; irof < nROFs; irof++) {
171 const auto& rofRec = mMCHTrackROFRec[irof];
172
173 int nBC = rofRec.getBCData().differenceInBC(mStartIR);
174 if (nBC < 0) {
175 if (BCDiffErrCount++ < MAXBCDiffErrCount) {
176 LOGP(alarm, "wrong bunches diff. {} for current IR {} wrt 1st TF orbit {} in MCH data", nBC, rofRec.getBCData().asString(), mStartIR.asString());
177 }
178 }
179 float tMin = nBC * o2::constants::lhc::LHCBunchSpacingMUS;
180 float tMax = (nBC + rofRec.getBCWidth()) * o2::constants::lhc::LHCBunchSpacingMUS;
181 auto mchTime = rofRec.getTimeMUS(mStartIR).first;
182
183 mMCHROFTimes.emplace_back(tMin, tMax); // MCH ROF min/max time
184 LOG(debug) << "MCH ROF # " << irof << " " << rofRec.getBCData() << " [tMin;tMax] = [" << tMin << ";" << tMax << "]";
185 int trlim = rofRec.getFirstIdx() + rofRec.getNEntries();
186 for (int it = rofRec.getFirstIdx(); it < trlim; it++) {
187 auto& trcOrig = mMCHTracks[it];
188 int nWorkTracks = mMCHWork.size();
189 mMCHID2Work[it] = nWorkTracks;
190 // working copy MCH track propagated to matching plane and converted to the forward track format
191 o2::mch::TrackParam tempParam(trcOrig.getZ(), trcOrig.getParameters(), trcOrig.getCovariances());
192 if (!o2::mch::TrackExtrap::extrapToVertexWithoutBranson(tempParam, mMatchingPlaneZ)) {
193 LOG(warning) << "MCH track propagation to matching plane failed!";
194 continue;
195 }
196 auto convertedTrack = MCHtoFwd(tempParam);
197 auto& thisMCHTrack = mMCHWork.emplace_back(TrackLocMCH{convertedTrack, {tMin, tMax}});
198 thisMCHTrack.setMCHTrackID(it);
199 thisMCHTrack.setTimeMUS(mchTime);
200 }
201 }
202 return true;
203}
204
205//_________________________________________________________
206bool MatchGlobalFwd::processMCHMIDMatches()
207{
208 if (mUseMIDMCHMatch) {
209 const auto& inp = *mRecoCont;
210
211 // Load MCHMID matches
212 mMCHMIDMatches = inp.getMCHMIDMatches();
213
214 LOG(info) << "Loaded " << mMCHMIDMatches.size() << " MCHMID matches";
215
216 for (const auto& MIDMatch : mMCHMIDMatches) {
217 const auto& MCHId = MIDMatch.getMCHRef().getIndex();
218 const auto& MIDId = MIDMatch.getMIDRef().getIndex();
219 auto& thisMuonTrack = mMCHWork[mMCHID2Work[MCHId]];
220 LOG(debug) << " MCHId: " << MCHId << " --> mMCHID2Work[MCHId]:" << mMCHID2Work[MCHId];
221 const auto& IR = MIDMatch.getIR();
222 int nBC = IR.differenceInBC(mStartIR);
223 float tMin = (nBC - 1) * o2::constants::lhc::LHCBunchSpacingMUS;
224 float tMax = (nBC + 2) * o2::constants::lhc::LHCBunchSpacingMUS;
225 thisMuonTrack.setMIDTrackID(MIDId);
226 thisMuonTrack.setTimeMUS(MIDMatch.getTimeMUS(mStartIR).first);
227 thisMuonTrack.tBracket.set(tMin, tMax);
228 thisMuonTrack.setMIDMatchingChi2(MIDMatch.getMatchChi2OverNDF());
229 }
230 }
231 return true;
232}
233
234//_________________________________________________________
235bool MatchGlobalFwd::prepareMFTData()
236{
237 const auto& inp = *mRecoCont;
238
239 // MFT clusters
240 mMFTClusterROFRec = inp.getMFTClustersROFRecords();
241 mMFTTrackClusIdx = inp.getMFTTracksClusterRefs();
242 const auto clusMFT = inp.getMFTClusters();
243 if (mMFTClusterROFRec.empty() || clusMFT.empty()) {
244 return false;
245 }
246 const auto patterns = inp.getMFTClustersPatterns();
247 auto pattIt = patterns.begin();
248 mMFTClusters.reserve(clusMFT.size());
249 o2::mft::ioutils::convertCompactClusters(clusMFT, pattIt, mMFTClusters, mMFTDict);
250
251 // Load MFT tracks
252 mMFTTracks = inp.getMFTTracks();
253 mMFTTrackROFRec = inp.getMFTTracksROFRecords();
254 if (mMCTruthON) {
255 mMFTTrkLabels = inp.getMFTTracksMCLabels();
256 }
257 int nROFs = mMFTTrackROFRec.size();
258
259 LOG(info) << "Loaded " << mMFTTracks.size() << " MFT Tracks in " << nROFs << " ROFs";
260 if (mMFTTracks.empty()) {
261 return false;
262 }
263 mMFTWork.reserve(mMFTTracks.size());
264 static int BCDiffErrCount = 0;
265 constexpr int MAXBCDiffErrCount = 2;
266
267 for (int irof = 0; irof < nROFs; irof++) {
268 const auto& rofRec = mMFTTrackROFRec[irof];
269 int nBC = rofRec.getBCData().differenceInBC(mStartIR);
270 if (nBC < 0) {
271 if (BCDiffErrCount++ < MAXBCDiffErrCount) {
272 LOGP(alarm, "TF dropped: wrong bunches diff. {} for current IR {} wrt 1st TF orbit {} in MFT data", nBC, rofRec.getBCData().asString(), mStartIR.asString());
273 }
274 return false;
275 }
276 float tMin = (nBC + mMFTROFrameBiasInBC) * o2::constants::lhc::LHCBunchSpacingMUS;
277 float tMax = (nBC + mMFTROFrameLengthInBC + mMFTROFrameBiasInBC) * o2::constants::lhc::LHCBunchSpacingMUS;
278 if (!mMFTTriggered) {
279 auto irofCont = (nBC + mMFTROFrameBiasInBC) / mMFTROFrameLengthInBC;
280 if (mMFTTrackROFContMapping.size() <= irofCont) { // there might be gaps in the non-empty rofs, this will map continuous ROFs index to non empty ones
281 mMFTTrackROFContMapping.resize((1 + irofCont / 128) * 128, 0);
282 }
283 mMFTTrackROFContMapping[irofCont] = irof;
284 }
285 mMFTROFTimes.emplace_back(tMin, tMax); // MFT ROF min/max time
286 LOG(debug) << "MFT ROF # " << irof << " " << rofRec.getBCData() << " [tMin;tMax] = [" << tMin << ";" << tMax << "]";
287
288 int trlim = rofRec.getFirstEntry() + rofRec.getNEntries();
289 for (int it = rofRec.getFirstEntry(); it < trlim; it++) {
290 const auto& trcOrig = mMFTTracks[it];
291
292 int nWorkTracks = mMFTWork.size();
293 // working copy of outer track param
294 auto& trc = mMFTWork.emplace_back(TrackLocMFT{trcOrig, {tMin, tMax}, irof});
295 trc.setParameters(trcOrig.getOutParam().getParameters());
296 trc.setZ(trcOrig.getOutParam().getZ());
297 trc.setCovariances(trcOrig.getOutParam().getCovariances());
298 trc.setTrackChi2(trcOrig.getOutParam().getTrackChi2());
299 // Extrapolate MFT track parameters and covariances matrix to "mMatchingPlaneZ"
300 // Parameters: helix track model; Error propagation: Quadratic
301 // If "mBz" is zero: linear track model
302 trc.propagateToZ(mMatchingPlaneZ, mBz);
303 }
304 }
305
306 return true;
307}
308
309//_________________________________________________________
310void MatchGlobalFwd::loadMatches()
311{
312
313 const auto& inp = *mRecoCont;
314 int nFakes = 0, nTrue = 0;
315
316 // Load MFT-MCH matching info
317 mMatchingInfoUpstream = inp.getMFTMCHMatches();
318
319 LOG(info) << "Loaded " << mMatchingInfoUpstream.size() << " MFTMCH Matches";
320
321 for (const auto& match : mMatchingInfoUpstream) {
322 auto MFTId = match.getMFTTrackID();
323 auto MCHId = match.getMCHTrackID();
324 LOG(debug) << " ==> MFTId = " << MFTId << " MCHId = " << MCHId << std::endl;
325
326 auto& thisMCHTrack = mMCHWork[mMCHID2Work[MCHId]];
327 thisMCHTrack.setMatchInfo(match);
328 mMatchedTracks.emplace_back(thisMCHTrack);
329 if (mMCTruthON) {
330 mMatchLabels.push_back(computeLabel(MCHId, MFTId));
331 mMatchLabels.back().isFake() ? nFakes++ : nTrue++;
332 }
333 }
334
335 LOG(info) << " Done matching from upstream " << mMFTWork.size() << " MFT tracks with " << mMCHWork.size() << " MCH Tracks.";
336 if (mMCTruthON) {
337 LOG(info) << " nFakes = " << nFakes << " nTrue = " << nTrue;
338 }
339}
340
341//_________________________________________________________
342template <Int_t saveAllMode>
343void MatchGlobalFwd::doMatching()
344{
345 // Range of compatible MCH ROFS for the first MFT track
346 int nMCHROFs = mMCHROFTimes.size();
347
348 LOG(info) << "Running MCH-MFT Track Matching.";
349 // ROFrame of first MFT track
350 auto firstMFTTrackIdInROF = 0;
351 auto MFTROFId = mMFTWork.front().roFrame;
352 LOG(debug) << "(*) nMCHROFs: " << nMCHROFs << ", mMFTTracks.size(): " << mMFTTracks.size() << " MFTROFId: " << MFTROFId << ", mMFTTrackROFRec.size(): " << mMFTTrackROFRec.size();
353
354 while ((firstMFTTrackIdInROF < mMFTTracks.size()) && (MFTROFId < mMFTTrackROFRec.size())) {
355 auto MFTROFId = mMFTWork[firstMFTTrackIdInROF].roFrame;
356 const auto& thisMFTBracket = mMFTROFTimes[MFTROFId];
357 auto nMFTTracksInROF = mMFTTrackROFRec[MFTROFId].getNEntries();
358 firstMFTTrackIdInROF = mMFTTrackROFRec[MFTROFId].getFirstEntry();
359 LOG(debug) << "MFT ROF = " << MFTROFId << "; interval: [" << thisMFTBracket.getMin() << "," << thisMFTBracket.getMax() << "]";
360 LOG(debug) << "ROF " << MFTROFId << " : firstMFTTrackIdInROF " << firstMFTTrackIdInROF << " ; nMFTTracksInROF = " << nMFTTracksInROF;
361 firstMFTTrackIdInROF += nMFTTracksInROF;
362
363 int mchROFMatchFirst = -1;
364 int mchROFMatchLast = -1;
365 int mchROF = 0;
366 // loop over MCH ROFs that are not newer than the current MFT ROF
367 while (mchROF < nMCHROFs && !(thisMFTBracket < mMCHROFTimes[mchROF])) {
368 // only consider non-empty MCH ROFs that overlap with the MFT one
369 if (mMCHTrackROFRec[mchROF].getNEntries() > 0 && !(thisMFTBracket.isOutside(mMCHROFTimes[mchROF]))) {
370 // set the index of the first MCH ROF if not yet initialized
371 if (mchROFMatchFirst < 0) {
372 mchROFMatchFirst = mchROF;
373 }
374 // update the index of the last MCH ROF
375 mchROFMatchLast = mchROF;
376 }
377 mchROF++;
378 }
379 // skip if the index of the first MCH ROF is not set
380 if (mchROFMatchFirst < 0) {
381 continue;
382 }
383 LOG(debug) << "FIRST MCH ROF " << mchROFMatchFirst << "; interval: ["
384 << mMCHROFTimes[mchROFMatchFirst].getMin() << ","
385 << mMCHROFTimes[mchROFMatchFirst].getMax() << "] size: " << mMCHTrackROFRec[mchROFMatchFirst].getNEntries();
386 LOG(debug) << "LAST MCH ROF " << mchROFMatchLast << "; interval: ["
387 << mMCHROFTimes[mchROFMatchLast].getMin() << ","
388 << mMCHROFTimes[mchROFMatchLast].getMax() << "] size: " << mMCHTrackROFRec[mchROFMatchLast].getNEntries();
389
390 ROFMatch<saveAllMode>(MFTROFId, mchROFMatchFirst, mchROFMatchLast);
391 }
392
393 if constexpr (saveAllMode == SaveMode::kBestMatch) { // Otherwise output container is filled by ROFMatch()
394 int nFakes = 0, nTrue = 0;
395 for (auto& thisMCHTrack : mMCHWork) {
396 auto bestMFTMatchID = thisMCHTrack.getMFTTrackID();
397 if (bestMFTMatchID >= 0) { // If there is a match, add to output container
398 if (mMCTruthON) {
399 mMatchLabels.push_back(computeLabel(thisMCHTrack.getMCHTrackID(), bestMFTMatchID));
400 mMatchLabels.back().isFake() ? nFakes++ : nTrue++;
401 }
402
403 thisMCHTrack.setMFTTrackID(bestMFTMatchID);
404 LOG(debug) << " thisMCHTrack.getMFTTrackID() = " << thisMCHTrack.getMFTTrackID()
405 << "; thisMCHTrack.getMFTMCHMatchingChi2() = " << thisMCHTrack.getMFTMCHMatchingChi2();
406
407 mMatchedTracks.emplace_back(thisMCHTrack);
408 mMatchingInfo.emplace_back(thisMCHTrack);
409 }
410 }
411 if (mMCTruthON) {
412 LOG(info) << " MFT-MCH Matching: nFakes = " << nFakes << " nTrue = " << nTrue;
413 }
414 } else if constexpr (saveAllMode == SaveMode::kSaveNCandidates) {
415 int nFakes = 0, nTrue = 0;
416 auto& matchAllChi2 = mMatchingFunctionMap["matchALL"];
417 for (auto MCHId = 0; MCHId < mMCHWork.size(); MCHId++) {
418 auto& thisMCHTrack = mMCHWork[MCHId];
419 for (auto& pairCandidate : mCandidates[MCHId]) {
420 thisMCHTrack.setMFTTrackID(pairCandidate.second);
421 auto& thisMFTTrack = mMFTWork[pairCandidate.second];
422 auto chi2 = matchAllChi2(thisMCHTrack, thisMFTTrack); // Matching chi2 is stored independently
423 thisMCHTrack.setMFTMCHMatchingScore(pairCandidate.first);
424 thisMCHTrack.setMFTMCHMatchingChi2(chi2);
425 mMatchedTracks.emplace_back(thisMCHTrack);
426 mMatchingInfo.emplace_back(thisMCHTrack);
427 if (mMCTruthON) {
428 mMatchLabels.push_back(computeLabel(MCHId, pairCandidate.second));
429 mMatchLabels.back().isFake() ? nFakes++ : nTrue++;
430 }
431 }
432 }
433 }
434}
435
436//_________________________________________________________
437template <Int_t saveAllMode>
438void MatchGlobalFwd::ROFMatch(int MFTROFId, int firstMCHROFId, int lastMCHROFId)
439{
441 const auto& thisMFTROF = mMFTTrackROFRec[MFTROFId];
442 const auto& thisMFTBracket = mMFTROFTimes[MFTROFId];
443 const auto& firstMCHROF = mMCHTrackROFRec[firstMCHROFId];
444 const auto& lastMCHROF = mMCHTrackROFRec[lastMCHROFId];
445 int nFakes = 0, nTrue = 0;
446
447 auto compare = [](const std::pair<int, int>& a, const std::pair<int, int>& b) {
448 return a.first < b.first;
449 };
450
451 auto firstMFTTrackID = thisMFTROF.getFirstEntry();
452 auto lastMFTTrackID = firstMFTTrackID + thisMFTROF.getNEntries() - 1;
453
454 auto firstMCHTrackID = firstMCHROF.getFirstIdx();
455 auto lastMCHTrackID = lastMCHROF.getLastIdx();
456
457 auto nMFTTracks = thisMFTROF.getNEntries();
458 auto nMCHTracks = lastMCHTrackID - firstMCHTrackID + 1;
459
460 auto& matchAllChi2 = mMatchingFunctionMap["matchALL"];
461
462 LOG(debug) << "Matching MFT ROF " << MFTROFId << " with MCH ROFs [" << firstMCHROFId << "->" << lastMCHROFId << "]";
463 LOG(debug) << " firstMFTTrackID = " << firstMFTTrackID << " ; lastMFTTrackID = " << lastMFTTrackID;
464 LOG(debug) << " firstMCHTrackID = " << firstMCHTrackID << " ; lastMCHTrackID = " << lastMCHTrackID;
465 LOG(debug) << " thisMFTROF: " << thisMFTROF.getBCData();
466 LOG(debug) << " firstMCHROF: " << firstMCHROF;
467 LOG(debug) << " lastMCHROF: " << lastMCHROF;
468
469 // loop over all MCH tracks
470 for (auto MCHId = firstMCHTrackID; MCHId <= lastMCHTrackID; MCHId++) {
471 auto& thisMCHTrack = mMCHWork[MCHId];
472
473 // If enabled, use the muon track time to check if the track is correlated with the MFT ROF
474 if (mUseTrackTime && (thisMFTBracket.isOutside(thisMCHTrack.tBracket))) {
475 continue;
476 }
477
478 o2::MCCompLabel matchLabel;
479 for (auto MFTId = firstMFTTrackID; MFTId <= lastMFTTrackID; MFTId++) {
480 auto& thisMFTTrack = mMFTWork[MFTId];
481 if (mMCTruthON) {
482 matchLabel = computeLabel(MCHId, MFTId);
483 }
484 if (mCutFunc(thisMCHTrack, thisMFTTrack)) {
485 thisMCHTrack.countMFTCandidate();
486 if (mMCTruthON) {
487 if (matchLabel.isCorrect()) {
488 thisMCHTrack.setCloseMatch();
489 }
490 }
491 auto score = mMatchFunc(thisMCHTrack, thisMFTTrack);
492 if (score < thisMCHTrack.getMFTMCHMatchingScore()) {
493 thisMCHTrack.setMFTTrackID(MFTId);
494 auto chi2 = matchAllChi2(thisMCHTrack, thisMFTTrack); // Matching chi2 is stored independently
495 thisMCHTrack.setMFTMCHMatchingScore(score);
496 thisMCHTrack.setMFTMCHMatchingChi2(chi2);
497 }
498 if constexpr (saveAllMode == SaveMode::kSaveAll) { // In saveAllmode save all pairs to output container
499 thisMCHTrack.setMFTTrackID(MFTId);
500 mMatchedTracks.emplace_back(thisMCHTrack);
501 mMatchingInfo.emplace_back(thisMCHTrack);
502 if (mMCTruthON) {
503 mMatchLabels.push_back(matchLabel);
504 mMatchLabels.back().isFake() ? nFakes++ : nTrue++;
505 }
506 }
507
508 if constexpr (saveAllMode == SaveMode::kSaveNCandidates) { // Save best N matching candidates
509 auto score = mMatchFunc(thisMCHTrack, thisMFTTrack);
510 std::pair<float, int> scoreID = {score, MFTId};
511 mCandidates[MCHId].push_back(scoreID);
512 std::sort(mCandidates[MCHId].begin(), mCandidates[MCHId].end(), compare);
513 if (mCandidates[MCHId].size() > mNCandidates) {
514 mCandidates[MCHId].pop_back();
515 }
516 }
517
518 if constexpr (saveAllMode == SaveMode::kSaveTrainingData) { // In save training data mode store track parameters at matching plane
519 thisMCHTrack.setMFTTrackID(MFTId);
520 mMatchingInfo.emplace_back(thisMCHTrack);
521 mMCHMatchPlaneParams.emplace_back(thisMCHTrack);
522 mMFTMatchPlaneParams.emplace_back(static_cast<o2::mft::TrackMFT>(thisMFTTrack));
523 if (mMCTruthON) {
524 mMatchLabels.push_back(matchLabel);
525 mMatchLabels.back().isFake() ? nFakes++ : nTrue++;
526 }
527 }
528 }
529 }
530 auto bestMFTMatchID = thisMCHTrack.getMFTTrackID();
531 LOG(debug) << " Matching MCHId = " << MCHId << " ==> bestMFTMatchID = " << thisMCHTrack.getMFTTrackID() << " ; thisMCHTrack.getMFTMCHMatchingChi2() = " << thisMCHTrack.getMFTMCHMatchingChi2();
532 LOG(debug) << " MCH COV<X,X> = " << thisMCHTrack.getSigma2X() << " ; COV<Y,Y> = " << thisMCHTrack.getSigma2Y() << " ; pt = " << thisMCHTrack.getPt();
533
534 } // /loop over MCH tracks seeds
535
536 LOG(debug) << "Finished matching MFT ROF " << MFTROFId << ": " << nMFTTracks << " MFT tracks and " << nMCHTracks << " MCH Tracks.";
537 if (mMCTruthON) {
538 LOG(debug) << " nFakes = " << nFakes << " nTrue = " << nTrue;
539 }
540}
541
542//_________________________________________________________
543o2::MCCompLabel MatchGlobalFwd::computeLabel(const int MCHId, const int MFTId)
544{
545 const auto& mchlabel = mMCHTrkLabels[MCHId];
546 const auto& mftlabel = mMFTTrkLabels[MFTId];
547 o2::MCCompLabel matchLabel = mchlabel;
548 matchLabel.setFakeFlag(mftlabel.compare(mchlabel) != 1);
549
550 LOG(debug) << " Computing MFTMCH matching label: MFTTruth = " << mftlabel << " ; MCHTruth = " << mchlabel << " ; Computed label = " << matchLabel;
551
552 return matchLabel;
553}
554
555//_________________________________________________________
556void MatchGlobalFwd::doMCMatching()
557{
558 int nFakes = 0, nTrue = 0;
559
560 // loop over all MCH tracks
561 for (auto MCHId = 0; MCHId < mMCHWork.size(); MCHId++) {
562 auto& thisMCHTrack = mMCHWork[MCHId];
563 const o2::MCCompLabel& thisMCHLabel = mMCHTrkLabels[mMCHID2Work[MCHId]];
564
565 LOG(debug) << " MCH Track # " << MCHId << " Label: " << thisMCHLabel;
566 if (!((thisMCHLabel).isSet())) {
567 continue;
568 }
569 for (auto MFTId = 0; MFTId < mMFTWork.size(); MFTId++) {
570 auto& thisMFTTrack = mMFTWork[MFTId];
571 o2::MCCompLabel matchLabel = computeLabel(MCHId, MFTId);
572
573 if (matchLabel.isCorrect()) {
574 nTrue++;
575 thisMCHTrack.setCloseMatch();
576 auto chi2 = mMatchFunc(thisMCHTrack, thisMFTTrack);
577 thisMCHTrack.setMFTTrackID(MFTId);
578 thisMCHTrack.setMFTMCHMatchingChi2(chi2);
579 mMatchedTracks.emplace_back(thisMCHTrack);
580 mMatchingInfo.emplace_back(thisMCHTrack);
581 mMatchLabels.push_back(matchLabel);
582 auto bestMFTMatchID = thisMCHTrack.getMFTTrackID();
583 LOG(debug) << " Matching MCHId = " << MCHId << " ==> bestMFTMatchID = " << thisMCHTrack.getMFTTrackID() << " ; thisMCHTrack.getMFTMCHMatchingChi2() = " << thisMCHTrack.getMFTMCHMatchingChi2();
584 LOG(debug) << " MCH COV<X,X> = " << thisMCHTrack.getSigma2X() << " ; COV<Y,Y> = " << thisMCHTrack.getSigma2Y() << " ; pt = " << thisMCHTrack.getPt();
585 LOG(debug) << " Label: " << matchLabel;
586 break;
587 }
588 }
589
590 } // /loop over MCH tracks seeds
591
592 auto nMFTTracks = mMFTWork.size();
593 auto nMCHTracks = mMCHWork.size();
594
595 LOG(info) << " Done MC matching of " << nMFTTracks << " MFT tracks with " << nMCHTracks << " MCH Tracks. nFakes = " << nFakes << " nTrue = " << nTrue;
596}
597
598//_________________________________________________________________________________________________
599void MatchGlobalFwd::fitTracks()
600{
601 LOG(info) << "Fitting global muon tracks...";
602
603 auto GTrackID = 0;
604
605 for (auto& track : mMatchedTracks) {
606 LOG(debug) << " ==> Fitting Global Track # " << GTrackID << " with MFT track # " << track.getMFTTrackID() << ":";
607 fitGlobalMuonTrack(track);
608 GTrackID++;
609 }
610
611 LOG(info) << "Finished fitting global muon tracks.";
612}
613
614//_________________________________________________________________________________________________
615void MatchGlobalFwd::fitGlobalMuonTrack(o2::dataformats::GlobalFwdTrack& gTrack)
616{
617 const auto& MFTMatchId = gTrack.getMFTTrackID();
618 const auto& mftTrack = mMFTTracks[MFTMatchId];
619 const auto& mftTrackOut = mMFTWork[MFTMatchId];
620 auto ncls = mftTrack.getNumberOfPoints();
621 auto offset = mftTrack.getExternalClusterIndexOffset();
622
623 LOG(debug) << "***************************** Start Fitting new track *****************************";
624 LOG(debug) << "N Clusters = " << ncls << " Best MFT Track Match ID " << gTrack.getMFTTrackID() << " MCHTrack: X = " << gTrack.getX() << " Y = " << gTrack.getY() << " Z = " << gTrack.getZ() << " Tgl = " << gTrack.getTanl() << " Phi = " << gTrack.getPhi() << " pz = " << gTrack.getPz() << " qpt = " << 1.0 / gTrack.getInvQPt();
625
626 LOG(debug) << "MFTTrack: X = " << mftTrackOut.getX()
627 << " Y = " << mftTrackOut.getY() << " Z = " << mftTrackOut.getZ()
628 << " Tgl = " << mftTrackOut.getTanl()
629 << " Phi = " << mftTrackOut.getPhi() << " pz = " << mftTrackOut.getPz()
630 << " qpt = " << 1.0 / mftTrackOut.getInvQPt();
631 LOG(debug) << " initTrack GlobalTrack: q/pt = " << gTrack.getInvQPt() << std::endl;
632
633 auto lastLayer = mMFTMapping.ChipID2Layer[mMFTClusters[offset + ncls - 1].getSensorID()];
634 LOG(debug) << "Starting by MFTCluster offset " << offset + ncls - 1 << " at lastLayer " << lastLayer;
635
636 for (int icls = ncls - 1; icls > -1; --icls) {
637 auto clsEntry = mMFTTrackClusIdx[offset + icls];
638 auto& thiscluster = mMFTClusters[clsEntry];
639 LOG(debug) << "Computing MFTCluster clsEntry " << clsEntry << " at Z = " << thiscluster.getZ();
640
641 computeCluster(gTrack, thiscluster, lastLayer);
642 }
643}
644
645//_________________________________________________________________________________________________
646bool MatchGlobalFwd::computeCluster(o2::dataformats::GlobalFwdTrack& track, const MFTCluster& cluster, int& startingLayerID)
647{
652
653 const auto& clx = cluster.getX();
654 const auto& cly = cluster.getY();
655 const auto& clz = cluster.getZ();
656 const auto& sigmaX2 = cluster.getSigmaY2() * mAlignResidual * mAlignResidual;
657 ; // ALPIDE local Y coordinate => MFT global X coordinate (ALPIDE rows)
658 const auto& sigmaY2 = cluster.getSigmaZ2() * mAlignResidual * mAlignResidual;
659 ; // ALPIDE local Z coordinate => MFT global Y coordinate (ALPIDE columns)
660
661 const auto& newLayerID = mMFTMapping.ChipID2Layer[cluster.getSensorID()];
662 LOG(debug) << "computeCluster: X = " << clx << " Y = " << cly << " Z = " << clz << " nCluster = " << newLayerID;
663
664 if (!propagateToNextClusterWithMCS(track, clz, startingLayerID, newLayerID)) {
665 return false;
666 }
667
668 LOG(debug) << " AfterExtrap: X = " << track.getX() << " Y = " << track.getY() << " Z = " << track.getZ() << " Tgl = " << track.getTanl() << " Phi = " << track.getPhi() << " pz = " << track.getPz() << " q/pt = " << track.getInvQPt();
669 LOG(debug) << "Track covariances after extrap:" << std::endl
670 << track.getCovariances() << std::endl;
671
672 // recompute parameters
673 const std::array<float, 2>& pos = {clx, cly};
674 const std::array<float, 2>& cov = {sigmaX2, sigmaY2};
675
676 if (track.update(pos, cov)) {
677 LOG(debug) << " New Cluster: X = " << clx << " Y = " << cly << " Z = " << clz;
678 LOG(debug) << " AfterKalman: X = " << track.getX() << " Y = " << track.getY() << " Z = " << track.getZ() << " Tgl = " << track.getTanl() << " Phi = " << track.getPhi() << " pz = " << track.getPz() << " q/pt = " << track.getInvQPt();
679
680 LOG(debug) << "Track covariances after Kalman update: \n"
681 << track.getCovariances() << std::endl;
682
683 return true;
684 }
685 return false;
686}
687
688//_________________________________________________________
690{
691 mMFTROFrameLengthMUS = fums;
692 mMFTROFrameLengthMUSInv = 1. / mMFTROFrameLengthMUS;
693 mMFTROFrameLengthInBC = std::max(1, int(mMFTROFrameLengthMUS / (o2::constants::lhc::LHCBunchSpacingNS * 1e-3)));
694}
695
696//_________________________________________________________
698{
699 mMFTROFrameLengthInBC = nbc;
700 mMFTROFrameLengthMUS = nbc * o2::constants::lhc::LHCBunchSpacingNS * 1e-3;
701 mMFTROFrameLengthMUSInv = 1. / mMFTROFrameLengthMUS;
702}
703
704//_________________________________________________________
706{
707 mMFTROFrameBiasInBC = nbc;
708 mMFTROFrameBiasMUS = nbc * o2::constants::lhc::LHCBunchSpacingNS * 1e-3;
709 mMFTROFrameBiasMUSInv = 1. / mMFTROFrameBiasMUS;
710}
711
712//_________________________________________________________
714{
715 mBunchFilling = bf;
716 // find closest (from above) filled bunch
717 int minBC = bf.getFirstFilledBC(), maxBC = bf.getLastFilledBC();
718 if (minBC < 0) {
719 LOG(error) << "Empty bunch filling is provided to MatchGlobalFwd, checks using it should be ignored";
720 return;
721 }
722 int bcAbove = minBC;
723 for (int i = o2::constants::lhc::LHCMaxBunches; i--;) {
724 if (bf.testBC(i)) {
725 bcAbove = i;
726 }
727 mClosestBunchAbove[i] = bcAbove;
728 }
729 int bcBelow = maxBC;
730 for (int i = 0; i < o2::constants::lhc::LHCMaxBunches; i++) {
731 if (bf.testBC(i)) {
732 bcBelow = i;
733 }
734 mClosestBunchBelow[i] = bcBelow;
735 }
736}
737
738//_________________________________________________________________________________________________
740{
741 // Convert a MCH Track parameters and covariances matrix to the
742 // Forward track format. Must be called after propagation though the absorber
743
744 o2::dataformats::GlobalFwdTrack convertedTrack;
745
746 // Parameter conversion
747 double alpha1, alpha3, alpha4, x2, x3, x4;
748
749 alpha1 = mchParam.getNonBendingSlope();
750 alpha3 = mchParam.getBendingSlope();
751 alpha4 = mchParam.getInverseBendingMomentum();
752
753 x2 = TMath::ATan2(-alpha3, -alpha1);
754 x3 = -1. / TMath::Sqrt(alpha3 * alpha3 + alpha1 * alpha1);
755 x4 = alpha4 * -x3 * TMath::Sqrt(1 + alpha3 * alpha3);
756
757 auto K = alpha1 * alpha1 + alpha3 * alpha3;
758 auto K32 = K * TMath::Sqrt(K);
759 auto L = TMath::Sqrt(alpha3 * alpha3 + 1);
760
761 // Covariances matrix conversion
762 SMatrix55Std jacobian;
763 SMatrix55Sym covariances;
764
765 if (0) {
766
767 std::cout << " MCHtoGlobal - MCH Covariances:\n";
768 std::cout << " mchParam.getCovariances()(0, 0) = "
769 << mchParam.getCovariances()(0, 0)
770 << " ; mchParam.getCovariances()(2, 2) = "
771 << mchParam.getCovariances()(2, 2) << std::endl;
772 }
773 covariances(0, 0) = mchParam.getCovariances()(0, 0);
774 covariances(0, 1) = mchParam.getCovariances()(0, 1);
775 covariances(0, 2) = mchParam.getCovariances()(0, 2);
776 covariances(0, 3) = mchParam.getCovariances()(0, 3);
777 covariances(0, 4) = mchParam.getCovariances()(0, 4);
778
779 covariances(1, 1) = mchParam.getCovariances()(1, 1);
780 covariances(1, 2) = mchParam.getCovariances()(1, 2);
781 covariances(1, 3) = mchParam.getCovariances()(1, 3);
782 covariances(1, 4) = mchParam.getCovariances()(1, 4);
783
784 covariances(2, 2) = mchParam.getCovariances()(2, 2);
785 covariances(2, 3) = mchParam.getCovariances()(2, 3);
786 covariances(2, 4) = mchParam.getCovariances()(2, 4);
787
788 covariances(3, 3) = mchParam.getCovariances()(3, 3);
789 covariances(3, 4) = mchParam.getCovariances()(3, 4);
790
791 covariances(4, 4) = mchParam.getCovariances()(4, 4);
792
793 jacobian(0, 0) = 1;
794
795 jacobian(1, 2) = 1;
796
797 jacobian(2, 1) = -alpha3 / K;
798 jacobian(2, 3) = alpha1 / K;
799
800 jacobian(3, 1) = alpha1 / K32;
801 jacobian(3, 3) = alpha3 / K32;
802
803 jacobian(4, 1) = -alpha1 * alpha4 * L / K32;
804 jacobian(4, 3) = alpha3 * alpha4 * (1 / (TMath::Sqrt(K) * L) - L / K32);
805 jacobian(4, 4) = L / TMath::Sqrt(K);
806
807 // jacobian*covariances*jacobian^T
808 covariances = ROOT::Math::Similarity(jacobian, covariances);
809
810 // Set output
811 convertedTrack.setX(mchParam.getNonBendingCoor());
812 convertedTrack.setY(mchParam.getBendingCoor());
813 convertedTrack.setZ(mchParam.getZ());
814 convertedTrack.setPhi(x2);
815 convertedTrack.setTanl(x3);
816 convertedTrack.setInvQPt(x4);
817 convertedTrack.setCharge(mchParam.getCharge());
818 convertedTrack.setCovariances(covariances);
819
820 return convertedTrack;
821}
822
823//_________________________________________________________________________________________________
825{
826 // Convert Forward Track parameters and covariances matrix to the
827 // MCH track format.
828
829 // Parameter conversion
830 double alpha1, alpha3, alpha4, x2, x3, x4;
831
832 x2 = fwdtrack.getPhi();
833 x3 = fwdtrack.getTanl();
834 x4 = fwdtrack.getInvQPt();
835
836 auto sinx2 = TMath::Sin(x2);
837 auto cosx2 = TMath::Cos(x2);
838
839 alpha1 = cosx2 / x3;
840 alpha3 = sinx2 / x3;
841 alpha4 = x4 / TMath::Sqrt(x3 * x3 + sinx2 * sinx2);
842
843 auto K = TMath::Sqrt(x3 * x3 + sinx2 * sinx2);
844 auto K3 = K * K * K;
845
846 // Covariances matrix conversion
847 SMatrix55Std jacobian;
848 SMatrix55Sym covariances;
849
850 covariances(0, 0) = fwdtrack.getCovariances()(0, 0);
851 covariances(0, 1) = fwdtrack.getCovariances()(0, 1);
852 covariances(0, 2) = fwdtrack.getCovariances()(0, 2);
853 covariances(0, 3) = fwdtrack.getCovariances()(0, 3);
854 covariances(0, 4) = fwdtrack.getCovariances()(0, 4);
855
856 covariances(1, 1) = fwdtrack.getCovariances()(1, 1);
857 covariances(1, 2) = fwdtrack.getCovariances()(1, 2);
858 covariances(1, 3) = fwdtrack.getCovariances()(1, 3);
859 covariances(1, 4) = fwdtrack.getCovariances()(1, 4);
860
861 covariances(2, 2) = fwdtrack.getCovariances()(2, 2);
862 covariances(2, 3) = fwdtrack.getCovariances()(2, 3);
863 covariances(2, 4) = fwdtrack.getCovariances()(2, 4);
864
865 covariances(3, 3) = fwdtrack.getCovariances()(3, 3);
866 covariances(3, 4) = fwdtrack.getCovariances()(3, 4);
867
868 covariances(4, 4) = fwdtrack.getCovariances()(4, 4);
869
870 jacobian(0, 0) = 1;
871
872 jacobian(1, 2) = -sinx2 / x3;
873 jacobian(1, 3) = -cosx2 / (x3 * x3);
874
875 jacobian(2, 1) = 1;
876
877 jacobian(3, 2) = cosx2 / x3;
878 jacobian(3, 3) = -sinx2 / (x3 * x3);
879
880 jacobian(4, 2) = -x4 * sinx2 * cosx2 / K3;
881 jacobian(4, 3) = -x3 * x4 / K3;
882 jacobian(4, 4) = 1 / K;
883 // jacobian*covariances*jacobian^T
884 covariances = ROOT::Math::Similarity(jacobian, covariances);
885
886 double cov[] = {covariances(0, 0), covariances(1, 0), covariances(1, 1), covariances(2, 0), covariances(2, 1), covariances(2, 2), covariances(3, 0), covariances(3, 1), covariances(3, 2), covariances(3, 3), covariances(4, 0), covariances(4, 1), covariances(4, 2), covariances(4, 3), covariances(4, 4)};
887 double param[] = {fwdtrack.getX(), alpha1, fwdtrack.getY(), alpha3, alpha4};
888
889 o2::mch::TrackParam convertedTrack(fwdtrack.getZ(), param, cov);
890 return o2::mch::TrackParam(convertedTrack);
891}
892
893//_________________________________________________________________________________________________
895{
896 mClosestBunchAbove[0] = mClosestBunchAbove[0] = -1;
897
898 // Define built-in matching functions
899 //________________________________________________________________________________
900 mMatchingFunctionMap["matchALL"] = [](const GlobalFwdTrack& mchTrack, const TrackParCovFwd& mftTrack) -> double {
901 // Match two tracks evaluating all parameters: X,Y, phi, tanl & q/pt
902
903 SMatrix55Sym I = ROOT::Math::SMatrixIdentity(), H_k, V_k;
904 SVector5 m_k(mftTrack.getX(), mftTrack.getY(), mftTrack.getPhi(),
905 mftTrack.getTanl(), mftTrack.getInvQPt()),
906 r_k_kminus1;
907 SVector5 GlobalMuonTrackParameters = mchTrack.getParameters();
908 SMatrix55Sym GlobalMuonTrackCovariances = mchTrack.getCovariances();
909 V_k(0, 0) = mftTrack.getCovariances()(0, 0);
910 V_k(1, 1) = mftTrack.getCovariances()(1, 1);
911 V_k(2, 2) = mftTrack.getCovariances()(2, 2);
912 V_k(3, 3) = mftTrack.getCovariances()(3, 3);
913 V_k(4, 4) = mftTrack.getCovariances()(4, 4);
914 H_k(0, 0) = 1.0;
915 H_k(1, 1) = 1.0;
916 H_k(2, 2) = 1.0;
917 H_k(3, 3) = 1.0;
918 H_k(4, 4) = 1.0;
919
920 // Covariance of residuals
921 SMatrix55Std invResCov = (V_k + ROOT::Math::Similarity(H_k, GlobalMuonTrackCovariances));
922 invResCov.Invert();
923
924 // Kalman Gain Matrix
925 SMatrix55Std K_k = GlobalMuonTrackCovariances * ROOT::Math::Transpose(H_k) * invResCov;
926
927 // Update Parameters
928 r_k_kminus1 = m_k - H_k * GlobalMuonTrackParameters; // Residuals of prediction
929
930 // Restrict the phi residual to the [-pi, pi] range
931 o2::math_utils::bringToPMPiGend(r_k_kminus1[2]);
932
933 auto matchChi2Track = ROOT::Math::Similarity(r_k_kminus1, invResCov);
934
935 return matchChi2Track;
936 };
937
938 //________________________________________________________________________________
939 mMatchingFunctionMap["matchsXYPhiTanl"] = [](const GlobalFwdTrack& mchTrack, const TrackParCovFwd& mftTrack) -> double {
940
941 // Match two tracks evaluating positions & angles
942
943 SMatrix55Sym I = ROOT::Math::SMatrixIdentity();
944 SMatrix45 H_k;
945 SMatrix44 V_k;
946 SVector4 m_k(mftTrack.getX(), mftTrack.getY(), mftTrack.getPhi(),
947 mftTrack.getTanl()),
948 r_k_kminus1;
949 SVector5 GlobalMuonTrackParameters = mchTrack.getParameters();
950 SMatrix55Sym GlobalMuonTrackCovariances = mchTrack.getCovariances();
951 V_k(0, 0) = mftTrack.getCovariances()(0, 0);
952 V_k(1, 1) = mftTrack.getCovariances()(1, 1);
953 V_k(2, 2) = mftTrack.getCovariances()(2, 2);
954 V_k(3, 3) = mftTrack.getCovariances()(3, 3);
955 H_k(0, 0) = 1.0;
956 H_k(1, 1) = 1.0;
957 H_k(2, 2) = 1.0;
958 H_k(3, 3) = 1.0;
959
960 // Covariance of residuals
961 SMatrix44 invResCov = (V_k + ROOT::Math::Similarity(H_k, GlobalMuonTrackCovariances));
962 invResCov.Invert();
963
964 // Kalman Gain Matrix
965 SMatrix54 K_k = GlobalMuonTrackCovariances * ROOT::Math::Transpose(H_k) * invResCov;
966
967 // Residuals of prediction
968 r_k_kminus1 = m_k - H_k * GlobalMuonTrackParameters;
969
970 // Restrict the phi residual to the [-pi, pi] range
971 o2::math_utils::bringToPMPiGend(r_k_kminus1[2]);
972
973 auto matchChi2Track = ROOT::Math::Similarity(r_k_kminus1, invResCov);
974
975 return matchChi2Track; };
976
977 //________________________________________________________________________________
978 mMatchingFunctionMap["matchXY"] = [](const GlobalFwdTrack& mchTrack, const TrackParCovFwd& mftTrack) -> double {
979
980 // Calculate Matching Chi2 - X and Y positions
981
982 SMatrix55Sym I = ROOT::Math::SMatrixIdentity();
983 SMatrix25 H_k;
984 SMatrix22 V_k;
985 SVector2 m_k(mftTrack.getX(), mftTrack.getY()), r_k_kminus1;
986 SVector5 GlobalMuonTrackParameters = mchTrack.getParameters();
987 SMatrix55Sym GlobalMuonTrackCovariances = mchTrack.getCovariances();
988 V_k(0, 0) = mftTrack.getCovariances()(0, 0);
989 V_k(1, 1) = mftTrack.getCovariances()(1, 1);
990 H_k(0, 0) = 1.0;
991 H_k(1, 1) = 1.0;
992
993 // Covariance of residuals
994 SMatrix22 invResCov = (V_k + ROOT::Math::Similarity(H_k, GlobalMuonTrackCovariances));
995 invResCov.Invert();
996
997 // Kalman Gain Matrix
998 SMatrix52 K_k = GlobalMuonTrackCovariances * ROOT::Math::Transpose(H_k) * invResCov;
999
1000 // Residuals of prediction
1001 r_k_kminus1 = m_k - H_k * GlobalMuonTrackParameters;
1002 auto matchChi2Track = ROOT::Math::Similarity(r_k_kminus1, invResCov);
1003
1004 return matchChi2Track; };
1005
1006 //________________________________________________________________________________
1007 mMatchingFunctionMap["matchNeedsName"] = [this](const GlobalFwdTrack& mchTrack, const TrackParCovFwd& mftTrack) -> double {
1008
1009 //Hiroshima's Matching function needs a physics-based name
1010
1011 //Matching constants
1012 Double_t LAbs = 415.; //Absorber Length[cm]
1013 Double_t mumass = 0.106; //mass of muon [GeV/c^2]
1014 Double_t l; //the length that extrapolated MCHtrack passes through absorber
1015
1016 if (mMatchingPlaneZ >= -90.0) {
1017 l = LAbs;
1018 } else {
1019 l = 505.0 + mMatchingPlaneZ;
1020 }
1021
1022 //defference between MFTtrack and MCHtrack
1023
1024 auto dx = mftTrack.getX() - mchTrack.getX();
1025 auto dy = mftTrack.getY() - mchTrack.getY();
1026 auto dthetax = TMath::ATan(mftTrack.getPx() / TMath::Abs(mftTrack.getPz())) - TMath::ATan(mchTrack.getPx() / TMath::Abs(mchTrack.getPz()));
1027 auto dthetay = TMath::ATan(mftTrack.getPy() / TMath::Abs(mftTrack.getPz())) - TMath::ATan(mchTrack.getPy() / TMath::Abs(mchTrack.getPz()));
1028
1029 //Multiple Scattering(=MS)
1030
1031 auto pMCH = mchTrack.getP();
1032 auto lorentzbeta = pMCH / TMath::Sqrt(mumass * mumass + pMCH * pMCH);
1033 auto zMS = copysign(1.0, mchTrack.getCharge());
1034 auto thetaMS = 13.6 / (1000.0 * pMCH * lorentzbeta * 1.0) * zMS * TMath::Sqrt(60.0 * l / LAbs) * (1.0 + 0.038 * TMath::Log(60.0 * l / LAbs));
1035 auto xMS = thetaMS * l / TMath::Sqrt(3.0);
1036
1037 //normalize by theoritical Multiple Coulomb Scattering width to be momentum-independent
1038 //make the dx and dtheta dimensionless
1039
1040 auto dxnorm = dx / xMS;
1041 auto dynorm = dy / xMS;
1042 auto dthetaxnorm = dthetax / thetaMS;
1043 auto dthetaynorm = dthetay / thetaMS;
1044
1045 //rotate distribution
1046
1047 auto dxrot = dxnorm * TMath::Cos(TMath::Pi() / 4.0) - dthetaxnorm * TMath::Sin(TMath::Pi() / 4.0);
1048 auto dthetaxrot = dxnorm * TMath::Sin(TMath::Pi() / 4.0) + dthetaxnorm * TMath::Cos(TMath::Pi() / 4.0);
1049 auto dyrot = dynorm * TMath::Cos(TMath::Pi() / 4.0) - dthetaynorm * TMath::Sin(TMath::Pi() / 4.0);
1050 auto dthetayrot = dynorm * TMath::Sin(TMath::Pi() / 4.0) + dthetaynorm * TMath::Cos(TMath::Pi() / 4.0);
1051
1052 //convert ellipse to circle
1053
1054 auto k = 0.7; //need to optimize!!
1055 auto dxcircle = dxrot;
1056 auto dycircle = dyrot;
1057 auto dthetaxcircle = dthetaxrot / k;
1058 auto dthetaycircle = dthetayrot / k;
1059
1060 //score
1061
1062 auto scoreX = TMath::Sqrt(dxcircle * dxcircle + dthetaxcircle * dthetaxcircle);
1063 auto scoreY = TMath::Sqrt(dycircle * dycircle + dthetaycircle * dthetaycircle);
1064 auto score = TMath::Sqrt(scoreX * scoreX + scoreY * scoreY);
1065
1066 return score; };
1067
1068 // Define built-in candidate cut functions
1069
1070 //________________________________________________________________________________
1071 mCutFunctionMap["cutDisabled"] = [](const GlobalFwdTrack& mchTrack, const TrackParCovFwd& mftTrack) -> bool {
1072 return true;
1073 };
1074
1075 //________________________________________________________________________________
1076 mCutFunctionMap["cut3Sigma"] = [](const GlobalFwdTrack& mchTrack, const TrackParCovFwd& mftTrack) -> bool {
1077 auto dx = mchTrack.getX() - mftTrack.getX();
1078 auto dy = mchTrack.getY() - mftTrack.getY();
1079 auto dPhi = mchTrack.getPhi() - mftTrack.getPhi();
1080 auto dTanl = TMath::Abs(mchTrack.getTanl() - mftTrack.getTanl());
1081 auto dInvQPt = TMath::Abs(mchTrack.getInvQPt() - mftTrack.getInvQPt());
1082 auto distanceSq = dx * dx + dy * dy;
1083 auto cutDistanceSq = 9 * (mchTrack.getSigma2X() + mchTrack.getSigma2Y());
1084 auto cutPhiSq = 9 * (mchTrack.getSigma2Phi() + mftTrack.getSigma2Phi());
1085 auto cutTanlSq = 9 * (mchTrack.getSigma2Tanl() + mftTrack.getSigma2Tanl());
1086 auto cutInvQPtSq = 9 * (mchTrack.getSigma2InvQPt() + mftTrack.getSigma2InvQPt());
1087 return (distanceSq < cutDistanceSq) and (dPhi * dPhi < cutPhiSq) and (dTanl * dTanl < cutTanlSq) and (dInvQPt * dInvQPt < cutInvQPtSq);
1088 };
1089
1090 //________________________________________________________________________________
1091 mCutFunctionMap["cut3SigmaXYAngles"] = [](const GlobalFwdTrack& mchTrack, const TrackParCovFwd& mftTrack) -> bool {
1092 auto dx = mchTrack.getX() - mftTrack.getX();
1093 auto dy = mchTrack.getY() - mftTrack.getY();
1094 auto dPhi = mchTrack.getPhi() - mftTrack.getPhi();
1095 auto dTanl = TMath::Abs(mchTrack.getTanl() - mftTrack.getTanl());
1096 auto distanceSq = dx * dx + dy * dy;
1097 auto cutDistanceSq = 9 * (mchTrack.getSigma2X() + mchTrack.getSigma2Y());
1098 auto cutPhiSq = 9 * (mchTrack.getSigma2Phi() + mftTrack.getSigma2Phi());
1099 auto cutTanlSq = 9 * (mchTrack.getSigma2Tanl() + mftTrack.getSigma2Tanl());
1100 return (distanceSq < cutDistanceSq) and (dPhi * dPhi < cutPhiSq) and (dTanl * dTanl < cutTanlSq);
1101 };
1102}
General auxilliary methods.
std::ostringstream debug
int32_t i
float chi2
Class to perform MFT MCH (and MID) matching.
uint16_t pos
Definition RawData.h:3
T getSigmaZ2() const
Definition BaseCluster.h:66
T getX() const
Definition BaseCluster.h:62
T getSigmaY2() const
Definition BaseCluster.h:65
T getY() const
Definition BaseCluster.h:63
std::int16_t getSensorID() const
Definition BaseCluster.h:81
T getZ() const
Definition BaseCluster.h:64
int getLastFilledBC(int dir=-1) const
bool testBC(int bcID, int dir=-1) const
int getFirstFilledBC(int dir=-1) const
void setFakeFlag(bool v=true)
bool isCorrect() const
Definition MCCompLabel.h:87
const auto & getMFTTrackID() const
void setBunchFilling(const o2::BunchFilling &bf)
set Bunch filling and init helpers for validation by BCs
void setMFTROFrameLengthMUS(float fums)
set MFT ROFrame duration in BC (continuous mode only)
void setMFTROFrameLengthInBC(int nbc)
set MFT ROFrame bias in BC (continuous mode only) or time shift applied already as MFTAlpideParam....
void run(const o2::globaltracking::RecoContainer &inp)
@ MATCHINGFUNC
MFT-MCH matching modes.
@ MATCHINGUPSTREAM
MFT-MCH track matching loaded from input file.
o2::mch::TrackParam FwdtoMCH(const o2::dataformats::GlobalFwdTrack &fwdtrack)
Converts FwdTrack parameters to MCH coordinate system.
o2::dataformats::GlobalFwdTrack MCHtoFwd(const o2::mch::TrackParam &mchTrack)
Converts mchTrack parameters to Forward coordinate system.
static constexpr std::array< int, NChips > ChipID2Layer
static bool extrapToVertexWithoutBranson(TrackParam &trackParam, double zVtx, double xUpstream=0., double yUpstream=0., std::optional< double > zUpstream=std::nullopt)
Definition TrackExtrap.h:74
track parameters for internal use
Definition TrackParam.h:34
Double_t getInverseBendingMomentum() const
return inverse bending momentum (GeV/c ** -1) times the charge (assumed forward motion)
Definition TrackParam.h:67
Double_t getNonBendingCoor() const
return non bending coordinate (cm)
Definition TrackParam.h:51
Double_t getZ() const
return Z coordinate (cm)
Definition TrackParam.h:47
Double_t getNonBendingSlope() const
return non bending slope (cm ** -1)
Definition TrackParam.h:55
const TMatrixD & getCovariances() const
Double_t getBendingCoor() const
return bending coordinate (cm)
Definition TrackParam.h:59
Double_t getBendingSlope() const
return bending slope (cm ** -1)
Definition TrackParam.h:63
Double_t getCharge() const
return the charge (assumed forward motion)
Definition TrackParam.h:71
void setCovariances(const SMatrix55Sym &covariances)
Definition TrackFwd.h:161
Double_t getSigma2Y() const
Definition TrackFwd.h:165
const SMatrix55Sym & getCovariances() const
Definition TrackFwd.h:160
Double_t getSigma2InvQPt() const
Definition TrackFwd.h:169
Double_t getSigma2Phi() const
Definition TrackFwd.h:167
Double_t getSigma2Tanl() const
Definition TrackFwd.h:168
Double_t getSigma2X() const
Definition TrackFwd.h:164
Double_t getPx() const
Definition TrackFwd.h:89
void setCharge(Double_t charge)
set the charge (assumed forward motion)
Definition TrackFwd.h:107
void setTanl(Double_t tanl)
Definition TrackFwd.h:80
void setInvQPt(Double_t invqpt)
Definition TrackFwd.h:85
Double_t getTanl() const
Definition TrackFwd.h:81
Double_t getPhi() const
Definition TrackFwd.h:65
Double_t getZ() const
return Z coordinate (cm)
Definition TrackFwd.h:55
void setPhi(Double_t phi)
Definition TrackFwd.h:64
void setX(Double_t x)
Definition TrackFwd.h:59
Double_t getY() const
Definition TrackFwd.h:61
const SMatrix5 & getParameters() const
return track parameters
Definition TrackFwd.h:115
Double_t getP() const
Definition TrackFwd.h:92
Double_t getCharge() const
return the charge (assumed forward motion)
Definition TrackFwd.h:105
Double_t getX() const
Definition TrackFwd.h:58
void setZ(Double_t z)
set Z coordinate (cm)
Definition TrackFwd.h:57
Double_t getInvQPt() const
Definition TrackFwd.h:86
void setY(Double_t y)
Definition TrackFwd.h:62
Double_t getPz() const
Definition TrackFwd.h:91
Double_t getPy() const
Definition TrackFwd.h:90
bool match(const std::vector< std::string > &queries, const char *pattern)
Definition dcs-ccdb.cxx:229
GLsizeiptr size
Definition glcorearb.h:659
GLuint GLuint end
Definition glcorearb.h:469
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLintptr offset
Definition glcorearb.h:660
GLenum GLfloat param
Definition glcorearb.h:271
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
const bool const int TrackITSInternal< NLayers > & track
void bringToPMPiGend(double &phi)
Definition Utils.h:65
void convertCompactClusters(gsl::span< const itsmft::CompClusterExt > clusters, gsl::span< const unsigned char >::iterator &pattIt, std::vector< o2::BaseCluster< float > > &output, const itsmft::TopologyDictionary *dict)
convert compact clusters to 3D spacepoints into std::vector<o2::BaseCluster<float>>
Definition IOUtils.cxx:111
unsigned long int nFakes
Enum< T >::Iterator begin(Enum< T >)
Definition Defs.h:158
std::string asString() const
int64_t differenceInBC(const InteractionRecord &other) const
void compare(std::string_view s1, std::string_view s2)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"