ATLAS Offline Software
Loading...
Searching...
No Matches
FEI4SimTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3 */
4#include "FEI4SimTool.h"
6
7#include "PixelConditionsData/ChargeCalibParameters.h" //for Thresholds
11
15//
16#include "CLHEP/Random/RandGaussZiggurat.h"
17#include "CLHEP/Random/RandFlat.h"
18#include "PixelNoiseFunctions.h"
19#include <array>
20#include <algorithm>
21
22
23using namespace PixelDigitization;
24
25
26
27namespace{
28 double
29 getSigma(int tot){
30 constexpr std::array<double,17> sigmas{0.0,0.50,0.50,0.50,0.50,0.50,0.60,0.60,0.60,0.60,0.65,0.70,0.75,0.80,0.80,0.80,0.80};
31 return sigmas.at(tot);
32 }
33
34}
35
36
37
38FEI4SimTool::FEI4SimTool(const std::string& type, const std::string& name, const IInterface* parent) :
39 FrontEndSimTool(type, name, parent) {
40}
41
44 ATH_MSG_DEBUG("FEI4SimTool::initialize()");
45 ATH_CHECK(m_moduleDataKey.initialize());
46
47 return StatusCode::SUCCESS;
48}
49
50void FEI4SimTool::process(const EventContext& ctx,
51 SiChargedDiodeCollection& chargedDiodes, PixelRDO_Collection& rdoCollection,
52 CLHEP::HepRandomEngine* rndmEngine) const {
53 const InDetDD::PixelModuleDesign* p_design =
54 static_cast<const InDetDD::PixelModuleDesign*>(&(chargedDiodes.element())->design());
55
57 return;
58 }
59
60 const PixelID* pixelId = static_cast<const PixelID*>(chargedDiodes.element()->getIdHelper());
61 const IdentifierHash moduleHash = pixelId->wafer_hash(chargedDiodes.identify()); // wafer hash
62 Identifier moduleID = pixelId->wafer_id(chargedDiodes.element()->identify());
63
64 int barrel_ec = pixelId->barrel_ec(chargedDiodes.element()->identify());
65 int layerIndex = pixelId->layer_disk(chargedDiodes.element()->identify());
66
67 if (std::abs(barrel_ec) != m_BarrelEC) {
68 return;
69 }
70
72 const PixelModuleData *moduleData = *moduleDataHandle;
74 const PixelChargeCalibCondData *calibData = *calibDataHandle;
75
76 int maxFEI4SmallHit = 2;
77 int overflowToT = calibData->getFEI4OverflowToT();
78
79 std::vector<std::unique_ptr<Pixel1RawData>> p_rdo_small_fei4;
80 int nSmallHitsFEI4 = 0;
81 std::vector<int> row, col;
82 const int maxRow = p_design->rowsPerCircuit();
83 const int maxCol = p_design->columnsPerCircuit();
84 std::vector<std::vector<int> > FEI4Map(maxRow + 16, std::vector<int>(maxCol + 16));
85
86 // Add cross-talk
87 crossTalk(moduleData->getCrossTalk(barrel_ec, layerIndex), chargedDiodes);
88
89 if (m_doNoise) {
90 // Add thermal noise
91 thermalNoise(m_thermalNoise, chargedDiodes, rndmEngine);
92
93 // Add random noise
94 randomNoise(chargedDiodes, moduleData, m_numberOfBcid, calibData, rndmEngine, m_pixelReadout.get());
95 }
96
97 // Add random diabled pixels
98 randomDisable(chargedDiodes, moduleData, rndmEngine); // FIXME How should we handle disabling pixels in Overlay jobs?
99
100 for (SiChargedDiodeOrderedIterator i_chargedDiode = chargedDiodes.orderedBegin();
101 i_chargedDiode != chargedDiodes.orderedEnd(); ++i_chargedDiode) {
102 SiChargedDiode& diode = **i_chargedDiode;
103
104 Identifier diodeID = chargedDiodes.getId(diode.diode());
105 double charge = diode.charge();
106
107 // charge scaling function applied. (Reference: ATL-COM-INDET-2018-052)
108
109 double corrQ = 1.11 *
110 (1.0 - (-7.09 * 1000.0) / (23.72 * 1000.0 + charge) + (-0.22 * 1000.0) /
111 (-0.42 * 1000.0 + charge));
112 if (corrQ < 1.0) {
113 corrQ = 1.0;
114 }
115 charge *= 1.0 / corrQ;
116
117 //could scale if necessary
118
119 unsigned int FE = m_pixelReadout->getFE(diodeID, moduleID);
120 InDetDD::PixelDiodeType type = m_pixelReadout->getDiodeType(diodeID);
121 if ((FE == InDetDD::invalidFrontEnd) or (type == InDetDD::PixelDiodeType::NONE)) continue;//invalid frontend
122
123 // Apply analog threshold, timing simulation
124 const auto & thresholds = calibData->getThresholds(type, moduleHash, FE);
125 double threshold = PixelDigitization::randomThreshold(thresholds, rndmEngine);
126 // This noise check is unaffected by digitizationFlags.doInDetNoise in
127 // 21.0 - see PixelCellDiscriminator.cxx in that branch
128
129 if (charge > threshold) {
130 int bunchSim;
131 if (diode.totalCharge().fromTrack()) {
132 bunchSim =
133 static_cast<int>(std::floor((getG4Time(diode.totalCharge()) +
135 } else {
136 bunchSim = CLHEP::RandFlat::shootInt(rndmEngine, m_numberOfBcid);
137 }
138
139 if (bunchSim < 0 || bunchSim > m_numberOfBcid) {
140 SiHelper::belowThreshold(diode, true, true);
141 } else {
142 SiHelper::SetBunch(diode, bunchSim);
143 }
144 } else {
145 SiHelper::belowThreshold(diode, true, true);
146 }
147
148 // charge to ToT conversion
149 double tot = calibData->getToT(type, moduleHash, FE, charge);
150 double totsig = calibData->getTotRes(moduleHash, FE, tot);
151 int nToT = static_cast<int>(CLHEP::RandGaussZiggurat::shoot(rndmEngine, tot, totsig));
152
153 // This is for new IBL calibration, since above method (stat_cast) is not effective.
154 if (totsig==0.0) {
155 double totIBLsig = getSigma(nToT);
156 if (totIBLsig) {
157 if (CLHEP::RandFlat::shoot(rndmEngine,0.0,1.0)<std::exp(-0.5/totIBLsig/totIBLsig)) {
158 if (CLHEP::RandFlat::shoot(rndmEngine,0.0,1.0)<0.5) { nToT--; }
159 else { nToT++; }
160 }
161 }
162 }
163
164
165
166 // FEI4 HitDiscConfig
167 if (nToT == 2 && maxFEI4SmallHit == 2) {
168 nToT = 1;
169 }
170
171 nToT=std::clamp(nToT, 1, overflowToT);
172
173 if (nToT <= moduleData->getToTThreshold(barrel_ec, layerIndex)) {
174 SiHelper::belowThreshold(diode, true, true);
175 }
176
177 // Filter events
178 if (SiHelper::isMaskOut(diode)) {
179 continue;
180 }
181 if (SiHelper::isDisabled(diode)) {
182 continue;
183 }
184
185 if (!m_pixelConditionsTool->isActive(moduleHash, diodeID, ctx)) {
186 SiHelper::disabled(diode, true, true);
187 continue;
188 }
189
190 int flag = diode.flag();
191 int bunch = (flag >> 8) & 0xff;
192
194 const Identifier id_readout = chargedDiodes.element()->identifierFromCellId(cellId);
195
196 int iirow = cellId.phiIndex();
197 int iicol = cellId.etaIndex();
198 if (iicol >= maxCol) {
199 iicol = iicol - maxCol;
200 } // FEI4 copy mechanism works per FE.
201
202 // Front-End simulation
203 if (bunch >= 0 && bunch < m_numberOfBcid) {
204 auto p_rdo = std::make_unique<Pixel1RawData>(id_readout, nToT, bunch, 0, bunch);
205 if (nToT > maxFEI4SmallHit) {
206 rdoCollection.push_back(p_rdo.release());
207 FEI4Map[iirow][iicol] = 2; //Flag for "big hits"
208 } else {
209 p_rdo_small_fei4.push_back(std::move(p_rdo));
210 row.push_back(iirow);
211 col.push_back(iicol);
212 FEI4Map[iirow][iicol] = 1; //Flag for low hits
213 nSmallHitsFEI4++;
214 }
215 }
216 }
217
218 // Copy mechanism for IBL small hits:
219 if (nSmallHitsFEI4 > 0) {
220 bool recorded = false;
221
222 //First case: Record small hits which are in the same Pixel Digital Region than a big hit:
223 for (int ismall = 0; ismall < nSmallHitsFEI4; ismall++) {
224 int rowPDR = row[ismall] / 2;
225 int colPDR = col[ismall] / 2;
226 for (int rowBigHit = 2 * rowPDR; rowBigHit != 2 * rowPDR + 2 && rowBigHit < maxRow; ++rowBigHit) {
227 for (int colBigHit = 2 * colPDR; colBigHit != 2 * colPDR + 2 && colBigHit < maxCol; ++colBigHit) {
229 "rowBig = " << rowBigHit << " colBig = " << colBigHit << " Map Content = " <<
230 FEI4Map[rowBigHit][colBigHit]);
231 if (FEI4Map[rowBigHit][colBigHit] == 2 && !recorded) {
232 rdoCollection.push_back(p_rdo_small_fei4[ismall].release());
233 recorded = true;
234 }
235 }
236 }
237
238 // Second case: Record small hits which are phi-neighbours with a big hit:
239 if (!recorded && row[ismall] < maxRow - 1) {
240 if (FEI4Map[row[ismall] + 1][col[ismall]] == 2) {
241 rdoCollection.push_back(p_rdo_small_fei4[ismall].release());
242 recorded = true;
243 }
244 }
245 if (!recorded && row[ismall] != 0) {
246 if (FEI4Map[row[ismall] - 1][col[ismall]] == 2) {
247 rdoCollection.push_back(p_rdo_small_fei4[ismall].release());
248 recorded = true;
249 }
250 }
251 }
252 }
253 }
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x)
double charge(const T &p)
Definition AtlasPID.h:997
Structs for holding charge calibration parameterisation and data.
This is an Identifier helper class for the Pixel subdetector.
InDetRawDataCollection< PixelRDORawData > PixelRDO_Collection
SiChargedDiodeOrderedSet::iterator SiChargedDiodeOrderedIterator
value_type push_back(value_type pElem)
virtual void process(const EventContext &ctx, SiChargedDiodeCollection &chargedDiodes, PixelRDO_Collection &rdoCollection, CLHEP::HepRandomEngine *rndmEngine) const override
FEI4SimTool(const std::string &type, const std::string &name, const IInterface *parent)
SG::ReadCondHandleKey< PixelModuleData > m_moduleDataKey
Definition FEI4SimTool.h:32
virtual StatusCode initialize() override
SG::ReadCondHandleKey< PixelChargeCalibCondData > m_chargeDataKey
ServiceHandle< InDetDD::IPixelReadoutManager > m_pixelReadout
virtual StatusCode initialize() override
static constexpr double m_bunchSpace
ToolHandle< IInDetConditionsTool > m_pixelConditionsTool
Gaudi::Property< bool > m_doNoise
Gaudi::Property< int > m_BarrelEC
This is a "hash" representation of an Identifier.
Class used to describe the design of a module (diode segmentation and readout scheme).
PixelReadoutTechnology getReadoutTechnology() const
int rowsPerCircuit() const
Number of cell rows per circuit:
int columnsPerCircuit() const
Number of cell columns per circuit:
int phiIndex() const
Get phi index. Equivalent to strip().
Definition SiCellId.h:122
int etaIndex() const
Get eta index.
Definition SiCellId.h:114
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...
constexpr int getFEI4OverflowToT() const
PixelChargeCalib::Thresholds getThresholds(InDetDD::PixelDiodeType type, unsigned int moduleHash, unsigned int FE) const
float getToT(InDetDD::PixelDiodeType type, unsigned int moduleHash, unsigned int FE, float Q) const
float getTotRes(unsigned int moduleHash, unsigned int FE, float Q) const
This is an Identifier helper class for the Pixel subdetector.
Definition PixelID.h:69
int layer_disk(const Identifier &id) const
Definition PixelID.h:602
Identifier wafer_id(int barrel_ec, int layer_disk, int phi_module, int eta_module) const
For a single crystal.
Definition PixelID.h:355
int barrel_ec(const Identifier &id) const
Values of different levels (failure returns 0).
Definition PixelID.h:595
IdentifierHash wafer_hash(Identifier wafer_id) const
wafer hash from id
Definition PixelID.h:378
double getCrossTalk(int barrel_ec, int layer) const
virtual Identifier identify() const override final
SiChargedDiodeOrderedIterator orderedEnd()
SiChargedDiodeOrderedIterator orderedBegin()
Identifier getId(const InDetDD::SiCellId &id) const
const InDetDD::SolidStateDetectorElementBase * element() const
const InDetDD::SiCellId & diode() const
int flag() const
double charge() const
const SiTotalCharge & totalCharge() const
const InDetDD::SiReadoutCellId & getReadoutCell() const
static bool isMaskOut(SiChargedDiode &chDiode)
Definition SiHelper.h:171
static void SetBunch(SiChargedDiode &chDiode, int bunch, MsgStream *log=nullptr)
Definition SiHelper.h:129
static void disabled(SiChargedDiode &chDiode, bool flag, bool mask=false)
Definition SiHelper.h:93
static void belowThreshold(SiChargedDiode &chDiode, bool flag, bool mask=false)
Definition SiHelper.h:84
static bool isDisabled(SiChargedDiode &chDiode)
Definition SiHelper.h:179
bool fromTrack() const
static std::string release
Definition computils.h:50
constexpr uint32_t invalidFrontEnd
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)
double randomThreshold(const PixelChargeCalib::Thresholds &t, CLHEP::HepRandomEngine *pEngine)
void randomNoise(SiChargedDiodeCollection &chargedDiodes, const PixelModuleData *moduleData, int nBcid, const PixelChargeCalibCondData *chargeCalibData, CLHEP::HepRandomEngine *rndmEngine, InDetDD::IPixelReadoutManager *pixelReadout)
double getG4Time(const SiTotalCharge &totalCharge)