CbmRoot
Loading...
Searching...
No Matches
CbmStsSimModule.cxx
Go to the documentation of this file.
1/* Copyright (C) 2013-2020 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Volker Friese [committer], Florian Uhlig */
4
9
10#include "CbmStsSimModule.h"
11
12#include "CbmStsDigitize.h"
13#include "CbmStsElement.h"
14
15
16using namespace std;
17
19
20
21 // ----- Default constructor -------------------------------------------
23 : fElement(element)
24 , fDigitizer(digitizer)
25 , fParams(params)
26{
27}
28// -------------------------------------------------------------------------
29
30
31// --- Destructor --------------------------------------------------------
33{
34
35 // --- Clean analog buffer
36 for (auto chanIt = fAnalogBuffer.begin(); chanIt != fAnalogBuffer.end(); chanIt++) {
37 for (auto sigIt = (chanIt->second).begin(); sigIt != (chanIt->second).end(); sigIt++) {
38 delete (*sigIt);
39 }
40 }
41}
42// -------------------------------------------------------------------------
43
44
45// ----- Add a signal to the buffer ------------------------------------
46void CbmStsSimModule::AddSignal(UShort_t channel, Double_t time, Double_t charge, Int_t index, Int_t entry, Int_t file)
47{
48
49 // --- Check channel number
50 assert(channel < GetNofChannels());
51
52 // --- Discard charge if the channel is dead
53 if (!fParams->IsChannelActive(channel)) return;
54
55 // --- If the channel is not yet active: create a new set and insert
56 // --- new signal into it.
57 if (fAnalogBuffer.find(channel) == fAnalogBuffer.end()) {
58 CbmStsSignal* signal = new CbmStsSignal(time, charge, index, entry, file);
59 fAnalogBuffer[channel].insert(signal);
60 return;
61 } //? Channel not yet active
62
63 // --- The channel is active: there are already signals in.
64 // --- Loop over all signals in the channels and compare their time.
65 //TODO: Loop over all signals is not needed, since they are time-ordered.
66 Bool_t isMerged = kFALSE;
67 sigset::iterator it;
68 Double_t deadTime = fParams->GetParAsic(channel).GetDeadTime();
69 for (it = fAnalogBuffer[channel].begin(); it != fAnalogBuffer[channel].end(); it++) {
70
71 // Time between new and old signal smaller than dead time: merge signals
72 if (TMath::Abs((*it)->GetTime() - time) < deadTime) {
73
74 // Current implementation of merging signals:
75 // Add charges, keep first signal time
76 // TODO: Check with STS electronics people on more realistic behaviour.
77 (*it)->SetTime(TMath::Min((*it)->GetTime(), time));
78 (*it)->AddLink(charge, index, entry, file);
79 isMerged = kTRUE; // mark new signal as merged
80 break; // Merging should be necessary only for one buffer signal
81
82 } //? Time difference smaller than dead time
83
84 } // Loop over signals in buffer for this channel
85
86 // --- If signal was merged: no further action
87 if (isMerged) return;
88
89 // --- Arriving here, the signal did not interfere with existing ones.
90 // --- So, it is added to the analog buffer.
91 CbmStsSignal* signal = new CbmStsSignal(time, charge, index, entry, file);
92 fAnalogBuffer[channel].insert(signal);
93
94 // TODO: This method is not optimized w.r.t. runtime, since it assumes that the
95 // content of the analog buffers is small. Is it is substantial, the current
96 // implementation can have serious runtime implications. Possible optimizations
97 // could limit the loop over existing signals and insert with a placement hint.
98 // See https://redmine.cbm.gsi.de/issues/3782.
99}
100// -------------------------------------------------------------------------
101
102
103// ----- Status of analogue buffer -------------------------------------
104void CbmStsSimModule::BufferStatus(Int_t& nofSignals, Double_t& timeFirst, Double_t& timeLast)
105{
106
107
108 Int_t nSignals = 0;
109 Double_t tFirst = -1.;
110 Double_t tLast = -1.;
111 Double_t tSignal = -1.;
112
113 // --- Loop over active channels
114 for (auto chanIt = fAnalogBuffer.begin(); chanIt != fAnalogBuffer.end(); chanIt++) {
115
116 // --- Loop over signals in channel
117 for (auto sigIt = (chanIt->second).begin(); sigIt != (chanIt->second).end(); sigIt++) {
118
119 tSignal = (*sigIt)->GetTime();
120 nSignals++;
121 tFirst = tFirst < 0. ? tSignal : TMath::Min(tFirst, tSignal);
122 tLast = TMath::Max(tLast, tSignal);
123
124 } // signals in channel
125
126 } // channels in module
127
128 nofSignals = nSignals;
129 timeFirst = tFirst;
130 timeLast = tLast;
131}
132// -------------------------------------------------------------------------
133
134
135// ----- Digitise an analogue charge signal ----------------------------
136void CbmStsSimModule::Digitize(UShort_t channel, CbmStsSignal* signal)
137{
138
139 // --- Check channel number
140 assert(channel < GetNofChannels());
141
142 auto& asic = fParams->GetParAsic(channel);
143
144 // --- No action if charge is below threshold
145 Double_t charge = signal->GetCharge();
146
147 // --- Digitise charge
148 Short_t adc = asic.ChargeToAdc(charge);
149 if (adc < 1) return; // Charge below threshold
150
151 // --- Digitise time
152 Double_t deltaT = 0.;
153 if (!(asic.GetTimeResol() < 0.)) deltaT = gRandom->Gaus(0., asic.GetTimeResol());
154 Long64_t dTime = Long64_t(round(signal->GetTime() + deltaT));
155
156 // --- Send the message to the digitiser task
157 UInt_t address = fElement->GetAddress();
158 if (fDigitizer) fDigitizer->CreateDigi(address, channel, dTime, adc, signal->GetMatch());
159
160 // --- If no digitiser task is present (debug mode): create a digi and
161 // --- add it to the digi buffer.
162 else
163 return;
164}
165// -------------------------------------------------------------------------
166
167
168// ----- Generate noise ------------------------------------------------
169Int_t CbmStsSimModule::GenerateNoise(Double_t t1, Double_t t2)
170{
171
172 if (!(t2 > t1)) return 0;
173 Int_t nNoiseAll = 0;
174 UInt_t nAsicChannels = fParams->GetNofAsicChannels();
175
176 for (UInt_t iAsic = 0; iAsic < fParams->GetNofAsics(); iAsic++) {
177 auto& asic = fParams->GetAsicParams().at(iAsic);
178
179 // --- Mean number of noise digis in [t1, t2]
180 Double_t nNoiseMean = asic.GetNoiseRate() * nAsicChannels * (t2 - t1);
181
182 // --- Sample number of noise digis
183 Int_t nNoise = gRandom->Poisson(nNoiseMean);
184
185 // --- Create noise digis
186 for (Int_t iNoise = 0; iNoise < nNoise; iNoise++) {
187
188 // --- Random channel number, time and charge
189 UInt_t channel = UInt_t(gRandom->Uniform(Double_t(nAsicChannels)));
190 Double_t time = gRandom->Uniform(t1, t2);
191 Double_t charge = asic.GetRandomNoiseCharge();
192 UInt_t moduleChannel = iAsic * nAsicChannels + channel;
193
194 // --- Insert a signal object (without link index, entry and file)
195 // --- into the analogue buffer.
196 AddSignal(moduleChannel, time, charge, -1, -1, -1);
197 } //# noise digis
198
199 nNoiseAll += nNoise;
200 }
201
202 return nNoiseAll;
203}
204// -------------------------------------------------------------------------
205
206
207// ----- Get the unique address from the sensor name (static) ----------
209{
210
211 Bool_t isValid = kTRUE;
212 if (name.Length() != 16) isValid = kFALSE;
213 if (isValid) {
214 if (!name.BeginsWith("STS")) isValid = kFALSE;
215 if (name[4] != 'U') isValid = kFALSE;
216 if (name[8] != 'L') isValid = kFALSE;
217 if (name[13] != 'M') isValid = kFALSE;
218 }
219 assert(isValid);
220
221 Int_t unit = 10 * (name[5] - '0') + name[6] - '0' - 1;
222 Int_t ladder = 10 * (name[9] - '0') + name[10] - '0' - 1;
223 Int_t hLadder = (name[11] == 'U' ? 0 : 1);
224 Int_t module = 10 * (name[14] - '0') + name[15] - '0' - 1;
225
226 return CbmStsAddress::GetAddress(unit, ladder, hLadder, module);
227}
228// -------------------------------------------------------------------------
229
230
231// ----- Initialise the analogue buffer ---------------------------------
233{
234
235 for (UShort_t channel = 0; channel < fParams->GetNofChannels(); channel++) {
236 multiset<CbmStsSignal*, CbmStsSignal::Before> mset;
237 fAnalogBuffer[channel] = mset;
238 } //# channels
239}
240// -------------------------------------------------------------------------
241
242
243// ----- Process the analogue buffer -----------------------------------
245{
246
247 // --- Counter
248 Int_t nDigis = 0;
249
250 // Create iterators needed for inner loop
251 sigset::iterator sigIt;
252 ;
253 sigset::iterator oldIt;
254 sigset::iterator endIt;
255
256 // --- Iterate over active channels
257 for (auto& chanIt : fAnalogBuffer) {
258
259 // Only do something if there are signals for the channel
260 if (!(chanIt.second).empty()) {
261 auto& asic = fParams->GetParAsic(chanIt.first);
262
263 // --- Time limit up to which signals are digitised and sent to DAQ.
264 // --- Up to that limit, it is guaranteed that future signals do not
265 // --- interfere with the buffered ones. The readoutTime is the time
266 // --- of the last processed StsPoint. All coming points will be later
267 // --- in time. So, the time limit is defined by this time minus
268 // --- 5 times the time resolution (maximal deviation of signal time
269 // --- from StsPoint time) minus the dead time, within which
270 // --- interference of signals can happen.
271 Double_t timeLimit = readoutTime - 5. * asic.GetTimeResol() - asic.GetDeadTime();
272
273 // --- Digitise all signals up to the specified time limit
274 sigIt = (chanIt.second).begin();
275 oldIt = sigIt;
276 endIt = (chanIt.second).end();
277 while (sigIt != endIt) {
278
279 // --- Exit loop if signal time is larger than time limit
280 // --- N.b.: Readout time < 0 means digitise everything
281 if (readoutTime >= 0. && (*sigIt)->GetTime() > timeLimit) break;
282
283 // --- Digitise signal
284 Digitize(chanIt.first, (*sigIt));
285 nDigis++;
286
287 // --- Increment iterator before it becomes invalid
288 oldIt = sigIt;
289 sigIt++;
290
291 // --- Delete digitised signal
292 delete (*oldIt);
293 (chanIt.second).erase(oldIt);
294 } // Iterate over signals in channel
295 } // if there are signals
296 } // Iterate over channels
297
298 return nDigis;
299}
300// -------------------------------------------------------------------------
301
302
303// ----- String output -------------------------------------------------
305{
306 stringstream ss;
307 auto& asic = fParams->GetParAsic(0);
308 ss << "Module " << fElement->GetName() << ": dynRange " << asic.GetDynRange() << "e, thresh. " << asic.GetThreshold()
309 << "e, nAdc " << asic.GetNofAdc() << ", time res. " << asic.GetTimeResol() << "ns, dead time "
310 << asic.GetDeadTime() << "ns, noise " << asic.GetNoise() << "e, zero noise rate " << asic.GetZeroNoiseRate()
311 << "/ns";
312 return ss.str();
313}
314// -------------------------------------------------------------------------
ClassImp(CbmStsSimModule) CbmStsSimModule
int Int_t
bool Bool_t
Task class for simulating the detector response of the STS.
Class representing an element of the STS setup.
Parameters for one STS module.
Data class for an analog signal in the STS.
const CbmMatch & GetMatch() const
Double_t GetCharge() const
Double_t GetTime() const
Class for the simulation of a readout unit in the CBM-STS.
Int_t ProcessAnalogBuffer(Double_t readoutTime)
CbmStsSimModule(CbmStsElement *setupModule=nullptr, const CbmStsParModule *modulePar=nullptr, CbmStsDigitize *digitizer=nullptr)
Standard constructor.
const CbmStsParModule * fParams
Digitizer.
void AddSignal(UShort_t channel, Double_t time, Double_t charge, Int_t index=0, Int_t entry=0, Int_t file=0)
static Int_t GetAddressFromName(TString name)
Get the address from the module name (static)
void Digitize(UShort_t channel, CbmStsSignal *signal)
UShort_t GetNofChannels() const
Number of electronic channels @value Number of ADC channels.
std::map< UShort_t, sigset > fAnalogBuffer
std::string ToString() const
CbmStsElement * fElement
virtual ~CbmStsSimModule()
Destructor.
Int_t GenerateNoise(Double_t t1, Double_t t2)
Generate noise.
void BufferStatus(Int_t &nofSignals, Double_t &timeFirst, Double_t &timeLast)
CbmStsDigitize * fDigitizer
Element in geometry setup.
int32_t GetAddress(uint32_t unit=0, uint32_t ladder=0, uint32_t halfladder=0, uint32_t module=0, uint32_t sensor=0, uint32_t side=0, uint32_t version=kCurrentVersion)
Construct address.
Hash for CbmL1LinkKey.