diff --git a/Detectors/TPC/CMakeLists.txt b/Detectors/TPC/CMakeLists.txt index b602e61e49fe2..e3de1ca57c1be 100644 --- a/Detectors/TPC/CMakeLists.txt +++ b/Detectors/TPC/CMakeLists.txt @@ -13,6 +13,7 @@ add_subdirectory(base) add_subdirectory(reconstruction) add_subdirectory(calibration) add_subdirectory(simulation) +add_subdirectory(simworkflow) add_subdirectory(monitor) add_subdirectory(workflow) add_subdirectory(qc) diff --git a/Detectors/TPC/simworkflow/CMakeLists.txt b/Detectors/TPC/simworkflow/CMakeLists.txt new file mode 100644 index 0000000000000..e442d45fab63f --- /dev/null +++ b/Detectors/TPC/simworkflow/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(TPCSimWorkflow + SOURCES + src/ChunkedDigitPublisher.cxx + src/TPCDigitRootWriterSpec.cxx + PUBLIC_LINK_LIBRARIES O2::TPCSimulation O2::Framework) + +o2_add_executable(chunkeddigit-merger + COMPONENT_NAME tpc + TARGETVARNAME mergertargetName + SOURCES src/ChunkedDigitPublisher.cxx + PUBLIC_LINK_LIBRARIES O2::TPCSimWorkflow) + +if(OpenMP_CXX_FOUND) + # Must be private, depending libraries might be compiled by compiler not understanding -fopenmp + target_compile_definitions(${mergertargetName} PRIVATE WITH_OPENMP) + target_link_libraries(${mergertargetName} PRIVATE OpenMP::OpenMP_CXX) +endif() diff --git a/Steer/DigitizerWorkflow/src/TPCDigitRootWriterSpec.h b/Detectors/TPC/simworkflow/include/TPCSimWorkflow/TPCDigitRootWriterSpec.h similarity index 100% rename from Steer/DigitizerWorkflow/src/TPCDigitRootWriterSpec.h rename to Detectors/TPC/simworkflow/include/TPCSimWorkflow/TPCDigitRootWriterSpec.h diff --git a/Detectors/TPC/workflow/src/ChunkedDigitPublisher.cxx b/Detectors/TPC/simworkflow/src/ChunkedDigitPublisher.cxx similarity index 75% rename from Detectors/TPC/workflow/src/ChunkedDigitPublisher.cxx rename to Detectors/TPC/simworkflow/src/ChunkedDigitPublisher.cxx index adf0cba944c03..bdc2f358a4169 100644 --- a/Detectors/TPC/workflow/src/ChunkedDigitPublisher.cxx +++ b/Detectors/TPC/simworkflow/src/ChunkedDigitPublisher.cxx @@ -19,6 +19,7 @@ #include "Framework/DataAllocator.h" #include "Framework/ControlService.h" #include "DataFormatsTPC/Digit.h" +#include "TPCSimWorkflow/TPCDigitRootWriterSpec.h" #include "CommonUtils/ConfigurableParam.h" #include "DetectorsRaw/HBFUtilsInitializer.h" #include "TPCSimulation/CommonMode.h" @@ -46,6 +47,9 @@ #include #endif #include +#include "CommonDataFormat/RangeReference.h" + +using DigiGroupRef = o2::dataformats::RangeReference; using SubSpecificationType = o2::framework::DataAllocator::SubSpecificationType; @@ -71,6 +75,9 @@ void customize(std::vector& workflowOptions) workflowOptions.push_back( ConfigParamSpec{"tpc-sectors", VariantType::String, sectorDefault.c_str(), {sectorshelp}}); + // option to write merged data to file + workflowOptions.push_back(ConfigParamSpec{"writer-mode", o2::framework::VariantType::Bool, false, {"enable ROOT file output"}}); + // option to disable MC truth workflowOptions.push_back(ConfigParamSpec{"disable-mc", o2::framework::VariantType::Bool, false, {"disable mc-truth"}}); workflowOptions.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}); @@ -104,14 +111,30 @@ void copyHelper(MCTruthContainer const& origin, MCTruthContain target.mergeAtBack(origin); } +// a trait to map TPC data types to a DPL channel name +template +struct OutputChannelName; +template <> +struct OutputChannelName> { + static constexpr char value[] = "DIGITS"; +}; +template <> +struct OutputChannelName> { + static constexpr char value[] = "COMMONMODE"; +}; +template <> +struct OutputChannelName> { + static constexpr char value[] = "DIGTRIGGERS"; +}; + template auto makePublishBuffer(framework::ProcessingContext& pc, int sector, uint64_t activeSectors) { - LOG(info) << "PUBLISHING SECTOR " << sector; + LOG(info) << "PUBLISHING SECTOR " << sector << " FOR CHANNEL " << OutputChannelName::value; o2::tpc::TPCSectorHeader header{sector}; header.activeSectors = activeSectors; - return &pc.outputs().make(Output{"TPC", "DIGITS", static_cast(sector), header}); + return &pc.outputs().make(Output{"TPC", OutputChannelName::value, static_cast(sector), header}); } template <> @@ -187,6 +210,30 @@ void mergeHelper(const char* brprefix, std::vector const& tpcsectors, uint6 } } +template <> +void mergeHelper>(const char* brprefix, std::vector const& tpcsectors, uint64_t activeSectors, + TFile& originfile, framework::ProcessingContext& pc) +{ + // specialization for TPC Trigger + auto keyslist = originfile.GetListOfKeys(); + for (int i = 0; i < keyslist->GetEntries(); ++i) { + auto key = keyslist->At(i); + int sector = atoi(key->GetName()); + if (std::find(tpcsectors.begin(), tpcsectors.end(), sector) == tpcsectors.end()) { + // do nothing if sector not wanted + continue; + } + + using AccumType = std::decay_t>(pc, sector, activeSectors))>; + AccumType accum; +#pragma omp critical + accum = makePublishBuffer>(pc, sector, activeSectors); + // no actual data sent. Continuous mode. + + publishBuffer(pc, sector, activeSectors, accum); + } +} + void publishMergedTimeframes(std::vector const& lanes, std::vector const& tpcsectors, bool domctruth, framework::ProcessingContext& pc) { uint64_t activeSectors = 0; @@ -208,13 +255,21 @@ void publishMergedTimeframes(std::vector const& lanes, std::vector con auto originfile = new TFile(filename.c_str(), "OPEN"); assert(originfile); - //data definitions + // data definitions using DigitsType = std::vector; using LabelType = o2::dataformats::MCTruthContainer; mergeHelper("TPCDigit_", tpcsectors, activeSectors, *originfile, pc); if (domctruth) { mergeHelper("TPCDigitMCTruth_", tpcsectors, activeSectors, *originfile, pc); } + + // we also merge common modes and publish a (fake) trigger entry + using CommonModeType = std::vector; + mergeHelper("TPCCommonMode_", tpcsectors, activeSectors, *originfile, pc); + + using TriggerType = std::vector; + mergeHelper("TPCCommonMode_", tpcsectors, activeSectors, *originfile, pc); + originfile->Close(); delete originfile; } @@ -257,7 +312,7 @@ class Task /// MC truth information is also aggregated and written out DataProcessorSpec getSpec(std::vector const& laneConfiguration, std::vector const& tpcsectors, bool mctruth, bool publish = true) { - //data definitions + // data definitions using DigitsOutputType = std::vector; using CommonModeOutputType = std::vector; @@ -266,10 +321,14 @@ DataProcessorSpec getSpec(std::vector const& laneConfiguration, std::vector // effectively the input expects one sector per subspecification for (int s = 0; s < 36; ++s) { OutputLabel binding{std::to_string(s)}; - outputs.emplace_back(/*binding,*/ "TPC", "DIGITS", static_cast(s), Lifetime::Timeframe); + outputs.emplace_back("TPC", "DIGITS", static_cast(s), Lifetime::Timeframe); if (mctruth) { - outputs.emplace_back(/*binding,*/ "TPC", "DIGITSMCTR", static_cast(s), Lifetime::Timeframe); + outputs.emplace_back("TPC", "DIGITSMCTR", static_cast(s), Lifetime::Timeframe); } + // common mode + outputs.emplace_back("TPC", "COMMONMODE", static_cast(s), Lifetime::Timeframe); + // trigger records + outputs.emplace_back("TPC", "DIGTRIGGERS", static_cast(s), Lifetime::Timeframe); } } @@ -287,12 +346,25 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) auto numlanes = configcontext.options().get("tpc-lanes"); bool mctruth = !configcontext.options().get("disable-mc"); + bool writeout = configcontext.options().get("writer-mode"); auto tpcsectors = o2::RangeTokenizer::tokenize(configcontext.options().get("tpc-sectors")); std::vector lanes(numlanes); std::iota(lanes.begin(), lanes.end(), 0); specs.emplace_back(o2::tpc::getSpec(lanes, tpcsectors, mctruth)); + if (writeout) { + // for now writeout to a ROOT file only works if all sectors + // are included + if (tpcsectors.size() != 36) { + LOG(error) << "You currently need to include all TPC sectors in the ROOT writer-mode"; + } else { + std::vector writerlanes(tpcsectors.size()); + std::iota(writerlanes.begin(), writerlanes.end(), 0); + specs.emplace_back(o2::tpc::getTPCDigitRootWriterSpec(writerlanes, mctruth)); + } + } + // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); return specs; diff --git a/Steer/DigitizerWorkflow/src/TPCDigitRootWriterSpec.cxx b/Detectors/TPC/simworkflow/src/TPCDigitRootWriterSpec.cxx similarity index 95% rename from Steer/DigitizerWorkflow/src/TPCDigitRootWriterSpec.cxx rename to Detectors/TPC/simworkflow/src/TPCDigitRootWriterSpec.cxx index 9bc9b9ba45e71..a907a73281884 100644 --- a/Steer/DigitizerWorkflow/src/TPCDigitRootWriterSpec.cxx +++ b/Detectors/TPC/simworkflow/src/TPCDigitRootWriterSpec.cxx @@ -14,7 +14,7 @@ /// @since 2018-04-19 /// @brief Processor spec for a ROOT file writer for TPC digits -#include "TPCDigitRootWriterSpec.h" +#include "TPCSimWorkflow/TPCDigitRootWriterSpec.h" #include "DataFormatsTPC/TPCSectorHeader.h" #include "CommonDataFormat/RangeReference.h" #include "Framework/InputRecord.h" @@ -77,7 +77,7 @@ DataProcessorSpec getTPCDigitRootWriterSpec(std::vector const& laneConfigur } }; - //branch definitions for RootTreeWriter spec + // branch definitions for RootTreeWriter spec using DigitsOutputType = std::vector; using CommonModeOutputType = std::vector; @@ -156,8 +156,8 @@ DataProcessorSpec getTPCDigitRootWriterSpec(std::vector const& laneConfigur LOG(info) << "DIGIT SIZE " << digiData.size(); const auto& trigS = (*trigP2Sect.get())[sector]; int entries = 0; - if (!trigS.size()) { - std::runtime_error("Digits for sector " + std::to_string(sector) + " are received w/o info on grouping in triggers"); + if (trigS.size() == 0) { + LOG(warn) << "Digits for sector " + std::to_string(sector) + " are received w/o trigger info. Will assume continuous mode"; } else { // check consistency of Ndigits with that of expected from the trigger int nExp = trigS.back().getFirstEntry() + trigS.back().getEntries() - trigS.front().getFirstEntry(); if (nExp != digiData.size()) { @@ -167,7 +167,7 @@ DataProcessorSpec getTPCDigitRootWriterSpec(std::vector const& laneConfigur } { - if (trigS.size() == 1) { // just 1 entry (continous mode?), use digits directly + if (trigS.size() <= 1) { // just 1 entry (continous mode?), use digits directly auto ptr = &digiData; branch.SetAddress(&ptr); branch.Fill(); @@ -214,8 +214,8 @@ DataProcessorSpec getTPCDigitRootWriterSpec(std::vector const& laneConfigur LOG(info) << "MCTRUTH ELEMENTS " << labeldata.getIndexedSize() << " WITH " << labeldata.getNElements() << " LABELS"; const auto& trigS = (*trigP2Sect.get())[sector]; - if (!trigS.size()) { - throw std::runtime_error("MCTruth for sector " + std::to_string(sector) + " are received w/o info on grouping in triggers"); + if (trigS.size() == 0) { + LOG(warn) << "MCTruth for sector " + std::to_string(sector) + " received w/o trigger info. Will assume continuous mode"; } else { int nExp = trigS.back().getFirstEntry() + trigS.back().getEntries() - trigS.front().getFirstEntry(); if (nExp != labeldata.getIndexedSize()) { @@ -225,7 +225,7 @@ DataProcessorSpec getTPCDigitRootWriterSpec(std::vector const& laneConfigur } } { - if (trigS.size() == 1) { // just 1 entry (continous mode?), use labels directly + if (trigS.size() <= 1) { // just 0 or 1 entry (continous mode?), use labels directly outputcontainer.adopt(labelbuffer); br->Fill(); br->ResetAddress(); diff --git a/Detectors/TPC/workflow/CMakeLists.txt b/Detectors/TPC/workflow/CMakeLists.txt index fe7c9175968b5..48ebb54ac4070 100644 --- a/Detectors/TPC/workflow/CMakeLists.txt +++ b/Detectors/TPC/workflow/CMakeLists.txt @@ -70,17 +70,6 @@ o2_add_library(TPCWorkflowStudies O2::GlobalTrackingWorkflow ) -o2_add_executable(chunkeddigit-merger - COMPONENT_NAME tpc - TARGETVARNAME mergertargetName - SOURCES src/ChunkedDigitPublisher.cxx - PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) - -if(OpenMP_CXX_FOUND) - # Must be private, depending libraries might be compiled by compiler not understanding -fopenmp - target_compile_definitions(${mergertargetName} PRIVATE WITH_OPENMP) - target_link_libraries(${mergertargetName} PRIVATE OpenMP::OpenMP_CXX) -endif() o2_add_executable(reco-workflow diff --git a/Detectors/TPC/workflow/readers/CMakeLists.txt b/Detectors/TPC/workflow/readers/CMakeLists.txt index 80e967c287404..28d101caf188c 100644 --- a/Detectors/TPC/workflow/readers/CMakeLists.txt +++ b/Detectors/TPC/workflow/readers/CMakeLists.txt @@ -21,9 +21,3 @@ o2_add_library(TPCReaderWorkflow O2::DPLUtils O2::TPCBase ) - -if(OpenMP_CXX_FOUND) - # Must be private, depending libraries might be compiled by compiler not understanding -fopenmp - target_compile_definitions(${mergertargetName} PRIVATE WITH_OPENMP) - target_link_libraries(${mergertargetName} PRIVATE OpenMP::OpenMP_CXX) -endif() diff --git a/Steer/DigitizerWorkflow/CMakeLists.txt b/Steer/DigitizerWorkflow/CMakeLists.txt index babc5fce4d864..6b31550c83636 100644 --- a/Steer/DigitizerWorkflow/CMakeLists.txt +++ b/Steer/DigitizerWorkflow/CMakeLists.txt @@ -24,7 +24,6 @@ o2_add_executable(digitizer-workflow src/CPVDigitizerSpec.cxx src/SimReaderSpec.cxx src/SimpleDigitizerWorkflow.cxx - src/TPCDigitRootWriterSpec.cxx src/TPCDigitizerSpec.cxx src/ZDCDigitizerSpec.cxx src/TOFDigitizerSpec.cxx @@ -59,6 +58,7 @@ o2_add_executable(digitizer-workflow O2::TOFReconstruction O2::TOFWorkflowIO O2::TPCSimulation + O2::TPCSimWorkflow O2::TRDSimulation O2::TRDWorkflow O2::TRDWorkflowIO diff --git a/Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx b/Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx index e86ee47550f13..ea5c6ba272ec6 100644 --- a/Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx +++ b/Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx @@ -30,7 +30,7 @@ // for TPC #include "TPCDigitizerSpec.h" -#include "TPCDigitRootWriterSpec.h" +#include "TPCSimWorkflow/TPCDigitRootWriterSpec.h" #include "TPCBase/Sector.h" #include "TPCBase/CDBInterface.h" // needed in order to init the **SHARED** polyadist file (to be done before the digitizers initialize)