Project
Loading...
Searching...
No Matches
TrackerSpec.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
15
16#include "MFTTracking/ROframe.h"
17#include "MFTTracking/IOUtils.h"
18#include "MFTTracking/Tracker.h"
19#include "MFTTracking/TrackCA.h"
20#include "MFTBase/GeometryTGeo.h"
21
22#include <vector>
23#include <future>
24
25#include "TGeoGlobalMagField.h"
26
35#include "Field/MagneticField.h"
40
41using namespace o2::framework;
42
43namespace o2
44{
45namespace mft
46{
47//#define _TIMING_
48
50{
52 for (int sw = 0; sw < NStopWatches; sw++) {
53 mTimer[sw].Stop();
54 mTimer[sw].Reset();
55 }
56
57 // tracking configuration parameters
58 auto& trackingParam = MFTTrackingParam::Instance(); // to avoid loading interpreter during the run
59}
60
62{
63 mTimer[SWTot].Start(false);
64
65 updateTimeDependentParams(pc);
66 gsl::span<const unsigned char> patterns = pc.inputs().get<gsl::span<unsigned char>>("patterns");
67 auto compClusters = pc.inputs().get<const std::vector<o2::itsmft::CompClusterExt>>("compClusters");
68 auto ntracks = 0;
69
70 // code further down does assignment to the rofs and the altered object is used for output
71 // we therefore need a copy of the vector rather than an object created directly on the input data,
72 // the output vector however is created directly inside the message memory thus avoiding copy by
73 // snapshot
74 auto rofsinput = pc.inputs().get<const std::vector<o2::itsmft::ROFRecord>>("ROframes");
75 auto& rofs = pc.outputs().make<std::vector<o2::itsmft::ROFRecord>>(Output{"MFT", "MFTTrackROF", 0}, rofsinput.begin(), rofsinput.end());
76
77 ROFFilter filter = [](const o2::itsmft::ROFRecord& r) { return true; };
78
79 LOG(info) << "MFTTracker pulled " << compClusters.size() << " compressed clusters in " << rofsinput.size() << " RO frames";
80
81 auto& trackingParam = MFTTrackingParam::Instance();
82 if (trackingParam.irFramesOnly) {
83 // selects only those ROFs that overlap ITS IRFrame
84 LOG(info) << "MFTTracker IRFrame filter enabled: loading ITS IR Frames. ";
85 auto irFrames = pc.inputs().get<gsl::span<o2::dataformats::IRFrame>>("IRFramesITS");
86 filter = createIRFrameFilter(irFrames);
87
88 if (fair::Logger::Logging(fair::Severity::debug)) {
89 for (const auto& irf : irFrames) {
90 LOG(debug) << "IRFrame.info = " << irf.info << " ; min = " << irf.getMin().bc << " ; max = " << irf.getMax().bc;
91 }
92 }
93 }
94
95 if (trackingParam.isMultCutRequested()) {
96 LOG(info) << "MFTTracker multiplicity filter enabled. ROF selection: Min nClusters = " << trackingParam.cutMultClusLow << " ; Max nClusters = " << trackingParam.cutMultClusHigh;
97 }
98
99 const dataformats::MCTruthContainer<MCCompLabel>* labels = mUseMC ? pc.inputs().get<const dataformats::MCTruthContainer<MCCompLabel>*>("labels").release() : nullptr;
100 gsl::span<itsmft::MC2ROFRecord const> mc2rofs;
101 if (mUseMC) {
102 // get the array as read-only span, a snapshot of the object is sent forward
103 mc2rofs = pc.inputs().get<gsl::span<itsmft::MC2ROFRecord>>("MC2ROframes");
104 LOG(info) << labels->getIndexedSize() << " MC label objects , in " << mc2rofs.size() << " MC events";
105 }
106
107 auto& allClusIdx = pc.outputs().make<std::vector<int>>(Output{"MFT", "TRACKCLSID", 0});
108 std::vector<o2::MCCompLabel> trackLabels;
109 std::vector<o2::MCCompLabel> allTrackLabels;
110 std::vector<o2::mft::TrackLTF> tracks;
111 std::vector<o2::mft::TrackLTFL> tracksL;
112 auto& allTracksMFT = pc.outputs().make<std::vector<o2::mft::TrackMFT>>(Output{"MFT", "TRACKS", 0});
113
114 std::uint32_t roFrameId = 0;
115 int nROFs = rofs.size();
116 auto rofsPerWorker = std::max(1, nROFs / mNThreads);
117 LOG(debug) << "nROFs = " << nROFs << " rofsPerWorker = " << rofsPerWorker;
118
119 auto loadData = [&, this](auto& trackerVec, auto& roFrameDataVec) {
120 auto& tracker = trackerVec[0]; // Use first tracker to load the data: serial operation
121 gsl::span<const unsigned char>::iterator pattIt = patterns.begin();
122
123 auto iROF = 0;
124
125 for (const auto& rof : rofs) {
126 int worker = std::min(int(iROF / rofsPerWorker), mNThreads - 1);
127 auto& roFrameData = roFrameDataVec[worker].emplace_back();
128 int nclUsed = ioutils::loadROFrameData(rof, roFrameData, compClusters, pattIt, mDict, labels, tracker.get(), filter);
129 LOG(debug) << "ROframeId: " << iROF << ", clusters loaded : " << nclUsed << " on worker " << worker;
130 iROF++;
131 }
132 };
133
134 auto launchTrackFinder = [](auto* tracker, auto* workerROFs) {
135#ifdef _TIMING_
136 long tStart = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now()).time_since_epoch().count(), tStartROF = tStart, tEnd = tStart;
137 size_t rofCNT = 0;
138#endif
139 for (auto& rofData : *workerROFs) {
140 tracker->findTracks(rofData);
141#ifdef _TIMING_
142 long tEndROF = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
143 LOGP(info, "launchTrackFinder| tracker:{} did {}-th ROF in {} mus: {} clusters -> {} tracks", tracker->getTrackerID(), ++rofCNT, tEndROF - tStartROF, rofData.getTotalClusters(), rofData.getTracks().size());
144 tStartROF = tEnd = tEndROF;
145#endif
146 }
147#ifdef _TIMING_
148 LOGP(info, "launchTrackFinder| done: tracker:{} processed {} ROFS in {} mus", tracker->getTrackerID(), workerROFs->size(), tEnd - tStart);
149#endif
150 };
151
152 auto launchFitter = [](auto* tracker, auto* workerROFs) {
153#ifdef _TIMING_
154 long tStart = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
155#endif
156 for (auto& rofData : *workerROFs) {
157 tracker->fitTracks(rofData);
158 }
159#ifdef _TIMING_
160 long tEnd = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
161 LOGP(info, "launchTrackFitter| done: tracker:{} fitted {} ROFS in {} mus", tracker->getTrackerID(), workerROFs->size(), tEnd - tStart);
162#endif
163 };
164
165 auto runMFTTrackFinder = [&, this](auto& trackerVec, auto& roFrameDataVec) {
166 std::vector<std::future<void>> finder;
167 for (int i = 0; i < mNThreads; i++) {
168 auto& tracker = trackerVec[i];
169 auto& workerData = roFrameDataVec[i];
170 auto f = std::async(std::launch::async, launchTrackFinder, tracker.get(), &workerData);
171 finder.push_back(std::move(f));
172 }
173
174 for (int i = 0; i < mNThreads; i++) {
175 finder[i].wait();
176 }
177 };
178
179 auto runTrackFitter = [&, this](auto& trackerVec, auto& roFrameDataVec) {
180 std::vector<std::future<void>> fitter;
181 for (int i = 0; i < mNThreads; i++) {
182 auto& tracker = trackerVec[i];
183 auto& workerData = roFrameDataVec[i];
184 auto f = std::async(std::launch::async, launchFitter, tracker.get(), &workerData);
185 fitter.push_back(std::move(f));
186 }
187
188 for (int i = 0; i < mNThreads; i++) {
189 fitter[i].wait();
190 }
191 };
192
193 // snippet to convert found tracks to final output tracks with separate cluster indices
194 auto copyTracks = [](auto& new_tracks, auto& allTracks, auto& allClusIdx) {
195 for (auto& trc : new_tracks) {
196 trc.setExternalClusterIndexOffset(allClusIdx.size());
197 int ncl = trc.getNumberOfPoints();
198 for (int ic = 0; ic < ncl; ic++) {
199 auto externalClusterID = trc.getExternalClusterIndex(ic);
200 auto clusterSize = trc.getExternalClusterSize(ic);
201 auto clusterLayer = trc.getExternalClusterLayer(ic);
202 trc.setClusterSize(clusterLayer, clusterSize);
203 allClusIdx.push_back(externalClusterID);
204 }
205 allTracks.emplace_back(trc);
206 }
207 };
208
209 if (mFieldOn) {
210
211 std::vector<std::vector<o2::mft::ROframe<TrackLTF>>> roFrameVec(mNThreads); // One vector of ROFrames per thread
212 LOG(debug) << "Reserving ROFs ";
213
214 for (auto& rof : roFrameVec) {
215 rof.reserve(rofsPerWorker);
216 }
217 LOG(debug) << "Loading data into ROFs.";
218
219 mTimer[SWLoadData].Start(false);
220 loadData(mTrackerVec, roFrameVec);
221 mTimer[SWLoadData].Stop();
222
223 LOG(debug) << "Running MFT Track finder.";
224
225 mTimer[SWFindMFTTracks].Start(false);
226 runMFTTrackFinder(mTrackerVec, roFrameVec);
227 mTimer[SWFindMFTTracks].Stop();
228
229 LOG(debug) << "Runnig track fitter.";
230
231 mTimer[SWFitTracks].Start(false);
232 runTrackFitter(mTrackerVec, roFrameVec);
233 mTimer[SWFitTracks].Stop();
234
235 if (mUseMC) {
236 LOG(debug) << "Computing MC Labels.";
237
238 mTimer[SWComputeLabels].Start(false);
239 auto& tracker = mTrackerVec[0];
240
241 for (int i = 0; i < mNThreads; i++) {
242 for (auto& rofData : roFrameVec[i]) {
243 tracker->computeTracksMClabels(rofData.getTracks());
244 trackLabels.swap(tracker->getTrackLabels());
245 std::copy(trackLabels.begin(), trackLabels.end(), std::back_inserter(allTrackLabels));
246 trackLabels.clear();
247 }
248 }
249 mTimer[SWComputeLabels].Stop();
250 }
251
252 auto rof = rofs.begin();
253
254 for (int i = 0; i < mNThreads; i++) {
255 for (auto& rofData : roFrameVec[i]) {
256 int ntracksROF = 0, firstROFTrackEntry = allTracksMFT.size();
257 tracks.swap(rofData.getTracks());
258 ntracksROF = tracks.size();
259 copyTracks(tracks, allTracksMFT, allClusIdx);
260
261 rof->setFirstEntry(firstROFTrackEntry);
262 rof->setNEntries(ntracksROF);
263 *rof++;
264 roFrameId++;
265 }
266 }
267
268 } else {
269 LOG(debug) << "Field is off! ";
270 std::vector<std::vector<o2::mft::ROframe<TrackLTFL>>> roFrameVec(mNThreads); // One vector of ROFrames per thread
271 LOG(debug) << "Reserving ROFs ";
272
273 for (auto& rof : roFrameVec) {
274 rof.reserve(rofsPerWorker);
275 }
276 LOG(debug) << "Loading data into ROFs.";
277
278 mTimer[SWLoadData].Start(false);
279 loadData(mTrackerLVec, roFrameVec);
280 mTimer[SWLoadData].Stop();
281
282 LOG(debug) << "Running MFT Track finder.";
283
284 mTimer[SWFindMFTTracks].Start(false);
285 runMFTTrackFinder(mTrackerLVec, roFrameVec);
286 mTimer[SWFindMFTTracks].Stop();
287
288 LOG(debug) << "Runnig track fitter.";
289
290 mTimer[SWFitTracks].Start(false);
291 runTrackFitter(mTrackerLVec, roFrameVec);
292 mTimer[SWFitTracks].Stop();
293
294 if (mUseMC) {
295 LOG(debug) << "Computing MC Labels.";
296
297 mTimer[SWComputeLabels].Start(false);
298 auto& tracker = mTrackerLVec[0];
299
300 for (int i = 0; i < mNThreads; i++) {
301 for (auto& rofData : roFrameVec[i]) {
302 tracker->computeTracksMClabels(rofData.getTracks());
303 trackLabels.swap(tracker->getTrackLabels());
304 std::copy(trackLabels.begin(), trackLabels.end(), std::back_inserter(allTrackLabels));
305 trackLabels.clear();
306 }
307 }
308 mTimer[SWComputeLabels].Stop();
309 }
310
311 auto rof = rofs.begin();
312
313 for (int i = 0; i < mNThreads; i++) {
314 for (auto& rofData : roFrameVec[i]) {
315 int ntracksROF = 0, firstROFTrackEntry = allTracksMFT.size();
316 tracksL.swap(rofData.getTracks());
317 ntracksROF = tracksL.size();
318 copyTracks(tracksL, allTracksMFT, allClusIdx);
319 rof->setFirstEntry(firstROFTrackEntry);
320 rof->setNEntries(ntracksROF);
321 *rof++;
322 roFrameId++;
323 }
324 }
325 }
326
327 LOG(info) << "MFTTracker pushed " << allTracksMFT.size() << " tracks";
328
329 if (mUseMC) {
330 pc.outputs().snapshot(Output{"MFT", "TRACKSMCTR", 0}, allTrackLabels);
331 pc.outputs().snapshot(Output{"MFT", "TRACKSMC2ROF", 0}, mc2rofs);
332 }
333
334 mTimer[SWTot].Stop();
335}
336
338{
339 for (int i = 0; i < NStopWatches; i++) {
340 LOGF(info, "Timing %18s: Cpu: %.3e s; Real: %.3e s in %d slots", TimerName[i], mTimer[i].CpuTime(), mTimer[i].RealTime(), mTimer[i].Counter() - 1);
341 }
342}
344void TrackerDPL::updateTimeDependentParams(ProcessingContext& pc)
345{
347 static bool initOnceDone = false;
348 if (!initOnceDone) { // this params need to be queried only once
349 initOnceDone = true;
350 if (pc.inputs().getPos("mftTGeo") >= 0) {
351 pc.inputs().get<o2::mft::GeometryTGeo*>("mftTGeo");
352 }
353 pc.inputs().get<o2::itsmft::TopologyDictionary*>("cldict"); // just to trigger the finaliseCCDB
354 bool continuous = o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::MFT);
355 LOG(info) << "MFTTracker RO: continuous =" << continuous;
356 mMFTTriggered = !continuous;
358 if (mMFTTriggered) {
359 setMFTROFrameLengthMUS(alpParams.roFrameLengthTrig / 1.e3); // MFT ROFrame duration in \mus
360 } else {
361 setMFTROFrameLengthInBC(alpParams.roFrameLengthInBC); // MFT ROFrame duration in BC
362 }
363
367 // tracking configuration parameters
368 auto& trackingParam = MFTTrackingParam::Instance();
369 auto field = static_cast<o2::field::MagneticField*>(TGeoGlobalMagField::Instance()->GetField());
370 double centerMFT[3] = {0, 0, -61.4}; // Field at center of MFT
371 auto Bz = field->getBz(centerMFT);
372 if (Bz == 0 || trackingParam.forceZeroField) {
373 LOG(info) << "Starting MFT Linear tracker: Field is off!";
374 LOG(info) << " MFT tracker running with " << mNThreads << " threads";
375 mFieldOn = false;
376 for (auto i = 0; i < mNThreads; i++) {
377 auto& tracker = mTrackerLVec.emplace_back(std::make_unique<o2::mft::Tracker<TrackLTFL>>(mUseMC));
378 tracker->setBz(0);
379 tracker->configure(trackingParam, i);
380 }
381 } else {
382 LOG(info) << "Starting MFT tracker: Field is on! Bz = " << Bz;
383 LOG(info) << " MFT tracker running with " << mNThreads << " threads";
384 mFieldOn = true;
385 for (auto i = 0; i < mNThreads; i++) {
386 auto& tracker = mTrackerVec.emplace_back(std::make_unique<o2::mft::Tracker<TrackLTF>>(mUseMC));
387 tracker->setBz(Bz);
388 tracker->configure(trackingParam, i);
389 }
390 }
391 }
392}
393
396{
398 return;
399 }
400 if (matcher == ConcreteDataMatcher("MFT", "CLUSDICT", 0)) {
401 LOG(info) << "cluster dictionary updated";
402 mDict = (const o2::itsmft::TopologyDictionary*)obj;
403 return;
404 }
405 if (matcher == ConcreteDataMatcher("MFT", "GEOMTGEO", 0)) {
406 LOG(info) << "MFT GeomtetryTGeo loaded from ccdb";
408 return;
409 }
410}
411
413void TrackerDPL::setMFTROFrameLengthMUS(float fums)
414{
415 mMFTROFrameLengthMUS = fums;
416 mMFTROFrameLengthMUSInv = 1. / mMFTROFrameLengthMUS;
417 mMFTROFrameLengthInBC = std::max(1, int(mMFTROFrameLengthMUS / (o2::constants::lhc::LHCBunchSpacingNS * 1e-3)));
418}
419
421void TrackerDPL::setMFTROFrameLengthInBC(int nbc)
422{
423 mMFTROFrameLengthInBC = nbc;
424 mMFTROFrameLengthMUS = nbc * o2::constants::lhc::LHCBunchSpacingNS * 1e-3;
425 mMFTROFrameLengthMUSInv = 1. / mMFTROFrameLengthMUS;
426}
427
429DataProcessorSpec getTrackerSpec(bool useMC, bool useGeom, int nThreads)
430{
431 std::vector<InputSpec> inputs;
432 inputs.emplace_back("compClusters", "MFT", "COMPCLUSTERS", 0, Lifetime::Timeframe);
433 inputs.emplace_back("patterns", "MFT", "PATTERNS", 0, Lifetime::Timeframe);
434 inputs.emplace_back("ROframes", "MFT", "CLUSTERSROF", 0, Lifetime::Timeframe);
435 inputs.emplace_back("cldict", "MFT", "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec("MFT/Calib/ClusterDictionary"));
436
437 auto& trackingParam = MFTTrackingParam::Instance();
438 if (trackingParam.irFramesOnly) {
439 inputs.emplace_back("IRFramesITS", "ITS", "IRFRAMES", 0, Lifetime::Timeframe);
440 }
441
442 auto ggRequest = std::make_shared<o2::base::GRPGeomRequest>(false, // orbitResetTime
443 true, // GRPECS=true
444 false, // GRPLHCIF
445 true, // GRPMagField
446 false, // askMatLUT
448 inputs,
449 true);
450 if (!useGeom) {
451 ggRequest->addInput({"mftTGeo", "MFT", "GEOMTGEO", 0, Lifetime::Condition, framework::ccdbParamSpec("MFT/Config/Geometry")}, inputs);
452 }
453 std::vector<OutputSpec> outputs;
454 outputs.emplace_back("MFT", "TRACKS", 0, Lifetime::Timeframe);
455 outputs.emplace_back("MFT", "MFTTrackROF", 0, Lifetime::Timeframe);
456 outputs.emplace_back("MFT", "TRACKCLSID", 0, Lifetime::Timeframe);
457
458 if (useMC) {
459 inputs.emplace_back("labels", "MFT", "CLUSTERSMCTR", 0, Lifetime::Timeframe);
460 inputs.emplace_back("MC2ROframes", "MFT", "CLUSTERSMC2ROF", 0, Lifetime::Timeframe);
461 outputs.emplace_back("MFT", "TRACKSMCTR", 0, Lifetime::Timeframe);
462 outputs.emplace_back("MFT", "TRACKSMC2ROF", 0, Lifetime::Timeframe);
463 }
464
465 return DataProcessorSpec{
466 "mft-tracker",
467 inputs,
468 outputs,
469 AlgorithmSpec{adaptFromTask<TrackerDPL>(ggRequest, useMC, nThreads)},
470 Options{}};
471}
472
473} // namespace mft
474} // namespace o2
Definition of the ITS/MFT clusterer settings.
Definition of the ITSMFT compact cluster.
Definition of the Names Generator class.
Definition of the GeometryManager class.
int32_t i
Load pulled clusters, for a given read-out-frame, in a dedicated container.
Class for the standalone track finding.
Definition of the ITSMFT ROFrame (trigger) record.
Definition of a container to keep Monte Carlo truth external to simulation objects.
The main container for the standalone track finding within a read-out-frame.
Definition of the MagF class.
Standalone classes for the track found by the Linear-Track-Finder (LTF) and by the Cellular-Automaton...
std::ostringstream debug
int clusterSize
void checkUpdates(o2::framework::ProcessingContext &pc)
static GRPGeomHelper & instance()
void setRequest(std::shared_ptr< GRPGeomRequest > req)
A container to hold and manage MC truth information/labels.
static constexpr ID MFT
Definition DetID.h:71
Double_t getBz(const Double_t *xyz) const
Method to calculate the field at point xyz.
void snapshot(const Output &spec, T const &object)
decltype(auto) make(const Output &spec, Args... args)
int getPos(const char *name) const
decltype(auto) get(R binding, int part=0) const
DataAllocator & outputs()
The data allocator is used to allocate memory for the output data.
InputRecord & inputs()
The inputs associated with this processing context.
void fillMatrixCache(Int_t mask) override
static GeometryTGeo * Instance()
static void adopt(GeometryTGeo *raw, bool canDelete=false)
void init(framework::InitContext &ic) final
void run(framework::ProcessingContext &pc) final
void endOfStream(framework::EndOfStreamContext &ec) final
This is invoked whenever we have an EndOfStream event.
void finaliseCCDB(framework::ConcreteDataMatcher &matcher, void *obj) final
GLdouble f
Definition glcorearb.h:310
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition glcorearb.h:1308
GLboolean r
Definition glcorearb.h:1233
constexpr double LHCBunchSpacingNS
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
std::vector< ConfigParamSpec > ccdbParamSpec(std::string const &path, int runDependent, std::vector< CCDBMetadata > metadata={}, int qrate=0)
std::vector< ConfigParamSpec > Options
int loadROFrameData(const o2::itsmft::ROFRecord &rof, ROframe< T > &events, gsl::span< const itsmft::CompClusterExt > clusters, gsl::span< const unsigned char >::iterator &pattIt, const itsmft::TopologyDictionary *dict, const dataformats::MCTruthContainer< MCCompLabel > *mClsLabels=nullptr, const o2::mft::Tracker< T > *tracker=nullptr)
Definition IOUtils.cxx:148
o2::framework::DataProcessorSpec getTrackerSpec(bool useMC, bool useGeom, int nThreads)
create a processor spec
std::function< bool(const ROFRecord &)> ROFFilter
Definition Tracker.h:40
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::tuple< TFile *, TTreeReader * > loadData(const std::string inFile)
static constexpr int T2L
Definition Cartesian.h:55
static constexpr int T2GRot
Definition Cartesian.h:57
static constexpr int T2G
Definition Cartesian.h:56
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
TStopwatch sw
std::array< std::vector< ROFRecord >, NEvTypes > rofData