Skip to content

Commit 1320d76

Browse files
authored
Add optional per-sector seeding to the TPC digitizer (#16085)
Add optional per-sector seeding to the TPC digitizer This adds an option that makes the TPC digits independent of the lane assignment, as a preparation for MT digitization. - Two shared static workspaces of the digitizer are now members, and the SAMPAProcessing used for the output is passed down from DigitContainer. - With --tpc-sector-seeding, each Digitizer owns its ElectronTransport, GEMAmplification and SAMPAProcessing, fills their random rings once from DigiParams.seed, and moves the rings to positions derived from the seed, the sector and the timeframe. - RandomRing can be filled from a given generator, moved to a random position, and wraps vector reads at its end. - DigitContainer uses one call for all digitization modes. - Without the option, the output is unchanged. https://its.cern.ch/jira/browse/O2-7309
1 parent dbc9f17 commit 1320d76

14 files changed

Lines changed: 210 additions & 62 deletions

File tree

‎Common/MathUtils/include/MathUtils/RandomRing.h‎

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,19 +54,22 @@ class RandomRing
5454

5555
/// constructor
5656
/// @param [in] randomType type of the random generator
57-
RandomRing(const RandomType randomType = RandomType::Gaus);
57+
/// @param [in] rng random generator to draw from, gRandom if null
58+
RandomRing(const RandomType randomType = RandomType::Gaus, TRandom* rng = nullptr);
5859

5960
/// constructor accepting TF1
6061
/// @param [in] function TF1 function
6162
RandomRing(TF1& function);
6263

6364
/// initialisation of the random ring
6465
/// @param [in] randomType type of the random generator
65-
void initialize(const RandomType randomType = RandomType::Gaus);
66+
/// @param [in] rng random generator to draw from, gRandom if null
67+
void initialize(const RandomType randomType = RandomType::Gaus, TRandom* rng = nullptr);
6668

6769
/// initialisation of the random ring
68-
/// @param [in] randomType type of the random generator
69-
void initialize(TF1& function);
70+
/// @param [in] function TF1 function
71+
/// @param [in] rng random generator to draw from, gRandom if null
72+
void initialize(TF1& function, TRandom* rng = nullptr);
7073

7174
/// initialisation of the random ring
7275
/// @param [in] randomType type of the random generator
@@ -98,6 +101,10 @@ class RandomRing
98101
// within this header file (to reduce memory problems during compilation).
99102
// The hope is that the calling user calls this with a
100103
// correct Vc type (Vc::float_v) in a source file.
104+
// a vector must not run past the end of the ring, also after setRandomPosition()
105+
if (mRingPosition + VcType::size() > mRandomNumbers.size()) {
106+
mRingPosition = 0;
107+
}
101108
const VcType value = VcType(&mRandomNumbers[mRingPosition]);
102109
mRingPosition += VcType::size();
103110
if (mRingPosition >= mRandomNumbers.size()) {
@@ -110,6 +117,10 @@ class RandomRing
110117
/// @return position in the ring buffer
111118
unsigned int getRingPosition() const { return mRingPosition; }
112119

120+
/// move to a random position in the ring buffer
121+
/// @param [in] rng random generator to draw the position from
122+
void setRandomPosition(TRandom& rng) { mRingPosition = rng.Integer(N); }
123+
113124
private:
114125
// =========================================================================
115126
// ===| members |===========================================================
@@ -123,12 +134,12 @@ class RandomRing
123134

124135
//______________________________________________________________________________
125136
template <size_t N>
126-
inline RandomRing<N>::RandomRing(const RandomType randomType)
137+
inline RandomRing<N>::RandomRing(const RandomType randomType, TRandom* rng)
127138
: mRandomType(randomType),
128139
mRandomNumbers()
129140

130141
{
131-
initialize(randomType);
142+
initialize(randomType, rng);
132143
}
133144

134145
//______________________________________________________________________________
@@ -142,18 +153,18 @@ inline RandomRing<N>::RandomRing(TF1& function)
142153

143154
//______________________________________________________________________________
144155
template <size_t N>
145-
inline void RandomRing<N>::initialize(const RandomType randomType)
156+
inline void RandomRing<N>::initialize(const RandomType randomType, TRandom* rng)
146157
{
147-
158+
TRandom* random = rng ? rng : gRandom;
148159
for (auto& v : mRandomNumbers) {
149160
// TODO: configurable mean and sigma
150161
switch (randomType) {
151162
case RandomType::Gaus: {
152-
v = gRandom->Gaus(0, 1);
163+
v = random->Gaus(0, 1);
153164
break;
154165
}
155166
case RandomType::Flat: {
156-
v = gRandom->Rndm();
167+
v = random->Rndm();
157168
break;
158169
}
159170
default: {
@@ -166,11 +177,11 @@ inline void RandomRing<N>::initialize(const RandomType randomType)
166177

167178
//______________________________________________________________________________
168179
template <size_t N>
169-
inline void RandomRing<N>::initialize(TF1& function)
180+
inline void RandomRing<N>::initialize(TF1& function, TRandom* rng)
170181
{
171182
mRandomType = RandomType::CustomTF1;
172183
for (auto& v : mRandomNumbers) {
173-
v = function.GetRandom();
184+
v = function.GetRandom(rng);
174185
}
175186
}
176187

‎Detectors/TPC/simulation/include/TPCSimulation/DigitContainer.h‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "TPCBase/CRU.h"
2222
#include "DataFormatsTPC/Defs.h"
2323
#include "TPCSimulation/DigitTime.h"
24+
#include "TPCSimulation/SAMPAProcessing.h"
2425
#include "TPCBase/CalDet.h"
2526
#include "CommonUtils/DebugStreamer.h"
2627
#include "TPCBase/ParameterDetector.h"
@@ -87,6 +88,9 @@ class DigitContainer
8788
/// Get the size of the container for one event
8889
size_t size() const { return mTimeBins.size(); }
8990

91+
/// Use this SAMPAProcessing instead of the singleton when filling the output
92+
void setSAMPAProcessing(SAMPAProcessing* sampaProcessing) { mSAMPAProcessing = sampaProcessing; }
93+
9094
/// Fetch the calibration objects used by fillOutputContainer from the CDBInterface
9195
/// Must be called after the CDBInterface is configured; fillOutputContainer calls it lazily otherwise
9296
void updateCalibrations();
@@ -103,6 +107,8 @@ class DigitContainer
103107
const CalDet<bool>* mDeadMap = nullptr; //!< Dead channel map
104108
bool mCMCEnabled = false; //!< Common mode correction enabled in the FEE config (DigiMode Auto)
105109
bool mCalibrationsUpdated = false; //!< Whether updateCalibrations was called
110+
SAMPAProcessing* mSAMPAProcessing = nullptr; //!< SAMPAProcessing used for the output, the singleton if not set
111+
std::vector<std::pair<MCCompLabel, int>> mLabelCollector; //!< Workspace to sort the MC labels of a digit
106112

107113
void reportSettings();
108114
};

‎Detectors/TPC/simulation/include/TPCSimulation/DigitGlobalPad.h‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ class DigitGlobalPad
9797
const CRU& cru, TimeBin timeBin,
9898
GlobalPadNumber globalPad,
9999
o2::dataformats::LabelContainer<std::pair<MCCompLabel, int>, false>& labelContainer,
100+
SAMPAProcessing& sampaProcessing, std::vector<std::pair<MCCompLabel, int>>& labelCollector,
100101
float commonMode = 0.f, const PrevDigitInfo& prevDigit = PrevDigitInfo(), Streamer* debugStream = nullptr, const CalDet<bool>* deadMap = nullptr);
101102

102103
private:
@@ -210,12 +211,11 @@ inline void DigitGlobalPad::fillOutputContainer(std::vector<Digit>& output,
210211
const CRU& cru, TimeBin timeBin,
211212
GlobalPadNumber globalPad,
212213
o2::dataformats::LabelContainer<std::pair<MCCompLabel, int>, false>& labels,
214+
SAMPAProcessing& sampaProcessing, std::vector<std::pair<MCCompLabel, int>>& labelCollector,
213215
float commonMode, const PrevDigitInfo& prevDigit, Streamer* debugStream, const CalDet<bool>* deadMap)
214216
{
215217
const Mapper& mapper = Mapper::instance();
216-
SAMPAProcessing& sampaProcessing = SAMPAProcessing::instance();
217218
const PadPos pad = mapper.padPos(globalPad);
218-
static std::vector<std::pair<MCCompLabel, int>> labelCollector; // static workspace container for sorting
219219

220220
/// The charge accumulated on that pad is converted into ADC counts, saturation of the SAMPA is applied and a Digit
221221
/// is created in written out

‎Detectors/TPC/simulation/include/TPCSimulation/DigitTime.h‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ class DigitTime
7878
template <DigitzationMode MODE>
7979
void fillOutputContainer(std::vector<Digit>& output, dataformats::MCTruthContainer<MCCompLabel>& mcTruth,
8080
std::vector<CommonMode>& commonModeOutput, const Sector& sector, TimeBin timeBin,
81+
SAMPAProcessing& sampaProcessing, std::vector<std::pair<MCCompLabel, int>>& labelCollector,
8182
PrevDigitInfoArray* prevTime = nullptr, Streamer* debugStream = nullptr,
8283
const CalPad* padParams[3] = nullptr, const CalDet<bool>* deadMap = nullptr);
8384

@@ -129,6 +130,7 @@ inline float DigitTime::getCommonMode(const GEMstack& gemstack) const
129130
template <DigitzationMode MODE>
130131
inline void DigitTime::fillOutputContainer(std::vector<Digit>& output, dataformats::MCTruthContainer<MCCompLabel>& mcTruth,
131132
std::vector<CommonMode>& commonModeOutput, const Sector& sector, TimeBin timeBin,
133+
SAMPAProcessing& sampaProcessing, std::vector<std::pair<MCCompLabel, int>>& labelCollector,
132134
PrevDigitInfoArray* prevTime, Streamer* debugStream, const CalPad* padParams[3],
133135
const CalDet<bool>* deadMap)
134136
{
@@ -167,7 +169,7 @@ inline void DigitTime::fillOutputContainer(std::vector<Digit>& output, dataforma
167169
prevDigit = (*prevTime)[iPad];
168170
}
169171
const CRU cru = mapper.getCRU(sector, iPad);
170-
digit.fillOutputContainer<MODE>(output, mcTruth, cru, timeBin, iPad, mLabels, getCommonMode(cru), prevDigit, debugStream, deadMap);
172+
digit.fillOutputContainer<MODE>(output, mcTruth, cru, timeBin, iPad, mLabels, sampaProcessing, labelCollector, getCommonMode(cru), prevDigit, debugStream, deadMap);
171173
}
172174
}
173175
}

‎Detectors/TPC/simulation/include/TPCSimulation/Digitizer.h‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ namespace tpc
3131
{
3232

3333
class DigitContainer;
34+
class ElectronTransport;
35+
class GEMAmplification;
3436

3537
template <class T>
3638
class SpaceCharge;
@@ -141,8 +143,28 @@ class Digitizer
141143
/// in case of scaled distortions, the distortions can be recalculated to ensure consistent distortions and corrections
142144
void recalculateDistortions();
143145

146+
/// Use digitizer-owned random rings filled from seed and positioned per sector and timeframe in init(),
147+
/// so that the digits of a sector do not depend on which sectors were processed before
148+
/// \param seed base seed, typically DigiParams.seed
149+
void setUseSectorSeeding(ULong64_t seed);
150+
151+
/// Set the timeframe identifier that enters the sector seeding
152+
void setSeedingTimeframe(ULong64_t timeframe) { mSeedingTimeframe = timeframe; }
153+
144154
private:
155+
ElectronTransport& electronTransport();
156+
GEMAmplification& gemAmplification();
157+
SAMPAProcessing& sampaProcessing();
158+
159+
std::unique_ptr<ElectronTransport> mElectronTransport; //!< Digitizer-owned instance with sector seeding, else the singleton is used
160+
std::unique_ptr<GEMAmplification> mGEMAmplification; //!< Digitizer-owned instance with sector seeding, else the singleton is used
161+
std::unique_ptr<SAMPAProcessing> mSAMPAProcessing; //!< Digitizer-owned instance with sector seeding, else the singleton is used
162+
ULong64_t mSeed = 0; //!< Base seed for sector seeding
163+
ULong64_t mSeedingTimeframe = 0; //!< Timeframe identifier for sector seeding
164+
bool mUseSectorSeeding = false; //!< Whether sector seeding is used
165+
145166
DigitContainer mDigitContainer; ///< Container for the Digits
167+
std::vector<float> mSignalArray; //!< Workspace for the shaped signal of one electron
146168
std::unique_ptr<SC> mSpaceChargeOwned; //!< Distortions created by the digitizer itself
147169
SC* mSpaceCharge = nullptr; //!< Handler of full distortions (static + IR dependant), owned by mSpaceChargeOwned or by the caller
148170
SC* mSpaceChargeDer = nullptr; //!< Handler of reference static distortions, owned by the caller

‎Detectors/TPC/simulation/include/TPCSimulation/ElectronTransport.h‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,16 @@ class ElectronTransport
4141
return electronTransport;
4242
}
4343

44+
/// Constructor
45+
/// \param rng random generator to fill the random rings from, gRandom if null
46+
explicit ElectronTransport(TRandom* rng = nullptr);
47+
4448
/// Destructor
4549
~ElectronTransport() = default;
4650

51+
/// Move the random rings to new positions drawn from rng
52+
void setRandomRingPositions(TRandom& rng);
53+
4754
/// Update the OCDB parameters cached in the class. To be called once per event
4855
void updateParameters(float vdrift = 0);
4956

@@ -72,8 +79,6 @@ class ElectronTransport
7279
float getDriftTime(float zPos, float signChange = 1.f) const;
7380

7481
private:
75-
ElectronTransport();
76-
7782
/// Circular random buffer containing random values of the Gauss distribution to take into account diffusion of the
7883
/// electrons
7984
math_utils::RandomRing<> mRandomGaus;

‎Detectors/TPC/simulation/include/TPCSimulation/GEMAmplification.h‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,16 @@ class GEMAmplification
4343
return gemAmplification;
4444
}
4545

46+
/// Constructor
47+
/// \param rng random generator to fill the random rings from, gRandom if null
48+
explicit GEMAmplification(TRandom* rng = nullptr);
49+
4650
/// Destructor
4751
~GEMAmplification() = default;
4852

53+
/// Move the random rings to new positions drawn from rng
54+
void setRandomRingPositions(TRandom& rng);
55+
4956
/// Update the OCDB parameters cached in the class. To be called once per event
5057
void updateParameters();
5158

@@ -90,8 +97,6 @@ class GEMAmplification
9097
int getGEMMultiplication(int nElectrons, int GEM);
9198

9299
private:
93-
GEMAmplification();
94-
95100
/// Circular random buffer containing random Gaus values for gain fluctuation if the number of electrons is larger
96101
/// (central limit theorem)
97102
math_utils::RandomRing<> mRandomGaus;

‎Detectors/TPC/simulation/include/TPCSimulation/SAMPAProcessing.h‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,16 @@ class SAMPAProcessing
4545
static SAMPAProcessing sampaProcessing;
4646
return sampaProcessing;
4747
}
48+
/// Constructor
49+
/// \param rng random generator to fill the random ring from, gRandom if null
50+
explicit SAMPAProcessing(TRandom* rng = nullptr);
51+
4852
/// Destructor
4953
~SAMPAProcessing() = default;
5054

55+
/// Move the random ring to a new position drawn from rng
56+
void setRandomRingPositions(TRandom& rng) { mRandomNoiseRing.setRandomPosition(rng); }
57+
5158
/// Update the OCDB parameters cached in the class. To be called once per event
5259
void updateParameters(float vdrift = 0);
5360

@@ -134,7 +141,6 @@ class SAMPAProcessing
134141
float getPedestalCRU(const int sector, const int globalPadInSector) const;
135142

136143
private:
137-
SAMPAProcessing();
138144
const ParameterGas* mGasParam; ///< Caching of the parameter class to avoid multiple CDB calls
139145
const ParameterDetector* mDetParam; ///< Caching of the parameter class to avoid multiple CDB calls
140146
const ParameterElectronics* mEleParam; ///< Caching of the parameter class to avoid multiple CDB calls

‎Detectors/TPC/simulation/src/DigitContainer.cxx‎

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include "TPCSimulation/DigitContainer.h"
1717
#include <memory>
18+
#include <type_traits>
1819
#include <fairlogger/Logger.h>
1920
#include "TPCBase/Mapper.h"
2021
#include "TPCBaseRecSim/CDBInterface.h"
@@ -48,6 +49,9 @@ void DigitContainer::fillOutputContainer(std::vector<Digit>& output,
4849
updateCalibrations();
4950
}
5051

52+
// after updateCalibrations, which may reload the FEE parameters that SAMPAProcessing picks up
53+
auto& sampaProcessing = mSAMPAProcessing ? *mSAMPAProcessing : SAMPAProcessing::instance();
54+
5155
const bool needsPrevDigArray = eleParam.doIonTail || eleParam.doIonTailPerPad || eleParam.doSaturationTail;
5256
const bool needsEmptyTimeBins = needsPrevDigArray || eleParam.doNoiseEmptyPads;
5357

@@ -89,39 +93,37 @@ void DigitContainer::fillOutputContainer(std::vector<Digit>& output,
8993
// fmt::print("Processing secotor: {}, time bin: {}, mFirstTimeBin: {}, dgitTime: {}\n", sector.getSector(), timeBin, mFirstTimeBin, (void*)time);
9094

9195
if (time) {
96+
// the digitization mode is a template parameter of fillOutputContainer
97+
auto fill = [&](auto mode) {
98+
time->fillOutputContainer<decltype(mode)::value>(output, mcTruth, commonModeOutput, sector, timeBin, sampaProcessing, mLabelCollector, mPrevDigArr.get(), debugStream, mPadParams, mDeadMap);
99+
};
100+
using M = DigitzationMode;
92101
switch (digitizationMode) {
93-
case DigitzationMode::FullMode: {
94-
time->fillOutputContainer<DigitzationMode::FullMode>(output, mcTruth, commonModeOutput, sector, timeBin, mPrevDigArr.get(), debugStream, mPadParams, mDeadMap);
102+
case M::FullMode:
103+
fill(std::integral_constant<M, M::FullMode>{});
95104
break;
96-
}
97-
case DigitzationMode::ZeroSuppression: {
98-
time->fillOutputContainer<DigitzationMode::ZeroSuppression>(output, mcTruth, commonModeOutput, sector, timeBin, mPrevDigArr.get(), debugStream, mPadParams, mDeadMap);
105+
case M::ZeroSuppression:
106+
fill(std::integral_constant<M, M::ZeroSuppression>{});
99107
break;
100-
}
101-
case DigitzationMode::ZeroSuppressionCMCorr: {
102-
time->fillOutputContainer<DigitzationMode::ZeroSuppressionCMCorr>(output, mcTruth, commonModeOutput, sector, timeBin, mPrevDigArr.get(), debugStream, mPadParams, mDeadMap);
108+
case M::ZeroSuppressionCMCorr:
109+
fill(std::integral_constant<M, M::ZeroSuppressionCMCorr>{});
103110
break;
104-
}
105-
case DigitzationMode::SubtractPedestal: {
106-
time->fillOutputContainer<DigitzationMode::SubtractPedestal>(output, mcTruth, commonModeOutput, sector, timeBin, mPrevDigArr.get(), debugStream, mPadParams, mDeadMap);
111+
case M::SubtractPedestal:
112+
fill(std::integral_constant<M, M::SubtractPedestal>{});
107113
break;
108-
}
109-
case DigitzationMode::NoSaturation: {
110-
time->fillOutputContainer<DigitzationMode::NoSaturation>(output, mcTruth, commonModeOutput, sector, timeBin, mPrevDigArr.get(), debugStream, mPadParams, mDeadMap);
114+
case M::NoSaturation:
115+
fill(std::integral_constant<M, M::NoSaturation>{});
111116
break;
112-
}
113-
case DigitzationMode::PropagateADC: {
114-
time->fillOutputContainer<DigitzationMode::PropagateADC>(output, mcTruth, commonModeOutput, sector, timeBin, mPrevDigArr.get(), debugStream, mPadParams, mDeadMap);
117+
case M::PropagateADC:
118+
fill(std::integral_constant<M, M::PropagateADC>{});
115119
break;
116-
}
117-
case DigitzationMode::Auto: {
120+
case M::Auto:
118121
if (mCMCEnabled) {
119-
time->fillOutputContainer<DigitzationMode::ZeroSuppressionCMCorr>(output, mcTruth, commonModeOutput, sector, timeBin, mPrevDigArr.get(), debugStream, mPadParams, mDeadMap);
122+
fill(std::integral_constant<M, M::ZeroSuppressionCMCorr>{});
120123
} else {
121-
time->fillOutputContainer<DigitzationMode::ZeroSuppression>(output, mcTruth, commonModeOutput, sector, timeBin, mPrevDigArr.get(), debugStream, mPadParams, mDeadMap);
124+
fill(std::integral_constant<M, M::ZeroSuppression>{});
122125
}
123126
break;
124-
}
125127
}
126128
}
127129

0 commit comments

Comments
 (0)