ATLAS Offline Software
Loading...
Searching...
No Matches
SCT_FrontEnd.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "SCT_FrontEnd.h"
6
12
13// Random number
14#include "CLHEP/Random/RandFlat.h"
15#include "CLHEP/Random/RandGaussZiggurat.h" // for RandGaussZiggurat
16#include "CLHEP/Random/RandPoisson.h"
17#include "CLHEP/Random/RandomEngine.h"
18
19// C++ Standard Library
20#include <algorithm>
21#include <cmath>
22#include <iostream>
23
24// #define SCT_DIG_DEBUG
25
26using namespace InDetDD;
27
28// constructor
29SCT_FrontEnd::SCT_FrontEnd(const std::string& type, const std::string& name, const IInterface* parent)
30 : base_class(type, name, parent) {
31}
32
33// ----------------------------------------------------------------------
34// Initialize
35// ----------------------------------------------------------------------
37 if (m_NoiseOn and (not m_analogueNoiseOn)) {
38 ATH_MSG_FATAL("AnalogueNoiseOn/m_analogueNoiseOn should be true if NoiseOn/m_NoiseOn is true.");
39 return StatusCode::FAILURE;
40 }
41
42 ATH_MSG_DEBUG("SCT_FrontEnd::initialize()");
43 // Get SCT helper
44 ATH_CHECK(detStore()->retrieve(m_sct_id, "SCT_ID"));
45 // Get SCT detector manager
46 ATH_CHECK(detStore()->retrieve(m_SCTdetMgr,m_detMgrName));
47 // Get the amplifier tool
48 ATH_CHECK(m_sct_amplifier.retrieve());
49 ATH_MSG_DEBUG("SCT Amplifier tool located ");
50
51 // Get the SCT_ReadCaliDataSvc
52 if (m_useCalibData) {
54 ATH_MSG_DEBUG("CalibChipData Service located ");
55 } else {
57 }
58
59 constexpr float fC = 6242.2;
61
62#ifdef SCT_DIG_DEBUG
63 ATH_MSG_INFO("\tNoise factors:");
64 ATH_MSG_INFO("\tBarrel = " << m_NoiseBarrel << " Outer Barrel = " << m_NoiseBarrel3 <<
65 " EC, inners = " << m_NoiseInners << " EC, middles = " << m_NoiseMiddles <<
66 " EC, short middles = " << m_NoiseShortMiddles << " EC, outers = " << m_NoiseOuters);
67 ATH_MSG_INFO("\tThreshold=" << m_Threshold << " fC, time of Threshold=" << m_timeOfThreshold);
68#endif
69
70 ATH_MSG_INFO("m_Threshold (Threshold) = " << m_Threshold);
71 ATH_MSG_INFO("m_timeOfThreshold (TimeOfThreshold) = " << m_timeOfThreshold);
72 ATH_MSG_INFO("m_data_compression_mode (DataCompressionMode) = " << m_data_compression_mode);
73 ATH_MSG_INFO("m_data_readout_mode (DataReadOutMode) = " << m_data_readout_mode);
74
75 // Check configuration. If it is invalid, abort this job.
79 ATH_MSG_FATAL("m_data_compression_mode = " << m_data_compression_mode
80 << " is invalid. Abort this job!!!");
81 return StatusCode::FAILURE;
82 }
84 ATH_MSG_FATAL("m_data_readout_mode = " << m_data_readout_mode
85 << " is invalid. Abort this job!!!");
86 return StatusCode::FAILURE;
87 }
90 ATH_MSG_FATAL("m_data_compression_mode = " << m_data_compression_mode
91 << (m_data_compression_mode==Level_X1X ? " (Level_X1X)" : " (AnyHit_1XX_X1X_XX1)")
92 << " requires timing information."
93 << " However, m_data_readout_mode = " << m_data_readout_mode
94 << " (Condensed) does not keep timing information. Abort this job!!!");
95 return StatusCode::FAILURE;
96 }
97
98 return StatusCode::SUCCESS;
99}
100
102#ifdef SCT_DIG_DEBUG
103 ATH_MSG_INFO("SCT_FrontEnd::finalize()");
104#endif
105 return StatusCode::SUCCESS;
106}
107
108// ----------------------------------------------------------------------
109// Init the class variable vectors
110// ----------------------------------------------------------------------
111StatusCode SCT_FrontEnd::initVectors(int strips, SCT_FrontEndData& data) const {
112 data.m_GainFactor.resize(strips);
113
115 data.m_Analogue[0].resize(strips);
116 data.m_Analogue[1].resize(strips);
117 } else { // Expanded
118 data.m_Analogue[0].resize(strips);
119 data.m_Analogue[1].resize(strips);
120 data.m_Analogue[2].resize(strips);
121 }
122
123 return StatusCode::SUCCESS;
124}
125
126// ----------------------------------------------------------------------
127// prepare gain and offset for the strips for a given module
128// ----------------------------------------------------------------------
129StatusCode SCT_FrontEnd::prepareGainAndOffset(const EventContext& /*ctx*/, SiChargedDiodeCollection& collection, const Identifier& moduleId, CLHEP::HepRandomEngine * rndmEngine, SCT_FrontEndData& data, int strip_max) const {
130 // now we need to generate gain and offset channel by channel: some algebra
131 // for generation of partially correlated random numbers
133 float A = 4.0f * W * W + 1.0f;
134 float x1 = (A - std::sqrt(A)) / (2.0f * A);
135 float sinfi = std::sqrt(x1);
136 float cosfi = std::sqrt(1.0 - x1);
137
138 sinfi = sinfi * m_OGcorr / std::abs(m_OGcorr);
139 float S = m_GainRMS * m_GainRMS + m_Ospread * m_Ospread;
140 float D = (m_GainRMS * m_GainRMS - m_Ospread * m_Ospread) / (cosfi * cosfi - sinfi * sinfi);
141 float S1 = std::sqrt((S + D) * 0.5f);
142 float S2 = std::sqrt((S - D) * 0.5f);
143 float Noise = 0;
144 int mode = 1;
145
146 // To set noise values for different module types, barrel, EC, inners, middles, short middles, and outers
147 if (m_analogueNoiseOn) {
148 if (m_sct_id->barrel_ec(moduleId) == 0) { // barrel_ec=0 corresponds to barrel
149 if (m_sct_id->layer_disk(moduleId) == 3) { // outer barrel layer 10 degrees warmer
150 Noise = m_NoiseBarrel3;
151 } else {
152 Noise = m_NoiseBarrel;
153 }
154 } else {
155 int moduleType = m_sct_id->eta_module(moduleId);
156 switch (moduleType) { // eta = 0, 1, or 2 corresponds to outers, middles and inners?! (at least in the offline world)
157 case 0: {
158 Noise = m_NoiseOuters;
159 break;
160 }
161 case 1: {
162 if (m_sct_id->layer_disk(moduleId) == 7) {
163 Noise = m_NoiseShortMiddles;
164 } else {
165 Noise = m_NoiseMiddles;
166 }
167 break;
168 }
169 case 2: {
170 Noise = m_NoiseInners;
171 break;
172 }
173 default: {
174 Noise = m_NoiseBarrel;
175 ATH_MSG_ERROR("moduleType(eta): " << moduleType << " unknown, using barrel");
176 }
177 }// end of switch structure
178 }
179 }
180
181 // Loop over collection and setup gain/offset/noise for the hit and neighbouring strips
182 SiChargedDiodeIterator i_chargedDiode = collection.begin();
183 SiChargedDiodeIterator i_chargedDiode_end = collection.end();
184
185 for (; i_chargedDiode != i_chargedDiode_end; ++i_chargedDiode) {
186 const SiChargedDiode& diode = (*i_chargedDiode).second;
187 // should be const as we aren't trying to change it here - but getReadoutCell() is not a const method...
188 unsigned int flagmask = diode.flag() & 0xFE;
189 // Get the flag for this diode ( if flagmask = 1 If diode is disconnected/disabled skip it)
190 if (!flagmask) { // If the diode is OK (not flagged)
191 const SiReadoutCellId& roCell = diode.getReadoutCell();
192 if (roCell.isValid()) {
193 int strip = roCell.strip();
194 int i = std::max(strip - 1, 0);
195 int i_end = std::min(strip + 2, strip_max);
196
197 // loop over strips
198 for (; i < i_end; i++) {
199 // Need to check if strip is already setup
200 if (data.m_Analogue[1][i] <= 0.0) {
201 float g = CLHEP::RandGaussZiggurat::shoot(rndmEngine, 0.0, S1);
202 float o = CLHEP::RandGaussZiggurat::shoot(rndmEngine, 0.0, S2);
203
204 data.m_GainFactor[i] = 1.0f + (cosfi * g + sinfi * o);
205 //offset per channel
206 float offset_val = (cosfi * o - sinfi * g);
207 //noise factor per channel (from calib data noise per chip)
208 float noise_val = Noise * mode;
209
210 // Fill the noise and offset values into the Analogue
212 data.m_Analogue[0][i] = offset_val + noise_val * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
213 data.m_Analogue[1][i] = offset_val + noise_val * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
214 } else { // Expanded
215 data.m_Analogue[0][i] = offset_val + noise_val * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
216 data.m_Analogue[1][i] = offset_val + noise_val * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
217 data.m_Analogue[2][i] = offset_val + noise_val * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
218 }
219 }
220 }
221 }
222 }
223 }
224
225 return StatusCode::SUCCESS;
226}
227
228// ----------------------------------------------------------------------
229// prepare gain and offset for the strips for a given module using
230// Cond Db data to get the chip calibration data
231// ----------------------------------------------------------------------
232StatusCode SCT_FrontEnd::prepareGainAndOffset(const EventContext& ctx, SiChargedDiodeCollection& collection, int side, const Identifier& moduleId, CLHEP::HepRandomEngine * rndmEngine, SCT_FrontEndData& data, int strip_max) const {
233 // Get chip data from calib DB
234 std::vector<float> gainByChipVect = m_ReadCalibChipDataTool->getNPtGainData(moduleId, side, "GainByChip", ctx);
235 std::vector<float> gainRMSByChipVect = m_ReadCalibChipDataTool->getNPtGainData(moduleId, side, "GainRMSByChip", ctx);
236 std::vector<float> offsetByChipVect = m_ReadCalibChipDataTool->getNPtGainData(moduleId, side, "OffsetByChip", ctx);
237 std::vector<float> offsetRMSByChipVect = m_ReadCalibChipDataTool->getNPtGainData(moduleId, side, "OffsetRMSByChip", ctx);
238 std::vector<float> noiseByChipVect(6, 0.0);
239
240 if (m_analogueNoiseOn) { // Check if noise should be on or off
241 noiseByChipVect = m_ReadCalibChipDataTool->getNPtGainData(moduleId, side, "NoiseByChip", ctx);
242 }
243
244 // Need to check if empty, most should have data, but a few old DEAD modules don't
245 if (gainByChipVect.empty() or noiseByChipVect.empty()) {
246 ATH_MSG_DEBUG("No calibration data in cond DB for module " << moduleId << " using JO values");
247 if (StatusCode::SUCCESS != prepareGainAndOffset(ctx, collection, moduleId, rndmEngine, data,strip_max)) {
248 return StatusCode::FAILURE;
249 } else {
250 return StatusCode::SUCCESS;
251 }
252 }
253
254 // Don't really need to set up values for each chip...
255 float gainMeanValue = meanValue(gainByChipVect);
256 if (gainMeanValue < 0.0) {
257 ATH_MSG_DEBUG("All chip gain values are 0 for module " << moduleId << " using JO values");
258 if (StatusCode::SUCCESS != prepareGainAndOffset(ctx, collection, moduleId, rndmEngine, data,strip_max)) {
259 return StatusCode::FAILURE;
260 } else {
261 return StatusCode::SUCCESS;
262 }
263 }
264
265 std::vector<float> gain(6, 0.0);
266 std::vector<float> offset(6, 0.0);
267 std::vector<float> S1(6, 0.0);
268 std::vector<float> S2(6, 0.0);
269 std::vector<float> sinfi(6, 0.0);
270 std::vector<float> cosfi(6, 0.0);
271 float gainRMS = 0.0;
272 float offsetRMS = 0.0;
273
274 for (int i = 0; i < 6; ++i) {
275 // Some very few chips have 0 values, dead/bypassed/etc, so check and use some fixed values instead
276 if (gainByChipVect[i] > 0.1) {
277 gain[i] = gainByChipVect[i] / gainMeanValue;
278 offset[i] = offsetByChipVect[i] / m_Threshold;
279 gainRMS = gainRMSByChipVect[i] / gainMeanValue;
280 offsetRMS = offsetRMSByChipVect[i] / m_Threshold;
281 } else {
282 gain[i] = 55.0f / gainMeanValue;
283 offset[i] = 42.0f / m_Threshold;
284 gainRMS = 1.3f / gainMeanValue;
285 offsetRMS = 2.0f / m_Threshold;
286 }
287
288 float W = m_OGcorr * gainRMS * offsetRMS / (gainRMS * gainRMS - offsetRMS * offsetRMS);
289 float A = 4.0f * W * W + 1.0f;
290 float x1 = (A - std::sqrt(A)) / (2.0f * A);
291 sinfi[i] = std::sqrt(x1);
292 cosfi[i] = std::sqrt(1.0f - x1);
293 sinfi[i] = sinfi[i] * m_OGcorr / std::abs(m_OGcorr);
294 float S = gainRMS * gainRMS + offsetRMS * offsetRMS;
295 float D = (gainRMS * gainRMS - offsetRMS * offsetRMS) / (cosfi[i] * cosfi[i] - sinfi[i] * sinfi[i]);
296 S1[i] = std::sqrt((S + D) / 2.0f);
297 S2[i] = std::sqrt((S - D) / 2.0f);
298 }
299
300 // Loop over collection and setup gain/offset/noise for the hit and neighbouring strips
301 SiChargedDiodeIterator i_chargedDiode = collection.begin();
302 SiChargedDiodeIterator i_chargedDiode_end = collection.end();
303
304 for (; i_chargedDiode != i_chargedDiode_end; ++i_chargedDiode) {
305 const SiChargedDiode& diode = (*i_chargedDiode).second;
306 // should be const as we aren't trying to change it here - but getReadoutCell() is not a const method...
307 unsigned int flagmask = diode.flag() & 0xFE;
308 // Get the flag for this diode ( if flagmask = 1 If diode is disconnected/disabled skip it)
309 if (!flagmask) { // If the diode is OK (not flagged)
310 const SiReadoutCellId& roCell = diode.getReadoutCell();
311
312 if (roCell.isValid()) {
313 int strip = roCell.strip();
314 int i = std::max(strip - 1, 0);
315 int i_end = std::min(strip + 2, strip_max);
316
317 // loop over strips
318 for (; i < i_end; i++) {
319 // Need to check if strip is already setup
320 if (data.m_Analogue[1][i] <= 0.0) {
321 // Values depends on which chip the strip is on (complex when strip is on chip edge)
322 int chip = i / 128;
323 float g = CLHEP::RandGaussZiggurat::shoot(rndmEngine, 0.0, S1[chip]);
324 float o = CLHEP::RandGaussZiggurat::shoot(rndmEngine, 0.0, S2[chip]);
325
326 data.m_GainFactor[i] = gain[chip] + (cosfi[chip] * g + sinfi[chip] * o);
327 //offset per channel
328 float offset_val = offset[chip] + (cosfi[chip] * o - sinfi[chip] * g);
329 //noise factor per channel (from calib data noise per chip)
330 float noise_val = noiseByChipVect[chip];
331
332 // Fill the noise and offset values into the Analogue
334 data.m_Analogue[0][i] = offset_val + noise_val * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
335 data.m_Analogue[1][i] = offset_val + noise_val * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
336 } else { // Expanded
337 data.m_Analogue[0][i] = offset_val + noise_val * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
338 data.m_Analogue[1][i] = offset_val + noise_val * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
339 data.m_Analogue[2][i] = offset_val + noise_val * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
340 }
341 }
342 }
343 }
344 }
345 }
346
347 return StatusCode::SUCCESS;
348}
349
350// ----------------------------------------------------------------------
351//
352// ----------------------------------------------------------------------
353StatusCode SCT_FrontEnd::randomNoise(const EventContext& /*ctx*/, SiChargedDiodeCollection& collection, const Identifier& moduleId, CLHEP::HepRandomEngine * rndmEngine, SCT_FrontEndData& data, int strip_max) const {
354 // Add random noise
355
356 double occupancy = 0.0;
357 double NoiseOccupancy = 0.0;
358 float Noise = 0.0;
359 int nNoisyStrips = 0;
360 double mode = 1.;
361
362 const bool noise_expanded_mode = (m_data_compression_mode == AnyHit_1XX_X1X_XX1 and m_data_readout_mode == Expanded);
363
364 // Will give 3 times as much noise occupancy if running in any hit expanded mode
365 if (noise_expanded_mode) {
366 mode = 3.;
367 }
368
369 // Sets fixed noise occupancy values for different module types, barrel, EC,
370 // inners, middles
371 // short middles, and outers
372 if (m_sct_id->barrel_ec(moduleId) == 0) { // barrel_ec=0 corresponds to barrel
373 if (m_sct_id->layer_disk(moduleId) == 3) { // outer barrel layer 10 degrees warmer
374 NoiseOccupancy = m_NOBarrel3;
375 Noise = m_NoiseBarrel3;
376 } else {
377 NoiseOccupancy = m_NOBarrel;
378 Noise = m_NoiseBarrel;
379 }
380 } else {
381 int moduleType = m_sct_id->eta_module(moduleId);
382 switch (moduleType) { // eta = 0, 1, or 2 corresponds to outers, middles and inners?! (at least in the offline world)
383 case 0: {
384 NoiseOccupancy = m_NOOuters;
385 Noise = m_NoiseOuters;
386 break;
387 }
388 case 1: {
389 if (m_sct_id->layer_disk(moduleId) == 7) {
390 NoiseOccupancy = m_NOShortMiddles;
391 Noise = m_NoiseShortMiddles;
392 } else {
393 NoiseOccupancy = m_NOMiddles;
394 Noise = m_NoiseMiddles;
395 }
396 break;
397 }
398 case 2: {
399 NoiseOccupancy = m_NOInners;
400 Noise = m_NoiseInners;
401 break;
402 }
403 default: {
404 NoiseOccupancy = m_NOBarrel;
405 Noise = m_NoiseBarrel;
406 ATH_MSG_WARNING("moduleType(eta): " << moduleType << " unknown, using barrel");
407 }
408 }// end of switch structure
409 }
410
411 // Calculate the number of "free strips"
412 int nEmptyStrips = 0;
413 std::vector<int> emptyStrips;
414 emptyStrips.reserve(strip_max);
415 for (int i = 0; i < strip_max; i++) {
416 if (data.m_StripHitsOnWafer[i] == 0) {
417 emptyStrips.push_back(i);
418 ++nEmptyStrips;
419 }
420 }
421
422 if (nEmptyStrips != 0) {
423 // Should randomize the fixed NO values, so we get some differences per
424 // wafer
425 occupancy = CLHEP::RandGaussZiggurat::shoot(rndmEngine, NoiseOccupancy, NoiseOccupancy * 0.1);
426
427 // Modify the occupancy if threshold is not 1.0 fC
428 if (m_Threshold > 6242.3 or m_Threshold < 6242.1) {
429 const float fC = 6242.2;
430 occupancy = occupancy * exp(-(0.5 / (Noise * Noise) * (m_Threshold * m_Threshold - fC * fC)));
431 }
432 nNoisyStrips = CLHEP::RandPoisson::shoot(rndmEngine, strip_max * occupancy * mode);
433
434 // Check and adapt the number of noisy strips to the number of free strips
435 if (nEmptyStrips < nNoisyStrips) {
436 nNoisyStrips = nEmptyStrips;
437 }
438
439 // Find random strips to get noise hits
440 for (int i = 0; i < nNoisyStrips; i++) {
441 int index = CLHEP::RandFlat::shootInt(rndmEngine, nEmptyStrips - i); // strip == 10, 12 free strips
442 // have vector [10000100100200211001] 20 strips
443 int strip = emptyStrips.at(index);
444 emptyStrips.erase(emptyStrips.begin()+index); // Erase it not to use it again
445 if (data.m_StripHitsOnWafer[strip]!=0) {
446 ATH_MSG_ERROR(index << "-th empty strip, strip " << strip << " should be empty but is not empty! Something is wrong!");
447 }
448 data.m_StripHitsOnWafer[strip] = 3; // !< Random Noise hit
449 // Add tbin info to noise diode
450 if (noise_expanded_mode) { // !< if any hit mode, any time bin otherwise fixed tbin=2
451 int noise_tbin = CLHEP::RandFlat::shootInt(rndmEngine, 3);
452 // !< random number 0, 1 or 2
453 if (noise_tbin == 0) {
454 noise_tbin = 4; // !< now 1,2 or 4
455 }
456 if (StatusCode::SUCCESS != addNoiseDiode(collection, strip, noise_tbin)) {
457 ATH_MSG_ERROR("Can't add noise hit diode to collection (1)");
458 }
459 } else {
460 if (StatusCode::SUCCESS != addNoiseDiode(collection, strip, 2)) {
461 ATH_MSG_ERROR("Can't add noise hit diode to collection (2)");
462 }
463 }
464 }
465 }
466
467 return StatusCode::SUCCESS;
468}
469
470// ----------------------------------------------------------------------
471//
472// ----------------------------------------------------------------------
473StatusCode SCT_FrontEnd::randomNoise(const EventContext& ctx, SiChargedDiodeCollection& collection, const Identifier& moduleId, int side, CLHEP::HepRandomEngine * rndmEngine, SCT_FrontEndData& data, int strip_max) const {
474 const int n_chips = 6;
475 const int chipStripmax = strip_max / n_chips;
476 std::vector<float> NOByChipVect(n_chips, 0.0);
477 std::vector<float> ENCByChipVect(n_chips, 0.0);
478 std::vector<int> nNoisyStrips(n_chips, 0);
479 double mode = 1.;
480
481 const bool noise_expanded_mode = (m_data_compression_mode == AnyHit_1XX_X1X_XX1 and m_data_readout_mode == Expanded);
482
483 // Will give 3 times as much noise occupancy if running in any hit expanded mode
484 if (noise_expanded_mode) {
485 mode = 3.;
486 }
487
488 // Get chip data from calib DB
489 NOByChipVect = m_ReadCalibChipDataTool->getNoiseOccupancyData(moduleId, side, "OccupancyByChip", ctx);
490 ENCByChipVect = m_ReadCalibChipDataTool->getNPtGainData(moduleId, side, "NoiseByChip", ctx);
491
492 // Need to check if empty, most should have data, but a few old DEAD modules don't, and 9C...
493 if (NOByChipVect.empty()) {
494 ATH_MSG_DEBUG("No calibration data in cond DB for module " << moduleId << " using JO values");
495 if (StatusCode::SUCCESS != randomNoise(ctx, collection, moduleId, rndmEngine, data,strip_max)) {
496 return StatusCode::FAILURE;
497 } else {
498 return StatusCode::SUCCESS;
499 }
500 } else {
501 for (int i = 0; i < n_chips; i++) {
502 // A 0 value can mean two things now, chip out of config for long time and no value was uploaded
503 // or its short middles and inners and the value is for all purposes 0! so ok.
504
505 // Modify the occupancy if threshold is not 1.0 fC
506 if (m_Threshold > 6242.3 or m_Threshold < 6242.1) {
507 constexpr float fC = 6242.2;
508 NOByChipVect[i] = NOByChipVect[i] * exp(-(0.5 / (ENCByChipVect[i]*ENCByChipVect[i]) * (m_Threshold*m_Threshold - fC*fC)));
509 }
510
511 nNoisyStrips[i] = CLHEP::RandPoisson::shoot(rndmEngine, chipStripmax * NOByChipVect[i] * mode);
512 }
513 }
514
515 // Loop over the chips on the wafer
516 for (int chip_index = 0; chip_index < n_chips; ++chip_index) {
517 int chip_strip_offset = chipStripmax * chip_index; // First strip number on chip
518
519 // Calculate the number of "free strips" on this chip
520 int nEmptyStripsOnChip = 0;
521 std::vector<int> emptyStripsOnChip;
522 emptyStripsOnChip.reserve(chipStripmax);
523 for (int i = 0; i < chipStripmax; i++) {
524 if (data.m_StripHitsOnWafer[i + chip_strip_offset] == 0) {
525 emptyStripsOnChip.push_back(i);
526 ++nEmptyStripsOnChip;
527 }
528 }
529
530 // if no empty strips on chip do nothing
531 if (nEmptyStripsOnChip != 0) {
532 // Check and adapt the number of noisy strips to the number of free strips
533 if (nEmptyStripsOnChip < nNoisyStrips[chip_index]) {
534 nNoisyStrips[chip_index] = nEmptyStripsOnChip;
535 }
536
537 // Find random strips to get noise hits
538 for (int i = 0; i < nNoisyStrips[chip_index]; i++) {
539 int index = CLHEP::RandFlat::shootInt(rndmEngine, nEmptyStripsOnChip - i);
540 int strip_on_chip = emptyStripsOnChip.at(index);
541 emptyStripsOnChip.erase(emptyStripsOnChip.begin()+index); // Erase it not to use it again
542 int strip = strip_on_chip + chip_strip_offset;
543 if (data.m_StripHitsOnWafer[strip]!=0) {
544 ATH_MSG_ERROR(index << "-th empty strip, strip " << strip << " should be empty but is not empty! Something is wrong!");
545 }
546 data.m_StripHitsOnWafer[strip] = 3; // !< Random Noise hit
547 // Add tbin info to noise diode
548 if (noise_expanded_mode) { // !< if any hit mode, any time bin
549 // !< otherwise fixed tbin=2
550 int noise_tbin = CLHEP::RandFlat::shootInt(rndmEngine, 3);
551 // !< random number 0, 1 or 2
552 if (noise_tbin == 0) {
553 noise_tbin = 4; // !< now 1, 2 or 4
554 }
555 if (StatusCode::SUCCESS != addNoiseDiode(collection, strip, noise_tbin)) {
556 ATH_MSG_ERROR("Can't add noise hit diode to collection (3)");
557 }
558 } else {
559 if (StatusCode::SUCCESS != addNoiseDiode(collection, strip, 2)) {
560 ATH_MSG_ERROR("Can't add noise hit diode to collection (4)");
561 }
562 }
563 }
564 }
565 }
566
567 return StatusCode::SUCCESS;
568}
569
570// ----------------------------------------------------------------------
571// process the collection of pre digits this will need to go through
572// all single-strip pre-digits calculate the amplifier response add noise
573// (this could be moved elsewhere later) apply threshold do clustering
574// ----------------------------------------------------------------------
575void SCT_FrontEnd::process(SiChargedDiodeCollection& collection, CLHEP::HepRandomEngine * rndmEngine) const {
576
577 const EventContext& ctx = Gaudi::Hive::currentContext();
578
579 // get SCT module side design
580 const SCT_ModuleSideDesign *p_design = static_cast<const SCT_ModuleSideDesign*>(&(collection.design()));
581
582 SCT_FrontEndData data;
583
584 // Check number of strips in design and from manager(max number of strips on any module)
585 // The design value should always be equal or lower than the manager one
586 // However, no resizing is now done in case of a lower value
587 const int strip_max = p_design->cells();
588 // Init vectors
589 if (StatusCode::SUCCESS != initVectors(strip_max, data)) {
590 ATH_MSG_ERROR("Can't resize class variable vectors");
591 return;
592 }
593
594 // Contains strip hit info, reset to 0 for each wafer processed
595 data.m_StripHitsOnWafer.assign(strip_max, 0);
596
597 // data.m_Analogue contains the charge for each bin on each hit strip
598 // These vectors were cleared in initVectors().
599
600 // Get wafer, moduleId and side
601 Identifier waferId = collection.identify();
602 Identifier moduleId = m_sct_id->module_id(waferId);
603 const int side = m_sct_id->side(waferId);
604
605 // Check if collection empty
606 if (not collection.empty()) {
607 // Setup gain/offset/noise to the hit and neighbouring strips
608 if (m_useCalibData) { // Use calib cond DB data
609 if (StatusCode::SUCCESS != prepareGainAndOffset(ctx, collection, side, moduleId, rndmEngine, data, strip_max)) {
610 ATH_MSG_ERROR("\tCan't prepare Gain and Offset");
611 }
612 } else { // Use JO values
613 if (StatusCode::SUCCESS != prepareGainAndOffset(ctx, collection, moduleId, rndmEngine, data,strip_max)) {
614 ATH_MSG_ERROR("\tCan't prepare Gain and Offset");
615 }
616 }
617
618 if (StatusCode::SUCCESS != doSignalChargeForHits(collection, data, strip_max)) {
619 ATH_MSG_ERROR("\tCan't doSignalChargeForHits");
620 }
621
622 if (StatusCode::SUCCESS != doThresholdCheckForRealHits(collection, data, strip_max)) {
623 ATH_MSG_ERROR("\tCan't doThresholdCheckForRealHits");
624 }
625
626 if (StatusCode::SUCCESS != doThresholdCheckForCrosstalkHits(collection, data, strip_max)) {
627 ATH_MSG_ERROR("\tCan't doThresholdCheckForCrosstalkHits");
628 }
629 }
630
631 if (m_NoiseOn) {
632 if (m_useCalibData) { // Check if using DB or not
633 if (StatusCode::SUCCESS != randomNoise(ctx, collection, moduleId, side, rndmEngine, data, strip_max)) {
634 ATH_MSG_ERROR("\tCan't do random noise on wafer?!");
635 }
636 } else { // Use JO fixed values
637 if (StatusCode::SUCCESS != randomNoise(ctx, collection, moduleId, rndmEngine, data,strip_max)) {
638 ATH_MSG_ERROR("\tCan't do random noise on wafer?!");
639 }
640 }
641 }
642
643 // Check for strips above threshold and do clustering
644 if (StatusCode::SUCCESS != doClustering(collection, data,strip_max)) {
645 ATH_MSG_ERROR("\tCan't cluster the hits?!");
646 }
647}
648
649StatusCode SCT_FrontEnd::doSignalChargeForHits(SiChargedDiodeCollection& collection, SCT_FrontEndData& data, int strip_max) const {
650 using list_t = SiTotalCharge::list_t;
651
652 // *****************************************************************************
653 // Loop over the diodes (strips ) and for each of them define the total signal
654 // *****************************************************************************
655
656 // set up number of needed bins depending on the compression mode
657 short bin_max = 0;
659 bin_max = m_data_compression_mode;
660 } else {
661 bin_max = 3;
662 }
663
664 std::vector<float> response(bin_max);
665
666 SiChargedDiodeIterator i_chargedDiode = collection.begin();
667 SiChargedDiodeIterator i_chargedDiode_end = collection.end();
668 for (; i_chargedDiode != i_chargedDiode_end; ++i_chargedDiode) {
669 const SiChargedDiode& diode = (*i_chargedDiode).second;
670 // should be const as we aren't trying to change it here - but getReadoutCell() is not a const method...
671 unsigned int flagmask = diode.flag() & 0xFE;
672 // Get the flag for this diode ( if flagmask = 1 If diode is disconnected/disabled skip it)
673 if (!flagmask) { // If the diode is OK (not flagged)
674 const SiReadoutCellId& roCell = diode.getReadoutCell();
675
676 if (roCell.isValid()) {
677 int strip = roCell.strip();
678
679 const list_t &ChargesOnStrip = diode.totalCharge().chargeComposition();
680
682 // Amplifier response
683 m_sct_amplifier->response(ChargesOnStrip, m_timeOfThreshold, response);
684 for (short bin = 0; bin < bin_max; ++bin) {
685 data.m_Analogue[bin][strip] += data.m_GainFactor[strip] * response[bin];
686 }
687 // Add Crosstalk signal for neighboring strip
688 m_sct_amplifier->crosstalk(ChargesOnStrip, m_timeOfThreshold, response);
689 for (short bin = 0; bin < bin_max; ++bin) {
690 if (strip + 1 < strip_max) {
691 data.m_Analogue[bin][strip + 1] += data.m_GainFactor[strip + 1] * response[bin];
692 }
693 if (strip > 0) {
694 data.m_Analogue[bin][strip - 1] += data.m_GainFactor[strip - 1] * response[bin];
695 }
696 }
697 } else { // Expanded
698 // Amplifier response
699 m_sct_amplifier->response(ChargesOnStrip, m_timeOfThreshold, response);
700 for (short bin = 0; bin < bin_max; ++bin) {
701 data.m_Analogue[bin][strip] += data.m_GainFactor[strip] * response[bin];
702 }
703 // Add Crosstalk signal for neighboring strip
704 m_sct_amplifier->crosstalk(ChargesOnStrip, m_timeOfThreshold, response);
705 for (short bin = 0; bin < bin_max; ++bin) {
706 if (strip + 1 < strip_max) {
707 data.m_Analogue[bin][strip + 1] += data.m_GainFactor[strip + 1] * response[bin];
708 }
709 if (strip > 0) {
710 data.m_Analogue[bin][strip - 1] += data.m_GainFactor[strip - 1] * response[bin];
711 }
712 }
713 }
714 } else { // if roCell not valid
715 ATH_MSG_WARNING("\t Cannot get the cell ");
716 }
717 } else {// If diode is disconnected/disabled skip it
718 ATH_MSG_WARNING("\tDisabled or disconnected diode (strip)");
719 }
720 }
721 return StatusCode::SUCCESS;
722}
723
725 // **********************************************************************************
726 // Flag strips below threshold and flag the threshold check into data.m_StripHitsOnWafer
727 // **********************************************************************************
728
729 SiChargedDiodeIterator i_chargedDiode = collection.begin();
730 SiChargedDiodeIterator i_chargedDiode_end = collection.end();
731
732 for (; i_chargedDiode != i_chargedDiode_end; ++i_chargedDiode) {
733 SiChargedDiode& diode = (*i_chargedDiode).second;
734 const SiReadoutCellId& roCell = diode.getReadoutCell();
735 if (roCell.isValid()) {
736 int strip = roCell.strip();
737 if (strip > -1 and strip < strip_max) {
739 if ((data.m_Analogue[0][strip] >= m_Threshold or data.m_Analogue[1][strip] < m_Threshold)) {
740 SiHelper::belowThreshold(diode, true); // Below strip diode signal threshold
741 data.m_StripHitsOnWafer[strip] = -1;
742 } else if (((0x10 & diode.flag()) == 0x10) or ((0x4 & diode.flag()) == 0x4)) {
743 // previously a crazy strip number could have screwed things up here.
744 data.m_StripHitsOnWafer[strip] = -1;
745 } else {
746 data.m_StripHitsOnWafer[strip] = 1;
747 SiHelper::SetTimeBin(diode, 2, &msg()); // set timebin info
748 }
749 } else { // Expanded
750 int have_hit_bin = 0;
751 if (data.m_Analogue[0][strip] >= m_Threshold) {
752 have_hit_bin = 4;
753 }
754 if (data.m_Analogue[1][strip] >= m_Threshold) {
755 have_hit_bin += 2;
756 }
757 if (data.m_Analogue[2][strip] >= m_Threshold) {
758 have_hit_bin += 1;
759 }
760 if (((0x10 & diode.flag()) == 0x10) || ((0x4 & diode.flag()) == 0x4)) {
761 // previously a crazy strip number could have screwed things up here.
762 data.m_StripHitsOnWafer[strip] = -1;
763 } else if (m_data_compression_mode == Level_X1X) { // !< level and expanded mode
764 if (have_hit_bin == 2 or have_hit_bin == 3 or have_hit_bin == 6 or have_hit_bin == 7) {
765 data.m_StripHitsOnWafer[strip] = 1;
766 SiHelper::SetTimeBin(diode, have_hit_bin, &msg());
767 } else {
768 SiHelper::belowThreshold(diode, true); // Below strip diode signal threshold
769 data.m_StripHitsOnWafer[strip] = -1;
770 }
771 } else if (m_data_compression_mode == Edge_01X) { // !< edge and expanded mode
772 if (have_hit_bin == 2 or have_hit_bin == 3) {
773 data.m_StripHitsOnWafer[strip] = 1;
774 SiHelper::SetTimeBin(diode, have_hit_bin, &msg());
775 } else {
776 SiHelper::belowThreshold(diode, true); // Below strip diode signal threshold
777 data.m_StripHitsOnWafer[strip] = -1;
778 }
779 } else if (m_data_compression_mode == AnyHit_1XX_X1X_XX1) { // !< any hit mode
780 if (have_hit_bin == 0) {
781 SiHelper::belowThreshold(diode, true); // Below strip diode signal threshold
782 data.m_StripHitsOnWafer[strip] = -1;
783 } else {
784 data.m_StripHitsOnWafer[strip] = 1;
785 if (m_data_readout_mode == Expanded) { // !< check for exp mode or not
786 SiHelper::SetTimeBin(diode, have_hit_bin, &msg());
787 } else {
788 SiHelper::SetTimeBin(diode, 2, &msg());
789 }
790 }
791 }
792 }
793 }
794 }
795 }
796 return StatusCode::SUCCESS;
797}
798
799// ----------------------------------------------------------------------
800//
801// ----------------------------------------------------------------------
803 // Check for noise+crosstalk strips above threshold
804 // data.m_StripHitsOnWafer: real hits above threshold == 1 or below/disconnected
805 // == -1
806 // =0 for free strips or strips with charge to be checked (data.m_Analogue[1]!=0)
807 // Set 2 for crosstalk noise hits and -2 for below ones
808
809 for (int strip = 0; strip < strip_max; strip++) {
810 // Find strips with data.m_StripHitsOnWafer[strip] == 0
811 if (data.m_StripHitsOnWafer[strip] != 0) { // real hits already checked
812 continue;
813 }
814 if (data.m_Analogue[1][strip] > 0) { // Better way of doing this?!
815 // set data.m_StripHitsOnWafer to x in prepareGainAndOffset
817 if ((data.m_Analogue[0][strip] >= m_Threshold or data.m_Analogue[1][strip] < m_Threshold)) {
818 data.m_StripHitsOnWafer[strip] = -2; // Below threshold
819 } else {
820 data.m_StripHitsOnWafer[strip] = 2; // Crosstalk+Noise hit
821 if (StatusCode::SUCCESS != addNoiseDiode(collection, strip, 2)) {
822
823 ATH_MSG_ERROR("Can't add noise hit diode to collection (5)");
824 }
825 }
826 } else { // Expanded
827 int have_hit_bin = 0;
828 if (data.m_Analogue[0][strip] >= m_Threshold) {
829 have_hit_bin = 4;
830 }
831 if (data.m_Analogue[1][strip] >= m_Threshold) {
832 have_hit_bin += 2;
833 }
834 if (data.m_Analogue[2][strip] >= m_Threshold) {
835 have_hit_bin += 1;
836 }
837 if (m_data_compression_mode == Level_X1X) { // !< level and expanded mode
838 if (have_hit_bin == 2 or have_hit_bin == 3 or have_hit_bin == 6 or have_hit_bin == 7) {
839 data.m_StripHitsOnWafer[strip] = 2; // Crosstalk+Noise hit
840 if (StatusCode::SUCCESS != addNoiseDiode(collection, strip, have_hit_bin)) {
841 ATH_MSG_ERROR("Can't add noise hit diode to collection (6)");
842 }
843 } else {
844 data.m_StripHitsOnWafer[strip] = -2; // Below threshold
845 }
846 } else if (m_data_compression_mode == Edge_01X) { // !< edge and expanded mode
847 if (have_hit_bin == 2 or have_hit_bin == 3) {
848 data.m_StripHitsOnWafer[strip] = 2; // Noise hit
849 if (StatusCode::SUCCESS != addNoiseDiode(collection, strip, have_hit_bin)) {
850 ATH_MSG_ERROR("Can't add noise hit diode to collection (7)");
851 }
852 } else {
853 data.m_StripHitsOnWafer[strip] = -2; // Below threshold
854 }
855 } else if (m_data_compression_mode == AnyHit_1XX_X1X_XX1) { // !< any hit mode
856 if (have_hit_bin == 0) {
857 data.m_StripHitsOnWafer[strip] = -2; // Below threshold
858 } else {
859 data.m_StripHitsOnWafer[strip] = 2; // !< Crosstalk+Noise hit
860 if (m_data_readout_mode == Expanded) { // !< check for exp mode or not
861 if (StatusCode::SUCCESS != addNoiseDiode(collection, strip, have_hit_bin)) {
862 ATH_MSG_ERROR("Can't add noise hit diode to collection (8)");
863 }
864 } else {
865 if (StatusCode::SUCCESS != addNoiseDiode(collection, strip, 2)) {
866 ATH_MSG_ERROR("Can't add noise hit diode to collection (9)");
867 }
868 }
869 }
870 }
871 }
872 }
873 }
874
875 return StatusCode::SUCCESS;
876}
877
878StatusCode SCT_FrontEnd::doClustering(SiChargedDiodeCollection& collection, SCT_FrontEndData& data, int strip_max) const {
879 // ********************************
880 // now do clustering
881 // ********************************
882 int strip = 0;
883 int clusterSize = 0;
884
885 const SCT_ModuleSideDesign& sctDesign = static_cast<const SCT_ModuleSideDesign&>(collection.design());
886
887 SiCellId hitStrip;
888
890 do {
891 if (data.m_StripHitsOnWafer[strip] > 0) {
892 // ====== First step: Get the cluster size
893 // ===================================================
894 int clusterFirstStrip = strip;
895
896 // Find end of cluster. In multi-row sensors, cluster cannot span rows.
897 int row = sctDesign.row(strip);
898 if (row < 0) {
899 row = 0;
900 }
901
902 int lastStrip1DInRow = 0;
903 for (int i = 0; i < row + 1; ++i) {
904 lastStrip1DInRow += sctDesign.diodesInRow(i);
905 }
906
907 while (strip < lastStrip1DInRow-1 and data.m_StripHitsOnWafer[strip +1] > 0) {
908 ++strip; // !< Find first strip hit and add up the following strips
909 }
910 int clusterLastStrip = strip;
911
912 clusterSize = (clusterLastStrip - clusterFirstStrip) + 1;
913 hitStrip = SiCellId(clusterFirstStrip);
914 SiChargedDiode& HitDiode = *(collection.find(hitStrip));
915 SiHelper::SetStripNum(HitDiode, clusterSize, &msg());
916
917 SiChargedDiode *PreviousHitDiode = &HitDiode;
918 for (int i = clusterFirstStrip+1; i <= clusterLastStrip; ++i) {
919 hitStrip = SiCellId(i);
920 SiChargedDiode& HitDiode2 = *(collection.find(hitStrip));
921 SiHelper::ClusterUsed(HitDiode2, true);
922 PreviousHitDiode->setNextInCluster(&HitDiode2);
923 PreviousHitDiode = &HitDiode2;
924 }
925 }
926 ++strip; // !< This is the starting point of the next cluster within this collection
927 } while (strip < strip_max);
928 } else {
929 // Expanded read out mode, basically one RDO/strip per cluster
930 // But if consecutively fired strips have the same time bin, those are converted into one cluster.
931 do {
932 clusterSize = 1;
933 if (data.m_StripHitsOnWafer[strip] > 0) {
934 hitStrip = SiCellId(strip);
935 SiChargedDiode& hitDiode = *(collection.find(hitStrip));
936 int timeBin = SiHelper::GetTimeBin(hitDiode);
937 SiChargedDiode* previousHitDiode = &hitDiode;
938 // Check if consecutively fired strips have the same time bin
939 for (int newStrip=strip+1; newStrip<strip_max; newStrip++) {
940 if (not (data.m_StripHitsOnWafer[newStrip]>0)) break;
941 SiCellId newHitStrip = SiCellId(newStrip);
942 SiChargedDiode& newHitDiode = *(collection.find(newHitStrip));
943 if (timeBin!=SiHelper::GetTimeBin(newHitDiode)) break;
944 SiHelper::ClusterUsed(newHitDiode, true);
945 previousHitDiode->setNextInCluster(&newHitDiode);
946 previousHitDiode = &newHitDiode;
947 clusterSize++;
948 }
949 SiHelper::SetStripNum(hitDiode, clusterSize, &msg());
950
951#ifdef SCT_DIG_DEBUG
952 ATH_MSG_DEBUG("RDO Strip = " << strip << ", tbin = " <<
953 SiHelper::GetTimeBin(hitDiode) <<
954 ", HitInfo(1=real, 2=crosstalk, 3=noise): " <<
955 data.m_StripHitsOnWafer[strip]);
956#endif
957 }
958 strip += clusterSize; // If more than one strip fires, those following strips are skipped.
959 } while (strip < strip_max);
960 }
961
962 // clusters below threshold, only from pre-digits that existed before no
963 // pure noise clusters below threshold will be made
964 // D. Costanzo. I don't see why we should cluster the strips below
965 // threshold. I'll pass on the info of strips below threshold
966 // to the SDOs. I'll leave the SCT experts the joy to change this if they
967 // don't like what I did or if this requires too much memory/disk
968
969 return StatusCode::SUCCESS;
970}
971
972StatusCode SCT_FrontEnd::addNoiseDiode(SiChargedDiodeCollection& collection, int strip, int tbin) const {
973 const SiCellId ndiode(strip); // !< create a new diode
974 const SiCharge noiseCharge(2 * m_Threshold, 0, SiCharge::noise); // !< add some noise to it
975 collection.add(ndiode, noiseCharge); // !< add it to the collection
976
977 // Get the strip back to check
978 SiChargedDiode *NoiseDiode = (collection.find(strip));
979 if (NoiseDiode == nullptr) {
980 return StatusCode::FAILURE;
981 }
982 SiHelper::SetTimeBin(*NoiseDiode, tbin, &msg()); // set timebin info
983 return StatusCode::SUCCESS;
984}
985
986float SCT_FrontEnd::meanValue(std::vector<float>& calibDataVect) {
987 float mean_value = 0.0;
988 int nData = 0;
989
990 for (float calibData : calibDataVect) {
991 if (calibData > 0.1) {
992 mean_value += calibData;
993 ++nData;
994 }
995 }
996
997 if (nData == 0) {
998 return -1;
999 } else {
1000 return mean_value / nData;
1001 }
1002}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
MDT_Response response
This is an Identifier helper class for the SCT subdetector.
SiChargedDiodeMap::iterator SiChargedDiodeIterator
struct TBPatternUnitContext S2
struct TBPatternUnitContext S1
Base class for the SCT module side design, extended by the Forward and Barrel module design.
int cells() const
number of readout stips within module side:
virtual int row(int stripId1Dim) const
virtual int diodesInRow(const int row) const
Identifier for the strip or pixel cell.
Definition SiCellId.h:29
int strip() const
Get strip number. Equivalent to phiIndex().
Definition SiCellId.h:131
bool isValid() const
Test if its in a valid state.
Definition SiCellId.h:136
Identifier for the strip or pixel readout cell.
FloatProperty m_GainRMS
StatusCode prepareGainAndOffset(const EventContext &ctx, SiChargedDiodeCollection &collection, const Identifier &moduleId, CLHEP::HepRandomEngine *rndmEngine, SCT_FrontEndData &data, int stripMax) const
FloatProperty m_NoiseShortMiddles
StatusCode doClustering(SiChargedDiodeCollection &collection, SCT_FrontEndData &data, int stripMax) const
virtual void process(SiChargedDiodeCollection &collection, CLHEP::HepRandomEngine *rndmEngine) const override
process the collection of pre digits: needed to go through all single-strip pre-digits to calculate t...
BooleanProperty m_analogueNoiseOn
BooleanProperty m_NoiseOn
DoubleProperty m_NOShortMiddles
DoubleProperty m_NOMiddles
DoubleProperty m_NOInners
FloatProperty m_NoiseOuters
ToolHandle< ISCT_ReadCalibChipDataTool > m_ReadCalibChipDataTool
Handle to the Calibration ConditionsTool.
FloatProperty m_Ospread
FloatProperty m_NoiseBarrel3
ToolHandle< IAmplifier > m_sct_amplifier
Handle the Amplifier tool.
StatusCode doSignalChargeForHits(SiChargedDiodeCollection &collectione, SCT_FrontEndData &data, int stripMax) const
FloatProperty m_timeOfThreshold
StatusCode doThresholdCheckForCrosstalkHits(SiChargedDiodeCollection &collection, SCT_FrontEndData &data, int stripMax) const
StatusCode doThresholdCheckForRealHits(SiChargedDiodeCollection &collectione, SCT_FrontEndData &data, int stripMax) const
ShortProperty m_data_readout_mode
StatusCode initVectors(int strips, SCT_FrontEndData &data) const
BooleanProperty m_useCalibData
virtual StatusCode finalize() override
AlgTool finalize.
FloatProperty m_OGcorr
DoubleProperty m_NOOuters
FloatProperty m_NoiseInners
StatusCode randomNoise(const EventContext &ctx, SiChargedDiodeCollection &collection, const Identifier &moduleId, CLHEP::HepRandomEngine *rndmEngine, SCT_FrontEndData &data, int stripMax) const
DoubleProperty m_NOBarrel3
FloatProperty m_Threshold
DoubleProperty m_NOBarrel
virtual StatusCode initialize() override
AlgTool InterfaceID.
static float meanValue(std::vector< float > &calibDataVect)
SCT_FrontEnd(const std::string &type, const std::string &name, const IInterface *parent)
constructor
const InDetDD::SCT_DetectorManager * m_SCTdetMgr
Handle to SCT detector manager.
const SCT_ID * m_sct_id
Handle to SCT ID helper.
StatusCode addNoiseDiode(SiChargedDiodeCollection &collection, int strip, int tbin) const
FloatProperty m_NoiseBarrel
StringProperty m_detMgrName
ShortProperty m_data_compression_mode
FloatProperty m_NoiseMiddles
virtual Identifier identify() const override final
SiChargedDiodeIterator begin()
const InDetDD::DetectorDesign & design() const
SiChargedDiode * find(const InDetDD::SiCellId &siId)
void add(const InDetDD::SiCellId &diode, const T &charge)
void setNextInCluster(SiChargedDiode *nextInCluster)
int flag() const
const SiTotalCharge & totalCharge() const
const InDetDD::SiReadoutCellId & getReadoutCell() const
static void ClusterUsed(SiChargedDiode &chDiode, bool flag)
Definition SiHelper.h:121
static void SetTimeBin(SiChargedDiode &chDiode, int time, MsgStream *log=nullptr)
Definition SiHelper.h:149
static void SetStripNum(SiChargedDiode &chDiode, int nstrip, MsgStream *log=nullptr)
Definition SiHelper.h:139
static void belowThreshold(SiChargedDiode &chDiode, bool flag, bool mask=false)
Definition SiHelper.h:84
static int GetTimeBin(SiChargedDiode &chDiode)
Definition SiHelper.h:203
std::vector< SiCharge > list_t
const list_t & chargeComposition() const
Message Stream Member.
Definition index.py:1
hold the test vectors and ease the comparison
simulation of the SCT front-end electronics working as a SiPreDigitsProcessor models response of ABCD...
MsgStream & msg
Definition testRead.cxx:32