diff --git a/Framework/Core/include/Framework/AnalysisHelpers.h b/Framework/Core/include/Framework/AnalysisHelpers.h index 95be6c7e407b3..6e9b1e211bb76 100644 --- a/Framework/Core/include/Framework/AnalysisHelpers.h +++ b/Framework/Core/include/Framework/AnalysisHelpers.h @@ -340,8 +340,9 @@ concept is_spawns = requires(T t) { /// The actual expressions have to be set in init() for the configurable expression /// columns, used to define the table -template +template struct Defines : decltype(transformBase()) { + static constexpr bool delayed = DELAYED; using spawnable_t = T; using metadata = decltype(transformBase())::metadata; using extension_t = typename metadata::extension_table_t; @@ -373,13 +374,26 @@ struct Defines : decltype(transformBase()) { std::array projectors; std::shared_ptr projector = nullptr; std::shared_ptr schema = std::make_shared(o2::soa::createFieldsFromColumns(placeholders_pack_t{})); + std::shared_ptr inputSchema = nullptr; + + bool needRecompilation = false; + + void recompile() + { + projector = framework::expressions::createProjectorHelper(N, projectors.data(), inputSchema, schema->fields()); + } }; +template +using DefinesDelayed = Defines; + template concept is_defines = requires(T t) { typename T::metadata; requires std::same_as; requires std::same_as>; + requires std::same_as; + &T::recompile; }; /// Policy to control index building diff --git a/Framework/Core/include/Framework/AnalysisManagers.h b/Framework/Core/include/Framework/AnalysisManagers.h index 2a052c0b07218..7717d5cb3a6a2 100644 --- a/Framework/Core/include/Framework/AnalysisManagers.h +++ b/Framework/Core/include/Framework/AnalysisManagers.h @@ -307,6 +307,7 @@ bool prepareOutput(ProcessingContext& context, T& builds) template bool prepareOutput(ProcessingContext& context, T& defines) + requires(T::delayed == false) { using metadata = o2::aod::MetadataTrait>::metadata; auto originalTable = soa::ArrowHelpers::joinTables(extractOriginals(context), std::span{metadata::base_table_t::originalLabels}); @@ -314,6 +315,42 @@ bool prepareOutput(ProcessingContext& context, T& defines) using base_table_t = typename T::base_table_t::table_t; originalTable = makeEmptyTable(o2::aod::label()); } + if (defines.inputSchema == nullptr) { + defines.inputSchema = originalTable->schema(); + } + using D = o2::aod::Hash; + + defines.extension = std::make_shared(o2::framework::spawner(originalTable, + o2::aod::label(), + defines.projectors.data(), + defines.projector, + defines.schema)); + defines.table = std::make_shared(soa::ArrowHelpers::joinTables({defines.extension->asArrowTable(), originalTable}, std::span{T::spawnable_t::table_t::originalLabels})); + return true; +} + +template +bool prepareDelayedOutput(ProcessingContext&, T&) +{ + return false; +} + +template + requires(T::delayed == true) +bool prepareDelayedOutput(ProcessingContext& context, T& defines) +{ + if (defines.needRecompilation) { + defines.recompile(); + } + using metadata = o2::aod::MetadataTrait>::metadata; + auto originalTable = soa::ArrowHelpers::joinTables(extractOriginals(context), std::span{metadata::base_table_t::originalLabels}); + if (originalTable->schema()->fields().empty() == true) { + using base_table_t = typename T::base_table_t::table_t; + originalTable = makeEmptyTable(o2::aod::label()); + } + if (defines.inputSchema == nullptr) { + defines.inputSchema = originalTable->schema(); + } using D = o2::aod::Hash; defines.extension = std::make_shared(o2::framework::spawner(originalTable, diff --git a/Framework/Core/include/Framework/AnalysisTask.h b/Framework/Core/include/Framework/AnalysisTask.h index b53929f326712..56f9a91c240d2 100644 --- a/Framework/Core/include/Framework/AnalysisTask.h +++ b/Framework/Core/include/Framework/AnalysisTask.h @@ -643,6 +643,8 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) return false; }, *task.get()); + // prepare delayed outputs + homogeneous_apply_refs([&pc](auto& element) { return analysis_task_parsers::prepareDelayedOutput(pc, element); }, *task.get()); // finalize outputs homogeneous_apply_refs([&pc](auto& element) { return analysis_task_parsers::finalizeOutput(pc, element); }, *task.get()); }; diff --git a/Framework/Core/test/test_Concepts.cxx b/Framework/Core/test/test_Concepts.cxx index 4bf4f977ec3a8..5e2ad6d96b30f 100644 --- a/Framework/Core/test/test_Concepts.cxx +++ b/Framework/Core/test/test_Concepts.cxx @@ -32,6 +32,15 @@ struct P { PROCESS_SWITCH(P, process1, "", true); }; +namespace o2::aod +{ +namespace ct +{ +DECLARE_SOA_CONFIGURABLE_EXPRESSION_COLUMN(Test, test, float, "test"); +} +DECLARE_SOA_CONFIGURABLE_EXTENDED_TABLE(TracksMore, TracksIU, "TRKMORE", ct::Test); +} // namespace o2::aod + TEST_CASE("IdentificationConcepts") { // ASoA @@ -122,6 +131,11 @@ TEST_CASE("IdentificationConcepts") Builds bld; REQUIRE(is_builds); + Defines def; + DefinesDelayed ddef; + REQUIRE(is_defines); + REQUIRE(is_defines); + OutputObj oo{"test"}; REQUIRE(is_outputobj);