12#ifndef FRAMEWORK_ANALYSIS_TASK_H_
13#define FRAMEWORK_ANALYSIS_TASK_H_
31#include <fairmq/Version.h>
33#include <arrow/compute/kernel.h>
34#include <arrow/table.h>
35#include <gandiva/node.h>
56template <
int64_t BEGIN,
int64_t END,
int64_t STEP = 1>
64static constexpr bool is_enumeration_v =
false;
66template <
int64_t BEGIN,
int64_t END,
int64_t STEP>
67static constexpr bool is_enumeration_v<Enumeration<BEGIN, END, STEP>> =
true;
85inline auto matchersForArgument(
int argumentIndex)
87 return std::views::filter([argumentIndex](
auto const& pair) {
return pair.first == argumentIndex; });
90struct AnalysisDataProcessorBuilder {
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};
107 }(framework::pack<Args...>{}, bk, bku,
enabled);
110 template <soa::TableRef R>
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, {
"\"\""}});
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}});
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});
131 template <soa::is_table A>
133 static void addExpression(
int,
uint32_t, std::vector<ExpressionInfo>&)
137 template <soa::is_filtered_table A>
138 static void addExpression(
int ai,
uint32_t hash, std::vector<ExpressionInfo>& eInfos)
141 eInfos.emplace_back(ai,
hash, std::span{std::decay_t<A>::column_hashes}, std::make_shared<arrow::Schema>(
fields));
144 template <soa::is_iterator A>
145 static void addExpression(
int ai,
uint32_t hash, std::vector<ExpressionInfo>& eInfos)
147 addExpression<typename std::decay_t<A>::parent_t>(ai,
hash, eInfos);
151 template <soa::is_table A>
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()>());
164 ([&ai, &
hash, &eInfos, &
name, &
value, &inputs, &iInfos, newOrigin]()
mutable {
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));
174 template <
typename T>
175 inline static bool requestInputsFromArgs(T&, std::string
const&, std::vector<InputSpec>&, std::vector<ExpressionInfo>&, std::vector<InputInfo>&,
header::DataOrigin)
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"})
182 AnalysisDataProcessorBuilder::inputsFromArgs(pc.process, (
name +
"/" + pc.name).c_str(), pc.value, inputs, eis, iifs, newOrigin);
185 template <
typename T>
186 inline static bool requestCacheFromArgs(T&,
Cache&,
Cache&)
190 template <is_process_configurable T>
191 inline static bool requestCacheFromArgs(T& pc,
Cache& bk,
Cache& bku)
193 AnalysisDataProcessorBuilder::cacheFromArgs(pc.process, pc.value, bk, bku);
197 template <
typename C, is_enumeration A>
198 static void inputsFromArgs(
void (C::*)(
A),
const char* ,
bool , std::vector<InputSpec>& inputs, std::vector<ExpressionInfo>&, std::vector<InputInfo>&,
header::DataOrigin)
200 std::vector<ConfigParamSpec> inputMetadata;
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> && ...))
211 addInputsAndExpressions<typename std::decay_t<A>::parent_t, Args...>(
hash,
name,
value, inputs, eInfos, iInfos, std::move(newOrigin));
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> && ...)
220 addInputsAndExpressions<Args...>(
hash,
name,
value, inputs, eInfos, iInfos, std::move(newOrigin));
224 template <
typename C, is_enumeration A>
225 static void cacheFromArgs(
void (C::*)(
A), bool,
Cache&,
Cache&)
230 static void cacheFromArgs(
void (C::*)(
A, Args...),
bool value,
Cache& bk,
Cache& bku)
232 addGroupingCandidates<
A, Args...>(bk, bku,
value);
236 static void cacheFromArgs(
void (C::*)(
A, Args...), bool,
Cache&,
Cache&)
240 template <std::ranges::input_range R>
241 static auto extractTablesFromRecord(InputRecord& record,
R matchers)
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();
250 template <soa::is_table T, std::ranges::input_range R>
251 static auto extractFromRecord(InputRecord& record,
R matchers)
253 return T{extractTablesFromRecord(record,
matchers)};
256 template <soa::is_iterator T, std::ranges::input_range R>
257 static auto extractFromRecord(InputRecord& record,
R matchers)
259 return typename T::parent_t{extractTablesFromRecord(record,
matchers)};
262 template <soa::is_filtered T, std::ranges::input_range R>
268 if (info.selection ==
nullptr) {
273 return typename T::parent_t({table}, info.selection);
275 return T({table}, info.selection);
279 template <is_enumeration T,
int AI, std::ranges::input_range R>
280 static auto extract(InputRecord&,
R, std::vector<ExpressionInfo>&,
size_t)
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)
290 return extractFilteredFromRecord<T>(record,
matchers, *std::ranges::find_if(infos, [&phash](
ExpressionInfo const&
i) {
return (
i.processHash == phash &&
i.argumentIndex == AI); }));
292 return extractFromRecord<T>(record,
matchers);
297 static auto bindGroupingTable(InputRecord& record,
R matchers,
void (C::*)(Grouping, Args...), std::vector<ExpressionInfo>& infos)
298 requires(!std::same_as<Grouping, void>)
301 return extract<std::decay_t<Grouping>, 0>(record,
matchers | matchersForArgument(0), infos,
hash);
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)
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)...);
313 static void overwriteInternalIndices(std::tuple<As...>& dest, std::tuple<As...>
const&
src)
315 (std::get<As>(dest).bindInternalIndicesTo(&std::get<As>(
src)), ...);
321 using G = std::decay_t<Grouping>;
322 auto groupingTable = AnalysisDataProcessorBuilder::bindGroupingTable(inputs,
matchers, processingFunction, infos);
325 groupingTable.setPointerReconstructor(pointerReconstructor);
328 constexpr const int numElements = homogeneous_apply_refs_size<false, std::decay_t<Task>>();
331 homogeneous_apply_refs_sized<numElements>([&groupingTable](
auto&
element) {
338 if constexpr (
sizeof...(Associated) == 0) {
340 homogeneous_apply_refs_sized<numElements>([&groupingTable](
auto&
element) {
347 for (
auto&
element : groupingTable) {
348 std::invoke(processingFunction, task, *
element);
351 std::invoke(processingFunction, task, groupingTable);
355 auto associatedTables = AnalysisDataProcessorBuilder::bindAssociatedTables(inputs,
matchers, processingFunction, infos);
358 [&task](
auto&...
t)
mutable {
359 (homogeneous_apply_refs_sized<numElements>(
368 std::apply([&pointerReconstructor](
auto&... table) {
369 (table.setPointerReconstructor(pointerReconstructor), ...);
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 {
382 groupingTable.bindExternalIndices(&std::get<std::decay_t<Associated>>(associatedTables)...);
386 [&binder](
auto&...
x)
mutable {
392 homogeneous_apply_refs_sized<numElements>([&groupingTable, &associatedTables](
auto&
t) {
397 overwriteInternalIndices(associatedTables, associatedTables);
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), ...);
407 overwriteInternalIndices(associatedSlices, associatedTables);
409 [&binder](
auto&...
x)
mutable {
415 homogeneous_apply_refs_sized<numElements>([&groupingTable](
auto&
x) {
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);
427 homogeneous_apply_refs_sized<numElements>([&groupingTable](
auto&
x) {
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);
443 std::vector<std::pair<std::string, bool>>
map;
454template <
typename T,
typename...
A>
460template <
typename T,
typename...
A>
466template <
typename T,
typename...
A>
467std::string getTaskName(
A const&...)
472template <
typename T,
typename...
A>
473auto getTaskNameSetProcesses(std::string& outputName,
TaskName first, SetDefaultProcesses second,
A... args)
475 auto task = std::make_shared<T>(std::forward<A>(args)...);
476 for (
auto& setting : second.map) {
479 return analysis_task_parsers::setProcessSwitch(setting,
element);
483 outputName =
first.value;
487template <
typename T,
typename...
A>
488auto getTaskNameSetProcesses(std::string& outputName, SetDefaultProcesses
first,
TaskName second,
A... args)
490 auto task = std::make_shared<T>(std::forward<A>(args)...);
491 for (
auto& setting :
first.map) {
494 return analysis_task_parsers::setProcessSwitch(setting,
element);
498 outputName = second.
value;
502template <
typename T,
typename...
A>
503auto getTaskNameSetProcesses(std::string& outputName, SetDefaultProcesses
first,
A... args)
505 auto task = std::make_shared<T>(std::forward<A>(args)...);
506 for (
auto& setting :
first.map) {
509 return analysis_task_parsers::setProcessSwitch(setting,
element);
513 auto type_name_str = type_name<T>();
518template <
typename T,
typename...
A>
519auto getTaskNameSetProcesses(std::string& outputName,
TaskName first,
A... args)
521 auto task = std::make_shared<T>(std::forward<A>(args)...);
522 outputName =
first.value;
526template <
typename T,
typename...
A>
527auto getTaskNameSetProcesses(std::string& outputName,
A... args)
529 auto task = std::make_shared<T>(std::forward<A>(args)...);
530 auto type_name_str = type_name<T>();
538template <
typename T,
typename... Args>
541 if (
auto name = getTaskName<T>(args...) + ctx.options().get<std::string>(
"workflow-suffix"); !ctx.mayRun(
name)) {
545 TH1::AddDirectory(
false);
547 std::string name_str;
548 auto task = getTaskNameSetProcesses<T>(name_str, args...);
550 auto suffix = ctx.options().get<std::string>(
"workflow-suffix");
551 if (!suffix.empty()) {
554 const char*
name = name_str.c_str();
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;
564 std::string newOriginStr;
566 if (ctx.options().hasOption(
"aod-origin-replace")) {
567 newOriginStr = ctx.options().get<std::string>(
"aod-origin-replace");
568 if (newOriginStr.size() > 4UL) {
572 if (!newOriginStr.empty()) {
573 newOrigin.runtimeInit(newOriginStr.c_str(), std::min(newOriginStr.size(), 4UL));
576 constexpr const int numElements = homogeneous_apply_refs_size<false, std::decay_t<T>>();
584 if constexpr (
requires { &T::process; }) {
585 AnalysisDataProcessorBuilder::inputsFromArgs(&T::process,
"default",
true, inputs, expressionInfos, inputInfos, newOrigin);
587 homogeneous_apply_refs_sized<numElements>(
588 [
name = name_str, &expressionInfos, &inputs, &inputInfos, &newOrigin](
auto&
x)
mutable {
590 return AnalysisDataProcessorBuilder::requestInputsFromArgs(
x,
name, inputs, expressionInfos, inputInfos, newOrigin);
596 homogeneous_apply_refs_sized<numElements>([&inputs, &newOrigin](
auto&
element) {
602 if (inputs.empty() ==
true) {
603 LOG(warn) <<
"Task " << name_str <<
" has no inputs";
612 for (
auto& input : inputs) {
613 for (
auto& meta : input.metadata) {
614 if (meta.name.starts_with(
"ccdb:") && meta.name !=
"ccdb:") {
626 requiredServices.insert(requiredServices.end(), arrowServices.begin(), arrowServices.end());
633 [task = task, expressionInfos, inputInfos, newOrigin, newOriginStr](
InitContext& ic)
mutable {
635 Cache bindingsKeysUnsorted;
644 homogeneous_apply_refs_sized<numElements>([&eosContext](
auto&
element) {
655 if constexpr (
requires { task->init(ic); }) {
660 homogeneous_apply_refs_sized<numElements>(
664 homogeneous_apply_refs_sized<numElements>([&expressionInfos](
auto&
element) {
670 if constexpr (
requires { &T::process; }) {
671 AnalysisDataProcessorBuilder::cacheFromArgs(&T::process,
true, bindingsKeys, bindingsKeysUnsorted);
673 homogeneous_apply_refs_sized<numElements>(
674 [&bindingsKeys, &bindingsKeysUnsorted](
auto&
x) {
675 return AnalysisDataProcessorBuilder::requestCacheFromArgs(
x, bindingsKeys, bindingsKeysUnsorted);
680 std::ranges::transform(bindingsKeys, bindingsKeys.begin(), [&newOrigin](
Entry&
entry) {
681 if ((entry.matcher.origin == header::DataOrigin{
"AOD"}) && (newOrigin !=
header::DataOrigin{
"AOD"})) {
686 std::ranges::transform(bindingsKeysUnsorted, bindingsKeysUnsorted.begin(), [&newOrigin](
Entry&
entry) {
687 if ((entry.matcher.origin == header::DataOrigin{
"AOD"}) && (newOrigin !=
header::DataOrigin{
"AOD"})) {
699 return [task, expressionInfos, inputInfos, newOrigin, hasCCDBTables, pointerReconstructor](
ProcessingContext& pc)
mutable {
700 if (hasCCDBTables && (!pointerReconstructor)) {
703 pointerReconstructor = proxy.getShmPointerReconstructor(spec, 0);
710 std::ranges::for_each(expressionInfos, [](
auto& info) { info.resetSelection =
true; });
713 homogeneous_apply_refs_sized<numElements>([&slices](
auto&
element) {
722 if constexpr (
requires { task->run(pc); }) {
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);
732 homogeneous_apply_refs_sized<numElements>(
733 [&pc, &expressionInfos, &task, &slices, &inputInfos, &newOrigin, &pointerReconstructor](
auto&
x) {
735 if (
x.value ==
true) {
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);
std::vector< framework::ConcreteDataMatcher > matchers
std::vector< std::shared_ptr< arrow::Field > > fields
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)
bool match(const std::vector< std::string > &queries, const char *pattern)
GLuint const GLchar * name
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLsizei const GLfloat * value
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
bool prepareService(InitContext &, T &)
void bindExternalIndicesPartition(P &, 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)
void setPartition(P &, T &...)
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 newDataframePartition(T &)
bool prepareOutput(ProcessingContext &, T &)
bool appendOption(std::vector< ConfigParamSpec > &, O &)
Options handling.
bool updateSliceInfo(T &, ArrowTableSlicingCache &)
void bindInternalIndicesPartition(P &, T *)
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.
void updatePairList(Cache &list, Entry &entry)
std::function< std::byte *(fair::mq::shmem::MetaHeader &&)> PointerReconstructor
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)
auto createFieldsFromColumns(framework::pack< C... >)
void missingFilterDeclaration(int hash, int ai)
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)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"