Project
Loading...
Searching...
No Matches
DataInputDirector.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#include "DataInputDirector.h"
13#include "Framework/Logger.h"
17#include "Framework/Output.h"
18#include "Framework/Signpost.h"
20#include "Headers/DataHeader.h"
21#include "Monitoring/Tags.h"
22#include "Monitoring/Metric.h"
23#include "Monitoring/Monitoring.h"
24
25#include "rapidjson/document.h"
26#include "rapidjson/prettywriter.h"
27#include "rapidjson/filereadstream.h"
28
29#include "NativeAOD.h"
30#include "AODNative/Errors.h"
31
32#include "TGrid.h"
33#include "TFile.h"
34#include "TError.h"
35
36#include <arrow/dataset/file_base.h>
37#include <arrow/dataset/dataset.h>
38#include <uv.h>
39#include <exception>
40#include <memory>
41#include <string_view>
42#include <utility>
43
44#include <dlfcn.h>
45O2_DECLARE_DYNAMIC_LOG(reader_memory_dump);
46
47namespace o2::framework
48{
49using namespace rapidjson;
50
52{
53
54 FileNameHolder holder;
55 holder.fileName = fileName;
56 return holder;
57}
58
59namespace
60{
61// ROOT reports a failed key read (a folder's key list or the object itself) and carries on,
62// so the lookup returns nullptr, or an object built from whatever was in the buffer, and a
63// failed read looks like a missing object. Count the reports while the watch is alive.
64struct RootReadErrorWatch {
65 RootReadErrorWatch()
66 : mPrevious(SetErrorHandler(handler))
67 {
68 sPrevious = mPrevious;
69 sErrors = 0;
70 }
71 ~RootReadErrorWatch()
72 {
73 SetErrorHandler(mPrevious);
74 }
75 RootReadErrorWatch(RootReadErrorWatch const&) = delete;
76 RootReadErrorWatch& operator=(RootReadErrorWatch const&) = delete;
77
78 [[nodiscard]] bool failed() const { return sErrors > 0; }
79
80 static void handler(int level, Bool_t abort, char const* location, char const* msg)
81 {
82 if (level >= kError && location && std::string_view{location} == "TKey::ReadFile") {
83 ++sErrors;
84 }
85 (sPrevious ? sPrevious : DefaultErrorHandler)(level, abort, location, msg);
86 }
87
88 ErrorHandlerFunc_t mPrevious;
89 // Errors from other threads are passed on but not counted.
90 static inline thread_local int sErrors = 0;
91 static inline ErrorHandlerFunc_t sPrevious = nullptr;
92};
93} // namespace
94
96 : mAlienSupport(alienSupport),
97 mContext(context),
98 mLevel(level)
99{
100 std::vector<char const*> capabilitiesSpecs = {
101 "O2Framework:RNTupleObjectReadingCapability",
102 "O2Framework:TTreeObjectReadingCapability",
103 };
104 // The native reader comes first, so that it wins for files it opened. For
105 // files opened with ROOT it provides no handle, and the others are used.
106 if (mContext.readerBackend != "root") {
107 capabilitiesSpecs.insert(capabilitiesSpecs.begin(), "O2FrameworkAnalysisNativeAODSupport:NativeAODObjectReadingCapability");
108 }
109
110 std::vector<LoadablePlugin> plugins;
111 for (auto spec : capabilitiesSpecs) {
112 auto morePlugins = PluginManager::parsePluginSpecString(spec);
113 for (auto& extra : morePlugins) {
114 plugins.push_back(extra);
115 }
116 }
117
118 PluginManager::loadFromPlugin<RootObjectReadingCapability, RootObjectReadingCapabilityPlugin>(plugins, mFactory.capabilities);
119}
120
122{
123 LOGP(info, "DataInputDescriptor");
124 LOGP(info, " Table name : {}", tablename);
125 LOGP(info, " Tree name : {}", treename);
126 LOGP(info, " Input files file : {}", getInputfilesFilename());
127 LOGP(info, " File name regex : {}", getFilenamesRegexString());
128 LOGP(info, " Input files : {}", mfilenames.size());
129 for (auto& fn : mfilenames) {
130 LOGP(info, " {} {}", fn.fileName, fn.numberOfTimeFrames);
131 }
132 LOGP(info, " Total number of TF: {}", getNumberTimeFrames());
133}
134
136{
137 return (minputfilesFile.empty() && minputfilesFilePtr) ? (std::string)*minputfilesFilePtr : minputfilesFile;
138}
139
141{
142 return (mFilenameRegex.empty() && mFilenameRegexPtr) ? (std::string)*mFilenameRegexPtr : mFilenameRegex;
143}
144
146{
147 return std::regex(getFilenamesRegexString());
148}
149
151{
152 // remove leading file:// from file name
153 if (fn.fileName.rfind("file://", 0) == 0) {
154 fn.fileName.erase(0, 7);
155 } else if (!mAlienSupport && fn.fileName.rfind("alien://", 0) == 0 && !gGrid) {
156 LOGP(debug, "AliEn file requested. Enabling support.");
157 TGrid::Connect("alien://");
158 mAlienSupport = true;
159 }
160
161 mtotalNumberTimeFrames += fn.numberOfTimeFrames;
162 mfilenames.emplace_back(fn);
163}
164
165bool DataInputDescriptor::setFile(int counter, int wantedParentLevel, std::string_view origin)
166{
167 // no files left
168 if (counter >= getNumberInputfiles()) {
169 return false;
170 }
171
172 // In case the origin starts with a anything but AOD, we add the origin as the suffix
173 // of the filename. In the future we might expand this for proper rewriting of the
174 // filename based on the origin and the original file information.
175 std::string filename = mfilenames[counter].fileName;
176 // In case we do not need to remap parent levels, the requested origin is what
177 // drives the filename.
178 if (wantedParentLevel == -1 && !origin.starts_with("AOD")) {
179 filename = std::regex_replace(filename, std::regex("[.]root$"), fmt::format("_{}.root", origin));
180 }
181
182 // open file
183 if (mCurrentFile) {
184 if (mCurrentFile->name() == filename) {
185 return true;
186 }
188 }
189
190 TFile* externalFile = nullptr;
191 for (auto& [name, f] : mContext.openFiles) {
192 if (name == filename) {
193 externalFile = f;
194 break;
195 }
196 }
197 // In-memory files given by tests can only be read with ROOT.
198 auto backend = externalFile ? std::string("root") : mContext.readerBackend;
199 if (backend != "root") {
200 try {
201 mCurrentFile = openNativeAOD(filename, mFactory, mContext.nativeOptions);
202 } catch (std::exception const& e) {
203 if (backend == "native") {
204 throw AODReadError(AODReadError::Kind::FileOpen, fmt::format("Couldn't open file \"{}\" with the native reader: {}", filename, e.what()));
205 }
206 LOGP(info, "Reading \"{}\" with ROOT, the native reader cannot: {}", filename, e.what());
207 if (mContext.monitoring) {
208 mContext.monitoring->send(o2::monitoring::Metric{filename, "aod-native-fallback"}.addTag(o2::monitoring::tags::Key::Subsystem, o2::monitoring::tags::Value::DPL));
209 }
210 }
211 }
212 if (!mCurrentFile) {
213 mCurrentFile = RootAODInputFile::open(filename, mFactory, externalFile);
214 }
215 if (!mCurrentFile) {
216 throw AODReadError(AODReadError::Kind::FileOpen, fmt::format("Couldn't open file \"{}\"!", filename));
217 }
218 mCurrentFilesystem = mCurrentFile->filesystem();
220
221 // get the parent file map if exists
222 mParentFileMap = mCurrentFile->parentFiles();
223 if (!mParentFileMap.empty() && !mContext.parentFileReplacement.empty()) {
224 auto pos = mContext.parentFileReplacement.find(';');
225 if (pos == std::string::npos) {
226 throw std::runtime_error(fmt::format("Invalid syntax in aod-parent-base-path-replacement: \"{}\"", mContext.parentFileReplacement.c_str()));
227 }
228 auto from = mContext.parentFileReplacement.substr(0, pos);
229 auto to = mContext.parentFileReplacement.substr(pos + 1);
230
231 for (auto& [df, parent] : mParentFileMap) {
232 // Same as TString::ReplaceAll
233 for (size_t at = 0; !from.empty() && (at = parent.find(from, at)) != std::string::npos; at += to.size()) {
234 parent.replace(at, from.size(), to);
235 }
236 }
237 }
238
239 // get the directory names
240 if (mfilenames[counter].numberOfTimeFrames <= 0) {
241 const std::regex TFRegex = std::regex("/?DF_([0-9]+)(|-.*)$");
242
243 // extract TF numbers and sort accordingly
244 // We use an extra seen set to make sure we preserve the order in which
245 // we instert things in the final list and to make sure we do not have duplicates.
246 // Multiple folder numbers can happen if we use a flat structure /DF_<df>-<tablename>
247 std::unordered_set<size_t> seen;
248 for (auto& key : mCurrentFile->topLevelKeys()) {
249 std::smatch matchResult;
250 std::string const& keyName = key.name;
251 bool match = std::regex_match(keyName, matchResult, TFRegex);
252 if (match) {
253 auto folderNumber = std::stoul(matchResult[1].str());
254 if (seen.find(folderNumber) == seen.end()) {
255 seen.insert(folderNumber);
256 mfilenames[counter].listOfTimeFrameNumbers.emplace_back(folderNumber);
257 }
258 }
259 }
260
261 if (!mParentFileMap.empty()) {
262 // If we have a parent map, we should not process in DF alphabetical order but according to parent file to avoid swapping between files
263 auto parentOf = [this](long df) -> std::string const& {
264 static const std::string none;
265 auto it = mParentFileMap.find("DF_" + std::to_string(df));
266 return it == mParentFileMap.end() ? none : it->second;
267 };
268 std::ranges::sort(mfilenames[counter].listOfTimeFrameNumbers,
269 [&parentOf](long const& l1, long const& l2) -> bool {
270 return parentOf(l1) < parentOf(l2);
271 });
272 } else {
273 std::sort(mfilenames[counter].listOfTimeFrameNumbers.begin(), mfilenames[counter].listOfTimeFrameNumbers.end());
274 }
275
276 mfilenames[counter].alreadyRead.resize(mfilenames[counter].alreadyRead.size() + mfilenames[counter].listOfTimeFrameNumbers.size(), false);
277 mfilenames[counter].numberOfTimeFrames = mfilenames[counter].listOfTimeFrameNumbers.size();
278 }
279 std::vector<std::string> readOrder;
280 for (auto number : mfilenames[counter].listOfTimeFrameNumbers) {
281 readOrder.push_back(fmt::format("DF_{}", number));
282 }
283 mCurrentFile->setReadOrder(readOrder);
284
285 mCurrentFileID = counter;
286 mCurrentFileStartedAt = uv_hrtime();
287 mIOTime = 0;
288
289 return true;
290}
291
292uint64_t DataInputDescriptor::getTimeFrameNumber(int counter, int numTF, int wantedParentLevel, std::string_view wantedOrigin)
293{
294
295 // open file
296 if (!setFile(counter, wantedParentLevel, wantedOrigin)) {
297 return 0ul;
298 }
299
300 // no TF left
301 if (mfilenames[counter].numberOfTimeFrames > 0 && numTF >= mfilenames[counter].numberOfTimeFrames) {
302 return 0ul;
303 }
304
305 return (mfilenames[counter].listOfTimeFrameNumbers)[numTF];
306}
307
308std::pair<std::shared_ptr<DataInputDescriptor>, int> DataInputDescriptor::navigateToLevel(int counter, int numTF, int wantedParentLevel, std::string_view wantedOrigin)
309{
310 if (!setFile(counter, wantedParentLevel, wantedOrigin)) {
311 return {nullptr, -1};
312 }
313 if (numTF < 0 || numTF >= mfilenames[counter].numberOfTimeFrames) {
314 return {nullptr, -1};
315 }
316 recordTimeFrameRead(counter, numTF);
317 auto folderName = fmt::format("DF_{}", mfilenames[counter].listOfTimeFrameNumbers[numTF]);
318 auto parentFile = getParentFile(counter, numTF, "", wantedParentLevel, wantedOrigin);
319 if (parentFile == nullptr) {
320 return {nullptr, -1};
321 }
322 return {parentFile, parentFile->findDFNumber(0, folderName)};
323}
324
325arrow::dataset::FileSource DataInputDescriptor::getFileFolder(int counter, int numTF, int wantedParentLevel, std::string_view wantedOrigin)
326{
327 // If mapped to a parent level deeper than current, skip directly to the right level.
328 if ((wantedParentLevel != -1) && (mLevel < wantedParentLevel)) {
329 auto [parentFile, parentNumTF] = navigateToLevel(counter, numTF, wantedParentLevel, wantedOrigin);
330 if (parentFile == nullptr || parentNumTF == -1) {
331 return {};
332 }
333 return parentFile->getFileFolder(0, parentNumTF, wantedParentLevel, wantedOrigin);
334 }
335
336 // open file
337 if (!setFile(counter, wantedParentLevel, wantedOrigin)) {
338 return {};
339 }
340
341 // no TF left
342 if ((mfilenames[counter].numberOfTimeFrames > 0) && (numTF >= mfilenames[counter].numberOfTimeFrames)) {
343 return {};
344 }
345
346 recordTimeFrameRead(counter, numTF);
347 mfilenames[counter].alreadyRead[numTF] = true;
348
349 return {fmt::format("DF_{}", mfilenames[counter].listOfTimeFrameNumbers[numTF]), mCurrentFilesystem};
350}
351
352void DataInputDescriptor::recordTimeFrameRead(int counter, int numTF)
353{
354 auto read = std::pair{counter, numTF};
355 if (std::find(mTimeFrameReads.begin(), mTimeFrameReads.end(), read) == mTimeFrameReads.end()) {
356 mTimeFrameReads.push_back(read);
357 }
358}
359
361{
362 mTimeFrameReads.clear();
363 mTimeFrameActive = true;
364 if (mParentFile) {
365 mParentFile->beginTimeFrame();
366 }
367}
368
370{
371 mTimeFrameActive = false;
372 if (skipped) {
373 for (auto [file, df] : mTimeFrameReads) {
374 mfilenames[file].alreadyRead[df] = false;
375 ++mfilenames[file].invalidReadSkipped;
376 }
377 }
378 mTimeFrameReads.clear();
379 if (mParentFile) {
380 mParentFile->finishTimeFrame(skipped);
381 }
382 for (auto& parent : mRetainedParents) {
383 parent->finishTimeFrame(skipped);
384 parent->closeInputFile();
385 }
386 mRetainedParents.clear();
387 for (auto& [counter, info] : mPendingFileStatistics) {
388 reportFileStatistics(counter, std::move(info));
389 }
390 mPendingFileStatistics.clear();
391}
392
393void DataInputDescriptor::releaseParentFile()
394{
395 if (!mParentFile) {
396 return;
397 }
398 if (mTimeFrameActive) {
399 // Keep both the read bookkeeping and the open file for final statistics.
400 mRetainedParents.push_back(std::move(mParentFile));
401 } else {
402 mParentFile->closeInputFile();
403 mParentFile.reset();
404 }
405}
406
407std::shared_ptr<DataInputDescriptor> DataInputDescriptor::getParentFile(int counter, int numTF, std::string treename, int wantedParentLevel, std::string_view wantedOrigin)
408{
409 if (mParentFileMap.empty()) {
410 // This file has no parent map
411 return nullptr;
412 }
413
414 auto folderName = fmt::format("DF_{}", mfilenames[counter].listOfTimeFrameNumbers[numTF]);
415 auto parentEntry = mParentFileMap.find(folderName);
416 // The current DF is not found in the parent map (this should not happen and is a fatal error)
417 if (parentEntry == mParentFileMap.end()) {
418 throw AODReadError(AODReadError::Kind::InvalidTimeframe, fmt::format(R"(parent file map exists but does not contain the current DF "{}" in file "{}")", folderName.c_str(), mCurrentFile->name()));
419 }
420 auto const& parentFileName = parentEntry->second;
421
422 if (mParentFile) {
423 // Is this still the corresponding to the correct file?
424 if (parentFileName == mParentFile->mCurrentFile->name()) {
425 return mParentFile;
426 } else {
427 releaseParentFile();
428 }
429 }
430
431 if (mLevel == mContext.allowedParentLevel) {
432 throw std::runtime_error(fmt::format(R"(while looking for tree "{}", the parent file was requested but we are already at level {} of maximal allowed level {} for DF "{}" in file "{}")", treename.c_str(), mLevel, mContext.allowedParentLevel, folderName.c_str(),
433 mCurrentFile->name()));
434 }
435
436 LOGP(info, "Opening parent file {} for DF {}", parentFileName, folderName.c_str());
437 mParentFile = std::make_shared<DataInputDescriptor>(mAlienSupport, mLevel + 1, mContext);
438 mParentFile->mdefaultFilenamesPtr.emplace_back(makeFileNameHolder(parentFileName));
439 mParentFile->fillInputfiles();
440 try {
441 mParentFile->setFile(0, wantedParentLevel, wantedOrigin);
442 if (mTimeFrameActive) {
443 mParentFile->beginTimeFrame();
444 }
445 } catch (...) {
446 mParentFile.reset();
447 std::throw_with_nested(AODReadError(AODReadError::Kind::InvalidTimeframe, fmt::format("Unable to open parent file \"{}\" for {}", parentFileName, folderName)));
448 }
449 return mParentFile;
450}
451
453{
454 return mfilenames.at(counter).numberOfTimeFrames;
455}
456
458{
459 auto& list = mfilenames.at(counter).alreadyRead;
460 return std::count(list.begin(), list.end(), true);
461}
462
464{
465 std::string monitoringInfo(fmt::format("lfn={},size={}", mCurrentFile->name(), mCurrentFile->size()));
466 monitoringInfo += mCurrentFile->monitoringDetails();
467 if (mContext.monitoring) {
468 mContext.monitoring->send(o2::monitoring::Metric{monitoringInfo, "aod-file-open-info"}.addTag(o2::monitoring::tags::Key::Subsystem, o2::monitoring::tags::Value::DPL));
469 }
470 LOGP(info, "Opening file: {}", monitoringInfo);
471}
472
474{
475 int64_t wait_time = (int64_t)uv_hrtime() - (int64_t)mCurrentFileStartedAt - (int64_t)mIOTime;
476 if (wait_time < 0) {
477 wait_time = 0;
478 }
479 std::string monitoringInfo(fmt::format("lfn={},size={},total_df={},read_bytes={},read_calls={},io_time={:.1f},wait_time={:.1f},level={}", mCurrentFile->name(),
480 mCurrentFile->size(), getTimeFramesInFile(mCurrentFileID), mCurrentFile->bytesRead(), mCurrentFile->readCalls(),
481 ((float)mIOTime / 1e9), ((float)wait_time / 1e9), mLevel));
482 monitoringInfo += mCurrentFile->monitoringDetails();
483 if (mTimeFrameActive) {
484 // Snapshot I/O statistics now, but publish DF counts after commit or rollback.
485 mPendingFileStatistics.emplace_back(mCurrentFileID, std::move(monitoringInfo));
486 } else {
487 reportFileStatistics(mCurrentFileID, std::move(monitoringInfo));
488 }
489}
490
491void DataInputDescriptor::reportFileStatistics(int counter, std::string monitoringInfo)
492{
493 monitoringInfo += fmt::format(",read_df={},skipped_df={}", getReadTimeFramesInFile(counter), mfilenames.at(counter).invalidReadSkipped);
494 if (mContext.monitoring) {
495 mContext.monitoring->send(o2::monitoring::Metric{monitoringInfo, "aod-file-read-info"}.addTag(o2::monitoring::tags::Key::Subsystem, o2::monitoring::tags::Value::DPL));
496 }
497 LOGP(info, "Read info: {}", monitoringInfo);
498}
499
501{
502 if (mCurrentFile) {
503 releaseParentFile();
504
505 mParentFileMap.clear();
506
508 mCurrentFilesystem.reset();
509 mCurrentFile.reset();
510 }
511}
512
514{
515 if (getNumberInputfiles() > 0) {
516 // 1. mfilenames
517 return getNumberInputfiles();
518 }
519
520 auto fileName = getInputfilesFilename();
521 if (!fileName.empty()) {
522 // 2. getFilenamesRegex() @ getInputfilesFilename()
523 try {
524 std::ifstream filelist(fileName);
525 if (!filelist.is_open()) {
526 throw std::runtime_error(fmt::format(R"(Couldn't open file "{}")", fileName));
527 }
528 while (std::getline(filelist, fileName)) {
529 // remove white spaces, empty lines are skipped
530 fileName.erase(std::remove_if(fileName.begin(), fileName.end(), ::isspace), fileName.end());
531 if (!fileName.empty() && (getFilenamesRegexString().empty() ||
532 std::regex_match(fileName, getFilenamesRegex()))) {
534 }
535 }
536 } catch (...) {
537 LOGP(error, "Check the input files file! Unable to process \"{}\"!", getInputfilesFilename());
538 return 0;
539 }
540 } else {
541 // 3. getFilenamesRegex() @ mdefaultFilenamesPtr
542 if (!mdefaultFilenamesPtr.empty()) {
543 for (auto& fileNameHolder : mdefaultFilenamesPtr) {
544 if (getFilenamesRegexString().empty() ||
545 std::regex_match(fileNameHolder.fileName, getFilenamesRegex())) {
546 addFileNameHolder(fileNameHolder);
547 }
548 }
549 }
550 }
551
552 return getNumberInputfiles();
553}
554
555int DataInputDescriptor::findDFNumber(int file, std::string dfName)
556{
557 auto dfList = mfilenames[file].listOfTimeFrameNumbers;
558 auto it = std::find_if(dfList.begin(), dfList.end(), [dfName](size_t i) { return fmt::format("DF_{}", i) == dfName; });
559 if (it == dfList.end()) {
560 return -1;
561 }
562 return it - dfList.begin();
563}
564
567 : mTarget(target)
568 {
569 start = uv_hrtime();
570 }
572 {
573 if (!active) {
574 return;
575 }
576 O2_SIGNPOST_ACTION(reader_memory_dump, [](void*) {
577 void (*dump_)(const char*);
578 if (void* sym = dlsym(nullptr, "igprof_dump_now")) {
579 dump_ = __extension__(void (*)(const char*)) sym;
580 if (dump_) {
581 std::string filename = fmt::format("reader-memory-dump-{}.gz", uv_hrtime());
582 dump_(filename.c_str());
583 }
584 }
585 });
586 mTarget += (uv_hrtime() - start);
587 }
588
590 {
591 active = false;
592 }
593
594 bool active = true;
598};
599
600bool DataInputDescriptor::readTree(DataAllocator& outputs, header::DataHeader dh, int counter, int numTF, std::string treename, size_t& totalSizeCompressed, size_t& totalSizeUncompressed)
601try {
602 CalculateDelta t(mIOTime);
603 std::string wantedOrigin = dh.dataOrigin.as<std::string>();
604 int wantedLevel = mContext.levelForOrigin(wantedOrigin);
605
606 // If this origin is mapped to a parent level deeper than current, skip directly without
607 // attempting to read from this level.
608 if (wantedLevel != -1 && mLevel < wantedLevel) {
609 auto [parentFile, parentNumTF] = navigateToLevel(counter, numTF, wantedLevel, wantedOrigin);
610 if (counter >= getNumberInputfiles() || numTF < 0 || numTF >= mfilenames[counter].numberOfTimeFrames) {
611 t.deactivate();
612 return false;
613 }
614 if (parentFile == nullptr) {
615 throw AODReadError(AODReadError::Kind::InvalidTimeframe, fmt::format(R"(No parent file found for "{}" while looking for level {} in "{}")", treename, wantedLevel, mCurrentFile->name()));
616 }
617 if (parentNumTF == -1) {
618 throw AODReadError(AODReadError::Kind::InvalidTimeframe, fmt::format(R"(DF not found in parent file "{}")", parentFile->mCurrentFile->name()));
619 }
620 t.deactivate();
621 return parentFile->readTree(outputs, dh, 0, parentNumTF, treename, totalSizeCompressed, totalSizeUncompressed);
622 }
623
624 auto folder = getFileFolder(counter, numTF, wantedLevel, wantedOrigin);
625 if (!folder.filesystem()) {
626 t.deactivate();
627 return false;
628 }
629
630 auto rootFS = std::dynamic_pointer_cast<VirtualRootFileSystemBase>(folder.filesystem());
631
632 if (!rootFS) {
633 t.deactivate();
634 throw std::runtime_error(fmt::format(R"(Not a ROOT file filesystem!)"));
635 }
636 // FIXME: Ugly. We should detect the format from the treename, good enough for now.
637 std::shared_ptr<arrow::dataset::FileFormat> format;
638 FragmentToBatch::StreamerCreator creator = nullptr;
639
640 auto fullpath = arrow::dataset::FileSource{folder.path() + "/" + treename, folder.filesystem()};
641
642 for (auto& capability : mFactory.capabilities) {
643 auto objectPath = capability.lfn2objectPath(fullpath.path());
644 void* handle = nullptr;
645 bool readFailed = false;
646 try {
647 RootReadErrorWatch watch;
648 handle = capability.getHandle(rootFS, objectPath);
649 readFailed = watch.failed();
650 } catch (...) {
651 // Sizes from a partial read can be garbage, e.g. giving std::bad_alloc.
652 std::throw_with_nested(AODReadError(AODReadError::Kind::InvalidTimeframe, fmt::format(R"(Unable to look up "{}" in "{}")", objectPath, mCurrentFile->name())));
653 }
654 if (readFailed) {
655 throw AODReadError(AODReadError::Kind::InvalidTimeframe, fmt::format(R"(Unable to read "{}" from "{}")", objectPath, mCurrentFile->name()));
656 }
657 if (handle) {
658 format = capability.factory().format();
659 creator = capability.factory().deferredOutputStreamer;
660 // Account for the bytes we are about to read. This used to sit further down, where
661 // the TTree was opened by hand; moving the reading to the arrow::Dataset API left
662 // the accounting behind, which is why aod-bytes-read-* and the --aod-max-read-rate
663 // pacing that derives from them both read zero. Each format reports its own size,
664 // so we just ask; here is where the object is resolved and its size is known.
665 if (capability.accountBytes) {
666 capability.accountBytes(handle, totalSizeCompressed, totalSizeUncompressed);
667 }
668 break;
669 }
670 }
671
672 // FIXME: we should distinguish between an actually missing object and one which has a non compatible
673 // format.
674 if (!format) {
675 t.deactivate();
676 LOGP(debug, "Could not find tree {}. Trying in parent file.", fullpath.path());
677 auto parentFile = getParentFile(counter, numTF, treename, wantedLevel, wantedOrigin);
678 if (parentFile == nullptr) {
679 throw std::runtime_error(fmt::format(R"(Couldn't get TTree "{}" from "{}". Please check https://aliceo2group.github.io/analysis-framework/docs/troubleshooting/#tree-not-found for more information.)", fullpath.path(), mCurrentFile->name()));
680 }
681 int parentNumTF = parentFile->findDFNumber(0, folder.path());
682 if (parentNumTF == -1) {
683 throw AODReadError(AODReadError::Kind::InvalidTimeframe, fmt::format(R"(DF {} listed in parent file map but not found in the corresponding file "{}")", folder.path(), parentFile->mCurrentFile->name()));
684 }
685 // first argument is 0 as the parent file object contains only 1 file
686 return parentFile->readTree(outputs, dh, 0, parentNumTF, treename, totalSizeCompressed, totalSizeUncompressed);
687 }
688
689 auto schemaOpt = format->Inspect(fullpath);
690 if (!schemaOpt.ok()) {
691 throw AODReadError(AODReadError::Kind::InvalidTimeframe, fmt::format("Unable to inspect tree {}: {}", treename, schemaOpt.status().ToString()));
692 }
693 auto physicalSchema = schemaOpt;
694 std::vector<std::shared_ptr<arrow::Field>> fields;
695 for (auto& original : (*schemaOpt)->fields()) {
696 if (original->name().ends_with("_size")) {
697 continue;
698 }
699 fields.push_back(original);
700 }
701 auto datasetSchema = std::make_shared<arrow::Schema>(fields);
702
703 auto fragment = format->MakeFragment(fullpath, {}, *physicalSchema);
704
705 // create table output
706 auto o = Output(dh);
707
708 // FIXME: This should allow me to create a memory pool
709 // which I can then use to scan the dataset.
710 auto f2b = outputs.make<FragmentToBatch>(o, creator, *fragment);
711
714 f2b->setLabel(treename.c_str());
715 char const* operation = "read";
716 try {
717 f2b->fill(datasetSchema, format);
718 operation = "finalize";
719 f2b.release();
720 } catch (...) {
721 f2b.discard();
722 std::throw_with_nested(AODReadError(AODReadError::Kind::InvalidTimeframe, fmt::format("Unable to {} tree {}", operation, treename)));
723 }
724
725 return true;
726} catch (AODReadError const& e) {
727 auto filename = mCurrentFile ? mCurrentFile->name() : mfilenames.at(counter).fileName;
728 auto const& dfs = mfilenames.at(counter).listOfTimeFrameNumbers;
729 auto df = numTF >= 0 && static_cast<size_t>(numTF) < dfs.size() ? fmt::format("DF_{}", dfs[numTF]) : fmt::format("timeframe index {}", numTF);
730 std::throw_with_nested(AODReadError(e.getKind(), fmt::format("Reading tree {} in {} from file \"{}\" at parent level {}", treename, df, filename, mLevel)));
731}
732
733DataInputDirector::DataInputDirector(std::vector<std::string> inputFiles, DataInputDirectorContext&& context)
734 : mContext{context}
735{
736 if (inputFiles.size() == 1 && !inputFiles[0].empty() && inputFiles[0][0] == '@') {
737 setInputfilesFile(inputFiles.back().substr(1, -1));
738 } else {
739 for (auto inputFile : inputFiles) {
740 mdefaultInputFiles.emplace_back(makeFileNameHolder(inputFile));
741 }
742 }
743
745}
746
748{
749 mdefaultInputFiles.clear();
750 mdefaultDataInputDescriptor = nullptr;
751
752 mdataInputDescriptors.clear();
753}
754
756{
757 mdataInputDescriptors.clear();
758 mdefaultInputFiles.clear();
759 mFilenameRegex = std::string("");
760};
761
763{
764 if (mdefaultDataInputDescriptor) {
765 mdefaultDataInputDescriptor.reset();
766 }
767 mdefaultDataInputDescriptor = std::make_shared<DataInputDescriptor>(mAlienSupport, 0, mContext);
768
769 mdefaultDataInputDescriptor->setInputfilesFile(minputfilesFile);
770 mdefaultDataInputDescriptor->setFilenamesRegex(mFilenameRegex);
771 mdefaultDataInputDescriptor->setDefaultInputfiles(mdefaultInputFiles);
772 mdefaultDataInputDescriptor->tablename = "any";
773 mdefaultDataInputDescriptor->treename = "any";
774 mdefaultDataInputDescriptor->fillInputfiles();
775
776 mAlienSupport &= mdefaultDataInputDescriptor->isAlienSupportOn();
777}
778
779bool DataInputDirector::readJson(std::string const& fnjson)
780{
781 // open the file
782 FILE* f = fopen(fnjson.c_str(), "r");
783 if (!f) {
784 LOGP(error, "Could not open JSON file \"{}\"!", fnjson);
785 return false;
786 }
787
788 // create streamer
789 char readBuffer[65536];
790 FileReadStream inputStream(f, readBuffer, sizeof(readBuffer));
791
792 // parse the json file
793 Document jsonDoc;
794 jsonDoc.ParseStream(inputStream);
795 auto status = readJsonDocument(&jsonDoc);
796
797 // clean up
798 fclose(f);
799
800 return status;
801}
802
803bool DataInputDirector::readJsonDocument(Document* jsonDoc)
804{
805 // initialisations
806 std::string fileName("");
807 const char* itemName;
808
809 // is it a proper json document?
810 if (jsonDoc->HasParseError()) {
811 LOGP(error, "Check the JSON document! There is a problem with the format!");
812 return false;
813 }
814
815 // InputDirector
816 itemName = "InputDirector";
817 const Value& didirItem = (*jsonDoc)[itemName];
818 if (!didirItem.IsObject()) {
819 LOGP(info, "No \"{}\" object found in the JSON document!", itemName);
820 return true;
821 }
822
823 // now read various items
824 itemName = "debugmode";
825 if (didirItem.HasMember(itemName)) {
826 if (didirItem[itemName].IsBool()) {
827 mDebugMode = (didirItem[itemName].GetBool());
828 } else {
829 LOGP(error, "Check the JSON document! Item \"{}\" must be a boolean!", itemName);
830 return false;
831 }
832 } else {
833 mDebugMode = false;
834 }
835
836 if (mDebugMode) {
837 StringBuffer buffer;
838 buffer.Clear();
839 PrettyWriter<StringBuffer> writer(buffer);
840 didirItem.Accept(writer);
841 LOGP(info, "InputDirector object: {}", std::string(buffer.GetString()));
842 }
843
844 itemName = "fileregex";
845 if (didirItem.HasMember(itemName)) {
846 if (didirItem[itemName].IsString()) {
847 setFilenamesRegex(didirItem[itemName].GetString());
848 } else {
849 LOGP(error, "Check the JSON document! Item \"{}\" must be a string!", itemName);
850 return false;
851 }
852 }
853
854 itemName = "resfiles";
855 if (didirItem.HasMember(itemName)) {
856 if (didirItem[itemName].IsString()) {
857 fileName = didirItem[itemName].GetString();
858 if (fileName.size() && fileName[0] == '@') {
859 fileName.erase(0, 1);
860 setInputfilesFile(fileName);
861 } else {
863 mdefaultInputFiles.emplace_back(makeFileNameHolder(fileName));
864 }
865 } else if (didirItem[itemName].IsArray()) {
867 auto fns = didirItem[itemName].GetArray();
868 for (auto& fn : fns) {
869 mdefaultInputFiles.emplace_back(makeFileNameHolder(fn.GetString()));
870 }
871 } else {
872 LOGP(error, "Check the JSON document! Item \"{}\" must be a string or an array!", itemName);
873 return false;
874 }
875 }
876
877 itemName = "InputDescriptors";
878 if (didirItem.HasMember(itemName)) {
879 if (!didirItem[itemName].IsArray()) {
880 LOGP(error, "Check the JSON document! Item \"{}\" must be an array!", itemName);
881 return false;
882 }
883
884 // loop over DataInputDescriptors
885 for (auto& didescItem : didirItem[itemName].GetArray()) {
886 if (!didescItem.IsObject()) {
887 LOGP(error, "Check the JSON document! \"{}\" must be objects!", itemName);
888 return false;
889 }
890 // create a new dataInputDescriptor
891 auto didesc = DataInputDescriptor(mAlienSupport, 0, mContext);
892 didesc.setDefaultInputfiles(mdefaultInputFiles);
893
894 itemName = "table";
895 if (didescItem.HasMember(itemName)) {
896 if (didescItem[itemName].IsString()) {
897 didesc.tablename = didescItem[itemName].GetString();
898 didesc.matcher = DataDescriptorQueryBuilder::buildNode(didesc.tablename);
899 } else {
900 LOGP(error, "Check the JSON document! Item \"{}\" must be a string!", itemName);
901 return false;
902 }
903 } else {
904 LOGP(error, "Check the JSON document! Item \"{}\" is missing!", itemName);
905 return false;
906 }
907
908 itemName = "treename";
909 if (didescItem.HasMember(itemName)) {
910 if (didescItem[itemName].IsString()) {
911 didesc.treename = didescItem[itemName].GetString();
912 } else {
913 LOGP(error, "Check the JSON document! Item \"{}\" must be a string!", itemName);
914 return false;
915 }
916 } else {
917 auto m = DataDescriptorQueryBuilder::getTokens(didesc.tablename);
918 didesc.treename = m[2];
919 }
920
921 itemName = "fileregex";
922 if (didescItem.HasMember(itemName)) {
923 if (didescItem[itemName].IsString()) {
924 if (didesc.getNumberInputfiles() == 0) {
925 didesc.setFilenamesRegex(didescItem[itemName].GetString());
926 }
927 } else {
928 LOGP(error, "Check the JSON document! Item \"{}\" must be a string!", itemName);
929 return false;
930 }
931 } else {
932 if (didesc.getNumberInputfiles() == 0) {
933 didesc.setFilenamesRegex(mFilenameRegexPtr);
934 }
935 }
936
937 itemName = "resfiles";
938 if (didescItem.HasMember(itemName)) {
939 if (didescItem[itemName].IsString()) {
940 fileName = didescItem[itemName].GetString();
941 if (fileName.size() && fileName[0] == '@') {
942 didesc.setInputfilesFile(fileName.erase(0, 1));
943 } else {
944 if (didesc.getFilenamesRegexString().empty() ||
945 std::regex_match(fileName, didesc.getFilenamesRegex())) {
946 didesc.addFileNameHolder(makeFileNameHolder(fileName));
947 }
948 }
949 } else if (didescItem[itemName].IsArray()) {
950 auto fns = didescItem[itemName].GetArray();
951 for (auto& fn : fns) {
952 if (didesc.getFilenamesRegexString().empty() ||
953 std::regex_match(fn.GetString(), didesc.getFilenamesRegex())) {
954 didesc.addFileNameHolder(makeFileNameHolder(fn.GetString()));
955 }
956 }
957 } else {
958 LOGP(error, "Check the JSON document! Item \"{}\" must be a string or an array!", itemName);
959 return false;
960 }
961 } else {
962 didesc.setInputfilesFile(minputfilesFilePtr);
963 }
964
965 // fill mfilenames and add InputDescriptor to InputDirector
966 if (didesc.fillInputfiles() > 0) {
967 mdataInputDescriptors.emplace_back(didesc);
968 } else {
969 didesc.printOut();
970 LOGP(info, "This DataInputDescriptor is ignored because its file list is empty!");
971 }
972 mAlienSupport &= didesc.isAlienSupportOn();
973 }
974 }
975
976 // add a default DataInputDescriptor
978
979 // check that all DataInputDescriptors have the same number of input files
980 if (!isValid()) {
981 printOut();
982 return false;
983 }
984
985 // print the DataIputDirector
986 if (mDebugMode) {
987 printOut();
988 }
989
990 return true;
991}
992
994{
995 // compute list of matching outputs
997
998 for (auto& didesc : mdataInputDescriptors) {
999 if (didesc.matcher->match(dh, context)) {
1000 return &didesc;
1001 }
1002 }
1003
1004 return nullptr;
1005}
1006
1007arrow::dataset::FileSource DataInputDirector::getFileFolder(header::DataHeader dh, int counter, int numTF)
1008{
1009 auto didesc = getDataInputDescriptor(dh);
1010 // if NOT match then use defaultDataInputDescriptor
1011 if (!didesc) {
1012 didesc = mdefaultDataInputDescriptor.get();
1013 }
1014 std::string origin = dh.dataOrigin.as<std::string>();
1015 int wantedLevel = mContext.levelForOrigin(origin);
1016
1017 return didesc->getFileFolder(counter, numTF, wantedLevel, origin);
1018}
1019
1021{
1022 mdefaultDataInputDescriptor->beginTimeFrame();
1023 for (auto& descriptor : mdataInputDescriptors) {
1024 descriptor.beginTimeFrame();
1025 }
1026}
1027
1029{
1030 mdefaultDataInputDescriptor->finishTimeFrame(skipped);
1031 for (auto& descriptor : mdataInputDescriptors) {
1032 descriptor.finishTimeFrame(skipped);
1033 }
1034}
1035
1037{
1038 auto didesc = getDataInputDescriptor(dh);
1039 // if NOT match then use defaultDataInputDescriptor
1040 if (!didesc) {
1041 didesc = mdefaultDataInputDescriptor.get();
1042 }
1043
1044 return didesc->getTimeFramesInFile(counter);
1045}
1046
1048{
1049 auto didesc = getDataInputDescriptor(dh);
1050 // if NOT match then use defaultDataInputDescriptor
1051 if (!didesc) {
1052 didesc = mdefaultDataInputDescriptor.get();
1053 }
1054 std::string origin = dh.dataOrigin.as<std::string>();
1055 int wantedLevel = mContext.levelForOrigin(origin);
1056
1057 return didesc->getTimeFrameNumber(counter, numTF, wantedLevel, origin);
1058}
1059
1060bool DataInputDirector::readTree(DataAllocator& outputs, header::DataHeader dh, int counter, int numTF, size_t& totalSizeCompressed, size_t& totalSizeUncompressed, bool wasAOD)
1061{
1062 std::string treename;
1063
1064 auto didesc = getDataInputDescriptor(dh);
1065 if (didesc) {
1066 // if match then use filename and treename from DataInputDescriptor
1067 treename = didesc->treename;
1068 } else {
1069 // if NOT match then use
1070 // . filename from defaultDataInputDescriptor
1071 // . treename from DataHeader
1072 didesc = mdefaultDataInputDescriptor.get();
1073 treename = aod::datamodel::getTreeName(dh, wasAOD);
1074 }
1075 std::string origin = dh.dataOrigin.as<std::string>();
1076
1077 auto result = didesc->readTree(outputs, dh, counter, numTF, treename, totalSizeCompressed, totalSizeUncompressed);
1078 return result;
1079}
1080
1082{
1084 mdefaultDataInputDescriptor->closeInputFile();
1085 for (auto& didesc : mdataInputDescriptors) {
1086 didesc.closeInputFile();
1087 }
1088}
1089
1090bool DataInputDirector::isValid()
1091{
1092 bool status = true;
1093 int numberFiles = mdefaultDataInputDescriptor->getNumberInputfiles();
1094 for (auto& didesc : mdataInputDescriptors) {
1095 status &= didesc.getNumberInputfiles() == numberFiles;
1096 }
1097
1098 return status;
1099}
1100
1102{
1103 bool status = mdefaultDataInputDescriptor->getNumberInputfiles() <= counter;
1104 for (auto& didesc : mdataInputDescriptors) {
1105 status &= (didesc.getNumberInputfiles() <= counter);
1106 }
1107
1108 return status;
1109}
1110
1112{
1113 LOGP(info, "DataInputDirector");
1114 LOGP(info, " Default input files file : {}", minputfilesFile);
1115 LOGP(info, " Default file name regex : {}", mFilenameRegex);
1116 LOGP(info, " Default file names : {}", mdefaultInputFiles.size());
1117 for (auto const& fn : mdefaultInputFiles) {
1118 LOGP(info, " {} {}", fn.fileName, fn.numberOfTimeFrames);
1119 }
1120 LOGP(info, " Default DataInputDescriptor:");
1121 mdefaultDataInputDescriptor->printOut();
1122 LOGP(info, " DataInputDescriptors : {}", getNumberInputDescriptors());
1123 for (auto const& didesc : mdataInputDescriptors) {
1124 didesc.printOut();
1125 }
1126}
1127
1129{
1130 return mContext.levelForOrigin(origin.as<std::string>());
1131}
1132
1133} // namespace o2::framework
header::DataOrigin origin
o2::monitoring::tags::Value Value
ErrorHandlerFunc_t mPrevious
BasicOp operation
std::vector< std::shared_ptr< arrow::Field > > fields
std::ostringstream debug
int32_t i
configStandalone Light OpenGL display display_light Apply smoothing to points Enable Z buffer Highlight links Highlight seeds Highlight sector tracks Highlight final tracks Show individual Show related Highlight grid Show only individual collision Color clusters belonging to track objects Set line Enable drawing TPC data Enable drawing TOF data Enable drawing magnetic field Set field line step count Invert colors configStandalone Heavy OpenGL display display_heavy Show tracks with ITS contribution Show tracks with TOF contribution Enable propagation of loopers Show clusters at nominal x of pad row for early transformed data Split CE tracks when they cross the central Mark clusters Mark adjacent clusters Hide rejected tracks Apply filter on tracks to be displayed Separate increase X h configStandalone Camera window renderer OpenGL display display_camera Orient the camera such that the y axis is always upwards Full Screen MultiSample Anti Downsampling Anti Enable Vertical Sync Target frame or if the backend cannot limit to the refresh Use OpenGL indirect draws to reduce number of draw calls Display h configStandalone Vulkan display display_vulkan Have uniform buffers in host accessible device memory h configStandalone Internal display display_internal Number of updates the Qt GUI may send ahead of the last one the display has before it waits for the display Opacity of the console background Number of console lines the history is shortened to this when it reaches twice the size Time in seconds an info message fades out after setInfoTime h OpenGL display display Font size Do not use Freetype for font Renderer for event Frontend to use for event ROOT macros used as track filter Console script file
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char Directory with events to Events directory is and not inside events Show standalone event Run event generator maximum time bin of continuous for triggered for automatic continuous for automatic continuous triggered uint64_t
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char e
configStandalone Reconstruction rec_tpc multiplier for the combined cluster track error during track following area in cm for the search of for z only used if decrease removal by when above this local occupancy rowx Shift of TPC revert cluster flag edge bit distance to edge exceeds this ZOffset for secondary multiple of radius max P of electron K BB bands crossing max P of electron p BB bands crossing max P of electron d BB bands crossing max P of electron t BB bands crossing min accepted dEdxMaxTPC of the track Additive extra cluster error for Y2 if edge flag set Additive extra cluster error for Y2 if single set Additive extra cluster error for Y2 if or single set Additive extra cluster error for Z2 if or single set Extra errors to add to track when crossing depending on addErrorsCECrossing Inner portion of y range in sector that is not used in searching for extrapolated track candidates factor2YS for track merging factor2K for track merging Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y Max fraction of shared clusters for tracklet Except pad from cluster finding if total number of charges in a fragment is above this Except pad from cluster finding if number of consecutive charges in a fragment is above this Threshold where a timebin is considered disabling the noisy pad check for that pad Treat signal above this minimum as saturated Smoothing factor for the exponential Highly Ionising Particle tail filter Number of timebins to use for the averaging Add additional custom track errors when crossing relative as fraction of Do N fit passes in final fit of< 0:reject at max -n hits") AddOptionRTC(rejectIFCLowRadiusCluster, uint8_t, 1, "", 0, "Reject clusters that get the IFC mask error during refit") AddOptionRTC(dEdxTruncLow, uint8_t, 2, "", 0, "Low truncation threshold, fraction of 128") AddOptionRTC(dEdxTruncHigh, uint8_t, 77, "", 0, "High truncation threshold, fraction of 128") AddOptionRTC(extrapolationTracking, int8_t, 1, "", 0, "Enable Extrapolation Tracking(prolong tracks to adjacent sectors to find short segments)") AddOptionRTC(disableRefitAttachment, uint8_t, 0, "", 0, "Bitmask to disable certain attachment steps during refit(1:attachment, 2:propagation, 4:loop following, 8:mirroring)") AddOptionRTC(rejectionStrategy, uint8_t, o2::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression(0=no, 1=strategy A, 2=strategy B)") AddOptionRTC(mergeLoopersAfterburner, uint8_t, 1, "", 0, "Run afterburner for additional looper merging") AddOptionRTC(compressionTypeMask, uint8_t, o2::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits(1=truncate charge/width LSB, 2=differences, 4=track-model)") AddOptionRTC(compressionSortOrder, uint8_t, o2::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression(0=time, 1=pad, 2=Z-time-pad, 3=Z-pad-time, 4=no sorting(use incoming order))") AddOptionRTC(sigBitsCharge, uint8_t, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") AddOptionRTC(sigBitsWidth, uint8_t, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") AddOptionRTC(dropLoopers, uint8_t, 0, "", 0, "Drop looping tracks starting from second loop") AddOptionRTC(mergerInterpolateErrors, uint8_t, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") AddOptionRTC(mergerInterpolateRejectAlsoOnCurrentPosition, uint8_t, 1, "", 0, "When using mergerInterpolateErrors, reject based on chi2 twice computed with interpolated and current track position starting from NDF > mergerNonInterpolateRejectMinNDF Merge tracks accross the central electrode Enable PID response Add sub threshold clusters in TPC dEdx computation OR mask of TPC flags that will reject the cluster in alternative dEdx Reject edge clusters based on uncorrected track Y during track fit Increase decrease removal by when on this number of pads from the edge h configStandalone Reconstruction rec_trd Max chi2 for TRD tracklets to be matched to a track Chi2 cut for strict matching mode Number of sigmas for ITS TPC track time error estimate Addition to search road around track prolongation along Y in cm Optimal tracklet rphi resolution in maximum chi2 per attached tracklet for TRD tracks take into account the full likelihood of the slope including exponential tails Tracks with less attached tracklets are discarded after the tracking Post trigger Pile up integration time in BCs fits all iterations but the last one in projections Use material lookup table for TPC refit Apply workarounds to avoid cyclic merge should not be needed tpc dyn configStandalone Processing proc_rtc Replace constant variables static by constexpr expressions Compile RTC in deterministic with NO_FAST_MATH flags and GPUCA_DETERMINISTIC_MODE define Use RTC to optimize GPU code h configStandalone Processing proc_rtctech Use a file lock to serialize access to the cache folder Print launch bounds used for RTC code as debugging for exit after Allow RTC with slave GPUReconstruction instances with optConstexpr and optSpecialcode Maximum number of RTC cache files per backend in the cache folder
#define failed(...)
Definition Utils.h:42
char error[CURL_ERROR_SIZE]
CURL * handle
uint16_t pos
Definition RawData.h:3
#define O2_DECLARE_DYNAMIC_LOG(name)
Definition Signpost.h:490
#define O2_SIGNPOST_ACTION(log, callback)
Definition Signpost.h:511
StringRef key
decltype(auto) make(const Output &spec, Args... args)
uint64_t getTimeFrameNumber(int counter, int numTF, int wantedParentLevel, std::string_view wantedOrigin)
std::shared_ptr< DataInputDescriptor > getParentFile(int counter, int numTF, std::string treename, int wantedParentLevel, std::string_view wantedOrigin)
bool readTree(DataAllocator &outputs, header::DataHeader dh, int counter, int numTF, std::string treename, size_t &totalSizeCompressed, size_t &totalSizeUncompressed)
arrow::dataset::FileSource getFileFolder(int counter, int numTF, int wantedParentLevel, std::string_view wantedOrigin)
DataInputDescriptor(bool alienSupport, int level, DataInputDirectorContext &context)
void addFileNameHolder(FileNameHolder fn)
void finishTimeFrame(bool skipped=false)
bool setFile(int counter, int wantedParentLevel, std::string_view wantedOrigin)
int findDFNumber(int file, std::string dfName)
std::pair< std::shared_ptr< DataInputDescriptor >, int > navigateToLevel(int counter, int numTF, int wantedParentLevel, std::string_view wantedOrigin)
DataInputDescriptor * getDataInputDescriptor(header::DataHeader dh)
DataInputDirector(std::vector< std::string > inputFiles, DataInputDirectorContext &&context)
arrow::dataset::FileSource getFileFolder(header::DataHeader dh, int counter, int numTF)
void setInputfilesFile(std::string iffn)
int getTimeFramesInFile(header::DataHeader dh, int counter)
uint64_t getTimeFrameNumber(header::DataHeader dh, int counter, int numTF)
int getLevelForOrigin(header::DataOrigin origin) const
void setFilenamesRegex(std::string dfn)
void finishTimeFrame(bool skipped=false)
bool readJson(std::string const &fnjson)
bool readTree(DataAllocator &outputs, header::DataHeader dh, int counter, int numTF, size_t &totalSizeCompressed, size_t &totalSizeUncompressed, bool wasAOD)
std::function< std::shared_ptr< arrow::io::OutputStream >(std::shared_ptr< arrow::dataset::FileFragment >, const std::shared_ptr< arrow::ResizableBuffer > &buffer)> StreamerCreator
void setLabel(const char *label)
static std::shared_ptr< RootAODInputFile > open(std::string const &name, RootObjectReadingFactory &factory, TFile *external=nullptr)
bool match(const std::vector< std::string > &queries, const char *pattern)
Definition dcs-ccdb.cxx:229
const GLfloat * m
Definition glcorearb.h:4066
GLuint64EXT * result
Definition glcorearb.h:5662
GLuint buffer
Definition glcorearb.h:655
GLuint const GLchar * name
Definition glcorearb.h:781
GLdouble f
Definition glcorearb.h:310
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLint level
Definition glcorearb.h:275
GLint location
Definition glcorearb.h:800
GLint GLint GLsizei GLint GLenum format
Definition glcorearb.h:275
GLuint counter
Definition glcorearb.h:3987
std::string getTreeName(header::DataHeader dh, bool wasAOD)
std::shared_ptr< arrow::Schema > datasetSchema(std::shared_ptr< arrow::Schema > const &physical)
The physical schema without the *_size fields, as DataInputDirector derives it.
std::shared_ptr< arrow::Schema > physicalSchema(TreeInfo const &tree)
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
std::shared_ptr< AODInputFile > openNativeAOD(std::string const &filename, RootObjectReadingFactory &factory, o2::aod::native::Options const &options)
FileNameHolder makeFileNameHolder(std::string fileName)
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
std::string filename()
void empty(int)
static std::unique_ptr< data_matcher::DataDescriptorMatcher > buildNode(std::string const &nodeString)
static std::vector< std::string > getTokens(std::string const &nodeString)
o2::monitoring::Monitoring * monitoring
std::vector< std::pair< std::string, TFile * > > openFiles
int levelForOrigin(std::string_view origin) const
static std::vector< LoadablePlugin > parsePluginSpecString(char const *str)
Parse a comma separated list of <library>:<plugin-name> plugin declarations.
std::vector< RootObjectReadingCapability > capabilities
the main header struct
Definition DataHeader.h:623
T as() const
get the descriptor as std::string
Definition DataHeader.h:304
const std::string str
uint64_t const void const *restrict const msg
Definition x9.h:153