ATLAS Offline Software
Loading...
Searching...
No Matches
FEI4SimTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 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
43
46 ATH_MSG_DEBUG("FEI4SimTool::initialize()");
47 ATH_CHECK(m_moduleDataKey.initialize());
48
49 return StatusCode::SUCCESS;
50}
51
53 ATH_MSG_DEBUG("FEI4SimTool::finalize()");
54 return StatusCode::SUCCESS;
55}
56
58 CLHEP::HepRandomEngine* rndmEngine) const {
59 const InDetDD::PixelModuleDesign* p_design =
60 static_cast<const InDetDD::PixelModuleDesign*>(&(chargedDiodes.element())->design());
61
63 return;
64 }
65
66 const PixelID* pixelId = static_cast<const PixelID*>(chargedDiodes.element()->getIdHelper());
67 const IdentifierHash moduleHash = pixelId->wafer_hash(chargedDiodes.identify()); // wafer hash
68 Identifier moduleID = pixelId->wafer_id(chargedDiodes.element()->identify());
69
70 int barrel_ec = pixelId->barrel_ec(chargedDiodes.element()->identify());
71 int layerIndex = pixelId->layer_disk(chargedDiodes.element()->identify());
72
73 if (std::abs(barrel_ec) != m_BarrelEC) {
74 return;
75 }
76
77 const EventContext& ctx{Gaudi::Hive::currentContext()};
79 const PixelModuleData *moduleData = *moduleDataHandle;
81 const PixelChargeCalibCondData *calibData = *calibDataHandle;
82
83 int maxFEI4SmallHit = 2;
84 int overflowToT = calibData->getFEI4OverflowToT();
85
86 std::vector<std::unique_ptr<Pixel1RawData>> p_rdo_small_fei4;
87 int nSmallHitsFEI4 = 0;
88 std::vector<int> row, col;
89 const int maxRow = p_design->rowsPerCircuit();
90 const int maxCol = p_design->columnsPerCircuit();
91 std::vector<std::vector<int> > FEI4Map(maxRow + 16, std::vector<int>(maxCol + 16));
92
93 // Add cross-talk
94 crossTalk(moduleData->getCrossTalk(barrel_ec, layerIndex), chargedDiodes);
95
96 if (m_doNoise) {
97 // Add thermal noise
98 thermalNoise(m_thermalNoise, chargedDiodes, rndmEngine);
99
100 // Add random noise
101 randomNoise(chargedDiodes, moduleData, m_numberOfBcid, calibData, rndmEngine, m_pixelReadout.get());
102 }
103
104 // Add random diabled pixels
105 randomDisable(chargedDiodes, moduleData, rndmEngine); // FIXME How should we handle disabling pixels in Overlay jobs?
106
107 for (SiChargedDiodeOrderedIterator i_chargedDiode = chargedDiodes.orderedBegin();
108 i_chargedDiode != chargedDiodes.orderedEnd(); ++i_chargedDiode) {
109 SiChargedDiode& diode = **i_chargedDiode;
110
111 Identifier diodeID = chargedDiodes.getId(diode.diode());
112 double charge = diode.charge();
113
114 // charge scaling function applied. (Reference: ATL-COM-INDET-2018-052)
115
116 double corrQ = 1.11 *
117 (1.0 - (-7.09 * 1000.0) / (23.72 * 1000.0 + charge) + (-0.22 * 1000.0) /
118 (-0.42 * 1000.0 + charge));
119 if (corrQ < 1.0) {
120 corrQ = 1.0;
121 }
122 charge *= 1.0 / corrQ;
123
124 //could scale if necessary
125
126 unsigned int FE = m_pixelReadout->getFE(diodeID, moduleID);
127 InDetDD::PixelDiodeType type = m_pixelReadout->getDiodeType(diodeID);
128 if ((FE == InDetDD::invalidFrontEnd) or (type == InDetDD::PixelDiodeType::NONE)) continue;//invalid frontend
129
130 // Apply analog threshold, timing simulation
131 const auto & thresholds = calibData->getThresholds(type, moduleHash, FE);
132 double threshold = PixelDigitization::randomThreshold(thresholds, rndmEngine);
133 // This noise check is unaffected by digitizationFlags.doInDetNoise in
134 // 21.0 - see PixelCellDiscriminator.cxx in that branch
135
136 if (charge > threshold) {
137 int bunchSim;
138 if (diode.totalCharge().fromTrack()) {
139 bunchSim =
140 static_cast<int>(std::floor((getG4Time(diode.totalCharge()) +
142 } else {
143 bunchSim = CLHEP::RandFlat::shootInt(rndmEngine, m_numberOfBcid);
144 }
145
146 if (bunchSim < 0 || bunchSim > m_numberOfBcid) {
147 SiHelper::belowThreshold(diode, true, true);
148 } else {
149 SiHelper::SetBunch(diode, bunchSim);
150 }
151 } else {
152 SiHelper::belowThreshold(diode, true, true);
153 }
154
155 // charge to ToT conversion
156 double tot = calibData->getToT(type, moduleHash, FE, charge);
157 double totsig = calibData->getTotRes(moduleHash, FE, tot);
158 int nToT = static_cast<int>(CLHEP::RandGaussZiggurat::shoot(rndmEngine, tot, totsig));
159
160 // This is for new IBL calibration, since above method (stat_cast) is not effective.
161 if (totsig==0.0) {
162 double totIBLsig = getSigma(nToT);
163 if (totIBLsig) {
164 if (CLHEP::RandFlat::shoot(rndmEngine,0.0,1.0)<std::exp(-0.5/totIBLsig/totIBLsig)) {
165 if (CLHEP::RandFlat::shoot(rndmEngine,0.0,1.0)<0.5) { nToT--; }
166 else { nToT++; }
167 }
168 }
169 }
170
171
172
173 // FEI4 HitDiscConfig
174 if (nToT == 2 && maxFEI4SmallHit == 2) {
175 nToT = 1;
176 }
177
178 nToT=std::clamp(nToT, 1, overflowToT);
179
180 if (nToT <= moduleData->getToTThreshold(barrel_ec, layerIndex)) {
181 SiHelper::belowThreshold(diode, true, true);
182 }
183
184 // Filter events
185 if (SiHelper::isMaskOut(diode)) {
186 continue;
187 }
188 if (SiHelper::isDisabled(diode)) {
189 continue;
190 }
191
192 if (!m_pixelConditionsTool->isActive(moduleHash, diodeID, ctx)) {
193 SiHelper::disabled(diode, true, true);
194 continue;
195 }
196
197 int flag = diode.flag();
198 int bunch = (flag >> 8) & 0xff;
199
201 const Identifier id_readout = chargedDiodes.element()->identifierFromCellId(cellId);
202
203 int iirow = cellId.phiIndex();
204 int iicol = cellId.etaIndex();
205 if (iicol >= maxCol) {
206 iicol = iicol - maxCol;
207 } // FEI4 copy mechanism works per FE.
208
209 // Front-End simulation
210 if (bunch >= 0 && bunch < m_numberOfBcid) {
211 auto p_rdo = std::make_unique<Pixel1RawData>(id_readout, nToT, bunch, 0, bunch);
212 if (nToT > maxFEI4SmallHit) {
213 rdoCollection.push_back(p_rdo.release());
214 FEI4Map[iirow][iicol] = 2; //Flag for "big hits"
215 } else {
216 p_rdo_small_fei4.push_back(std::move(p_rdo));
217 row.push_back(iirow);
218 col.push_back(iicol);
219 FEI4Map[iirow][iicol] = 1; //Flag for low hits
220 nSmallHitsFEI4++;
221 }
222 }
223 }
224
225 // Copy mechanism for IBL small hits:
226 if (nSmallHitsFEI4 > 0) {
227 bool recorded = false;
228
229 //First case: Record small hits which are in the same Pixel Digital Region than a big hit:
230 for (int ismall = 0; ismall < nSmallHitsFEI4; ismall++) {
231 int rowPDR = row[ismall] / 2;
232 int colPDR = col[ismall] / 2;
233 for (int rowBigHit = 2 * rowPDR; rowBigHit != 2 * rowPDR + 2 && rowBigHit < maxRow; ++rowBigHit) {
234 for (int colBigHit = 2 * colPDR; colBigHit != 2 * colPDR + 2 && colBigHit < maxCol; ++colBigHit) {
236 "rowBig = " << rowBigHit << " colBig = " << colBigHit << " Map Content = " <<
237 FEI4Map[rowBigHit][colBigHit]);
238 if (FEI4Map[rowBigHit][colBigHit] == 2 && !recorded) {
239 rdoCollection.push_back(p_rdo_small_fei4[ismall].release());
240 recorded = true;
241 }
242 }
243 }
244
245 // Second case: Record small hits which are phi-neighbours with a big hit:
246 if (!recorded && row[ismall] < maxRow - 1) {
247 if (FEI4Map[row[ismall] + 1][col[ismall]] == 2) {
248 rdoCollection.push_back(p_rdo_small_fei4[ismall].release());
249 recorded = true;
250 }
251 }
252 if (!recorded && row[ismall] != 0) {
253 if (FEI4Map[row[ismall] - 1][col[ismall]] == 2) {
254 rdoCollection.push_back(p_rdo_small_fei4[ismall].release());
255 recorded = true;
256 }
257 }
258 }
259 }
260 }
#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 StatusCode initialize()
SG::ReadCondHandleKey< PixelModuleData > m_moduleDataKey
Definition FEI4SimTool.h:33
virtual StatusCode finalize()
virtual void process(SiChargedDiodeCollection &chargedDiodes, PixelRDO_Collection &rdoCollection, CLHEP::HepRandomEngine *rndmEngine) const
virtual ~FEI4SimTool()
SG::ReadCondHandleKey< PixelChargeCalibCondData > m_chargeDataKey
ServiceHandle< InDetDD::IPixelReadoutManager > m_pixelReadout
virtual StatusCode initialize() override
FrontEndSimTool(const std::string &type, const std::string &name, const IInterface *parent)
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:67
int layer_disk(const Identifier &id) const
Definition PixelID.h:607
Identifier wafer_id(int barrel_ec, int layer_disk, int phi_module, int eta_module) const
For a single crystal.
Definition PixelID.h:360
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
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)