Skip to content

Commit 34a7cd9

Browse files
sawenzelclaude
andcommitted
Move the TPC per-sector digitization loop into a shared function
This moves the per-sector loop of the TPC digitizer spec into a free function, as a preparation for MT digitization. - digitizeSector runs the collision loop and the flushes of one sector and returns the digit groups. - The output of each flush is handed to a callback, so the function makes no DPL calls. - The lane spec now calls it; the chunked writer and the DPL outputs stay in the spec. - The output is unchanged. https://its.cern.ch/jira/browse/O2-7309 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 096c6f3 commit 34a7cd9

4 files changed

Lines changed: 189 additions & 95 deletions

File tree

‎Steer/DigitizerWorkflow/CMakeLists.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ o2_add_executable(digitizer-workflow
2525
src/SimReaderSpec.cxx
2626
src/SimpleDigitizerWorkflow.cxx
2727
src/TPCDigitizerSpec.cxx
28+
src/TPCSectorDigitization.cxx
2829
src/ZDCDigitizerSpec.cxx
2930
src/TOFDigitizerSpec.cxx
3031
$<$<BOOL:${ENABLE_UPGRADES}>:src/ITS3DigitizerSpec.cxx>

‎Steer/DigitizerWorkflow/src/TPCDigitizerSpec.cxx‎

Lines changed: 13 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@
1515
#include <cassert>
1616
#include "Framework/RootSerializationSupport.h"
1717
#include "TPCDigitizerSpec.h"
18+
#include "TPCSectorDigitization.h"
1819
#include "Framework/ControlService.h"
1920
#include "Framework/ParallelContext.h"
2021
#include "Framework/ConfigParamRegistry.h"
2122
#include "Framework/DataProcessorSpec.h"
2223
#include "Framework/DataRefUtils.h"
2324
#include "Framework/Lifetime.h"
2425
#include "Framework/DeviceSpec.h"
25-
#include "DetectorsRaw/HBFUtils.h"
2626
#include "Headers/DataHeader.h"
2727
#include "TStopwatch.h"
2828
#include "Steer/HitProcessingManager.h" // for DigitizationContext
@@ -92,20 +92,6 @@ void writeToBranchHelper<o2::dataformats::MCTruthContainer<o2::MCCompLabel>>(TTr
9292
targetbr->DropBaskets("all");
9393
}
9494

95-
std::string getBranchNameLeft(int sector)
96-
{
97-
std::stringstream branchnamestreamleft;
98-
branchnamestreamleft << "TPCHitsShiftedSector" << int(o2::tpc::Sector::getLeft(o2::tpc::Sector(sector)));
99-
return branchnamestreamleft.str();
100-
}
101-
102-
std::string getBranchNameRight(int sector)
103-
{
104-
std::stringstream branchnamestreamright;
105-
branchnamestreamright << "TPCHitsShiftedSector" << sector;
106-
return branchnamestreamright.str();
107-
}
108-
10995
using namespace o2::base;
11096
class TPCDPLDigitizerTask : public BaseDPLDigitizer
11197
{
@@ -178,23 +164,23 @@ class TPCDPLDigitizerTask : public BaseDPLDigitizer
178164
{
179165
std::stringstream brname;
180166
brname << "TPCDigit_" << mSector;
181-
auto br = o2::base::getOrMakeBranch(*mInternalROOTFlushTTree, brname.str().c_str(), &mDigits);
167+
auto br = o2::base::getOrMakeBranch(*mInternalROOTFlushTTree, brname.str().c_str(), &mFlushBuffers.digits);
182168
br->Fill();
183169
br->ResetAddress();
184170
}
185171
if (mWithMCTruth) {
186172
// labels
187173
std::stringstream brname;
188174
brname << "TPCDigitMCTruth_" << mSector;
189-
auto br = o2::base::getOrMakeBranch(*mInternalROOTFlushTTree, brname.str().c_str(), &mLabels);
175+
auto br = o2::base::getOrMakeBranch(*mInternalROOTFlushTTree, brname.str().c_str(), &mFlushBuffers.labels);
190176
br->Fill();
191177
br->ResetAddress();
192178
}
193179
{
194180
// common
195181
std::stringstream brname;
196182
brname << "TPCCommonMode_" << mSector;
197-
auto br = o2::base::getOrMakeBranch(*mInternalROOTFlushTTree, brname.str().c_str(), &mCommonMode);
183+
auto br = o2::base::getOrMakeBranch(*mInternalROOTFlushTTree, brname.str().c_str(), &mFlushBuffers.commonMode);
198184
br->Fill();
199185
br->ResetAddress();
200186
}
@@ -286,7 +272,6 @@ class TPCDPLDigitizerTask : public BaseDPLDigitizer
286272
}
287273
// TODO: make generic reset method?
288274
mFlushCounter = 0;
289-
mDigitCounter = 0;
290275
}
291276
}
292277
}
@@ -391,88 +376,24 @@ class TPCDPLDigitizerTask : public BaseDPLDigitizer
391376
throw std::runtime_error("Digitizer can only work on single sectors");
392377
}
393378

394-
mDigitizer.setSector(sector);
395-
mDigitizer.setSeedingTimeframe(dh->tfCounter);
396-
mDigitizer.init();
397-
398-
auto& eventParts = context->getEventParts();
379+
TStopwatch timer;
380+
timer.Start();
399381

400-
auto flushDigitsAndLabels = [this, digitsAccum, &labelAccum, &commonModeAccum](bool finalFlush = false) {
382+
auto onFlush = [this, digitsAccum, &labelAccum, &commonModeAccum]() {
401383
mFlushCounter++;
402-
// flush previous buffer
403-
mDigits.clear();
404-
mLabels.clear();
405-
mCommonMode.clear();
406-
mDigitizer.flush(mDigits, mLabels, mCommonMode, finalFlush);
407-
LOG(info) << "TPC: Flushed " << mDigits.size() << " digits, " << mLabels.getNElements() << " labels and " << mCommonMode.size() << " common mode entries";
408-
409384
if (mInternalWriter) {
410385
// the natural place to write out this independent datachunk immediately ...
411386
writeToROOTFile();
412387
} else {
413388
// ... or to accumulate and later forward to next DPL proc
414-
std::copy(mDigits.begin(), mDigits.end(), std::back_inserter(*digitsAccum));
389+
std::copy(mFlushBuffers.digits.begin(), mFlushBuffers.digits.end(), std::back_inserter(*digitsAccum));
415390
if (mWithMCTruth) {
416-
labelAccum.mergeAtBack(mLabels);
391+
labelAccum.mergeAtBack(mFlushBuffers.labels);
417392
}
418-
std::copy(mCommonMode.begin(), mCommonMode.end(), std::back_inserter(commonModeAccum));
393+
std::copy(mFlushBuffers.commonMode.begin(), mFlushBuffers.commonMode.end(), std::back_inserter(commonModeAccum));
419394
}
420-
mDigitCounter += mDigits.size();
421395
};
422-
423-
if (isContinuous) {
424-
auto& hbfu = o2::raw::HBFUtils::Instance();
425-
double time = hbfu.getFirstIRofTF(o2::InteractionRecord(0, hbfu.orbitFirstSampled)).bc2ns() / 1000.;
426-
mDigitizer.setOutputDigitTimeOffset(time);
427-
if (!irecords.empty()) {
428-
mDigitizer.setStartTime(irecords[0].getTimeNS() / 1000.f);
429-
}
430-
}
431-
432-
TStopwatch timer;
433-
timer.Start();
434-
435-
// loop over all composite collisions given from context
436-
// (aka loop over all the interaction records)
437-
for (int collID = 0; collID < irecords.size(); ++collID) {
438-
const double eventTime = irecords[collID].getTimeNS() / 1000.f;
439-
LOG(info) << "TPC: Event time " << eventTime << " us";
440-
mDigitizer.setEventTime(eventTime);
441-
if (!isContinuous) {
442-
mDigitizer.setStartTime(eventTime);
443-
}
444-
size_t startSize = mDigitCounter; // digitsAccum->size();
445-
446-
// for each collision, loop over the constituents event and source IDs
447-
// (background signal merging is basically taking place here)
448-
for (auto& part : eventParts[collID]) {
449-
const int eventID = part.entryID;
450-
const int sourceID = part.sourceID;
451-
452-
// get the hits for this event and this source
453-
std::vector<o2::tpc::HitGroup> hitsLeft;
454-
std::vector<o2::tpc::HitGroup> hitsRight;
455-
context->retrieveHits(mSimChains, getBranchNameLeft(sector).c_str(), part.sourceID, part.entryID, &hitsLeft);
456-
context->retrieveHits(mSimChains, getBranchNameRight(sector).c_str(), part.sourceID, part.entryID, &hitsRight);
457-
LOG(debug) << "TPC: Found " << hitsLeft.size() << " hit groups left and " << hitsRight.size() << " hit groups right in collision " << collID << " eventID " << part.entryID;
458-
459-
mDigitizer.process(hitsLeft, eventID, sourceID);
460-
mDigitizer.process(hitsRight, eventID, sourceID);
461-
462-
flushDigitsAndLabels();
463-
464-
if (!isContinuous) {
465-
eventAccum.emplace_back(startSize, mDigits.size());
466-
}
467-
}
468-
}
469-
470-
// final flushing step; getting everything not yet written out
471-
if (isContinuous) {
472-
LOG(info) << "TPC: Final flush";
473-
flushDigitsAndLabels(true);
474-
eventAccum.emplace_back(0, mDigitCounter); // all digits are grouped to 1 super-event pseudo-triggered mode
475-
}
396+
eventAccum = digitizeSector(mDigitizer, *context, mSimChains, sector, dh->tfCounter, mFlushBuffers, onFlush);
476397

477398
if (!mInternalWriter) {
478399
// send out to next stage
@@ -490,13 +411,10 @@ class TPCDPLDigitizerTask : public BaseDPLDigitizer
490411
o2::tpc::Digitizer mDigitizer;
491412
o2::tpc::VDriftHelper mTPCVDriftHelper{};
492413
std::vector<TChain*> mSimChains;
493-
std::vector<o2::tpc::Digit> mDigits;
494-
o2::dataformats::MCTruthContainer<o2::MCCompLabel> mLabels;
495-
std::vector<o2::tpc::CommonMode> mCommonMode;
496-
std::vector<int> mListOfSectors; // a list of sectors treated by this task
414+
SectorFlushBuffers mFlushBuffers; // output of the latest flush
415+
std::vector<int> mListOfSectors; // a list of sectors treated by this task
497416
TFile* mInternalROOTFlushFile = nullptr;
498417
TTree* mInternalROOTFlushTTree = nullptr;
499-
size_t mDigitCounter = 0;
500418
size_t mFlushCounter = 0;
501419
int mLaneId = 0; // the id of the current process within the parallel pipeline
502420
int mSector = 0;
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
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+
#include "TPCSectorDigitization.h"
13+
#include <sstream>
14+
#include <string>
15+
#include <TChain.h>
16+
#include "DetectorsRaw/HBFUtils.h"
17+
#include "Framework/Logger.h"
18+
#include "SimulationDataFormat/DigitizationContext.h"
19+
#include "TPCBase/Sector.h"
20+
#include "TPCSimulation/Point.h"
21+
#include "TPCSimulation/Digitizer.h"
22+
23+
namespace o2::tpc
24+
{
25+
26+
namespace
27+
{
28+
std::string getBranchNameLeft(int sector)
29+
{
30+
std::stringstream branchnamestreamleft;
31+
branchnamestreamleft << "TPCHitsShiftedSector" << int(o2::tpc::Sector::getLeft(o2::tpc::Sector(sector)));
32+
return branchnamestreamleft.str();
33+
}
34+
35+
std::string getBranchNameRight(int sector)
36+
{
37+
std::stringstream branchnamestreamright;
38+
branchnamestreamright << "TPCHitsShiftedSector" << sector;
39+
return branchnamestreamright.str();
40+
}
41+
} // namespace
42+
43+
std::vector<dataformats::RangeReference<int, int>> digitizeSector(Digitizer& digitizer, const steer::DigitizationContext& context,
44+
const std::vector<TChain*>& simChains, int sector, ULong64_t timeframe,
45+
SectorFlushBuffers& buffers, const std::function<void()>& onFlush)
46+
{
47+
std::vector<dataformats::RangeReference<int, int>> events;
48+
const bool isContinuous = digitizer.isContinuousReadout();
49+
const auto& irecords = context.getEventRecords();
50+
const auto& eventParts = context.getEventParts();
51+
52+
digitizer.setSector(sector);
53+
digitizer.setSeedingTimeframe(timeframe);
54+
digitizer.init();
55+
56+
size_t digitCounter = 0;
57+
auto flush = [&](bool finalFlush = false) {
58+
buffers.digits.clear();
59+
buffers.labels.clear();
60+
buffers.commonMode.clear();
61+
digitizer.flush(buffers.digits, buffers.labels, buffers.commonMode, finalFlush);
62+
LOG(info) << "TPC: Flushed " << buffers.digits.size() << " digits, " << buffers.labels.getNElements() << " labels and " << buffers.commonMode.size() << " common mode entries";
63+
onFlush();
64+
digitCounter += buffers.digits.size();
65+
};
66+
67+
if (isContinuous) {
68+
auto& hbfu = o2::raw::HBFUtils::Instance();
69+
double time = hbfu.getFirstIRofTF(o2::InteractionRecord(0, hbfu.orbitFirstSampled)).bc2ns() / 1000.;
70+
digitizer.setOutputDigitTimeOffset(time);
71+
if (!irecords.empty()) {
72+
digitizer.setStartTime(irecords[0].getTimeNS() / 1000.f);
73+
}
74+
}
75+
76+
// loop over all composite collisions given from context
77+
// (aka loop over all the interaction records)
78+
for (int collID = 0; collID < irecords.size(); ++collID) {
79+
const double eventTime = irecords[collID].getTimeNS() / 1000.f;
80+
LOG(info) << "TPC: Event time " << eventTime << " us";
81+
digitizer.setEventTime(eventTime);
82+
if (!isContinuous) {
83+
digitizer.setStartTime(eventTime);
84+
}
85+
size_t startSize = digitCounter;
86+
87+
// for each collision, loop over the constituents event and source IDs
88+
// (background signal merging is basically taking place here)
89+
for (auto& part : eventParts[collID]) {
90+
const int eventID = part.entryID;
91+
const int sourceID = part.sourceID;
92+
93+
// get the hits for this event and this source
94+
std::vector<o2::tpc::HitGroup> hitsLeft;
95+
std::vector<o2::tpc::HitGroup> hitsRight;
96+
context.retrieveHits(simChains, getBranchNameLeft(sector).c_str(), part.sourceID, part.entryID, &hitsLeft);
97+
context.retrieveHits(simChains, getBranchNameRight(sector).c_str(), part.sourceID, part.entryID, &hitsRight);
98+
LOG(debug) << "TPC: Found " << hitsLeft.size() << " hit groups left and " << hitsRight.size() << " hit groups right in collision " << collID << " eventID " << part.entryID;
99+
100+
digitizer.process(hitsLeft, eventID, sourceID);
101+
digitizer.process(hitsRight, eventID, sourceID);
102+
103+
flush();
104+
105+
if (!isContinuous) {
106+
events.emplace_back(startSize, buffers.digits.size());
107+
}
108+
}
109+
}
110+
111+
// final flushing step; getting everything not yet written out
112+
if (isContinuous) {
113+
LOG(info) << "TPC: Final flush";
114+
flush(true);
115+
events.emplace_back(0, digitCounter); // all digits are grouped to 1 super-event pseudo-triggered mode
116+
}
117+
return events;
118+
}
119+
120+
} // namespace o2::tpc
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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+
#ifndef STEER_DIGITIZERWORKFLOW_TPCSECTORDIGITIZATION_H_
13+
#define STEER_DIGITIZERWORKFLOW_TPCSECTORDIGITIZATION_H_
14+
15+
#include <functional>
16+
#include <vector>
17+
#include <RtypesCore.h>
18+
#include "CommonDataFormat/RangeReference.h"
19+
#include "DataFormatsTPC/Digit.h"
20+
#include "SimulationDataFormat/MCCompLabel.h"
21+
#include "SimulationDataFormat/MCTruthContainer.h"
22+
#include "TPCSimulation/CommonMode.h"
23+
24+
class TChain;
25+
26+
namespace o2
27+
{
28+
namespace steer
29+
{
30+
class DigitizationContext;
31+
}
32+
namespace tpc
33+
{
34+
class Digitizer;
35+
36+
/// Output buffers of one flush of a sector
37+
struct SectorFlushBuffers {
38+
std::vector<Digit> digits;
39+
dataformats::MCTruthContainer<MCCompLabel> labels;
40+
std::vector<CommonMode> commonMode;
41+
};
42+
43+
/// Digitize all collisions of one sector of a timeframe.
44+
/// After each flush the new output is in buffers and onFlush is called on the calling thread.
45+
/// The function makes no DPL calls. Concurrent calls need one Digitizer with sector seeding and one set of chains
46+
/// per thread; Digitizer::init() is called here and is not thread-safe across Digitizer instances.
47+
/// \return the digit groups, one per collision part in triggered mode, one for the timeframe in continuous mode
48+
std::vector<dataformats::RangeReference<int, int>> digitizeSector(Digitizer& digitizer, const steer::DigitizationContext& context,
49+
const std::vector<TChain*>& simChains, int sector, ULong64_t timeframe,
50+
SectorFlushBuffers& buffers, const std::function<void()>& onFlush);
51+
52+
} // namespace tpc
53+
} // namespace o2
54+
55+
#endif

0 commit comments

Comments
 (0)