ATLAS Offline Software
Loading...
Searching...
No Matches
PixelNoiseFunctions.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include "CLHEP/Random/RandomEngine.h"
8#include "CLHEP/Random/RandGaussZiggurat.h"
9#include "CLHEP/Random/RandFlat.h"
10#include "CLHEP/Random/RandPoisson.h"
11
14
22
23#include <limits>
24
25
26namespace PixelDigitization{
27 void
29 const InDetDD::PixelModuleDesign* p_design =
30 static_cast<const InDetDD::PixelModuleDesign*>(&(chargedDiodes.element())->design());
31 SiChargedDiodeMap oldChargedDiodes = chargedDiodes.chargedDiodes();
32
33 for (SiChargedDiodeIterator i_chargedDiode = oldChargedDiodes.begin(); i_chargedDiode != oldChargedDiodes.end();
34 ++i_chargedDiode) {
35 InDetDD::SiCellId diode = (*i_chargedDiode).second.diode();
36 std::vector<InDetDD::SiCellId> neighbours;
37 p_design->neighboursOfCell(diode, neighbours);
38 for (std::vector<InDetDD::SiCellId>::const_iterator p_neighbour = neighbours.begin();
39 p_neighbour != neighbours.end(); ++p_neighbour) {
40 const double intersection = p_design->intersectionLength(diode, *p_neighbour);
41 // add cross talk only if the intersection is non-zero
42 // if the original pixel is at (col,row) then the intersection length is
43 // (col+-1, row+-1) : 0 -> diagonal
44 // (col , row+-1) : 0.4 mm (or 0.6 if long pixel) pixel width = 400um or 600um
45 // (col+-1, row ) : 0.05 mm , pixel height = 50um
46 // intersection length is just the length of the contact surface between the two pixels
47 if (intersection > 0) {
48 // create a new charge:
49 // Q(new) = Q*L*X
50 // Q = charge of source pixel
51 // L = intersection length [mm]
52 // X = crosstalk factor [mm-1]
53 const SiChargedDiode& siCharge = (*i_chargedDiode).second;
56 chargedDiodes.add(*p_neighbour, charge);
57 }
58 }
59 }
60 return;
61 }
62
63 void
65 CLHEP::HepRandomEngine* rndmEngine) {
66 for (SiChargedDiodeOrderedIterator i_chargedDiode = chargedDiodes.orderedBegin();
67 i_chargedDiode != chargedDiodes.orderedEnd(); ++i_chargedDiode) {
68 SiCharge charge(thermalNoise * CLHEP::RandGaussZiggurat::shoot(rndmEngine), 0, SiCharge::noise);
69 (*i_chargedDiode)->add(charge);
70 }
71 return;
72 }
73
74
75 void
76 randomNoise(SiChargedDiodeCollection& chargedDiodes, const PixelModuleData *moduleData,
77 int nBcid,
78 const PixelChargeCalibCondData *chargeCalibData, CLHEP::HepRandomEngine* rndmEngine,
79 InDetDD::IPixelReadoutManager * pixelReadout) {
80 const InDetDD::PixelModuleDesign* p_design =
81 static_cast<const InDetDD::PixelModuleDesign*>(&(chargedDiodes.element())->design());
82
83 const PixelID* pixelId = static_cast<const PixelID*>(chargedDiodes.element()->getIdHelper());
84 int barrel_ec = pixelId->barrel_ec(chargedDiodes.element()->identify());
85 int layerIndex = pixelId->layer_disk(chargedDiodes.element()->identify());
86 const double totalNoiseOccupancy = moduleData->getNoiseOccupancy(barrel_ec,layerIndex) * nBcid;
87 //prepare to enter loop
88 const std::vector<float> &noiseShape = moduleData->getNoiseShape(barrel_ec, layerIndex);
89 const auto technology = p_design->getReadoutTechnology();
90 // protection to the overflow ToT, that depends on the sensor technology
91 float overflowToT = std::numeric_limits<float>::max();
92 if (technology == InDetDD::PixelReadoutTechnology::FEI4) {
93 overflowToT = chargeCalibData->getFEI4OverflowToT();
94 } else if (technology == InDetDD::PixelReadoutTechnology::FEI3) {
95 overflowToT = moduleData->getFEI3Latency(barrel_ec, layerIndex);
96 }
97 return randomNoise(chargedDiodes, totalNoiseOccupancy, noiseShape, overflowToT, chargeCalibData, rndmEngine, pixelReadout);
98 }
99
100 void
102 int nBcid,
103 const PixelChargeCalibCondData *chargeCalibData, CLHEP::HepRandomEngine* rndmEngine,
104 InDetDD::IPixelReadoutManager * pixelReadout) {
105 const double totalNoiseOccupancy = chipData.noiseOccupancy() * nBcid;
106 //prepare to enter loop
107 const std::vector<float> &noiseShape = chipData.noiseShape();
108 // protection to the overflow ToT, that depends on the sensor technology
109 float overflowToT = std::numeric_limits<float>::max();
110 return randomNoise(chargedDiodes, totalNoiseOccupancy, noiseShape, overflowToT, chargeCalibData, rndmEngine, pixelReadout);
111 }
112
113
114 void
115 randomNoise(SiChargedDiodeCollection& chargedDiodes, const double totalNoiseOccupancy, const std::vector<float> &noiseShape, float overflowToT,
116 const PixelChargeCalibCondData *chargeCalibData, CLHEP::HepRandomEngine* rndmEngine, InDetDD::IPixelReadoutManager * pixelReadout){
117 const InDetDD::PixelModuleDesign* p_design =
118 static_cast<const InDetDD::PixelModuleDesign*>(&(chargedDiodes.element())->design());
119
120 const PixelID* pixelId = static_cast<const PixelID*>(chargedDiodes.element()->getIdHelper());
121 const IdentifierHash moduleHash = pixelId->wafer_hash(chargedDiodes.identify()); // wafer hash
122 const auto nCircuits = p_design->numberOfCircuits();
123 const auto nColumns = p_design->columnsPerCircuit();
124 const auto nRows = p_design->rowsPerCircuit();
125 const auto totalCells = nCircuits * nColumns * nRows;
126 int nNoise = CLHEP::RandPoisson::shoot(rndmEngine, totalCells * totalNoiseOccupancy);
127 //prepare to enter loop
128 const auto technology = p_design->getReadoutTechnology();
129 for (int i = 0; i < nNoise; i++) {
130 int circuit = CLHEP::RandFlat::shootInt(rndmEngine, nCircuits);
131 int column = CLHEP::RandFlat::shootInt(rndmEngine, nColumns);
132 int row = CLHEP::RandFlat::shootInt(rndmEngine, nRows);
133 if (row > 159 && technology == InDetDD::PixelReadoutTechnology::FEI3) {
134 row += 8;
135 } // jump over ganged pixels - rowsPerCircuit == 320 above
136
137 InDetDD::SiReadoutCellId roCell(row, nColumns * circuit + column);
138 Identifier noisyID = chargedDiodes.element()->identifierFromCellId(roCell);
139
140 if (roCell.isValid()) {
141 InDetDD::SiCellId diodeNoise = roCell;
142 float x = static_cast<float>(CLHEP::RandFlat::shoot(rndmEngine, 0., 1.)); // returns double
143 size_t bin{};
144 for (size_t j = 1; j < noiseShape.size(); j++) {
145 if (x > noiseShape[j - 1] && x <= noiseShape[j]) {
146 bin = j - 1;
147 break;
148 }
149 }
150 float noiseToTm = bin + 1.5f;
151 float noiseToT = CLHEP::RandGaussZiggurat::shoot(rndmEngine, noiseToTm, 1.f);
152 if (noiseToT < 1.f) { continue; } // throw away unphysical noise
153 noiseToT = std::min(noiseToT, overflowToT);
154 InDetDD::PixelDiodeType type = pixelReadout->getDiodeType(noisyID);
155 if (type == InDetDD::PixelDiodeType::NONE) continue;
156 float chargeShape = chargeCalibData->getCharge(type, moduleHash, circuit, noiseToT);
157 chargedDiodes.add(diodeNoise, SiCharge(chargeShape, 0, SiCharge::noise));
158 }
159 }
160 return;
161 }
162
163 void
165 CLHEP::HepRandomEngine* rndmEngine) {
166 const PixelID* pixelId = static_cast<const PixelID*>(chargedDiodes.element()->getIdHelper());
167 const int barrel_ec = pixelId->barrel_ec(chargedDiodes.element()->identify());
168 const int layerIndex = pixelId->layer_disk(chargedDiodes.element()->identify());
169 const double disableProbability = moduleData->getDisableProbability(barrel_ec, layerIndex);
170 return randomDisable(chargedDiodes, disableProbability, rndmEngine);
171 }
172 void
174 CLHEP::HepRandomEngine* rndmEngine) {
175 const double disableProbability = chipData.disableProbability();
176 return randomDisable(chargedDiodes, disableProbability, rndmEngine);
177 }
178
179 void
180 randomDisable(SiChargedDiodeCollection& chargedDiodes, double disableProbability,
181 CLHEP::HepRandomEngine* rndmEngine){
182 for (SiChargedDiodeOrderedIterator i_chargedDiode = chargedDiodes.orderedBegin();
183 i_chargedDiode != chargedDiodes.orderedEnd(); ++i_chargedDiode) {
184 if (CLHEP::RandFlat::shoot(rndmEngine) < disableProbability) {
185 SiHelper::disabled(**i_chargedDiode, true, false);
186 }
187 }
188 return;
189 }
190
191 int
192 generateToT(CLHEP::HepRandomEngine* rndmEngine, double mean, double sd, const std::pair<int, int>& range){
193 int nToT = static_cast<int>(CLHEP::RandGaussZiggurat::shoot(rndmEngine, mean, sd));
194 const auto &[lo,hi] = range;
195 //
196 if (nToT < lo) {
197 nToT = lo;
198 }
199 if (nToT >= hi) {
200 nToT = hi;
201 }
202 return nToT;
203 }
204
205 double
206 getG4Time(const SiTotalCharge& totalCharge) {
207 // If there is one single charge, return its time:
208 if (totalCharge.chargeComposition().empty()) {
209 return totalCharge.time();
210 }
211 auto p_charge = totalCharge.chargeComposition().begin();
212 int findfirst = 0;
213 SiCharge first = *p_charge;
214 // Look for first charge which is not noise
215 for (; p_charge != totalCharge.chargeComposition().end(); p_charge++) {
216 if (p_charge->processType() != SiCharge::noise) {
217 findfirst = 1;
218 break;
219 }
220 }
221 // if all charges were noise, return the time of the highest charge
222 if (findfirst == 0) {
223 return totalCharge.time();
224 }
225 // look for the earliest charge among the remaining non-noise charges:
226 first = *p_charge;
227 p_charge++;
228 for (; p_charge != totalCharge.chargeComposition().end(); p_charge++) {
229 if (p_charge->time() < first.time() && p_charge->processType() != SiCharge::noise) {
230 first = *p_charge;
231 }
232 }
233 return first.time();
234 }
235}
double charge(const T &p)
Definition AtlasPID.h:997
Simple data class for holding constants for use in the ITkPixV2 Chip simulation.
This is an Identifier helper class for the Pixel subdetector.
Store pixel constant parameters in PixelModuleData.
SiChargedDiodeMap::iterator SiChargedDiodeIterator
std::unordered_map< InDetDD::SiCellId, SiChargedDiode, SiChargedDiodeHash, std::equal_to< InDetDD::SiCellId >, SG::ArenaPoolSTLAllocator< std::pair< const InDetDD::SiCellId, SiChargedDiode > > > SiChargedDiodeMap
SiChargedDiodeOrderedSet::iterator SiChargedDiodeOrderedIterator
#define x
const std::vector< float > & noiseShape() const
This is a "hash" representation of an Identifier.
virtual PixelDiodeType getDiodeType(Identifier id) const =0
Class used to describe the design of a module (diode segmentation and readout scheme)
double intersectionLength(const SiCellId &diode1, const SiCellId &diode2) const
Compute the intersection length of two diodes: return: the intersection length when the two diodes ar...
PixelReadoutTechnology getReadoutTechnology() const
virtual void neighboursOfCell(const SiCellId &cellId, std::vector< SiCellId > &neighbours) const
Get the neighbouring diodes of a given diode: Cell for which the neighbours must be found List of cel...
int rowsPerCircuit() const
Number of cell rows per circuit:
int numberOfCircuits() const
Total number of circuits:
int columnsPerCircuit() const
Number of cell columns per circuit:
Identifier for the strip or pixel cell.
Definition SiCellId.h:29
bool isValid() const
Test if its in a valid state.
Definition SiCellId.h:136
Identifier for the strip or pixel readout cell.
virtual Identifier identify() const override final
identifier of this detector element (inline)
virtual Identifier identifierFromCellId(const SiCellId &cellId) const =0
Identifier <-> SiCellId (ie strip number or pixel eta_index,phi_index) Identifier from SiCellId (ie s...
float getCharge(InDetDD::PixelDiodeType type, unsigned int moduleHash, unsigned int FE, float ToT) const
constexpr int getFEI4OverflowToT() const
This is an Identifier helper class for the Pixel subdetector.
Definition PixelID.h:67
int layer_disk(const Identifier &id) const
Definition PixelID.h:607
int barrel_ec(const Identifier &id) const
Values of different levels (failure returns 0)
Definition PixelID.h:600
IdentifierHash wafer_hash(Identifier wafer_id) const
wafer hash from id
Definition PixelID.h:383
int getFEI3Latency(int barrel_ec, int layer) const
const std::vector< float > & getNoiseShape(int barrel_ec, int layer) const
double getNoiseOccupancy(int barrel_ec, int layer) const
double getDisableProbability(int barrel_ec, int layer) const
@ diodeX_Talk
Definition SiCharge.h:28
virtual Identifier identify() const override final
SiChargedDiodeMap & chargedDiodes()
SiChargedDiodeOrderedIterator orderedEnd()
SiChargedDiodeOrderedIterator orderedBegin()
const InDetDD::SolidStateDetectorElementBase * element() const
void add(const InDetDD::SiCellId &diode, const T &charge)
double charge() const
const SiTotalCharge & totalCharge() const
static void disabled(SiChargedDiode &chDiode, bool flag, bool mask=false)
Definition SiHelper.h:93
const HepMcParticleLink & particleLink() const
const list_t & chargeComposition() const
double time() const
std::vector< std::string > intersection(std::vector< std::string > &v1, std::vector< std::string > &v2)
void mean(std::vector< double > &bins, std::vector< double > &values, const std::vector< std::string > &files, const std::string &histname, const std::string &tplotname, const std::string &label="")
void randomDisable(SiChargedDiodeCollection &chargedDiodes, const PixelModuleData *moduleData, CLHEP::HepRandomEngine *rndmEngine)
void crossTalk(double crossTalk, SiChargedDiodeCollection &chargedDiodes)
void thermalNoise(double thermalNoise, SiChargedDiodeCollection &chargedDiodes, CLHEP::HepRandomEngine *rndmEngine)
void randomNoise(SiChargedDiodeCollection &chargedDiodes, const PixelModuleData *moduleData, int nBcid, const PixelChargeCalibCondData *chargeCalibData, CLHEP::HepRandomEngine *rndmEngine, InDetDD::IPixelReadoutManager *pixelReadout)
int generateToT(CLHEP::HepRandomEngine *rndmEngine, double mean, double sd, const std::pair< int, int > &range)
double getG4Time(const SiTotalCharge &totalCharge)