Project
Loading...
Searching...
No Matches
AnalysisTask.h
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
12#ifndef FRAMEWORK_ANALYSIS_TASK_H_
13#define FRAMEWORK_ANALYSIS_TASK_H_
14
31#include <fairmq/Version.h>
32
33#include <arrow/compute/kernel.h>
34#include <arrow/table.h>
35#include <gandiva/node.h>
36#include <type_traits>
37#include <utility>
38#include <memory>
39#include <tuple> // IWYU pragma: export
40
41namespace o2::framework
42{
44std::string type_to_task_name(std::string_view const& camelCase);
45
54};
55
56template <int64_t BEGIN, int64_t END, int64_t STEP = 1>
58 static constexpr int64_t begin = BEGIN;
59 static constexpr int64_t end = END;
60 static constexpr int64_t step = STEP;
61};
62
63template <typename T>
64static constexpr bool is_enumeration_v = false;
65
66template <int64_t BEGIN, int64_t END, int64_t STEP>
67static constexpr bool is_enumeration_v<Enumeration<BEGIN, END, STEP>> = true;
68
69template <typename T>
70concept is_enumeration = is_enumeration_v<std::decay_t<T>>;
71
72template <typename T>
74
75// Helper struct which builds a DataProcessorSpec from
76// the contents of an AnalysisTask...
77namespace
78{
79// One closure type for every argument index. Written inline inside the pack
80// expansion in bindAssociatedTables() below, the predicate lambda would get a
81// fresh closure type per Args, and with it its own std::ranges::filter_view,
82// __bind_back and __perfect_forward_impl instantiation -- paid once per
83// associated table per process function. Taking the index as a runtime capture
84// instead lets every call site share a single filter_view specialisation.
85inline auto matchersForArgument(int argumentIndex)
86{
87 return std::views::filter([argumentIndex](auto const& pair) { return pair.first == argumentIndex; });
88}
89
90struct AnalysisDataProcessorBuilder {
91 template <soa::is_iterator G, soa::is_table... Args>
92 static void addGroupingCandidates(Cache& bk, Cache& bku, bool enabled)
93 {
94 []<soa::is_table... As>(framework::pack<As...>, Cache& bk, Cache& bku, bool enabled) {
95 auto key = std::string{"fIndex"} + o2::framework::cutString(soa::getLabelFromType<std::decay_t<G>>());
96 ([](Cache& bk, Cache& bku, bool enabled, std::string const& key) {
97 if constexpr (soa::relatedByIndex<std::decay_t<G>, std::decay_t<As>>()) {
98 Entry e{soa::getLabelFromTypeForKey<std::decay_t<As>>(key), soa::getMatcherFromTypeForKey<std::decay_t<As>>(key), key, enabled};
101 } else {
103 }
104 }
105 }(bk, bku, enabled, key),
106 ...);
107 }(framework::pack<Args...>{}, bk, bku, enabled);
108 }
109
110 template <soa::TableRef R>
111 static void addOriginalRef(const char* name, bool value, std::vector<InputSpec>& inputs, std::vector<InputInfo>& iInfos, int ai, uint32_t hash, header::DataOrigin newOrigin = header::DataOrigin{"AOD"})
112 {
113 auto spec = soa::tableRef2InputSpec<R>(newOrigin);
114 if (R.origin_hash != "AOD"_h) {
115 spec.metadata.emplace_back(ConfigParamSpec{"aod-origin-replaced", VariantType::Bool, true, {"\"\""}});
116 }
117 spec.metadata.emplace_back(ConfigParamSpec{std::string{"control:"} + name, VariantType::Bool, value, {"\"\""}});
118 auto matcher = DataSpecUtils::asConcreteDataMatcher(spec);
119 DataSpecUtils::updateInputList(inputs, std::move(spec));
120 auto locate = std::ranges::find_if(iInfos, [&hash](auto const& info) { return info.hash == hash; });
121 if (locate == iInfos.end()) {
122 iInfos.emplace_back(hash, std::vector{std::pair{ai, matcher}});
123 } else {
124 if (std::ranges::none_of(locate->matchers, [&ai, &matcher](auto const& match) { return (match.first == ai) && (match.second == matcher); })) {
125 locate->matchers.emplace_back(std::pair{ai, matcher});
126 }
127 }
128 }
129
131 template <soa::is_table A>
133 static void addExpression(int, uint32_t, std::vector<ExpressionInfo>&)
134 {
135 }
136
137 template <soa::is_filtered_table A>
138 static void addExpression(int ai, uint32_t hash, std::vector<ExpressionInfo>& eInfos)
139 {
140 auto fields = soa::createFieldsFromColumns(typename std::decay_t<A>::persistent_columns_t{});
141 eInfos.emplace_back(ai, hash, std::span{std::decay_t<A>::column_hashes}, std::make_shared<arrow::Schema>(fields));
142 }
143
144 template <soa::is_iterator A>
145 static void addExpression(int ai, uint32_t hash, std::vector<ExpressionInfo>& eInfos)
146 {
147 addExpression<typename std::decay_t<A>::parent_t>(ai, hash, eInfos);
148 }
149
151 template <soa::is_table A>
152 static void addInput(const char* name, bool value, std::vector<InputSpec>& inputs, std::vector<InputInfo>& iInfos, int ai, uint32_t hash, header::DataOrigin&& newOrigin = header::DataOrigin{"AOD"})
153 {
154 [&name, &value, &inputs, &iInfos, &ai, &hash, newOrigin = std::move(newOrigin)]<size_t N, std::array<soa::TableRef, N> refs, size_t... Is>(std::index_sequence<Is...>) mutable {
155 (addOriginalRef<refs[Is]>(name, value, inputs, iInfos, ai, hash, newOrigin), ...);
156 }.template operator()<A::originals.size(), std::decay_t<A>::originals>(std::make_index_sequence<std::decay_t<A>::originals.size()>());
157 }
158
160 template <soa::is_table... As>
161 static void addInputsAndExpressions(uint32_t hash, const char* name, bool value, std::vector<InputSpec>& inputs, std::vector<ExpressionInfo>& eInfos, std::vector<InputInfo>& iInfos, header::DataOrigin&& newOrigin = header::DataOrigin{"AOD"})
162 {
163 int ai = -1;
164 ([&ai, &hash, &eInfos, &name, &value, &inputs, &iInfos, newOrigin]() mutable {
165 ++ai;
166 using T = std::decay_t<As>;
167 addExpression<T>(ai, hash, eInfos);
168 addInput<T>(name, value, inputs, iInfos, ai, hash, std::move(newOrigin));
169 }(),
170 ...);
171 }
172
174 template <typename T>
175 inline static bool requestInputsFromArgs(T&, std::string const&, std::vector<InputSpec>&, std::vector<ExpressionInfo>&, std::vector<InputInfo>&, header::DataOrigin)
176 {
177 return false;
178 }
179 template <is_process_configurable T>
180 inline static bool requestInputsFromArgs(T& pc, std::string const& name, std::vector<InputSpec>& inputs, std::vector<ExpressionInfo>& eis, std::vector<InputInfo>& iifs, header::DataOrigin newOrigin = header::DataOrigin{"AOD"})
181 {
182 AnalysisDataProcessorBuilder::inputsFromArgs(pc.process, (name + "/" + pc.name).c_str(), pc.value, inputs, eis, iifs, newOrigin);
183 return true;
184 }
185 template <typename T>
186 inline static bool requestCacheFromArgs(T&, Cache&, Cache&)
187 {
188 return false;
189 }
190 template <is_process_configurable T>
191 inline static bool requestCacheFromArgs(T& pc, Cache& bk, Cache& bku)
192 {
193 AnalysisDataProcessorBuilder::cacheFromArgs(pc.process, pc.value, bk, bku);
194 return true;
195 }
197 template <typename C, is_enumeration A>
198 static void inputsFromArgs(void (C::*)(A), const char* /*name*/, bool /*value*/, std::vector<InputSpec>& inputs, std::vector<ExpressionInfo>&, std::vector<InputInfo>&, header::DataOrigin)
199 {
200 std::vector<ConfigParamSpec> inputMetadata;
201 // FIXME: for the moment we do not support begin, end and step.
202 DataSpecUtils::updateInputList(inputs, InputSpec{"enumeration", "DPL", "ENUM", 0, Lifetime::Enumeration, inputMetadata});
203 }
204
206 template <typename C, soa::is_iterator A, soa::is_table... Args>
207 static void inputsFromArgs(void (C::*)(A, Args...), const char* name, bool value, std::vector<InputSpec>& inputs, std::vector<ExpressionInfo>& eInfos, std::vector<InputInfo>& iInfos, header::DataOrigin newOrigin = header::DataOrigin{"AOD"})
208 requires(std::is_lvalue_reference_v<A> && (std::is_lvalue_reference_v<Args> && ...))
209 {
210 constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId<void (C::*)(A, Args...)>();
211 addInputsAndExpressions<typename std::decay_t<A>::parent_t, Args...>(hash, name, value, inputs, eInfos, iInfos, std::move(newOrigin));
212 }
213
215 template <typename C, soa::is_table... Args>
216 static void inputsFromArgs(void (C::*)(Args...), const char* name, bool value, std::vector<InputSpec>& inputs, std::vector<ExpressionInfo>& eInfos, std::vector<InputInfo>& iInfos, header::DataOrigin newOrigin = header::DataOrigin{"AOD"})
217 requires(std::is_lvalue_reference_v<Args> && ...)
218 {
219 constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId<void (C::*)(Args...)>();
220 addInputsAndExpressions<Args...>(hash, name, value, inputs, eInfos, iInfos, std::move(newOrigin));
221 }
222
224 template <typename C, is_enumeration A>
225 static void cacheFromArgs(void (C::*)(A), bool, Cache&, Cache&)
226 {
227 }
229 template <typename C, soa::is_iterator A, soa::is_table... Args>
230 static void cacheFromArgs(void (C::*)(A, Args...), bool value, Cache& bk, Cache& bku)
231 {
232 addGroupingCandidates<A, Args...>(bk, bku, value);
233 }
235 template <typename C, soa::is_table A, soa::is_table... Args>
236 static void cacheFromArgs(void (C::*)(A, Args...), bool, Cache&, Cache&)
237 {
238 }
239
240 template <std::ranges::input_range R>
241 static auto extractTablesFromRecord(InputRecord& record, R matchers)
242 {
243 std::vector<soa::ArrowTableRef> tables;
244 std::ranges::transform(matchers, std::back_inserter(tables), [&record](auto const& m) {
245 return record.get<TableConsumer>(m.second)->asArrowTable();
246 });
247 return tables;
248 }
249
250 template <soa::is_table T, std::ranges::input_range R>
251 static auto extractFromRecord(InputRecord& record, R matchers)
252 {
253 return T{extractTablesFromRecord(record, matchers)};
254 }
255
256 template <soa::is_iterator T, std::ranges::input_range R>
257 static auto extractFromRecord(InputRecord& record, R matchers)
258 {
259 return typename T::parent_t{extractTablesFromRecord(record, matchers)};
260 }
261
262 template <soa::is_filtered T, std::ranges::input_range R>
263 static auto extractFilteredFromRecord(InputRecord& record, R matchers, ExpressionInfo& info)
264 {
265 auto table = soa::ArrowHelpers::joinTables(extractTablesFromRecord(record, matchers));
266 expressions::updateFilterInfo(info, table.tablePtr);
268 if (info.selection == nullptr) {
269 soa::missingFilterDeclaration(info.processHash, info.argumentIndex);
270 }
271 }
272 if constexpr (soa::is_iterator<T>) {
273 return typename T::parent_t({table}, info.selection);
274 } else {
275 return T({table}, info.selection);
276 }
277 }
278
279 template <is_enumeration T, int AI, std::ranges::input_range R>
280 static auto extract(InputRecord&, R, std::vector<ExpressionInfo>&, size_t)
281 {
282 return T{};
283 }
284
285 template <soa::is_table_or_iterator T, int AI, std::ranges::input_range R>
286 static auto extract(InputRecord& record, R matchers, std::vector<ExpressionInfo>& infos, size_t phash)
287 {
288 // auto matchers = std::ranges::find_if(iInfos, [&phash](auto const& info) { return info.hash == phash; })->matchers | std::views::filter([](auto const& pair) { return pair.first == AI; });
289 if constexpr (soa::is_filtered<T>) {
290 return extractFilteredFromRecord<T>(record, matchers, *std::ranges::find_if(infos, [&phash](ExpressionInfo const& i) { return (i.processHash == phash && i.argumentIndex == AI); }));
291 } else {
292 return extractFromRecord<T>(record, matchers);
293 }
294 }
295
296 template <std::ranges::input_range R, typename C, is_table_iterator_or_enumeration Grouping, soa::is_table... Args>
297 static auto bindGroupingTable(InputRecord& record, R matchers, void (C::*)(Grouping, Args...), std::vector<ExpressionInfo>& infos)
298 requires(!std::same_as<Grouping, void>)
299 {
300 constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId<void (C::*)(Grouping, Args...)>();
301 return extract<std::decay_t<Grouping>, 0>(record, matchers | matchersForArgument(0), infos, hash);
302 }
303
304 template <std::ranges::input_range R, typename C, is_table_iterator_or_enumeration Grouping, soa::is_table... Args>
305 static auto bindAssociatedTables(InputRecord& record, R matchers, void (C::*)(Grouping, Args...), std::vector<ExpressionInfo>& infos)
306 requires(!std::same_as<Grouping, void> && sizeof...(Args) > 0)
307 {
308 constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId<void (C::*)(Grouping, Args...)>();
309 return std::make_tuple(extract<std::decay_t<Args>, has_type_at_v<Args>(pack<Args...>{}) + 1>(record, matchers | matchersForArgument(has_type_at_v<Args>(pack<Args...>{}) + 1), infos, hash)...);
310 }
311
312 template <soa::is_table... As>
313 static void overwriteInternalIndices(std::tuple<As...>& dest, std::tuple<As...> const& src)
314 {
315 (std::get<As>(dest).bindInternalIndicesTo(&std::get<As>(src)), ...);
316 }
317
318 template <typename Task, is_table_iterator_or_enumeration Grouping, std::ranges::input_range R, soa::is_table... Associated>
319 static void invokeProcess(Task& task, InputRecord& inputs, R matchers, PointerReconstructor const& pointerReconstructor, void (Task::*processingFunction)(Grouping, Associated...), std::vector<ExpressionInfo>& infos, ArrowTableSlicingCache& slices, header::DataOrigin newOrigin = header::DataOrigin{"AOD"})
320 {
321 using G = std::decay_t<Grouping>;
322 auto groupingTable = AnalysisDataProcessorBuilder::bindGroupingTable(inputs, matchers, processingFunction, infos);
323
324 if constexpr (!is_enumeration<G>) {
325 groupingTable.setPointerReconstructor(pointerReconstructor);
326 }
327
328 constexpr const int numElements = homogeneous_apply_refs_size<false, std::decay_t<Task>>();
329
330 // set filtered tables for partitions with grouping
331 homogeneous_apply_refs_sized<numElements>([&groupingTable](auto& element) {
334 return true;
335 },
336 task);
337
338 if constexpr (sizeof...(Associated) == 0) {
339 // single argument to process
340 homogeneous_apply_refs_sized<numElements>([&groupingTable](auto& element) {
343 return true;
344 },
345 task);
346 if constexpr (soa::is_iterator<G>) {
347 for (auto& element : groupingTable) {
348 std::invoke(processingFunction, task, *element);
349 }
350 } else {
351 std::invoke(processingFunction, task, groupingTable);
352 }
353 } else {
354 // multiple arguments to process
355 auto associatedTables = AnalysisDataProcessorBuilder::bindAssociatedTables(inputs, matchers, processingFunction, infos);
356 // pre-bind self indices
357 std::apply(
358 [&task](auto&... t) mutable {
359 (homogeneous_apply_refs_sized<numElements>(
360 [&t](auto& p) {
362 return true;
363 },
364 task),
365 ...);
366 },
367 associatedTables);
368 std::apply([&pointerReconstructor](auto&... table) {
369 (table.setPointerReconstructor(pointerReconstructor), ...);
370 },
371 associatedTables);
372
373 auto binder = [&task, &groupingTable, &associatedTables](auto& x) mutable {
374 x.bindExternalIndices(&groupingTable, &std::get<std::decay_t<Associated>>(associatedTables)...);
375 homogeneous_apply_refs_sized<numElements>([&x](auto& t) mutable {
378 return true;
379 },
380 task);
381 };
382 groupingTable.bindExternalIndices(&std::get<std::decay_t<Associated>>(associatedTables)...);
383
384 // always pre-bind full tables to support index hierarchy
385 std::apply(
386 [&binder](auto&... x) mutable {
387 (binder(x), ...);
388 },
389 associatedTables);
390
391 // GroupedCombinations bound separately, as they should be set once for all associated tables
392 homogeneous_apply_refs_sized<numElements>([&groupingTable, &associatedTables](auto& t) {
393 analysis_task_parsers::setGroupedCombination(t, groupingTable, associatedTables);
394 return true;
395 },
396 task);
397 overwriteInternalIndices(associatedTables, associatedTables);
398 if constexpr (soa::is_iterator<G>) {
399 auto slicer = GroupSlicer(groupingTable, associatedTables, slices, newOrigin);
400 for (auto& slice : slicer) {
401 auto associatedSlices = slice.associatedTables();
402 std::apply([&pointerReconstructor](auto&... table) {
403 (table.setPointerReconstructor(pointerReconstructor), ...);
404 },
405 associatedSlices);
406
407 overwriteInternalIndices(associatedSlices, associatedTables);
408 std::apply(
409 [&binder](auto&... x) mutable {
410 (binder(x), ...);
411 },
412 associatedSlices);
413
414 // bind partitions and grouping table
415 homogeneous_apply_refs_sized<numElements>([&groupingTable](auto& x) {
417 return true;
418 },
419 task);
420
421 [](Task& task, void (Task::*processingFunction)(Grouping, Associated...), Grouping g, std::tuple<std::decay_t<Associated>...>& at) {
422 std::invoke(processingFunction, task, g, std::get<std::decay_t<Associated>>(at)...);
423 }(task, processingFunction, slice.groupingElement(), associatedSlices);
424 }
425 } else {
426 // bind partitions and grouping table
427 homogeneous_apply_refs_sized<numElements>([&groupingTable](auto& x) {
429 return true;
430 },
431 task);
432
433 [](Task& task, void (Task::*processingFunction)(Grouping, Associated...), Grouping g, std::tuple<std::decay_t<Associated>...>& at) {
434 std::invoke(processingFunction, task, g, std::get<std::decay_t<Associated>>(at)...);
435 }(task, processingFunction, groupingTable, associatedTables);
436 }
437 }
438 }
439};
440} // namespace
441
443 std::vector<std::pair<std::string, bool>> map;
444};
445
447struct TaskName {
448 TaskName(std::string name) : value{std::move(name)} {}
449 std::string value;
450};
451
452namespace
453{
454template <typename T, typename... A>
455std::string getTaskName(TaskName const& first, A const&...)
456{
457 return first.value;
458}
459
460template <typename T, typename... A>
461std::string getTaskName(SetDefaultProcesses const&, TaskName const& second, A const&...)
462{
463 return second.value;
464}
465
466template <typename T, typename... A>
467std::string getTaskName(A const&...)
468{
469 return type_to_task_name(type_name<T>());
470}
471
472template <typename T, typename... A>
473auto getTaskNameSetProcesses(std::string& outputName, TaskName first, SetDefaultProcesses second, A... args)
474{
475 auto task = std::make_shared<T>(std::forward<A>(args)...);
476 for (auto& setting : second.map) {
478 [&](auto& element) {
479 return analysis_task_parsers::setProcessSwitch(setting, element);
480 },
481 *task.get());
482 }
483 outputName = first.value;
484 return task;
485}
486
487template <typename T, typename... A>
488auto getTaskNameSetProcesses(std::string& outputName, SetDefaultProcesses first, TaskName second, A... args)
489{
490 auto task = std::make_shared<T>(std::forward<A>(args)...);
491 for (auto& setting : first.map) {
493 [&](auto& element) {
494 return analysis_task_parsers::setProcessSwitch(setting, element);
495 },
496 *task.get());
497 }
498 outputName = second.value;
499 return task;
500}
501
502template <typename T, typename... A>
503auto getTaskNameSetProcesses(std::string& outputName, SetDefaultProcesses first, A... args)
504{
505 auto task = std::make_shared<T>(std::forward<A>(args)...);
506 for (auto& setting : first.map) {
508 [&](auto& element) {
509 return analysis_task_parsers::setProcessSwitch(setting, element);
510 },
511 *task.get());
512 }
513 auto type_name_str = type_name<T>();
514 outputName = type_to_task_name(type_name_str);
515 return task;
516}
517
518template <typename T, typename... A>
519auto getTaskNameSetProcesses(std::string& outputName, TaskName first, A... args)
520{
521 auto task = std::make_shared<T>(std::forward<A>(args)...);
522 outputName = first.value;
523 return task;
524}
525
526template <typename T, typename... A>
527auto getTaskNameSetProcesses(std::string& outputName, A... args)
528{
529 auto task = std::make_shared<T>(std::forward<A>(args)...);
530 auto type_name_str = type_name<T>();
531 outputName = type_to_task_name(type_name_str);
532 return task;
533}
534} // namespace
535
538template <typename T, typename... Args>
540{
541 if (auto name = getTaskName<T>(args...) + ctx.options().get<std::string>("workflow-suffix"); !ctx.mayRun(name)) {
543 }
544
545 TH1::AddDirectory(false);
546
547 std::string name_str;
548 auto task = getTaskNameSetProcesses<T>(name_str, args...);
549
550 auto suffix = ctx.options().get<std::string>("workflow-suffix");
551 if (!suffix.empty()) {
552 name_str += suffix;
553 }
554 const char* name = name_str.c_str();
555
556 auto hash = runtime_hash(name);
557
558 std::vector<OutputSpec> outputs;
559 std::vector<InputSpec> inputs;
560 std::vector<ConfigParamSpec> options;
561 std::vector<ExpressionInfo> expressionInfos;
562 std::vector<InputInfo> inputInfos;
563
564 std::string newOriginStr;
565 header::DataOrigin newOrigin{"AOD"};
566 if (ctx.options().hasOption("aod-origin-replace")) {
567 newOriginStr = ctx.options().get<std::string>("aod-origin-replace");
568 if (newOriginStr.size() > 4UL) {
569 wrongOriginReplacement(newOriginStr);
570 }
571 }
572 if (!newOriginStr.empty()) {
573 newOrigin.runtimeInit(newOriginStr.c_str(), std::min(newOriginStr.size(), 4UL));
574 }
575
576 constexpr const int numElements = homogeneous_apply_refs_size<false, std::decay_t<T>>();
577
579 homogeneous_apply_refs_sized<numElements>([&options](auto& element) { return analysis_task_parsers::appendOption(options, element); }, *task.get());
581 homogeneous_apply_refs_sized<numElements>([&inputs](auto& element) { return analysis_task_parsers::appendCondition(inputs, element); }, *task.get());
582
584 if constexpr (requires { &T::process; }) {
585 AnalysisDataProcessorBuilder::inputsFromArgs(&T::process, "default", true, inputs, expressionInfos, inputInfos, newOrigin);
586 }
587 homogeneous_apply_refs_sized<numElements>(
588 [name = name_str, &expressionInfos, &inputs, &inputInfos, &newOrigin](auto& x) mutable {
589 // this pushes (argumentIndex, processHash, schemaPtr, nullptr) into expressionInfos for arguments that are Filtered/filtered_iterators
590 return AnalysisDataProcessorBuilder::requestInputsFromArgs(x, name, inputs, expressionInfos, inputInfos, newOrigin);
591 },
592 *task.get());
593
594 // request base tables for spawnable extended tables and indices to be built
595 // this checks for duplications
596 homogeneous_apply_refs_sized<numElements>([&inputs, &newOrigin](auto& element) {
597 return analysis_task_parsers::requestInputs(inputs, element, newOrigin);
598 },
599 *task.get());
600
601 // no static way to check if the task defines any processing, we can only make sure it subscribes to at least something
602 if (inputs.empty() == true) {
603 LOG(warn) << "Task " << name_str << " has no inputs";
604 }
605
606 // update OutputSpecs in output declarations
607 homogeneous_apply_refs_sized<numElements>([&newOrigin](auto& element) { return analysis_task_parsers::updateOutputSpec(element, newOrigin); }, *task.get());
608
609 // Auto-register default ccdb: path options from subscribed timestamped-table inputs.
610 // This allows tasks to accept --ccdb:fXxx overrides without requiring an explicit
611 // ConfigurableCCDBPath<> member for every column in the subscribed table.
612 for (auto& input : inputs) {
613 for (auto& meta : input.metadata) {
614 if (meta.name.starts_with("ccdb:") && meta.name != "ccdb:") {
616 }
617 }
618 }
619
620 // append outputs
621 homogeneous_apply_refs_sized<numElements>([&outputs, &hash](auto& element) { return analysis_task_parsers::appendOutput(outputs, element, hash); }, *task.get());
622
623 // request services
624 auto requiredServices = CommonServices::defaultServices();
625 auto arrowServices = CommonServices::arrowServices();
626 requiredServices.insert(requiredServices.end(), arrowServices.begin(), arrowServices.end());
627 homogeneous_apply_refs_sized<numElements>([&requiredServices](auto& element) { return analysis_task_parsers::addService(requiredServices, element); }, *task.get());
628
629 // replace origins in Preslice declarations
630 homogeneous_apply_refs_sized<numElements>([&newOrigin](auto& element) { return analysis_task_parsers::replaceOrigin(element, newOrigin); }, *task.get());
631
632 auto algo = AlgorithmSpec::InitCallback{
633 [task = task, expressionInfos, inputInfos, newOrigin, newOriginStr](InitContext& ic) mutable {
634 Cache bindingsKeys;
635 Cache bindingsKeysUnsorted;
636 // add preslice declarations to slicing cache definition
637 homogeneous_apply_refs_sized<numElements>([&bindingsKeys, &bindingsKeysUnsorted](auto& element) { return analysis_task_parsers::registerCache(element, bindingsKeys, bindingsKeysUnsorted); }, *task.get());
638
639 homogeneous_apply_refs_sized<numElements>([&ic](auto&& element) { return analysis_task_parsers::prepareOption(ic, element); }, *task.get());
640 homogeneous_apply_refs_sized<numElements>([&ic](auto&& element) { return analysis_task_parsers::prepareService(ic, element); }, *task.get());
641
642 auto& callbacks = ic.services().get<CallbackService>();
643 auto eoscb = [task](EndOfStreamContext& eosContext) {
644 homogeneous_apply_refs_sized<numElements>([&eosContext](auto& element) {
647 return true; },
648 *task.get());
649 eosContext.services().get<ControlService>().readyToQuit(QuitRequest::Me);
650 };
651
652 callbacks.set<CallbackService::Id::EndOfStream>(eoscb);
653
655 if constexpr (requires { task->init(ic); }) {
656 task->init(ic);
657 }
658
660 homogeneous_apply_refs_sized<numElements>(
661 [&ic](auto& element) -> bool { return analysis_task_parsers::updatePlaceholders(ic, element); },
662 *task.get());
664 homogeneous_apply_refs_sized<numElements>([&expressionInfos](auto& element) {
666 },
667 *task.get());
668
670 if constexpr (requires { &T::process; }) {
671 AnalysisDataProcessorBuilder::cacheFromArgs(&T::process, true, bindingsKeys, bindingsKeysUnsorted);
672 }
673 homogeneous_apply_refs_sized<numElements>(
674 [&bindingsKeys, &bindingsKeysUnsorted](auto& x) {
675 return AnalysisDataProcessorBuilder::requestCacheFromArgs(x, bindingsKeys, bindingsKeysUnsorted);
676 },
677 *task.get());
678
680 std::ranges::transform(bindingsKeys, bindingsKeys.begin(), [&newOrigin](Entry& entry) {
681 if ((entry.matcher.origin == header::DataOrigin{"AOD"}) && (newOrigin != header::DataOrigin{"AOD"})) {
682 entry.matcher = replaceOrigin(entry.matcher, newOrigin);
683 }
684 return entry;
685 });
686 std::ranges::transform(bindingsKeysUnsorted, bindingsKeysUnsorted.begin(), [&newOrigin](Entry& entry) {
687 if ((entry.matcher.origin == header::DataOrigin{"AOD"}) && (newOrigin != header::DataOrigin{"AOD"})) {
688 entry.matcher = replaceOrigin(entry.matcher, newOrigin);
689 }
690 return entry;
691 });
692
693 ic.services().get<ArrowTableSlicingCacheDef>().setCaches(std::move(bindingsKeys));
694 ic.services().get<ArrowTableSlicingCacheDef>().setCachesUnsorted(std::move(bindingsKeysUnsorted));
695 ic.services().get<ArrowTableSlicingCacheDef>().setOrigin(newOrigin);
696 PointerReconstructor pointerReconstructor(nullptr);
697 bool hasCCDBTables = !ic.services().get<DanglingEdgesContext>().requestedTIMs.empty();
698
699 return [task, expressionInfos, inputInfos, newOrigin, hasCCDBTables, pointerReconstructor](ProcessingContext& pc) mutable {
700 if (hasCCDBTables && (!pointerReconstructor)) {
701 auto& proxy = pc.services().get<FairMQDeviceProxy>();
702 auto& spec = pc.services().get<DanglingEdgesContext>().requestedTIMs.front();
703 pointerReconstructor = proxy.getShmPointerReconstructor(spec, 0);
704 }
705 // load the ccdb object from their cache
706 homogeneous_apply_refs_sized<numElements>([&pc](auto& element) { return analysis_task_parsers::newDataframeCondition(pc.inputs(), element); }, *task.get());
707 // reset partitions once per dataframe
708 homogeneous_apply_refs_sized<numElements>([](auto& element) { return analysis_task_parsers::newDataframePartition(element); }, *task.get());
709 // reset selections for the next dataframe
710 std::ranges::for_each(expressionInfos, [](auto& info) { info.resetSelection = true; });
711 // reset pre-slice for the next dataframe
712 auto& slices = pc.services().get<ArrowTableSlicingCache>();
713 homogeneous_apply_refs_sized<numElements>([&slices](auto& element) {
715 },
716 *(task.get()));
717 // initialize local caches
718 homogeneous_apply_refs_sized<numElements>([&pc](auto& element) { return analysis_task_parsers::initializeCache(pc, element); }, *(task.get()));
719 // prepare outputs
720 homogeneous_apply_refs_sized<numElements>([&pc](auto& element) { return analysis_task_parsers::prepareOutput(pc, element); }, *task.get());
721 // execute run()
722 if constexpr (requires { task->run(pc); }) {
723 task->run(pc);
724 }
725 // execute process()
726 if constexpr (requires { &T::process; }) {
727 auto loc = std::ranges::find_if(inputInfos, [](auto const& info) { return info.hash == o2::framework::TypeIdHelpers::uniqueId<decltype(&T::process)>(); });
728 auto matchers = loc == inputInfos.end() ? std::vector<std::pair<int, ConcreteDataMatcher>>{} : loc->matchers;
729 AnalysisDataProcessorBuilder::invokeProcess(*(task.get()), pc.inputs(), matchers, pointerReconstructor, &T::process, expressionInfos, slices, newOrigin);
730 }
731 // execute optional process()
732 homogeneous_apply_refs_sized<numElements>(
733 [&pc, &expressionInfos, &task, &slices, &inputInfos, &newOrigin, &pointerReconstructor](auto& x) {
734 if constexpr (is_process_configurable<decltype(x)>) {
735 if (x.value == true) {
736 auto loc = std::ranges::find_if(inputInfos, [](auto const& info) { return info.hash == o2::framework::TypeIdHelpers::uniqueId<decltype(x.process)>(); });
737 auto matchers = loc == inputInfos.end() ? std::vector<std::pair<int, ConcreteDataMatcher>>{} : loc->matchers;
738 AnalysisDataProcessorBuilder::invokeProcess(*task.get(), pc.inputs(), matchers, pointerReconstructor, x.process, expressionInfos, slices, newOrigin);
739 return true;
740 }
741 return false;
742 }
743 return false;
744 },
745 *task.get());
746 // prepare delayed outputs
747 homogeneous_apply_refs_sized<numElements>([&pc](auto& element) { return analysis_task_parsers::prepareDelayedOutput(pc, element); }, *task.get());
748 // finalize outputs
749 homogeneous_apply_refs_sized<numElements>([&pc](auto& element) { return analysis_task_parsers::finalizeOutput(pc, element); }, *task.get());
750 };
751 }};
752
753 return {
754 name,
755 inputs,
756 outputs,
757 algo,
758 options,
759 requiredServices};
760}
761
762} // namespace o2::framework
763#endif // FRAMEWORK_ANALYSISTASK_H_
std::vector< framework::ConcreteDataMatcher > matchers
uint32_t hash
atype::type element
std::vector< std::shared_ptr< arrow::Field > > fields
int32_t i
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
constexpr uint32_t runtime_hash(char const *str)
StringRef key
Definition A.h:16
bool match(const std::vector< std::string > &queries, const char *pattern)
Definition dcs-ccdb.cxx:229
GLboolean GLboolean g
Definition glcorearb.h:1233
GLint GLenum GLint x
Definition glcorearb.h:403
const GLfloat * m
Definition glcorearb.h:4066
GLuint entry
Definition glcorearb.h:5735
GLuint GLuint end
Definition glcorearb.h:469
GLuint const GLchar * name
Definition glcorearb.h:781
GLenum GLenum GLsizei const GLuint GLboolean enabled
Definition glcorearb.h:2513
GLint first
Definition glcorearb.h:399
GLsizei const GLfloat * value
Definition glcorearb.h:819
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
bool prepareService(InitContext &, T &)
void setGroupedCombination(C &, TG &, Ts &...)
Combinations handling.
bool initializeCache(ProcessingContext &, T &)
Cache handling.
bool replaceOrigin(T &, header::DataOrigin const &)
Preslice handling.
bool requestInputs(std::vector< InputSpec > &, T &, header::DataOrigin)
bool prepareDelayedOutput(ProcessingContext &, T &)
bool prepareOption(InitContext &, O &)
bool finalizeOutput(ProcessingContext &, T &)
bool registerCache(T &, Cache &, Cache &)
bool postRunOutput(EndOfStreamContext &, T &)
bool createExpressionTrees(std::vector< ExpressionInfo > &, T &)
bool prepareOutput(ProcessingContext &, T &)
bool appendOption(std::vector< ConfigParamSpec > &, O &)
Options handling.
bool updateSliceInfo(T &, ArrowTableSlicingCache &)
bool appendCondition(std::vector< InputSpec > &, C &)
Conditions handling.
bool postRunService(EndOfStreamContext &, T &)
bool addService(std::vector< ServiceSpec > &, T &)
Service handling.
bool updatePlaceholders(InitContext &, T &)
Filter handling.
constexpr bool appendOutput(std::vector< OutputSpec > &, T &, uint32_t)
Outputs handling.
bool newDataframeCondition(InputRecord &, C &)
bool updateOutputSpec(T &, header::DataOrigin)
void updateFilterInfo(ExpressionInfo &info, std::shared_ptr< arrow::Table > &table)
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
void updatePairList(Cache &list, Entry &entry)
std::function< std::byte *(fair::mq::shmem::MetaHeader &&)> PointerReconstructor
Definition ASoA.h:52
DataProcessorSpec adaptAnalysisTask(ConfigContext const &ctx, Args &&... args)
std::vector< Entry > Cache
std::string type_to_task_name(std::string_view const &camelCase)
Convert a CamelCase task struct name to snake-case task name.
@ Me
Only quit this data processor.
constexpr auto homogeneous_apply_refs(L l, T &&object)
ConfigParamSpec replaceOrigin(ConfigParamSpec &source, std::string const &originStr)
void wrongOriginReplacement(std::string_view replacement)
std::string cutString(std::string &&str)
Definition ASoA.cxx:322
Descriptor< gSizeDataOriginString > DataOrigin
Definition DataHeader.h:553
auto createFieldsFromColumns(framework::pack< C... >)
Definition ASoA.h:77
void missingFilterDeclaration(int hash, int ai)
Definition ASoA.cxx:33
std::function< ProcessCallback(InitContext &)> InitCallback
static std::vector< ServiceSpec > defaultServices(std::string extraPlugins="", int numWorkers=0)
Split a string into a vector of strings using : as a separator.
static std::vector< ServiceSpec > arrowServices()
static void addOptionIfMissing(std::vector< ConfigParamSpec > &specs, const ConfigParamSpec &spec)
static DataProcessorSpec placeholder(std::string name)
static ConcreteDataMatcher asConcreteDataMatcher(InputSpec const &input)
static void updateInputList(std::vector< InputSpec > &list, InputSpec &&input)
Updates list of InputSpecs by merging metadata.
static constexpr int64_t step
static constexpr int64_t begin
std::vector< std::pair< std::string, bool > > map
Struct to differentiate task names from possible task string arguments.
TaskName(std::string name)
static constexpr uint32_t uniqueId()
static o2::soa::ArrowTableRef joinTables(std::vector< std::shared_ptr< arrow::Table > > &&tables)
Definition ASoA.cxx:149
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"