14#include "CLHEP/Random/RandFlat.h"
15#include "CLHEP/Random/RandGaussZiggurat.h"
16#include "CLHEP/Random/RandPoisson.h"
17#include "CLHEP/Random/RandomEngine.h"
30 : base_class(
type, name, parent) {
38 ATH_MSG_FATAL(
"AnalogueNoiseOn/m_analogueNoiseOn should be true if NoiseOn/m_NoiseOn is true.");
39 return StatusCode::FAILURE;
59 constexpr float fC = 6242.2;
80 <<
" is invalid. Abort this job!!!");
81 return StatusCode::FAILURE;
85 <<
" is invalid. Abort this job!!!");
86 return StatusCode::FAILURE;
92 <<
" requires timing information."
94 <<
" (Condensed) does not keep timing information. Abort this job!!!");
95 return StatusCode::FAILURE;
98 return StatusCode::SUCCESS;
105 return StatusCode::SUCCESS;
112 data.m_GainFactor.resize(strips);
115 data.m_Analogue[0].resize(strips);
116 data.m_Analogue[1].resize(strips);
118 data.m_Analogue[0].resize(strips);
119 data.m_Analogue[1].resize(strips);
120 data.m_Analogue[2].resize(strips);
123 return StatusCode::SUCCESS;
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 = sqrt(1.0 - x1);
141 float S1 = std::sqrt((S + D) * 0.5f);
142 float S2 = std::sqrt((S - D) * 0.5f);
148 if (
m_sct_id->barrel_ec(moduleId) == 0) {
149 if (
m_sct_id->layer_disk(moduleId) == 3) {
155 int moduleType =
m_sct_id->eta_module(moduleId);
156 switch (moduleType) {
162 if (
m_sct_id->layer_disk(moduleId) == 7) {
175 ATH_MSG_ERROR(
"moduleType(eta): " << moduleType <<
" unknown, using barrel");
185 for (; i_chargedDiode != i_chargedDiode_end; ++i_chargedDiode) {
188 unsigned int flagmask = diode.
flag() & 0xFE;
194 int i = std::max(
strip - 1, 0);
195 int i_end = std::min(
strip + 2, strip_max);
198 for (; i < i_end; i++) {
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);
204 data.m_GainFactor[i] = 1.0f + (cosfi * g + sinfi * o);
206 float offset_val = (cosfi * o - sinfi * g);
208 float noise_val = Noise * mode;
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);
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);
225 return StatusCode::SUCCESS;
235 std::vector<float> gainRMSByChipVect =
m_ReadCalibChipDataTool->getNPtGainData(moduleId, side,
"GainRMSByChip");
237 std::vector<float> offsetRMSByChipVect =
m_ReadCalibChipDataTool->getNPtGainData(moduleId, side,
"OffsetRMSByChip");
238 std::vector<float> noiseByChipVect(6, 0.0);
245 if (gainByChipVect.empty() or noiseByChipVect.empty()) {
246 ATH_MSG_DEBUG(
"No calibration data in cond DB for module " << moduleId <<
" using JO values");
248 return StatusCode::FAILURE;
250 return StatusCode::SUCCESS;
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");
259 return StatusCode::FAILURE;
261 return StatusCode::SUCCESS;
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);
272 float offsetRMS = 0.0;
274 for (
int i = 0; i < 6; ++i) {
276 if (gainByChipVect[i] > 0.1) {
277 gain[i] = gainByChipVect[i] / gainMeanValue;
279 gainRMS = gainRMSByChipVect[i] / gainMeanValue;
282 gain[i] = 55.0f / gainMeanValue;
284 gainRMS = 1.3f / gainMeanValue;
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);
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);
304 for (; i_chargedDiode != i_chargedDiode_end; ++i_chargedDiode) {
307 unsigned int flagmask = diode.
flag() & 0xFE;
314 int i = std::max(
strip - 1, 0);
315 int i_end = std::min(
strip + 2, strip_max);
318 for (; i < i_end; i++) {
320 if (
data.m_Analogue[1][i] <= 0.0) {
323 float g = CLHEP::RandGaussZiggurat::shoot(rndmEngine, 0.0,
S1[chip]);
324 float o = CLHEP::RandGaussZiggurat::shoot(rndmEngine, 0.0,
S2[chip]);
326 data.m_GainFactor[i] = gain[chip] + (cosfi[chip] * g + sinfi[chip] * o);
328 float offset_val = offset[chip] + (cosfi[chip] * o - sinfi[chip] * g);
330 float noise_val = noiseByChipVect[chip];
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);
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);
347 return StatusCode::SUCCESS;
356 double occupancy = 0.0;
357 double NoiseOccupancy = 0.0;
359 int nNoisyStrips = 0;
365 if (noise_expanded_mode) {
372 if (
m_sct_id->barrel_ec(moduleId) == 0) {
373 if (
m_sct_id->layer_disk(moduleId) == 3) {
381 int moduleType =
m_sct_id->eta_module(moduleId);
382 switch (moduleType) {
389 if (
m_sct_id->layer_disk(moduleId) == 7) {
406 ATH_MSG_ERROR(
"moduleType(eta): " << moduleType <<
" unknown, using barrel");
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);
422 if (nEmptyStrips != 0) {
425 occupancy = CLHEP::RandGaussZiggurat::shoot(rndmEngine, NoiseOccupancy, NoiseOccupancy * 0.1);
429 const float fC = 6242.2;
432 nNoisyStrips = CLHEP::RandPoisson::shoot(rndmEngine, strip_max * occupancy * mode);
435 if (nEmptyStrips < nNoisyStrips) {
436 nNoisyStrips = nEmptyStrips;
440 for (
int i = 0; i < nNoisyStrips; i++) {
441 int index = CLHEP::RandFlat::shootInt(rndmEngine, nEmptyStrips - i);
444 emptyStrips.erase(emptyStrips.begin()+
index);
446 ATH_MSG_ERROR(
index <<
"-th empty strip, strip " <<
strip <<
" should be empty but is not empty! Something is wrong!");
450 if (noise_expanded_mode) {
451 int noise_tbin = CLHEP::RandFlat::shootInt(rndmEngine, 3);
453 if (noise_tbin == 0) {
457 ATH_MSG_ERROR(
"Can't add noise hit diode to collection (1)");
461 ATH_MSG_ERROR(
"Can't add noise hit diode to collection (2)");
467 return StatusCode::SUCCESS;
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);
484 if (noise_expanded_mode) {
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(collection, moduleId, rndmEngine,
data,strip_max)) {
496 return StatusCode::FAILURE;
498 return StatusCode::SUCCESS;
501 for (
int i = 0; i < n_chips; i++) {
507 constexpr float fC = 6242.2;
508 NOByChipVect[i] = NOByChipVect[i] * exp(-(0.5 / (ENCByChipVect[i]*ENCByChipVect[i]) * (
m_Threshold*
m_Threshold - fC*fC)));
511 nNoisyStrips[i] = CLHEP::RandPoisson::shoot(rndmEngine, chipStripmax * NOByChipVect[i] * mode);
516 for (
int chip_index = 0; chip_index < n_chips; ++chip_index) {
517 int chip_strip_offset = chipStripmax * chip_index;
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;
531 if (nEmptyStripsOnChip != 0) {
533 if (nEmptyStripsOnChip < nNoisyStrips[chip_index]) {
534 nNoisyStrips[chip_index] = nEmptyStripsOnChip;
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);
542 int strip = strip_on_chip + chip_strip_offset;
544 ATH_MSG_ERROR(
index <<
"-th empty strip, strip " <<
strip <<
" should be empty but is not empty! Something is wrong!");
548 if (noise_expanded_mode) {
550 int noise_tbin = CLHEP::RandFlat::shootInt(rndmEngine, 3);
552 if (noise_tbin == 0) {
556 ATH_MSG_ERROR(
"Can't add noise hit diode to collection (3)");
560 ATH_MSG_ERROR(
"Can't add noise hit diode to collection (4)");
567 return StatusCode::SUCCESS;
584 const int strip_max = p_design->
cells();
592 data.m_StripHitsOnWafer.assign(strip_max, 0);
600 const int side =
m_sct_id->side(waferId);
603 if (not collection.
empty()) {
630 if (StatusCode::SUCCESS !=
randomNoise(collection, moduleId, side, rndmEngine,
data, strip_max)) {
634 if (StatusCode::SUCCESS !=
randomNoise(collection, moduleId, rndmEngine,
data,strip_max)) {
661 std::vector<float>
response(bin_max);
665 for (; i_chargedDiode != i_chargedDiode_end; ++i_chargedDiode) {
668 unsigned int flagmask = diode.
flag() & 0xFE;
681 for (
short bin = 0;
bin < bin_max; ++
bin) {
686 for (
short bin = 0;
bin < bin_max; ++
bin) {
687 if (
strip + 1 < strip_max) {
697 for (
short bin = 0;
bin < bin_max; ++
bin) {
702 for (
short bin = 0;
bin < bin_max; ++
bin) {
703 if (
strip + 1 < strip_max) {
718 return StatusCode::SUCCESS;
729 for (; i_chargedDiode != i_chargedDiode_end; ++i_chargedDiode) {
739 }
else if (((0x10 & diode.
flag()) == 0x10) or ((0x4 & diode.
flag()) == 0x4)) {
747 int have_hit_bin = 0;
757 if (((0x10 & diode.
flag()) == 0x10) || ((0x4 & diode.
flag()) == 0x4)) {
761 if (have_hit_bin == 2 or have_hit_bin == 3 or have_hit_bin == 6 or have_hit_bin == 7) {
769 if (have_hit_bin == 2 or have_hit_bin == 3) {
777 if (have_hit_bin == 0) {
793 return StatusCode::SUCCESS;
808 if (
data.m_StripHitsOnWafer[
strip] != 0) {
820 ATH_MSG_ERROR(
"Can't add noise hit diode to collection (5)");
824 int have_hit_bin = 0;
835 if (have_hit_bin == 2 or have_hit_bin == 3 or have_hit_bin == 6 or have_hit_bin == 7) {
838 ATH_MSG_ERROR(
"Can't add noise hit diode to collection (6)");
844 if (have_hit_bin == 2 or have_hit_bin == 3) {
847 ATH_MSG_ERROR(
"Can't add noise hit diode to collection (7)");
853 if (have_hit_bin == 0) {
859 ATH_MSG_ERROR(
"Can't add noise hit diode to collection (8)");
863 ATH_MSG_ERROR(
"Can't add noise hit diode to collection (9)");
872 return StatusCode::SUCCESS;
888 if (
data.m_StripHitsOnWafer[
strip] > 0) {
891 int clusterFirstStrip =
strip;
899 int lastStrip1DInRow = 0;
900 for (
int i = 0; i < row + 1; ++i) {
904 while (
strip < lastStrip1DInRow-1 and
data.m_StripHitsOnWafer[
strip +1] > 0) {
907 int clusterLastStrip =
strip;
909 clusterSize = (clusterLastStrip - clusterFirstStrip) + 1;
910 hitStrip =
SiCellId(clusterFirstStrip);
915 for (
int i = clusterFirstStrip+1; i <= clusterLastStrip; ++i) {
920 PreviousHitDiode = &HitDiode2;
924 }
while (
strip < strip_max);
930 if (
data.m_StripHitsOnWafer[
strip] > 0) {
936 for (
int newStrip=
strip+1; newStrip<strip_max; newStrip++) {
937 if (not (
data.m_StripHitsOnWafer[newStrip]>0))
break;
943 previousHitDiode = &newHitDiode;
951 ", HitInfo(1=real, 2=crosstalk, 3=noise): " <<
955 strip += clusterSize;
956 }
while (
strip < strip_max);
966 return StatusCode::SUCCESS;
972 collection.
add(ndiode, noiseCharge);
976 if (NoiseDiode ==
nullptr) {
977 return StatusCode::FAILURE;
980 return StatusCode::SUCCESS;
984 float mean_value = 0.0;
986 const unsigned int vec_size = calibDataVect.size();
988 for (
unsigned int i = 0; i < vec_size; ++i) {
989 if (calibDataVect[i] > 0.1) {
990 mean_value += calibDataVect[i];
998 return mean_value / nData;
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_WARNING(x)
char data[hepevt_bytes_allocation_ATLAS]
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.
int strip() const
Get strip number. Equivalent to phiIndex().
bool isValid() const
Test if its in a valid state.
Identifier for the strip or pixel readout cell.
FloatProperty m_NoiseShortMiddles
StatusCode randomNoise(SiChargedDiodeCollection &collection, const Identifier &moduleId, CLHEP::HepRandomEngine *rndmEngine, SCT_FrontEndData &data, const 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_NoiseBarrel3
ToolHandle< IAmplifier > m_sct_amplifier
Handle the Amplifier tool.
FloatProperty m_timeOfThreshold
StatusCode doThresholdCheckForCrosstalkHits(SiChargedDiodeCollection &collection, SCT_FrontEndData &data, const 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.
DoubleProperty m_NOOuters
FloatProperty m_NoiseInners
DoubleProperty m_NOBarrel3
FloatProperty m_Threshold
StatusCode doThresholdCheckForRealHits(SiChargedDiodeCollection &collectione, SCT_FrontEndData &data, const int &stripMax) const
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
StatusCode doSignalChargeForHits(SiChargedDiodeCollection &collectione, SCT_FrontEndData &data, const int &stripMax) const
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
StatusCode doClustering(SiChargedDiodeCollection &collection, SCT_FrontEndData &data, const int &stripMax) const
FloatProperty m_NoiseBarrel
StatusCode prepareGainAndOffset(SiChargedDiodeCollection &collection, const Identifier &moduleId, CLHEP::HepRandomEngine *rndmEngine, SCT_FrontEndData &data, const int &stripMax) const
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)
SiChargedDiodeIterator end()
void add(const InDetDD::SiCellId &diode, const T &charge)
void setNextInCluster(SiChargedDiode *nextInCluster)
const SiTotalCharge & totalCharge() const
const InDetDD::SiReadoutCellId & getReadoutCell() const
static void ClusterUsed(SiChargedDiode &chDiode, bool flag)
static void SetTimeBin(SiChargedDiode &chDiode, int time, MsgStream *log=nullptr)
static void SetStripNum(SiChargedDiode &chDiode, int nstrip, MsgStream *log=nullptr)
static void belowThreshold(SiChargedDiode &chDiode, bool flag, bool mask=false)
static int GetTimeBin(SiChargedDiode &chDiode)
std::vector< SiCharge > list_t
const list_t & chargeComposition() const
hold the test vectors and ease the comparison
simulation of the SCT front-end electronics working as a SiPreDigitsProcessor models response of ABCD...