Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Detectors/TPC/workflow/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ o2_add_library(TPCWorkflow
src/TPCTimeSeriesWriterSpec.cxx
src/TPCScalerSpec.cxx
src/TPCPressureTemperatureSpec.cxx
src/TPCDigitRootWriterSpec.cxx
TARGETVARNAME targetName
PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsTPC
O2::DPLUtils O2::TPCReconstruction
Expand Down
97 changes: 85 additions & 12 deletions Detectors/TPC/workflow/src/ChunkedDigitPublisher.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,19 @@
#include "Framework/DataAllocator.h"
#include "Framework/ControlService.h"
#include "DataFormatsTPC/Digit.h"
#include "DataFormatsTPC/TPCSectorHeader.h"
#include "CommonUtils/ConfigurableParam.h"
#include "DetectorsRaw/HBFUtilsInitializer.h"
#include "TPCSimulation/CommonMode.h"
#include "DetectorsBase/Detector.h"
#include "DPLUtils/MakeRootTreeWriterSpec.h"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the normal TPC digitizer workflow, we employ a specialized header TPCDigitRootWriterSpec.h which defines a Writer class for TPC digits. I would try to utilize this. Likely it offers correct treatment for the MC truth classes.

#include <SimulationDataFormat/MCCompLabel.h>
#include <SimulationDataFormat/MCTruthContainer.h>
#include <SimulationDataFormat/ConstMCTruthContainer.h>
#include <CommonUtils/FileSystemUtils.h>
#include "Algorithm/RangeTokenizer.h"
#include "TPCBase/Sector.h"
#include "TPCWorkflow/TPCDigitRootWriterSpec.h"
#include <TFile.h>
#include <TTree.h>
#include <TBranch.h>
Expand All @@ -52,6 +55,13 @@ using SubSpecificationType = o2::framework::DataAllocator::SubSpecificationType;
using namespace o2::framework;
using namespace o2::header;

using namespace o2::framework;
using namespace o2::header;

template <typename T>
using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>;
using DigitOutputType = std::vector<o2::tpc::Digit>;

void customize(std::vector<o2::framework::CallbacksPolicy>& policies)
{
o2::raw::HBFUtilsInitializer::addNewTimeSliceCallback(policies);
Expand All @@ -74,6 +84,7 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions)
// 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 ..."}});
workflowOptions.push_back(ConfigParamSpec{"write-digits-file", VariantType::Int, 0, {"Enable writing of tpcdigis.root file"}});
o2::raw::HBFUtilsInitializer::addConfigOption(workflowOptions);
}

Expand Down Expand Up @@ -120,6 +131,15 @@ auto makePublishBuffer<MCTruthContainer>(framework::ProcessingContext& pc, int s
return new MCTruthContainer();
}

template <>
auto makePublishBuffer<std::vector<o2::tpc::CommonMode>>(framework::ProcessingContext& pc, int sector, uint64_t activeSectors)
{
LOG(info) << "PUBLISHING COMMONMODE SECTOR " << sector;
o2::tpc::TPCSectorHeader header{sector};
header.activeSectors = activeSectors;
return &pc.outputs().make<std::vector<o2::tpc::CommonMode>>(Output{"TPC", "COMMONMODE", static_cast<SubSpecificationType>(sector), header});
}

template <typename T>
void publishBuffer(framework::ProcessingContext& pc, int sector, uint64_t activeSectors, T* accum)
{
Expand All @@ -133,16 +153,27 @@ void publishBuffer<MCTruthContainer>(framework::ProcessingContext& pc, int secto
LOG(info) << "PUBLISHING MC LABELS " << accum->getNElements();
o2::tpc::TPCSectorHeader header{sector};
header.activeSectors = activeSectors;
using LabelType = std::decay_t<decltype(pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(Output{"", "", 0}))>;
LabelType* sharedlabels;

#pragma omp critical
sharedlabels = &pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(
Output{"TPC", "DIGITSMCTR", static_cast<SubSpecificationType>(sector), header});
{
// Convert to IOMCTruthContainerView format as expected by TPC reader
std::vector<char> flattened;
accum->flatten_to(flattened);

accum->flatten_to(*sharedlabels);
auto& sharedlabels = pc.outputs().make<o2::dataformats::IOMCTruthContainerView>(
Output{"TPC", "DIGITSMCTR", static_cast<SubSpecificationType>(sector), header});
sharedlabels.adopt(std::move(flattened));
}
delete accum;
}

template <>
void publishBuffer<std::vector<o2::tpc::CommonMode>>(framework::ProcessingContext& pc, int sector, uint64_t activeSectors, std::vector<o2::tpc::CommonMode>* accum)
{
// CommonMode data is already published by makePublishBuffer, so nothing special needed here
LOG(info) << "PUBLISHED COMMONMODE DATA FOR SECTOR " << sector << " SIZE " << accum->size();
}

template <typename T>
void mergeHelper(const char* brprefix, std::vector<int> const& tpcsectors, uint64_t activeSectors,
TFile& originfile, framework::ProcessingContext& pc)
Expand Down Expand Up @@ -187,7 +218,7 @@ void mergeHelper(const char* brprefix, std::vector<int> const& tpcsectors, uint6
}
}

void publishMergedTimeframes(std::vector<int> const& lanes, std::vector<int> const& tpcsectors, bool domctruth, framework::ProcessingContext& pc)
void publishMergedTimeframes(std::vector<int> const& lanes, std::vector<int> const& tpcsectors, bool domctruth, bool writeDigitsFile, framework::ProcessingContext& pc)
{
uint64_t activeSectors = 0;
for (auto s : tpcsectors) {
Expand Down Expand Up @@ -215,15 +246,49 @@ void publishMergedTimeframes(std::vector<int> const& lanes, std::vector<int> con
if (domctruth) {
mergeHelper<LabelType>("TPCDigitMCTruth_", tpcsectors, activeSectors, *originfile, pc);
}
if (writeDigitsFile) {
using CommonModeType = std::vector<o2::tpc::CommonMode>;
// Try to read common mode data from file, but don't fail if it doesn't exist
try {
mergeHelper<CommonModeType>("TPCCommonMode_", tpcsectors, activeSectors, *originfile, pc);
} catch (const std::exception& e) {
LOG(warning) << "CommonMode data not found in file, creating empty data: " << e.what();
// Create empty common mode data for each sector
for (auto sector : tpcsectors) {
o2::tpc::TPCSectorHeader header{sector};
header.activeSectors = activeSectors;
auto& emptyCommonMode = pc.outputs().make<std::vector<o2::tpc::CommonMode>>(
Output{"TPC", "COMMONMODE", static_cast<SubSpecificationType>(sector), header});
// emptyCommonMode is already empty by default
}
}
}
originfile->Close();
delete originfile;
}

// Create trigger information for continuous mode (one trigger covering all digits)
if (writeDigitsFile) {
for (auto sector : tpcsectors) {
o2::tpc::TPCSectorHeader header{sector};
header.activeSectors = activeSectors;
auto& triggers = pc.outputs().make<std::vector<o2::dataformats::RangeReference<int, int>>>(
Output{"TPC", "DIGTRIGGERS", static_cast<SubSpecificationType>(sector), header});

// For continuous mode, create a single trigger that covers all digits
// We need to count the digits for this sector across all files
// For now, create a placeholder trigger - the actual digit count will be determined
// by the digit writer when it processes the actual digits
triggers.emplace_back(0, 1); // placeholder: covers digits from 0 to 1 (will be adjusted by writer)
LOG(info) << "Created continuous mode trigger for sector " << sector;
}
}
}

class Task
{
public:
Task(std::vector<int> laneConfig, std::vector<int> tpcsectors, bool mctruth) : mLanes(laneConfig), mTPCSectors(tpcsectors), mDoMCTruth(mctruth)
Task(std::vector<int> laneConfig, std::vector<int> tpcsectors, bool mctruth, bool writeDigitsFile) : mLanes(laneConfig), mTPCSectors(tpcsectors), mDoMCTruth(mctruth), mWriteDigitsFile(writeDigitsFile)
{
}

Expand All @@ -233,7 +298,7 @@ class Task

TStopwatch w;
w.Start();
publishMergedTimeframes(mLanes, mTPCSectors, mDoMCTruth, pc);
publishMergedTimeframes(mLanes, mTPCSectors, mDoMCTruth, mWriteDigitsFile, pc);

pc.services().get<ControlService>().endOfStream();
pc.services().get<ControlService>().readyToQuit(QuitRequest::Me);
Expand All @@ -248,14 +313,15 @@ class Task

private:
bool mDoMCTruth = true;
bool mWriteDigitsFile = false;
std::vector<int> mLanes;
std::vector<int> mTPCSectors;
};

/// create the processor spec
/// describing a processor aggregating digits for various TPC sectors and writing them to file
/// MC truth information is also aggregated and written out
DataProcessorSpec getSpec(std::vector<int> const& laneConfiguration, std::vector<int> const& tpcsectors, bool mctruth, bool publish = true)
void getSpec(WorkflowSpec& specs, std::vector<int> const& laneConfiguration, std::vector<int> const& tpcsectors, bool mctruth, bool publish = true, bool writeDigitsFile = false)
{
//data definitions
using DigitsOutputType = std::vector<o2::tpc::Digit>;
Expand All @@ -270,11 +336,17 @@ DataProcessorSpec getSpec(std::vector<int> const& laneConfiguration, std::vector
if (mctruth) {
outputs.emplace_back(/*binding,*/ "TPC", "DIGITSMCTR", static_cast<SubSpecificationType>(s), Lifetime::Timeframe);
}
if (writeDigitsFile) {
outputs.emplace_back(/*binding,*/ "TPC", "COMMONMODE", static_cast<SubSpecificationType>(s), Lifetime::Timeframe);
outputs.emplace_back(/*binding,*/ "TPC", "DIGTRIGGERS", static_cast<SubSpecificationType>(s), Lifetime::Timeframe);
}
}
}
specs.emplace_back(DataProcessorSpec{"TPCDigitMerger", {}, outputs, AlgorithmSpec{o2::framework::adaptFromTask<Task>(laneConfiguration, tpcsectors, mctruth, writeDigitsFile)}, Options{}});

return DataProcessorSpec{
"TPCDigitMerger", {}, outputs, AlgorithmSpec{o2::framework::adaptFromTask<Task>(laneConfiguration, tpcsectors, mctruth)}, Options{}};
if (writeDigitsFile) {
specs.push_back(getTPCDigitRootWriterSpec(tpcsectors, mctruth));
}
}

} // end namespace tpc
Expand All @@ -287,11 +359,12 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext)

auto numlanes = configcontext.options().get<int>("tpc-lanes");
bool mctruth = !configcontext.options().get<bool>("disable-mc");
bool writeDigitsFile = configcontext.options().get<int>("write-digits-file");
auto tpcsectors = o2::RangeTokenizer::tokenize<int>(configcontext.options().get<std::string>("tpc-sectors"));

std::vector<int> lanes(numlanes);
std::iota(lanes.begin(), lanes.end(), 0);
specs.emplace_back(o2::tpc::getSpec(lanes, tpcsectors, mctruth));
o2::tpc::getSpec(specs, lanes, tpcsectors, mctruth, true, writeDigitsFile);

// configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit
o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
/// @since 2018-04-19
/// @brief Processor spec for a ROOT file writer for TPC digits

#include "TPCDigitRootWriterSpec.h"
#include "TPCWorkflow/TPCDigitRootWriterSpec.h"
#include "DataFormatsTPC/TPCSectorHeader.h"
#include "CommonDataFormat/RangeReference.h"
#include "Framework/InputRecord.h"
Expand Down
2 changes: 1 addition & 1 deletion Steer/DigitizerWorkflow/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -59,6 +58,7 @@ o2_add_executable(digitizer-workflow
O2::TOFReconstruction
O2::TOFWorkflowIO
O2::TPCSimulation
O2::TPCWorkflow
O2::TRDSimulation
O2::TRDWorkflow
O2::TRDWorkflowIO
Expand Down
2 changes: 1 addition & 1 deletion Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

// for TPC
#include "TPCDigitizerSpec.h"
#include "TPCDigitRootWriterSpec.h"
#include "TPCWorkflow/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)
Expand Down
Loading