15#include "CLHEP/Random/RandFlat.h"
16#include "CLHEP/Random/RandGaussZiggurat.h"
17#include "CLHEP/Random/RandPoisson.h"
18#include "CLHEP/Random/RandomEngine.h"
31 : base_class(
type, name, parent) {
39 ATH_MSG_FATAL(
"AnalogueNoiseOn/m_analogueNoiseOn should be true if NoiseOn/m_NoiseOn is true.");
40 return StatusCode::FAILURE;
60 constexpr float fC = 6242.2;
81 <<
" is invalid. Abort this job!!!");
82 return StatusCode::FAILURE;
86 <<
" is invalid. Abort this job!!!");
87 return StatusCode::FAILURE;
93 <<
" requires timing information."
95 <<
" (Condensed) does not keep timing information. Abort this job!!!");
96 return StatusCode::FAILURE;
99 return StatusCode::SUCCESS;
106 return StatusCode::SUCCESS;
113 data.m_GainFactor.resize(strips);
116 data.m_Analogue[0].resize(strips);
117 data.m_Analogue[1].resize(strips);
119 data.m_Analogue[0].resize(strips);
120 data.m_Analogue[1].resize(strips);
121 data.m_Analogue[2].resize(strips);
124 return StatusCode::SUCCESS;
134 float A = 4.0f * W * W + 1.0f;
135 float x1 = (
A - std::sqrt(
A)) / (2.0f *
A);
136 float sinfi = std::sqrt(x1);
137 float cosfi = std::sqrt(1.0 - x1);
142 float S1 = std::sqrt((S + D) * 0.5f);
143 float S2 = std::sqrt((S - D) * 0.5f);
149 if (
m_sct_id->barrel_ec(moduleId) == 0) {
150 if (
m_sct_id->layer_disk(moduleId) == 3) {
156 int moduleType =
m_sct_id->eta_module(moduleId);
157 switch (moduleType) {
163 if (
m_sct_id->layer_disk(moduleId) == 7) {
176 ATH_MSG_ERROR(
"moduleType(eta): " << moduleType <<
" unknown, using barrel");
186 for (; i_chargedDiode != i_chargedDiode_end; ++i_chargedDiode) {
189 unsigned int flagmask = diode.
flag() & 0xFE;
195 int i = std::max(
strip - 1, 0);
196 int i_end = std::min(
strip + 2, strip_max);
199 for (; i < i_end; i++) {
201 if (data.m_Analogue[1][i] <= 0.0) {
202 float g = CLHEP::RandGaussZiggurat::shoot(rndmEngine, 0.0,
S1);
203 float o = CLHEP::RandGaussZiggurat::shoot(rndmEngine, 0.0,
S2);
205 data.m_GainFactor[i] = 1.0f + (cosfi * g + sinfi * o);
207 float offset_val = (cosfi * o - sinfi * g);
209 float noise_val = Noise * mode;
213 data.m_Analogue[0][i] = offset_val + noise_val * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
214 data.m_Analogue[1][i] = offset_val + noise_val * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
216 data.m_Analogue[0][i] = offset_val + noise_val * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
217 data.m_Analogue[1][i] = offset_val + noise_val * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
218 data.m_Analogue[2][i] = offset_val + noise_val * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
226 return StatusCode::SUCCESS;
235 std::vector<float> gainByChipVect =
m_ReadCalibChipDataTool->getNPtGainData(moduleId, side,
"GainByChip", ctx);
236 std::vector<float> gainRMSByChipVect =
m_ReadCalibChipDataTool->getNPtGainData(moduleId, side,
"GainRMSByChip", ctx);
237 std::vector<float> offsetByChipVect =
m_ReadCalibChipDataTool->getNPtGainData(moduleId, side,
"OffsetByChip", ctx);
238 std::vector<float> offsetRMSByChipVect =
m_ReadCalibChipDataTool->getNPtGainData(moduleId, side,
"OffsetRMSByChip", ctx);
239 std::vector<float> noiseByChipVect(6, 0.0);
246 if (gainByChipVect.empty() or noiseByChipVect.empty()) {
247 ATH_MSG_DEBUG(
"No calibration data in cond DB for module " << moduleId <<
" using JO values");
248 if (StatusCode::SUCCESS !=
prepareGainAndOffset(ctx, collection, moduleId, rndmEngine, data,strip_max)) {
249 return StatusCode::FAILURE;
251 return StatusCode::SUCCESS;
256 float gainMeanValue =
meanValue(gainByChipVect);
257 if (gainMeanValue < 0.0) {
258 ATH_MSG_DEBUG(
"All chip gain values are 0 for module " << moduleId <<
" using JO values");
259 if (StatusCode::SUCCESS !=
prepareGainAndOffset(ctx, collection, moduleId, rndmEngine, data,strip_max)) {
260 return StatusCode::FAILURE;
262 return StatusCode::SUCCESS;
266 std::vector<float> gain(6, 0.0);
267 std::vector<float> offset(6, 0.0);
268 std::vector<float>
S1(6, 0.0);
269 std::vector<float>
S2(6, 0.0);
270 std::vector<float> sinfi(6, 0.0);
271 std::vector<float> cosfi(6, 0.0);
273 float offsetRMS = 0.0;
275 for (
int i = 0; i < 6; ++i) {
277 if (gainByChipVect[i] > 0.1) {
278 gain[i] = gainByChipVect[i] / gainMeanValue;
280 gainRMS = gainRMSByChipVect[i] / gainMeanValue;
285 gain[i] = 55.0f / gainMeanValue;
287 gainRMS = 1.3f / gainMeanValue;
291 float W =
m_OGcorr * gainRMS * offsetRMS / (gainRMS * gainRMS - offsetRMS * offsetRMS);
292 float A = 4.0f * W * W + 1.0f;
293 float x1 = (
A - std::sqrt(
A)) / (2.0f *
A);
294 sinfi[i] = std::sqrt(x1);
295 cosfi[i] = std::sqrt(1.0f - x1);
297 float S = gainRMS * gainRMS + offsetRMS * offsetRMS;
298 float D = (gainRMS * gainRMS - offsetRMS * offsetRMS) / (cosfi[i] * cosfi[i] - sinfi[i] * sinfi[i]);
299 S1[i] = std::sqrt((S + D) / 2.0f);
300 S2[i] = std::sqrt((S - D) / 2.0f);
307 for (; i_chargedDiode != i_chargedDiode_end; ++i_chargedDiode) {
310 unsigned int flagmask = diode.
flag() & 0xFE;
317 int i = std::max(
strip - 1, 0);
318 int i_end = std::min(
strip + 2, strip_max);
321 for (; i < i_end; i++) {
323 if (data.m_Analogue[1][i] <= 0.0) {
326 float g = CLHEP::RandGaussZiggurat::shoot(rndmEngine, 0.0,
S1[chip]);
327 float o = CLHEP::RandGaussZiggurat::shoot(rndmEngine, 0.0,
S2[chip]);
329 data.m_GainFactor[i] = gain[chip] + (cosfi[chip] * g + sinfi[chip] * o);
331 float offset_val = offset[chip] + (cosfi[chip] * o - sinfi[chip] * g);
333 float noise_val = noiseByChipVect[chip];
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);
340 data.m_Analogue[0][i] = offset_val + noise_val * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
341 data.m_Analogue[1][i] = offset_val + noise_val * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
342 data.m_Analogue[2][i] = offset_val + noise_val * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
350 return StatusCode::SUCCESS;
359 double occupancy = 0.0;
360 double NoiseOccupancy = 0.0;
362 int nNoisyStrips = 0;
368 if (noise_expanded_mode) {
375 if (
m_sct_id->barrel_ec(moduleId) == 0) {
376 if (
m_sct_id->layer_disk(moduleId) == 3) {
384 int moduleType =
m_sct_id->eta_module(moduleId);
385 switch (moduleType) {
392 if (
m_sct_id->layer_disk(moduleId) == 7) {
409 ATH_MSG_WARNING(
"moduleType(eta): " << moduleType <<
" unknown, using barrel");
415 int nEmptyStrips = 0;
416 std::vector<int> emptyStrips;
417 emptyStrips.reserve(strip_max);
418 for (
int i = 0; i < strip_max; i++) {
419 if (data.m_StripHitsOnWafer[i] == 0) {
420 emptyStrips.push_back(i);
425 if (nEmptyStrips != 0) {
428 occupancy = CLHEP::RandGaussZiggurat::shoot(rndmEngine, NoiseOccupancy, NoiseOccupancy * 0.1);
432 const float fC = 6242.2;
435 nNoisyStrips = CLHEP::RandPoisson::shoot(rndmEngine, strip_max * occupancy * mode);
438 if (nEmptyStrips < nNoisyStrips) {
439 nNoisyStrips = nEmptyStrips;
443 for (
int i = 0; i < nNoisyStrips; i++) {
444 int index = CLHEP::RandFlat::shootInt(rndmEngine, nEmptyStrips - i);
447 emptyStrips.erase(emptyStrips.begin()+
index);
448 if (data.m_StripHitsOnWafer[
strip]!=0) {
449 ATH_MSG_ERROR(
index <<
"-th empty strip, strip " <<
strip <<
" should be empty but is not empty! Something is wrong!");
451 data.m_StripHitsOnWafer[
strip] = 3;
453 if (noise_expanded_mode) {
454 int noise_tbin = CLHEP::RandFlat::shootInt(rndmEngine, 3);
456 if (noise_tbin == 0) {
460 ATH_MSG_ERROR(
"Can't add noise hit diode to collection (1)");
464 ATH_MSG_ERROR(
"Can't add noise hit diode to collection (2)");
470 return StatusCode::SUCCESS;
477 const int n_chips = 6;
478 const int chipStripmax = strip_max / n_chips;
479 std::vector<float> NOByChipVect(n_chips, 0.0);
480 std::vector<float> ENCByChipVect(n_chips, 0.0);
481 std::vector<int> nNoisyStrips(n_chips, 0);
487 if (noise_expanded_mode) {
496 if (NOByChipVect.empty()) {
497 ATH_MSG_DEBUG(
"No calibration data in cond DB for module " << moduleId <<
" using JO values");
498 if (StatusCode::SUCCESS !=
randomNoise(ctx, collection, moduleId, rndmEngine, data,strip_max)) {
499 return StatusCode::FAILURE;
501 return StatusCode::SUCCESS;
504 for (
int i = 0; i < n_chips; i++) {
510 constexpr float fC = 6242.2;
511 NOByChipVect[i] = NOByChipVect[i] * exp(-(0.5 / (ENCByChipVect[i]*ENCByChipVect[i]) * (
m_Threshold*
m_Threshold - fC*fC)));
514 nNoisyStrips[i] = CLHEP::RandPoisson::shoot(rndmEngine, chipStripmax * NOByChipVect[i] * mode);
519 for (
int chip_index = 0; chip_index < n_chips; ++chip_index) {
520 int chip_strip_offset = chipStripmax * chip_index;
523 int nEmptyStripsOnChip = 0;
524 std::vector<int> emptyStripsOnChip;
525 emptyStripsOnChip.reserve(chipStripmax);
526 for (
int i = 0; i < chipStripmax; i++) {
527 if (data.m_StripHitsOnWafer[i + chip_strip_offset] == 0) {
528 emptyStripsOnChip.push_back(i);
529 ++nEmptyStripsOnChip;
534 if (nEmptyStripsOnChip != 0) {
536 if (nEmptyStripsOnChip < nNoisyStrips[chip_index]) {
537 nNoisyStrips[chip_index] = nEmptyStripsOnChip;
541 for (
int i = 0; i < nNoisyStrips[chip_index]; i++) {
542 int index = CLHEP::RandFlat::shootInt(rndmEngine, nEmptyStripsOnChip - i);
543 int strip_on_chip = emptyStripsOnChip.at(
index);
544 emptyStripsOnChip.erase(emptyStripsOnChip.begin()+
index);
545 int strip = strip_on_chip + chip_strip_offset;
546 if (data.m_StripHitsOnWafer[
strip]!=0) {
547 ATH_MSG_ERROR(
index <<
"-th empty strip, strip " <<
strip <<
" should be empty but is not empty! Something is wrong!");
549 data.m_StripHitsOnWafer[
strip] = 3;
551 if (noise_expanded_mode) {
553 int noise_tbin = CLHEP::RandFlat::shootInt(rndmEngine, 3);
555 if (noise_tbin == 0) {
559 ATH_MSG_ERROR(
"Can't add noise hit diode to collection (3)");
563 ATH_MSG_ERROR(
"Can't add noise hit diode to collection (4)");
570 return StatusCode::SUCCESS;
580 const EventContext& ctx = Gaudi::Hive::currentContext();
590 const int strip_max = p_design->
cells();
592 if (StatusCode::SUCCESS !=
initVectors(strip_max, data)) {
598 data.m_StripHitsOnWafer.assign(strip_max, 0);
606 const int side =
m_sct_id->side(waferId);
609 if (not collection.
empty()) {
612 if (StatusCode::SUCCESS !=
prepareGainAndOffset(ctx, collection, side, moduleId, rndmEngine, data, strip_max)) {
616 if (StatusCode::SUCCESS !=
prepareGainAndOffset(ctx, collection, moduleId, rndmEngine, data,strip_max)) {
636 if (StatusCode::SUCCESS !=
randomNoise(ctx, collection, moduleId, side, rndmEngine, data, strip_max)) {
640 if (StatusCode::SUCCESS !=
randomNoise(ctx, collection, moduleId, rndmEngine, data,strip_max)) {
647 if (StatusCode::SUCCESS !=
doClustering(collection, data,strip_max)) {
667 std::vector<float>
response(bin_max);
671 for (; i_chargedDiode != i_chargedDiode_end; ++i_chargedDiode) {
674 unsigned int flagmask = diode.
flag() & 0xFE;
687 for (
short bin = 0;
bin < bin_max; ++
bin) {
692 for (
short bin = 0;
bin < bin_max; ++
bin) {
693 if (
strip + 1 < strip_max) {
703 for (
short bin = 0;
bin < bin_max; ++
bin) {
708 for (
short bin = 0;
bin < bin_max; ++
bin) {
709 if (
strip + 1 < strip_max) {
724 return StatusCode::SUCCESS;
735 for (; i_chargedDiode != i_chargedDiode_end; ++i_chargedDiode) {
744 data.m_StripHitsOnWafer[
strip] = -1;
745 }
else if (((0x10 & diode.
flag()) == 0x10) or ((0x4 & diode.
flag()) == 0x4)) {
747 data.m_StripHitsOnWafer[
strip] = -1;
749 data.m_StripHitsOnWafer[
strip] = 1;
753 int have_hit_bin = 0;
763 if (((0x10 & diode.
flag()) == 0x10) || ((0x4 & diode.
flag()) == 0x4)) {
765 data.m_StripHitsOnWafer[
strip] = -1;
767 if (have_hit_bin == 2 or have_hit_bin == 3 or have_hit_bin == 6 or have_hit_bin == 7) {
768 data.m_StripHitsOnWafer[
strip] = 1;
772 data.m_StripHitsOnWafer[
strip] = -1;
775 if (have_hit_bin == 2 or have_hit_bin == 3) {
776 data.m_StripHitsOnWafer[
strip] = 1;
780 data.m_StripHitsOnWafer[
strip] = -1;
783 if (have_hit_bin == 0) {
785 data.m_StripHitsOnWafer[
strip] = -1;
787 data.m_StripHitsOnWafer[
strip] = 1;
799 return StatusCode::SUCCESS;
814 if (data.m_StripHitsOnWafer[
strip] != 0) {
817 if (data.m_Analogue[1][
strip] > 0) {
821 data.m_StripHitsOnWafer[
strip] = -2;
823 data.m_StripHitsOnWafer[
strip] = 2;
826 ATH_MSG_ERROR(
"Can't add noise hit diode to collection (5)");
830 int have_hit_bin = 0;
841 if (have_hit_bin == 2 or have_hit_bin == 3 or have_hit_bin == 6 or have_hit_bin == 7) {
842 data.m_StripHitsOnWafer[
strip] = 2;
844 ATH_MSG_ERROR(
"Can't add noise hit diode to collection (6)");
847 data.m_StripHitsOnWafer[
strip] = -2;
850 if (have_hit_bin == 2 or have_hit_bin == 3) {
851 data.m_StripHitsOnWafer[
strip] = 2;
853 ATH_MSG_ERROR(
"Can't add noise hit diode to collection (7)");
856 data.m_StripHitsOnWafer[
strip] = -2;
859 if (have_hit_bin == 0) {
860 data.m_StripHitsOnWafer[
strip] = -2;
862 data.m_StripHitsOnWafer[
strip] = 2;
865 ATH_MSG_ERROR(
"Can't add noise hit diode to collection (8)");
869 ATH_MSG_ERROR(
"Can't add noise hit diode to collection (9)");
878 return StatusCode::SUCCESS;
894 if (data.m_StripHitsOnWafer[
strip] > 0) {
897 int clusterFirstStrip =
strip;
905 int lastStrip1DInRow = 0;
906 for (
int i = 0; i < row + 1; ++i) {
910 while (
strip < lastStrip1DInRow-1 and data.m_StripHitsOnWafer[
strip +1] > 0) {
913 int clusterLastStrip =
strip;
915 clusterSize = (clusterLastStrip - clusterFirstStrip) + 1;
916 hitStrip =
SiCellId(clusterFirstStrip);
921 for (
int i = clusterFirstStrip+1; i <= clusterLastStrip; ++i) {
926 PreviousHitDiode = &HitDiode2;
930 }
while (
strip < strip_max);
936 if (data.m_StripHitsOnWafer[
strip] > 0) {
942 for (
int newStrip=
strip+1; newStrip<strip_max; newStrip++) {
943 if (not (data.m_StripHitsOnWafer[newStrip]>0))
break;
949 previousHitDiode = &newHitDiode;
957 ", HitInfo(1=real, 2=crosstalk, 3=noise): " <<
958 data.m_StripHitsOnWafer[
strip]);
961 strip += clusterSize;
962 }
while (
strip < strip_max);
972 return StatusCode::SUCCESS;
978 collection.
add(ndiode, noiseCharge);
982 if (NoiseDiode ==
nullptr) {
983 return StatusCode::FAILURE;
986 return StatusCode::SUCCESS;
992 float mean_value = 0.0;
995 for (
float calibData : calibDataVect) {
996 if (calibData > 0.1) {
997 mean_value += calibData;
1005 return mean_value / nData;
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_WARNING(x)
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.
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_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.
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)
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...
Tell the compiler to optimize assuming that FP may trap.
#define CXXUTILS_TRAPPING_FP