ATLAS Offline Software
Loading...
Searching...
No Matches
FEI3SimTool.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 "FEI3SimTool.h"
7#include "PixelConditionsData/ChargeCalibParameters.h" //for Thresholds
13//
14#include "CLHEP/Random/RandGaussZiggurat.h"
15#include "CLHEP/Random/RandFlat.h"
16
17#include <cmath>
18#include "PixelNoiseFunctions.h"
19
20using namespace PixelDigitization;
21
22
23FEI3SimTool::FEI3SimTool(const std::string& type, const std::string& name, const IInterface* parent) :
24 FrontEndSimTool(type, name, parent) {
25}
26
28
31 ATH_MSG_DEBUG("FEI3SimTool::initialize()");
32 ATH_CHECK(m_moduleDataKey.initialize());
33 return StatusCode::SUCCESS;
34}
35
37 ATH_MSG_DEBUG("FEI3SimTool::finalize()");
38 return StatusCode::SUCCESS;
39}
40
42 CLHEP::HepRandomEngine* rndmEngine) const {
43 const InDetDD::PixelModuleDesign* p_design =
44 static_cast<const InDetDD::PixelModuleDesign*>(&(chargedDiodes.element())->design());
45
47 return;
48 }
49
50 const PixelID* pixelId = static_cast<const PixelID*>(chargedDiodes.element()->getIdHelper());
51 const IdentifierHash moduleHash = pixelId->wafer_hash(chargedDiodes.identify()); // wafer hash
52 Identifier moduleID = pixelId->wafer_id(chargedDiodes.element()->identify());
53
54 int barrel_ec = pixelId->barrel_ec(chargedDiodes.element()->identify());
55 int layerIndex = pixelId->layer_disk(chargedDiodes.element()->identify());
56 int moduleIndex = pixelId->eta_module(chargedDiodes.element()->identify());
57
58 if (std::abs(barrel_ec) != m_BarrelEC) {
59 return;
60 }
61
62 const EventContext& ctx{Gaudi::Hive::currentContext()};
64 const PixelModuleData *moduleData = *moduleDataHandle;
66 const PixelChargeCalibCondData *calibData = *calibDataHandle;
67 const auto selectedTuneYear = moduleData->getFEI3TimingSimTune(barrel_ec, layerIndex);
68 // Add cross-talk
69 crossTalk(moduleData->getCrossTalk(barrel_ec, layerIndex), chargedDiodes);
70
71 if (m_doNoise) {
72 // Add thermal noise
73 thermalNoise(m_thermalNoise, chargedDiodes, rndmEngine);
74
75 // Add random noise
76 randomNoise(chargedDiodes, moduleData, m_numberOfBcid, calibData, rndmEngine, m_pixelReadout.get());
77 }
78
79 // Add random diabled pixels
80 randomDisable(chargedDiodes, moduleData, rndmEngine); // FIXME How should we handle disabling pixels in Overlay jobs?
81 const InDetDD::SiDetectorElement * siDetEl = static_cast<const InDetDD::SiDetectorElement *>(chargedDiodes.element());
82 for (auto &[mapId,mapDiode]:chargedDiodes) {
83 // Merge ganged pixel
84 InDetDD::SiCellId cellID = chargedDiodes.element()->cellIdFromIdentifier(chargedDiodes.getId( mapId));
85 InDetDD::SiCellId gangedCell = siDetEl->gangedCell(cellID);
86 Identifier gangedID = chargedDiodes.element()->identifierFromCellId(gangedCell);
87 if (gangedCell.isValid()) {
88 SiChargedDiode* gangedChargeDiode = chargedDiodes.find(gangedID);
89 int phiGanged = pixelId->phi_index(gangedID);
90 int phiThis = pixelId->phi_index(chargedDiodes.getId( mapId));
91
92 if (gangedChargeDiode) { // merge charges
93 bool maskGanged = ((phiGanged > 159) && (phiGanged < 168));
94 bool maskThis = ((phiThis > 159) && (phiThis < 168));
95 // mask the one ganged pixel that does not correspond to the readout electronics.
96 // not really sure this is needed
97 if (maskGanged && maskThis) {
98 ATH_MSG_ERROR("FEI3SimTool: both ganged pixels are in the mask out region -> BUG!");
99 }
100 if (maskGanged) {
101 mapDiode.add(gangedChargeDiode->totalCharge()); // merged org pixel
102 SiHelper::maskOut(*gangedChargeDiode, true);
103 } else {
104 gangedChargeDiode->add(mapDiode.totalCharge()); // merged org pixel
105 SiHelper::maskOut(mapDiode, true);
106 }
107 }
108 }
109 }
110
111 for (SiChargedDiodeOrderedIterator i_chargedDiode = chargedDiodes.orderedBegin();
112 i_chargedDiode != chargedDiodes.orderedEnd(); ++i_chargedDiode) {
113 SiChargedDiode& diode = **i_chargedDiode;
114
115 Identifier diodeID = chargedDiodes.getId(diode.diode());
116 double charge = diode.charge();
117
118 unsigned int FE = m_pixelReadout->getFE(diodeID, moduleID);
119 InDetDD::PixelDiodeType type = m_pixelReadout->getDiodeType(diodeID);
120 if ((FE == InDetDD::invalidFrontEnd) or (type == InDetDD::PixelDiodeType::NONE)) continue;//invalid frontend
121
122 // charge to ToT conversion
123 double tot = calibData->getToT(type, moduleHash, FE, charge);
124 const auto thresholds = calibData->getThresholds(type, moduleHash, FE);
125 // Apply analog threshold, timing simulation
126 double th0 = thresholds.value;
127 double ith0 = thresholds.inTimeValue;
128 double threshold = PixelDigitization::randomThreshold(thresholds, rndmEngine);
129 // This noise check is unaffected by digitizationFlags.doInDetNoise in
130 // 21.0 - see PixelCellDiscriminator.cxx in that branch
131
132 if (charge > threshold) {
133 int bunchSim = 0;
134 if (diode.totalCharge().fromTrack()) {
135 const std::vector<float> & totCharges = moduleData->getTimingIndex(barrel_ec, layerIndex);
136 const std::vector<float> & probArray = moduleData->getTimingProbability(barrel_ec, layerIndex, moduleIndex);
137
138 double prob = 0.0;
139 if (selectedTuneYear==2023) { prob = getProbability(totCharges, probArray, tot); }
140 if (selectedTuneYear==2022) { prob = getProbability(totCharges, probArray, tot); }
141 if (selectedTuneYear==2018) { prob = getProbability(totCharges, probArray, diode.totalCharge().charge()); }
142 if (selectedTuneYear==2015) { prob = getProbability(totCharges, probArray, diode.totalCharge().charge()); }
143
144 double G4Time = getG4Time(diode.totalCharge());
145 double rnd = CLHEP::RandFlat::shoot(rndmEngine, 0.0, 1.0);
146
147 double timeWalk = 0.0;
148 if (rnd<prob) { timeWalk = 25.0; }
149 bunchSim = static_cast<int>(std::floor((G4Time+m_timeOffset+timeWalk)/m_bunchSpace));
150
151 if (selectedTuneYear == 2009) { // RUN1 procedure (based on 2007 cosmic data)
152 double intimethreshold = (ith0 / th0) * threshold;
153 bunchSim = relativeBunch2009(threshold, intimethreshold, diode.totalCharge(), rndmEngine);
154 }
155 }
156 else {
157 if (moduleData->getFEI3TimingSimTune(barrel_ec, layerIndex) > 0) {
158 bunchSim = CLHEP::RandFlat::shootInt(rndmEngine, m_numberOfBcid);
159 }
160 }
161
162 if (bunchSim < 0 || bunchSim > m_numberOfBcid) {
163 SiHelper::belowThreshold(diode, true, true);
164 } else {
165 SiHelper::SetBunch(diode, bunchSim);
166 }
167 } else {
168 SiHelper::belowThreshold(diode, true, true);
169 }
170
171 double totsig = calibData->getTotRes(moduleHash, FE, tot);
172 int nToT = static_cast<int>(CLHEP::RandGaussZiggurat::shoot(rndmEngine, tot, totsig));
173
174 if (nToT < 1) {
175 nToT = 1;
176 }
177
178 if (nToT <= moduleData->getToTThreshold(barrel_ec, layerIndex)) {
179 SiHelper::belowThreshold(diode, true, true);
180 }
181
182 if (nToT >= moduleData->getFEI3Latency(barrel_ec, layerIndex)) {
183 SiHelper::belowThreshold(diode, true, true);
184 }
185
186 // Filter events
187 if (SiHelper::isMaskOut(diode)) {
188 continue;
189 }
190 if (SiHelper::isDisabled(diode)) {
191 continue;
192 }
193
194 if (!m_pixelConditionsTool->isActive(moduleHash, diodeID, ctx)) {
195 SiHelper::disabled(diode, true, true);
196 continue;
197 }
198
199 int flag = diode.flag();
200 int bunch = (flag >> 8) & 0xff;
201
203 const Identifier id_readout = chargedDiodes.element()->identifierFromCellId(cellId);
204
205 // Front-End simulation
206 if (bunch >= 0 && bunch < m_numberOfBcid) {
207 rdoCollection.push_back(new Pixel1RawData(id_readout, nToT, bunch, 0, bunch));
208 }
209
210 // Duplication mechanism for FEI3 small hits :
211 if (m_duplication) {//is true for run1 only
212 static constexpr int smallHitThreshold{7}; //constant for both barrel and endcap, never changes
213 bool smallHitChk = false;
214 if (nToT <= smallHitThreshold) {
215 smallHitChk = true;
216 }
217 if (smallHitChk && bunch > 0 && bunch <= m_numberOfBcid) {
218 rdoCollection.push_back(new Pixel1RawData(id_readout, nToT, bunch - 1, 0, bunch - 1));
219 }
220 }
221 }
222 }
223
224int FEI3SimTool::relativeBunch2009(const double threshold, const double intimethreshold,
225 const SiTotalCharge& totalCharge,
226 CLHEP::HepRandomEngine* rndmEngine) const {
227 int BCID = 0;
228 double myTimeWalkEff = 0.;
229 double overdrive = intimethreshold - threshold;
230
231 //my TimeWalk computation through PARAMETRIZATION (by Francesco De Lorenzi - Milan)
232 //double curvature = 7.6e7*overdrive-2.64e10;
233 //double divergence = -1.6*overdrive+942 ;
234 //double myTimeWalk = curvature/(pow((totalCharge.charge()-divergence),2.5));
235
236 //my TimeWalk computation through PARAMETRIZATION from 2009 cosmic data (by I. Ibragimov and D. Miller)
237 double p1 = 20. / std::log(intimethreshold / overdrive);
238 double p0 = p1 * std::log(1. - threshold / 100000.);
239
240 double myTimeWalk = -p0 - p1 * std::log(1. - threshold / totalCharge.charge());
241
242 myTimeWalkEff = myTimeWalk + myTimeWalk * 0.2 * CLHEP::RandGaussZiggurat::shoot(rndmEngine);
243 const double limit = m_timeJitter * 0.5;
244 double randomJitter = CLHEP::RandFlat::shoot(rndmEngine, - limit, limit);
245
246 //double G4Time = totalCharge.time();
247
248 double G4Time = getG4Time(totalCharge);
249 double timing = m_timeOffset + myTimeWalkEff + randomJitter + G4Time;
250 BCID = static_cast<int>(std::floor(timing / m_bunchSpace));
251 //ATH_MSG_DEBUG ( CTW << " , " << myTimeWalkEff << " , " << G4Time << " , " << timing << " , " << BCID );
252
253 return BCID;
254}
255
256double FEI3SimTool::getProbability(const std::vector<float> &bounds, const std::vector<float> &probs, const double &val) const {
257 auto pCategory = std::upper_bound(bounds.begin(), bounds.end(),val);
258 if (pCategory == bounds.end()) return 0.0;
259 auto idx = std::distance(bounds.begin(), pCategory);
260 return probs[idx];
261}
262
263
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_DEBUG(x)
double charge(const T &p)
Definition AtlasPID.h:997
Structs for holding charge calibration parameterisation and data.
static TRandom * rnd
This is an Identifier helper class for the Pixel subdetector.
InDetRawDataCollection< PixelRDORawData > PixelRDO_Collection
SiChargedDiodeOrderedSet::iterator SiChargedDiodeOrderedIterator
value_type push_back(value_type pElem)
int relativeBunch2009(const double threshold, const double intimethreshold, const SiTotalCharge &totalCharge, CLHEP::HepRandomEngine *rndmEngine) const
FEI3SimTool(const std::string &type, const std::string &name, const IInterface *parent)
virtual ~FEI3SimTool()
virtual void process(SiChargedDiodeCollection &chargedDiodes, PixelRDO_Collection &rdoCollection, CLHEP::HepRandomEngine *rndmEngine) const
virtual StatusCode initialize()
double getProbability(const std::vector< float > &bounds, const std::vector< float > &probs, const double &val) const
Gaudi::Property< bool > m_duplication
Definition FEI3SimTool.h:41
SG::ReadCondHandleKey< PixelModuleData > m_moduleDataKey
Definition FEI3SimTool.h:36
virtual StatusCode finalize()
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
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
Class to hold geometrical description of a silicon detector element.
SiCellId gangedCell(const SiCellId &cellId) const
If cell is ganged return the id of the other cell which shares the readout for this cell,...
Identifier for the strip or pixel readout cell.
virtual SiCellId cellIdFromIdentifier(const Identifier &identifier) const =0
SiCellId from Identifier.
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...
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
int eta_module(const Identifier &id) const
Definition PixelID.h:632
int phi_index(const Identifier &id) const
Definition PixelID.h:639
int getFEI3Latency(int barrel_ec, int layer) const
int getFEI3TimingSimTune(int barrel_ec, int layer) const
std::vector< float > getTimingProbability(int barrel_ec, int layer, int eta) const
std::vector< float > getTimingIndex(int barrel_ec, int layer) const
double getCrossTalk(int barrel_ec, int layer) const
virtual Identifier identify() const override final
SiChargedDiodeOrderedIterator orderedEnd()
SiChargedDiodeOrderedIterator orderedBegin()
SiChargedDiode * find(const InDetDD::SiCellId &siId)
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
void add(const SiCharge &charge)
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 maskOut(SiChargedDiode &chDiode, bool flag)
Definition SiHelper.h:67
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
double charge() const
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)