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