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#include <TMap.h>
22#include <TObjString.h>
23#include <vector>
24#include <future>
25
26#include "TGeoGlobalMagField.h"
27
37#include "Field/MagneticField.h"
42
43using namespace o2::framework;
44
45namespace o2
46{
47namespace mft
48{
49// #define _TIMING_
50
52{
54 for (int sw = 0; sw < NStopWatches; sw++) {
55 mTimer[sw].Stop();
56 mTimer[sw].Reset();
57 }
58
59 // tracking configuration parameters
60 auto& trackingParam = MFTTrackingParam::Instance(); // to avoid loading interpreter during the run
61}
62
64{
65 mTimer[SWTot].Start(false);
66
67 updateTimeDependentParams(pc);
68 storeConfigs(pc);
69 gsl::span<const unsigned char> patterns = pc.inputs().get<gsl::span<unsigned char>>("patterns");
70 auto compClusters = pc.inputs().get<const std::vector<o2::itsmft::CompClusterExt>>("compClusters");
71 auto ntracks = 0;
72
73 // The output ROFs are mutable copies of the input payload; the output vector
74 // is allocated directly in message memory.
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 // Keep only ROFs overlapping an 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 // Convert tracks while collecting their 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 mTimer[SWTot].Stop();
329}
330
331void TrackerDPL::storeConfigs(ProcessingContext& pc)
332{
333 static bool first = true;
334 if (first) {
335 first = false;
337 const auto& conf = o2::mft::MFTTrackingParam::Instance();
339 TMap md;
340 md.SetOwnerKeyValue();
341 md.Add(new TObjString(conf.getName().c_str()), new TObjString(o2::conf::ConfigurableParam::asJSON(conf.getName()).c_str()));
342 pc.outputs().snapshot(Output{"META", "MFTTRACKER", 0}, md);
343 }
344 }
345}
346
348{
349 for (int i = 0; i < NStopWatches; i++) {
350 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);
351 }
352}
354void TrackerDPL::updateTimeDependentParams(ProcessingContext& pc)
355{
357 static bool initOnceDone = false;
358 if (!initOnceDone) { // this params need to be queried only once
359 initOnceDone = true;
360 if (pc.inputs().getPos("mftTGeo") >= 0) {
361 pc.inputs().get<o2::mft::GeometryTGeo*>("mftTGeo");
362 }
363 pc.inputs().get<o2::itsmft::TopologyDictionary*>("cldict"); // just to trigger the finaliseCCDB
364 bool continuous = o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::MFT);
365 LOG(info) << "MFTTracker RO: continuous =" << continuous;
366 mMFTTriggered = !continuous;
368 if (mMFTTriggered) {
369 setMFTROFrameLengthMUS(alpParams.roFrameLengthTrig / 1.e3); // MFT ROFrame duration in \mus
370 } else {
371 setMFTROFrameLengthInBC(alpParams.roFrameLengthInBC); // MFT ROFrame duration in BC
372 }
373
375 geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::T2GRot,
376 o2::math_utils::TransformType::T2G));
377 // tracking configuration parameters
378 auto& trackingParam = MFTTrackingParam::Instance();
379 auto field = static_cast<o2::field::MagneticField*>(TGeoGlobalMagField::Instance()->GetField());
380 double centerMFT[3] = {0, 0, -61.4}; // Field at center of MFT
381 auto Bz = field->getBz(centerMFT);
382 if (Bz == 0 || trackingParam.forceZeroField) {
383 LOG(info) << "Starting MFT Linear tracker: Field is off!";
384 LOG(info) << " MFT tracker running with " << mNThreads << " threads";
385 mFieldOn = false;
386 for (auto i = 0; i < mNThreads; i++) {
387 auto& tracker = mTrackerLVec.emplace_back(std::make_unique<o2::mft::Tracker<TrackLTFL>>(mUseMC));
388 tracker->setBz(0);
389 tracker->configure(trackingParam, i);
390 }
391 } else {
392 LOG(info) << "Starting MFT tracker: Field is on! Bz = " << Bz;
393 LOG(info) << " MFT tracker running with " << mNThreads << " threads";
394 mFieldOn = true;
395 for (auto i = 0; i < mNThreads; i++) {
396 auto& tracker = mTrackerVec.emplace_back(std::make_unique<o2::mft::Tracker<TrackLTF>>(mUseMC));
397 tracker->setBz(Bz);
398 tracker->configure(trackingParam, i);
399 }
400 }
401 }
402}
403
406{
408 return;
409 }
410 if (matcher == ConcreteDataMatcher("MFT", "CLUSDICT", 0)) {
411 LOG(info) << "cluster dictionary updated";
412 mDict = (const o2::itsmft::TopologyDictionary*)obj;
413 return;
414 }
415 if (matcher == ConcreteDataMatcher("MFT", "GEOMTGEO", 0)) {
416 LOG(info) << "MFT GeomtetryTGeo loaded from ccdb";
418 return;
419 }
420}
421
423void TrackerDPL::setMFTROFrameLengthMUS(float fums)
424{
425 mMFTROFrameLengthMUS = fums;
426 mMFTROFrameLengthMUSInv = 1. / mMFTROFrameLengthMUS;
427 mMFTROFrameLengthInBC = std::max(1, int(mMFTROFrameLengthMUS / (o2::constants::lhc::LHCBunchSpacingNS * 1e-3)));
428}
429
431void TrackerDPL::setMFTROFrameLengthInBC(int nbc)
432{
433 mMFTROFrameLengthInBC = nbc;
434 mMFTROFrameLengthMUS = nbc * o2::constants::lhc::LHCBunchSpacingNS * 1e-3;
435 mMFTROFrameLengthMUSInv = 1. / mMFTROFrameLengthMUS;
436}
437
439DataProcessorSpec getTrackerSpec(bool useMC, bool useGeom, int nThreads)
440{
441 std::vector<InputSpec> inputs;
442 inputs.emplace_back("compClusters", "MFT", "COMPCLUSTERS", 0, Lifetime::Timeframe);
443 inputs.emplace_back("patterns", "MFT", "PATTERNS", 0, Lifetime::Timeframe);
444 inputs.emplace_back("ROframes", "MFT", "CLUSTERSROF", 0, Lifetime::Timeframe);
445 inputs.emplace_back("cldict", "MFT", "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec("MFT/Calib/ClusterDictionary"));
446
447 auto& trackingParam = MFTTrackingParam::Instance();
448 if (trackingParam.irFramesOnly) {
449 inputs.emplace_back("IRFramesITS", "ITS", "IRFRAMES", 0, Lifetime::Timeframe);
450 }
451
452 auto ggRequest = std::make_shared<o2::base::GRPGeomRequest>(false, // orbitResetTime
453 true, // GRPECS=true
454 false, // GRPLHCIF
455 true, // GRPMagField
456 false, // askMatLUT
458 inputs,
459 true);
460 if (!useGeom) {
461 ggRequest->addInput({"mftTGeo", "MFT", "GEOMTGEO", 0, Lifetime::Condition, framework::ccdbParamSpec("MFT/Config/Geometry")}, inputs);
462 }
463 std::vector<OutputSpec> outputs;
464 outputs.emplace_back("MFT", "TRACKS", 0, Lifetime::Timeframe);
465 outputs.emplace_back("MFT", "MFTTrackROF", 0, Lifetime::Timeframe);
466 outputs.emplace_back("MFT", "TRACKCLSID", 0, Lifetime::Timeframe);
467
468 if (useMC) {
469 inputs.emplace_back("labels", "MFT", "CLUSTERSMCTR", 0, Lifetime::Timeframe);
470 outputs.emplace_back("MFT", "TRACKSMCTR", 0, Lifetime::Timeframe);
471 }
472
473 outputs.emplace_back("META", "MFTTRACKER", 0, Lifetime::Sporadic);
474
475 return DataProcessorSpec{
476 "mft-tracker",
477 inputs,
478 outputs,
479 AlgorithmSpec{adaptFromTask<TrackerDPL>(ggRequest, useMC, nThreads)},
480 Options{}};
481}
482
483} // namespace mft
484} // namespace o2
Definition of the ITSMFT compact cluster.
Definition of the Names Generator class.
Definition of the GeometryManager class.
std::ostringstream debug
int32_t i
Definition of the ITSMFT ROFrame (trigger) record.
Definition of the ITS/MFT clusterer settings.
std::vector< o2::MCCompLabel > labels
std::vector< o2::its::TrackITS > tracks
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:138
static std::string asJSON(std::string const &keyOnly="")
static void write(std::string const &filename, std::string const &keyOnly="")
A container to hold and manage MC truth information/labels.
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
GLint first
Definition glcorearb.h:399
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
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
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
TStopwatch sw
std::array< std::vector< ROFRecord >, NEvTypes > rofData