Skip to content

Commit 06c1b84

Browse files
authored
Enable ROOT file output in TPC chunked-digit merger (#14608)
We can now regenerate a TPC digit file using the TPC chunked-digit merger. This is useful when we have the TPC "drift-time" digits (as in O2DPG) and want to obtain the full timeframe of TPC digits in ROOT file tpcdigits.root. There is a new special mode for this and the command line to use is ``` ${O2_ROOT}/bin/o2-tpc-chunkeddigit-merger --writer-mode --tpc-lanes 8 ``` for the case in which we had 8 separate lanes of drift-time digits. This commit includes: * small modularity and library refactoring * do not fatal in the TPCDigitRootWriter if no triggers are sent * merging/treatment of the TPC common modes in the merger (so far not done) Co-author: @ChSonnabend.
1 parent 9b8fb23 commit 06c1b84

File tree

9 files changed

+117
-33
lines changed

9 files changed

+117
-33
lines changed

Detectors/TPC/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ add_subdirectory(base)
1313
add_subdirectory(reconstruction)
1414
add_subdirectory(calibration)
1515
add_subdirectory(simulation)
16+
add_subdirectory(simworkflow)
1617
add_subdirectory(monitor)
1718
add_subdirectory(workflow)
1819
add_subdirectory(qc)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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+
o2_add_library(TPCSimWorkflow
13+
SOURCES
14+
src/ChunkedDigitPublisher.cxx
15+
src/TPCDigitRootWriterSpec.cxx
16+
PUBLIC_LINK_LIBRARIES O2::TPCSimulation O2::Framework)
17+
18+
o2_add_executable(chunkeddigit-merger
19+
COMPONENT_NAME tpc
20+
TARGETVARNAME mergertargetName
21+
SOURCES src/ChunkedDigitPublisher.cxx
22+
PUBLIC_LINK_LIBRARIES O2::TPCSimWorkflow)
23+
24+
if(OpenMP_CXX_FOUND)
25+
# Must be private, depending libraries might be compiled by compiler not understanding -fopenmp
26+
target_compile_definitions(${mergertargetName} PRIVATE WITH_OPENMP)
27+
target_link_libraries(${mergertargetName} PRIVATE OpenMP::OpenMP_CXX)
28+
endif()

Steer/DigitizerWorkflow/src/TPCDigitRootWriterSpec.h renamed to Detectors/TPC/simworkflow/include/TPCSimWorkflow/TPCDigitRootWriterSpec.h

File renamed without changes.

Detectors/TPC/workflow/src/ChunkedDigitPublisher.cxx renamed to Detectors/TPC/simworkflow/src/ChunkedDigitPublisher.cxx

Lines changed: 78 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "Framework/DataAllocator.h"
2020
#include "Framework/ControlService.h"
2121
#include "DataFormatsTPC/Digit.h"
22+
#include "TPCSimWorkflow/TPCDigitRootWriterSpec.h"
2223
#include "CommonUtils/ConfigurableParam.h"
2324
#include "DetectorsRaw/HBFUtilsInitializer.h"
2425
#include "TPCSimulation/CommonMode.h"
@@ -46,6 +47,9 @@
4647
#include <omp.h>
4748
#endif
4849
#include <TStopwatch.h>
50+
#include "CommonDataFormat/RangeReference.h"
51+
52+
using DigiGroupRef = o2::dataformats::RangeReference<int, int>;
4953

5054
using SubSpecificationType = o2::framework::DataAllocator::SubSpecificationType;
5155

@@ -71,6 +75,9 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions)
7175
workflowOptions.push_back(
7276
ConfigParamSpec{"tpc-sectors", VariantType::String, sectorDefault.c_str(), {sectorshelp}});
7377

78+
// option to write merged data to file
79+
workflowOptions.push_back(ConfigParamSpec{"writer-mode", o2::framework::VariantType::Bool, false, {"enable ROOT file output"}});
80+
7481
// option to disable MC truth
7582
workflowOptions.push_back(ConfigParamSpec{"disable-mc", o2::framework::VariantType::Bool, false, {"disable mc-truth"}});
7683
workflowOptions.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}});
@@ -104,14 +111,30 @@ void copyHelper<MCTruthContainer>(MCTruthContainer const& origin, MCTruthContain
104111
target.mergeAtBack(origin);
105112
}
106113

114+
// a trait to map TPC data types to a DPL channel name
115+
template <typename T>
116+
struct OutputChannelName;
117+
template <>
118+
struct OutputChannelName<std::vector<o2::tpc::Digit>> {
119+
static constexpr char value[] = "DIGITS";
120+
};
121+
template <>
122+
struct OutputChannelName<std::vector<o2::tpc::CommonMode>> {
123+
static constexpr char value[] = "COMMONMODE";
124+
};
125+
template <>
126+
struct OutputChannelName<std::vector<DigiGroupRef>> {
127+
static constexpr char value[] = "DIGTRIGGERS";
128+
};
129+
107130
template <typename T>
108131
auto makePublishBuffer(framework::ProcessingContext& pc, int sector, uint64_t activeSectors)
109132
{
110-
LOG(info) << "PUBLISHING SECTOR " << sector;
133+
LOG(info) << "PUBLISHING SECTOR " << sector << " FOR CHANNEL " << OutputChannelName<T>::value;
111134

112135
o2::tpc::TPCSectorHeader header{sector};
113136
header.activeSectors = activeSectors;
114-
return &pc.outputs().make<T>(Output{"TPC", "DIGITS", static_cast<SubSpecificationType>(sector), header});
137+
return &pc.outputs().make<T>(Output{"TPC", OutputChannelName<T>::value, static_cast<SubSpecificationType>(sector), header});
115138
}
116139

117140
template <>
@@ -187,6 +210,30 @@ void mergeHelper(const char* brprefix, std::vector<int> const& tpcsectors, uint6
187210
}
188211
}
189212

213+
template <>
214+
void mergeHelper<std::vector<DigiGroupRef>>(const char* brprefix, std::vector<int> const& tpcsectors, uint64_t activeSectors,
215+
TFile& originfile, framework::ProcessingContext& pc)
216+
{
217+
// specialization for TPC Trigger
218+
auto keyslist = originfile.GetListOfKeys();
219+
for (int i = 0; i < keyslist->GetEntries(); ++i) {
220+
auto key = keyslist->At(i);
221+
int sector = atoi(key->GetName());
222+
if (std::find(tpcsectors.begin(), tpcsectors.end(), sector) == tpcsectors.end()) {
223+
// do nothing if sector not wanted
224+
continue;
225+
}
226+
227+
using AccumType = std::decay_t<decltype(makePublishBuffer<std::vector<DigiGroupRef>>(pc, sector, activeSectors))>;
228+
AccumType accum;
229+
#pragma omp critical
230+
accum = makePublishBuffer<std::vector<DigiGroupRef>>(pc, sector, activeSectors);
231+
// no actual data sent. Continuous mode.
232+
233+
publishBuffer(pc, sector, activeSectors, accum);
234+
}
235+
}
236+
190237
void publishMergedTimeframes(std::vector<int> const& lanes, std::vector<int> const& tpcsectors, bool domctruth, framework::ProcessingContext& pc)
191238
{
192239
uint64_t activeSectors = 0;
@@ -208,13 +255,21 @@ void publishMergedTimeframes(std::vector<int> const& lanes, std::vector<int> con
208255
auto originfile = new TFile(filename.c_str(), "OPEN");
209256
assert(originfile);
210257

211-
//data definitions
258+
// data definitions
212259
using DigitsType = std::vector<o2::tpc::Digit>;
213260
using LabelType = o2::dataformats::MCTruthContainer<o2::MCCompLabel>;
214261
mergeHelper<DigitsType>("TPCDigit_", tpcsectors, activeSectors, *originfile, pc);
215262
if (domctruth) {
216263
mergeHelper<LabelType>("TPCDigitMCTruth_", tpcsectors, activeSectors, *originfile, pc);
217264
}
265+
266+
// we also merge common modes and publish a (fake) trigger entry
267+
using CommonModeType = std::vector<o2::tpc::CommonMode>;
268+
mergeHelper<CommonModeType>("TPCCommonMode_", tpcsectors, activeSectors, *originfile, pc);
269+
270+
using TriggerType = std::vector<DigiGroupRef>;
271+
mergeHelper<TriggerType>("TPCCommonMode_", tpcsectors, activeSectors, *originfile, pc);
272+
218273
originfile->Close();
219274
delete originfile;
220275
}
@@ -257,7 +312,7 @@ class Task
257312
/// MC truth information is also aggregated and written out
258313
DataProcessorSpec getSpec(std::vector<int> const& laneConfiguration, std::vector<int> const& tpcsectors, bool mctruth, bool publish = true)
259314
{
260-
//data definitions
315+
// data definitions
261316
using DigitsOutputType = std::vector<o2::tpc::Digit>;
262317
using CommonModeOutputType = std::vector<o2::tpc::CommonMode>;
263318

@@ -266,10 +321,14 @@ DataProcessorSpec getSpec(std::vector<int> const& laneConfiguration, std::vector
266321
// effectively the input expects one sector per subspecification
267322
for (int s = 0; s < 36; ++s) {
268323
OutputLabel binding{std::to_string(s)};
269-
outputs.emplace_back(/*binding,*/ "TPC", "DIGITS", static_cast<SubSpecificationType>(s), Lifetime::Timeframe);
324+
outputs.emplace_back("TPC", "DIGITS", static_cast<SubSpecificationType>(s), Lifetime::Timeframe);
270325
if (mctruth) {
271-
outputs.emplace_back(/*binding,*/ "TPC", "DIGITSMCTR", static_cast<SubSpecificationType>(s), Lifetime::Timeframe);
326+
outputs.emplace_back("TPC", "DIGITSMCTR", static_cast<SubSpecificationType>(s), Lifetime::Timeframe);
272327
}
328+
// common mode
329+
outputs.emplace_back("TPC", "COMMONMODE", static_cast<SubSpecificationType>(s), Lifetime::Timeframe);
330+
// trigger records
331+
outputs.emplace_back("TPC", "DIGTRIGGERS", static_cast<SubSpecificationType>(s), Lifetime::Timeframe);
273332
}
274333
}
275334

@@ -287,12 +346,25 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext)
287346

288347
auto numlanes = configcontext.options().get<int>("tpc-lanes");
289348
bool mctruth = !configcontext.options().get<bool>("disable-mc");
349+
bool writeout = configcontext.options().get<bool>("writer-mode");
290350
auto tpcsectors = o2::RangeTokenizer::tokenize<int>(configcontext.options().get<std::string>("tpc-sectors"));
291351

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

356+
if (writeout) {
357+
// for now writeout to a ROOT file only works if all sectors
358+
// are included
359+
if (tpcsectors.size() != 36) {
360+
LOG(error) << "You currently need to include all TPC sectors in the ROOT writer-mode";
361+
} else {
362+
std::vector<int> writerlanes(tpcsectors.size());
363+
std::iota(writerlanes.begin(), writerlanes.end(), 0);
364+
specs.emplace_back(o2::tpc::getTPCDigitRootWriterSpec(writerlanes, mctruth));
365+
}
366+
}
367+
296368
// configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit
297369
o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs);
298370
return specs;

Steer/DigitizerWorkflow/src/TPCDigitRootWriterSpec.cxx renamed to Detectors/TPC/simworkflow/src/TPCDigitRootWriterSpec.cxx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
/// @since 2018-04-19
1515
/// @brief Processor spec for a ROOT file writer for TPC digits
1616

17-
#include "TPCDigitRootWriterSpec.h"
17+
#include "TPCSimWorkflow/TPCDigitRootWriterSpec.h"
1818
#include "DataFormatsTPC/TPCSectorHeader.h"
1919
#include "CommonDataFormat/RangeReference.h"
2020
#include "Framework/InputRecord.h"
@@ -77,7 +77,7 @@ DataProcessorSpec getTPCDigitRootWriterSpec(std::vector<int> const& laneConfigur
7777
}
7878
};
7979

80-
//branch definitions for RootTreeWriter spec
80+
// branch definitions for RootTreeWriter spec
8181
using DigitsOutputType = std::vector<o2::tpc::Digit>;
8282
using CommonModeOutputType = std::vector<o2::tpc::CommonMode>;
8383

@@ -156,8 +156,8 @@ DataProcessorSpec getTPCDigitRootWriterSpec(std::vector<int> const& laneConfigur
156156
LOG(info) << "DIGIT SIZE " << digiData.size();
157157
const auto& trigS = (*trigP2Sect.get())[sector];
158158
int entries = 0;
159-
if (!trigS.size()) {
160-
std::runtime_error("Digits for sector " + std::to_string(sector) + " are received w/o info on grouping in triggers");
159+
if (trigS.size() == 0) {
160+
LOG(warn) << "Digits for sector " + std::to_string(sector) + " are received w/o trigger info. Will assume continuous mode";
161161
} else { // check consistency of Ndigits with that of expected from the trigger
162162
int nExp = trigS.back().getFirstEntry() + trigS.back().getEntries() - trigS.front().getFirstEntry();
163163
if (nExp != digiData.size()) {
@@ -167,7 +167,7 @@ DataProcessorSpec getTPCDigitRootWriterSpec(std::vector<int> const& laneConfigur
167167
}
168168

169169
{
170-
if (trigS.size() == 1) { // just 1 entry (continous mode?), use digits directly
170+
if (trigS.size() <= 1) { // just 1 entry (continous mode?), use digits directly
171171
auto ptr = &digiData;
172172
branch.SetAddress(&ptr);
173173
branch.Fill();
@@ -214,8 +214,8 @@ DataProcessorSpec getTPCDigitRootWriterSpec(std::vector<int> const& laneConfigur
214214
LOG(info) << "MCTRUTH ELEMENTS " << labeldata.getIndexedSize()
215215
<< " WITH " << labeldata.getNElements() << " LABELS";
216216
const auto& trigS = (*trigP2Sect.get())[sector];
217-
if (!trigS.size()) {
218-
throw std::runtime_error("MCTruth for sector " + std::to_string(sector) + " are received w/o info on grouping in triggers");
217+
if (trigS.size() == 0) {
218+
LOG(warn) << "MCTruth for sector " + std::to_string(sector) + " received w/o trigger info. Will assume continuous mode";
219219
} else {
220220
int nExp = trigS.back().getFirstEntry() + trigS.back().getEntries() - trigS.front().getFirstEntry();
221221
if (nExp != labeldata.getIndexedSize()) {
@@ -225,7 +225,7 @@ DataProcessorSpec getTPCDigitRootWriterSpec(std::vector<int> const& laneConfigur
225225
}
226226
}
227227
{
228-
if (trigS.size() == 1) { // just 1 entry (continous mode?), use labels directly
228+
if (trigS.size() <= 1) { // just 0 or 1 entry (continous mode?), use labels directly
229229
outputcontainer.adopt(labelbuffer);
230230
br->Fill();
231231
br->ResetAddress();

Detectors/TPC/workflow/CMakeLists.txt

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -70,17 +70,6 @@ o2_add_library(TPCWorkflowStudies
7070
O2::GlobalTrackingWorkflow
7171
)
7272

73-
o2_add_executable(chunkeddigit-merger
74-
COMPONENT_NAME tpc
75-
TARGETVARNAME mergertargetName
76-
SOURCES src/ChunkedDigitPublisher.cxx
77-
PUBLIC_LINK_LIBRARIES O2::TPCWorkflow)
78-
79-
if(OpenMP_CXX_FOUND)
80-
# Must be private, depending libraries might be compiled by compiler not understanding -fopenmp
81-
target_compile_definitions(${mergertargetName} PRIVATE WITH_OPENMP)
82-
target_link_libraries(${mergertargetName} PRIVATE OpenMP::OpenMP_CXX)
83-
endif()
8473

8574

8675
o2_add_executable(reco-workflow

Detectors/TPC/workflow/readers/CMakeLists.txt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,3 @@ o2_add_library(TPCReaderWorkflow
2121
O2::DPLUtils
2222
O2::TPCBase
2323
)
24-
25-
if(OpenMP_CXX_FOUND)
26-
# Must be private, depending libraries might be compiled by compiler not understanding -fopenmp
27-
target_compile_definitions(${mergertargetName} PRIVATE WITH_OPENMP)
28-
target_link_libraries(${mergertargetName} PRIVATE OpenMP::OpenMP_CXX)
29-
endif()

Steer/DigitizerWorkflow/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ o2_add_executable(digitizer-workflow
2424
src/CPVDigitizerSpec.cxx
2525
src/SimReaderSpec.cxx
2626
src/SimpleDigitizerWorkflow.cxx
27-
src/TPCDigitRootWriterSpec.cxx
2827
src/TPCDigitizerSpec.cxx
2928
src/ZDCDigitizerSpec.cxx
3029
src/TOFDigitizerSpec.cxx
@@ -59,6 +58,7 @@ o2_add_executable(digitizer-workflow
5958
O2::TOFReconstruction
6059
O2::TOFWorkflowIO
6160
O2::TPCSimulation
61+
O2::TPCSimWorkflow
6262
O2::TRDSimulation
6363
O2::TRDWorkflow
6464
O2::TRDWorkflowIO

Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
// for TPC
3232
#include "TPCDigitizerSpec.h"
33-
#include "TPCDigitRootWriterSpec.h"
33+
#include "TPCSimWorkflow/TPCDigitRootWriterSpec.h"
3434
#include "TPCBase/Sector.h"
3535
#include "TPCBase/CDBInterface.h"
3636
// needed in order to init the **SHARED** polyadist file (to be done before the digitizers initialize)

0 commit comments

Comments
 (0)