ATLAS Offline Software
Loading...
Searching...
No Matches
TgcFastDigiTool.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 "TgcFastDigiTool.h"
6#include "CLHEP/Random/RandGaussZiggurat.h"
7#include "CLHEP/Random/RandFlat.h"
9namespace {
10 constexpr double percentage(unsigned int numerator, unsigned int denom) {
11 return 100. * numerator / std::max(denom, 1u);
12 }
13}
14namespace MuonR4 {
15
18 ATH_CHECK(m_writeKey.initialize());
19 ATH_CHECK(m_effiDataKey.initialize(!m_effiDataKey.empty()));
20 return StatusCode::SUCCESS;
21 }
23 ATH_MSG_INFO("Tried to convert "<<m_allHits[0]<<"/"<<m_allHits[1]<<" hits. In, "
24 <<percentage(m_acceptedHits[0], m_allHits[0]) <<"/"
25 <<percentage(m_acceptedHits[1], m_allHits[1]) <<"% of the cases, the conversion was successful");
26 return StatusCode::SUCCESS;
27 }
28
29 int TgcFastDigiTool::associateBCIdTag(const EventContext& /*ctx*/,
30 const TimedHit& /*timedHit*/) const {
32 }
33
34 bool TgcFastDigiTool::digitizeWireHit(const EventContext& ctx,
35 const TimedHit& timedHit,
36 const Muon::DigitEffiData* efficiencyMap,
37 TgcDigitCollection& outColl,
38 CLHEP::HepRandomEngine* rndEngine,
39 DeadTimeMap& deadTimes) const {
40
41
43 const Identifier hitId = timedHit->identify();
44 const TgcIdHelper& idHelper{m_idHelperSvc->tgcIdHelper()};
45 const MuonGMR4::TgcReadoutElement* readOutEle = m_detMgr->getTgcReadoutElement(hitId);
46 const IdentifierHash measHash = readOutEle->measurementHash(hitId);
47 const Amg::Vector3D locSimHitPos{xAOD::toEigen(timedHit->localPosition())};
48 if (!readOutEle->numWireGangs(measHash)) {
49 ATH_MSG_VERBOSE("There're no wires in "<<m_idHelperSvc->toString(hitId)<<" nothing to do");
50 return false;
51 }
52 ++m_allHits[false];
53 if (efficiencyMap && efficiencyMap->getEfficiency(hitId) < CLHEP::RandFlat::shoot(rndEngine,0.,1.)){
54 ATH_MSG_VERBOSE("Simulated hit "<<Amg::toString(locSimHitPos)
55 << m_idHelperSvc->toString(hitId) <<" is rejected because of efficency modelling");
56 return false;
57 }
58
59 const Amg::Vector2D locPos2D{readOutEle->sensorLayout(measHash)->to2D(locSimHitPos, false)};
60
61 const MuonGMR4::WireGroupDesign& design{readOutEle->wireGangLayout(measHash)};
62 if (!design.insideTrapezoid(locPos2D)) {
63 ATH_MSG_DEBUG("The hit "<<Amg::toString(locPos2D)<<" in "<<m_idHelperSvc->toStringGasGap(hitId)
64 <<" is outside of the trapezoid "<<design);
65 return false;
66 }
67 const int wireGrpNum = design.stripNumber(locPos2D);
68
69 if (wireGrpNum < 0) {
70 ATH_MSG_DEBUG("True hit "<<Amg::toString(locPos2D)<<" "<<m_idHelperSvc->toStringGasGap(hitId)
71 <<" is not covered by any wire gang");
72 return false;
73 }
74
75 const double uncert = design.stripPitch() * design.numWiresInGroup(wireGrpNum) / std::sqrt(12);
76 const double locX = CLHEP::RandGaussZiggurat::shoot(rndEngine, locPos2D.x(), uncert);
79 const Amg::Vector2D smearedPos{locX, locPos2D.y()};
80 const int prdWireNum = design.stripNumber(smearedPos);
81
82 if (prdWireNum < 0) {
83 if (design.insideTrapezoid(smearedPos)) {
84 ATH_MSG_WARNING("True hit "<<Amg::toString(locPos2D, 2)<<" corresponding to "<<wireGrpNum<<" --> "
85 <<Amg::toString(smearedPos)<<" "<<uncert<<" is outside of "<<design);
86 }
87 return false;
88 }
89 bool isValid{false};
90 const Identifier digitId{idHelper.channelID(hitId, readOutEle->gasGapNumber(measHash), false, prdWireNum, isValid)};
91 if (!isValid) {
92 ATH_MSG_WARNING("Invalid channel "<< m_idHelperSvc->toStringGasGap(hitId)<<", channel: "<<prdWireNum);
93 return false;
94 }
95
96 if (!passDeadTime(digitId, hitTime(timedHit), m_deadTime, deadTimes)) {
97 ATH_MSG_VERBOSE("Reject hit due to dead map constraint");
98 return false;
99 }
100 ATH_MSG_VERBOSE("Convert simulated hit "<<m_idHelperSvc->toString(digitId)<<" located at "
101 <<Amg::toString(locSimHitPos, 2)<<" wire group number: "<<prdWireNum<<", time: "<<hitTime(timedHit)
102 <<" wiregroup pos "<<Amg::toString(design.center(prdWireNum).value_or(Amg::Vector2D::Zero()), 2));
103 outColl.push_back(std::make_unique<TgcDigit>(digitId, associateBCIdTag(ctx, timedHit)));
104 ++m_acceptedHits[false];
105 return true;
106 }
107 bool TgcFastDigiTool::digitizeStripHit(const EventContext& ctx,
108 const TimedHit& timedHit,
109 const Muon::DigitEffiData* efficiencyMap,
110 TgcDigitCollection& outColl,
111 CLHEP::HepRandomEngine* rndEngine,
112 DeadTimeMap& deadTimes) const {
113
114 const Identifier hitId = timedHit->identify();
115 const TgcIdHelper& idHelper{m_idHelperSvc->tgcIdHelper()};
116 const MuonGMR4::TgcReadoutElement* readOutEle = m_detMgr->getTgcReadoutElement(hitId);
117
118 const IdentifierHash measHash = readOutEle->measurementHash(hitId);
119 if (!readOutEle->numStrips(measHash)) {
120 ATH_MSG_DEBUG("There're no strips in "<<m_idHelperSvc->toString(hitId)<<" nothing to do");
121 return false;
122 }
123 ++(m_allHits[true]);
124
126 if (efficiencyMap && efficiencyMap->getEfficiency(hitId) < CLHEP::RandFlat::shoot(rndEngine,0.,1.)){
127 ATH_MSG_VERBOSE("Simulated hit "<<xAOD::toEigen(timedHit->localPosition())
128 << m_idHelperSvc->toString(hitId) <<" is rejected because of efficency modelling");
129 return false;
130 }
131
132
133 const Amg::Vector2D locSimHitPos{readOutEle->sensorLayout(measHash)->to2D(xAOD::toEigen(timedHit->localPosition()),true)};
134
135
136 const MuonGMR4::RadialStripDesign& design{readOutEle->stripLayout(measHash)};
137 if (!design.insideTrapezoid(locSimHitPos)) {
138 ATH_MSG_DEBUG("The eta hit "<<Amg::toString(locSimHitPos)<<" in "<<m_idHelperSvc->toStringGasGap(hitId)
139 <<" is outside of the trapezoid "<<std::endl<<design);
140 return false;
141 }
142 int stripNum = design.stripNumber(locSimHitPos);
143 if (stripNum < 0) {
144 ATH_MSG_WARNING("Strip hit "<<Amg::toString(locSimHitPos)<<" cannot be assigned to any active strip for "
145 <<m_idHelperSvc->toStringGasGap(hitId)<<". "<<design);
146 return false;
147 }
149 const Amg::Vector2D stripNorm{design.stripNormal(stripNum)};
150
153 const double stripPitch = std::abs(*Amg::intersect<2>(design.stripLeftBottom(stripNum), design.stripLeftEdge(stripNum),
154 locSimHitPos, stripNorm)) +
155 std::abs(*Amg::intersect<2>(design.stripRightBottom(stripNum), design.stripRightEdge(stripNum),
156 locSimHitPos, stripNorm));
157
158 const double uncert = stripPitch / std::sqrt(12);
159 const double locX = CLHEP::RandGaussZiggurat::shoot(rndEngine, locSimHitPos.x(), uncert);
162 const Amg::Vector2D smearedPos{locX, locSimHitPos.y()};
163 const int digitStripNum = design.stripNumber(smearedPos);
164
165 if (digitStripNum < 0) {
166 if (design.insideTrapezoid(smearedPos)) {
167 ATH_MSG_WARNING("True phi hit "<<Amg::toString(locSimHitPos, 2)<<" corresponding to "<<stripNum<<" --> "
168 <<Amg::toString(smearedPos)<<" "<<uncert<<" is outside of "<<design);
169 }
170 return false;
171 }
172
173 bool isValid{false};
174 const Identifier digitId{idHelper.channelID(hitId, readOutEle->gasGapNumber(measHash), true, digitStripNum, isValid)};
175 if (!isValid) {
176 ATH_MSG_WARNING("Invalid channel "<< m_idHelperSvc->toStringGasGap(hitId)<<", channel: "<<digitStripNum);
177 return false;
178 }
179
180 if (!passDeadTime(digitId, hitTime(timedHit), m_deadTime, deadTimes)) {
181 ATH_MSG_VERBOSE("Reject hit due to dead time constraint.");
182 return false;
183 }
184 ATH_MSG_VERBOSE("Convert simulated hit "<<m_idHelperSvc->toString(digitId)<<" located at "
185 <<Amg::toString(locSimHitPos, 2)<<" phi strip number: "<<digitStripNum<<", time: "<<hitTime(timedHit)
186 <<" strip position "<<Amg::toString(design.center(digitStripNum).value_or(Amg::Vector2D::Zero()), 2));
187
188 outColl.push_back(std::make_unique<TgcDigit>(digitId, associateBCIdTag(ctx, timedHit)));
189
190 ++(m_acceptedHits[true]);
191 return true;
192 }
193 StatusCode TgcFastDigiTool::digitize(const EventContext& ctx,
194 const TimedHits& hitsToDigit,
195 xAOD::MuonSimHitContainer* sdoContainer) const {
196
197 // Prepare the temporary cache
198 DigiCache digitCache{};
200 const Muon::DigitEffiData* efficiencyMap{nullptr};
201 ATH_CHECK(SG::get( efficiencyMap, m_effiDataKey, ctx));
202 const TgcIdHelper& idHelper{m_idHelperSvc->tgcIdHelper()};
203
204 CLHEP::HepRandomEngine* rndEngine = getRandomEngine(ctx);
205
206 xAOD::ChamberViewer viewer{hitsToDigit, m_idHelperSvc.get()};
207 do {
208 DeadTimeMap deadTimes{};
209 for (const TimedHit& simHit : viewer) {
211 if (m_digitizeMuonOnly && !MC::isMuon(simHit)) {
212 continue;
213 }
214 TgcDigitCollection* outColl = fetchCollection(simHit->identify(), digitCache);
215
216 const bool digitizedEta = digitizeWireHit(ctx,simHit, efficiencyMap,*outColl, rndEngine, deadTimes);
217 const bool digitizedPhi = digitizeStripHit(ctx, simHit, efficiencyMap,*outColl, rndEngine, deadTimes);
218
219 if (digitizedEta) {
220 xAOD::MuonSimHit* sdo = addSDO(simHit, sdoContainer);
221 sdo->setIdentifier(outColl->at(outColl->size() - 1 - digitizedPhi)->identify());
222 } else if (digitizedPhi) {
223 xAOD::MuonSimHit* sdo = addSDO(simHit, sdoContainer);
224 sdo->setIdentifier(outColl->at(outColl->size() - 1)->identify());
225 const MuonGMR4::TgcReadoutElement* re{m_detMgr->getTgcReadoutElement(simHit->identify())};
226
227 const Amg::Transform3D etaToPhi{re->globalToLocalTrans(getGeoCtx(ctx), re->layerHash(sdo->identify())) *
228 re->localToGlobalTrans(getGeoCtx(ctx), re->layerHash(simHit->identify()))};
229
230 sdo->setLocalDirection(xAOD::toStorage(etaToPhi * xAOD::toEigen(sdo->localDirection())));
231 sdo->setLocalPosition(xAOD::toStorage(etaToPhi * xAOD::toEigen(sdo->localPosition())));
232 }
233 }
234 } while(viewer.next());
236 ATH_CHECK(writeDigitContainer(ctx, m_writeKey, std::move(digitCache), idHelper.module_hash_max()));
237 return StatusCode::SUCCESS;
238 }
239}
const boost::regex re(r_e)
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
bool isValid(const T &p)
Av: we implement here an ATLAS-sepcific convention: all particles which are 99xxxxx are fine.
Definition AtlasPID.h:878
ATLAS-specific HepMC functions.
const T * at(size_type n) const
Access an element, as an rvalue.
value_type push_back(value_type pElem)
Add an element to the end of the collection.
size_type size() const noexcept
Returns the number of elements in the collection.
This is a "hash" representation of an Identifier.
Identifier identify() const
Definition MuonDigit.h:30
Amg::Vector2D stripNormal(int stripNumber) const
@bief: Returns the vector perpendicular to the stripDir and pointing to the next strip
Amg::Vector2D stripLeftEdge(int stripNumber) const
: Returns the direction of the left edge
Amg::Vector2D stripRightBottom(int stripNumber) const
: Returns the intersecton of the strip right edge at the bottom panel's edge
Amg::Vector2D stripRightEdge(int stripNumber) const
: Returns the direction of the right edge
int stripNumber(const Amg::Vector2D &extPos) const override final
Returns the associated channel number of an external vector.
Amg::Vector2D stripLeftBottom(int stripNumber) const
: Returns the intersection of the left strip edge at the bottom panel's edge
CheckVector2D center(int stripNumb) const
Returns the bisector of the strip (Global numbering scheme)
double stripPitch() const
Distance between two adjacent strips.
bool insideTrapezoid(const Amg::Vector2D &extPos) const
Checks whether an external point is inside the trapezoidal area.
const StripLayerPtr & sensorLayout(const IdentifierHash &hash) const
Returns the pointer to the strip layer associated with the gas gap.
unsigned numWireGangs(const IdentifierHash &layHash) const
Returns the number of wire gangs for a given gasGap [1-3].
static unsigned gasGapNumber(const IdentifierHash &measHash)
Unpacks the gas gap number from the measurement hash.
const RadialStripDesign & stripLayout(const IdentifierHash &layHash) const
Returns access to the strip design of the given gasGap [1-3] If the gap does not have strips an excep...
IdentifierHash measurementHash(const Identifier &measId) const override final
Constructs the identifier hash from the full measurement Identifier.
const WireGroupDesign & wireGangLayout(const IdentifierHash &layHash) const
Returns access to the wire group design of the given gasGap [1-3] If the gap does not have a wires an...
unsigned numStrips(const IdentifierHash &layHash) const
Returns the number of strips for a given gasGap [1-3].
int stripNumber(const Amg::Vector2D &pos) const override
Calculates the number of the strip whose center is closest to the given point.
unsigned int numWiresInGroup(unsigned int groupNum) const
Returns the number of wires in a given group.
size_type module_hash_max() const
the maximum hash value
xAOD::MuonSimHit * addSDO(const TimedHit &hit, xAOD::MuonSimHitContainer *sdoContainer) const
Adds the timed simHit to the output SDO container.
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
std::vector< TimedHitPtr< xAOD::MuonSimHit > > TimedHits
CLHEP::HepRandomEngine * getRandomEngine(const EventContext &ctx) const
static bool passDeadTime(const Identifier &channelId, const double hitTime, const double deadTimeWindow, DeadTimeMap &deadTimeMap)
Returns whether the new digit is within the dead time window.
TimedHitPtr< xAOD::MuonSimHit > TimedHit
DigitColl * fetchCollection(const Identifier &hitId, OutDigitCache_t< DigitColl > &digitCache) const
Helper function that provides fetches the proper DigitCollection from the DigitCache for a given hit ...
const MuonGMR4::MuonDetectorManager * m_detMgr
StatusCode writeDigitContainer(const EventContext &ctx, const SG::WriteHandleKey< DigitCont > &key, OutDigitCache_t< DigitColl > &&digitCache, unsigned int hashMax) const
Helper function to move the collected digits into the final DigitContainer.
const ActsTrk::GeometryContext & getGeoCtx(const EventContext &ctx) const
Returns the reference to the ActsTrk::GeometryContext needed to fetch global positions from the Reado...
static double hitTime(const TimedHit &hit)
Returns the global time of the hit which is the sum of eventTime & individual hit time.
std::unordered_map< Identifier, double > DeadTimeMap
StatusCode finalize() override final
OutDigitCache_t< TgcDigitCollection > DigiCache
StatusCode digitize(const EventContext &ctx, const TimedHits &hitsToDigit, xAOD::MuonSimHitContainer *sdoContainer) const override final
Digitize the time ordered hits and write them to the digit format specific for the detector technolog...
StatusCode initialize() override final
SG::WriteHandleKey< TgcDigitContainer > m_writeKey
bool digitizeStripHit(const EventContext &ctx, const TimedHit &timedHit, const Muon::DigitEffiData *efficiencyMap, TgcDigitCollection &outColl, CLHEP::HepRandomEngine *rndEngine, DeadTimeMap &deadTimes) const
Digitize the strip hit by smearing the truth hit position according to the wire group pitch and then ...
Gaudi::Property< bool > m_digitizeMuonOnly
SG::ReadCondHandleKey< Muon::DigitEffiData > m_effiDataKey
bool digitizeWireHit(const EventContext &ctx, const TimedHit &timedHit, const Muon::DigitEffiData *efficiencyMap, TgcDigitCollection &outColl, CLHEP::HepRandomEngine *rndEngine, DeadTimeMap &deadTimes) const
Digitize the wire hit by smearing the truth hit position according to the wire group pitch and then a...
int associateBCIdTag(const EventContext &ctx, const TimedHit &timedHit) const
: Associates the global bcIdTag to the digit
Gaudi::Property< double > m_deadTime
double getEfficiency(const Identifier &channelId, bool isInnerQ1=false) const
Returns the signal generation efficiency of the sTgc channel.
@ BC_CURRENT
Definition TgcDigit.h:37
Identifier channelID(int stationName, int stationEta, int stationPhi, int gasGap, int isStrip, int channel) const
bool next() noexcept
Loads the hits from the next chamber.
void setLocalDirection(MeasVector< 3 > vec)
Sets the local direction of the traversing particle.
ConstVectorMap< 3 > localDirection() const
Returns the local direction of the traversing particle.
void setIdentifier(const Identifier &id)
Sets the global ATLAS identifier.
Identifier identify() const
Returns the global ATLAS identifier of the SimHit.
ConstVectorMap< 3 > localPosition() const
Returns the local postion of the traversing particle.
void setLocalPosition(MeasVector< 3 > vec)
Sets the local position of the traversing particle.
std::optional< double > intersect(const AmgVector(N)&posA, const AmgVector(N)&dirA, const AmgVector(N)&posB, const AmgVector(N)&dirB)
Calculates the point B' along the line B that's closest to a second line A.
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
bool isMuon(const T &p)
This header ties the generic definitions in this package.
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
MuonSimHit_v1 MuonSimHit
Defined the version of the MuonSimHit.
Definition MuonSimHit.h:12
MeasVector< N > toStorage(const AmgVector(N)&amgVec)
Converts the double precision of the AmgVector into the floating point storage precision of the MeasV...
MuonSimHitContainer_v1 MuonSimHitContainer
Define the version of the pixel cluster container.