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