8#include "CLHEP/Random/RandGaussZiggurat.h"
36 ATH_MSG_WARNING(
"STGC run voltage must be within fit domain of 2.3 kV to 3.2 kV");
37 return StatusCode::FAILURE;
39 double meanGasGain = 2.15 * 1E-4 * std::exp(6.88*
m_runVoltage);
44 return StatusCode::SUCCESS;
49 int bunchInteger = (digitTime > 0) ?
static_cast<int>(std::abs(digitTime / 25.0))
50 :
static_cast<int>(std::abs(digitTime / 25.0)) + 1;
51 bctag = (bctag | bunchInteger);
52 if (digitTime < 0) bctag = ~bctag;
60 float elecThreshold = 0.0;
61 if (!thresholdData.
getThreshold(channelID, elecThreshold)) {
62 THROW_EXCEPTION(
"Cannot retrieve VMM threshold from conditions database!");
66 THROW_EXCEPTION(
"Cannot convert VMM charge threshold via conditions data!");
87 double earliestEventTime = std::numeric_limits<double>::max();
89 const double angular_tolerance = 1e-3;
92 if (viewer.
size() == 0) {
96 std::array<sTgcSimDigitVec , 3> simDigitsByChType{};
104 double eventTime = hit.eventTime();
105 earliestEventTime = std::min(earliestEventTime, eventTime);
113 const Amg::Vector3D locHitPos = xAOD::toEigen(hit->localPosition());
114 const Amg::Vector3D locHitDir = xAOD::toEigen(hit->localDirection());
116 const double hitKineticEnergy = hit->kineticEnergy();
118 ATH_MSG_DEBUG(
"Skip electron hit with kinetic energy " << hitKineticEnergy
125 const double theta = std::acos(locHitDir.z());
126 const double ninetyDegrees = std::numbers::pi / 2;
128 if (std::abs(
theta - ninetyDegrees) < angular_tolerance) {
132 if (std::abs(locHitDir.z()) < 0.00001) {
137 ATH_MSG_DEBUG(
"Updated hit global time to include off set of " << eventTime <<
" ns from OOT bunch.");
147 bool acceptHit =
true;
156 double globalHitTime = hit->globalTime() + eventTime;
157 double tofCorrection = globalHitPos.mag() / CLHEP::c_light;
158 double bunchTime = globalHitTime - tofCorrection;
163 <<
" globalHitPosition " <<
Amg::toString(globalHitPos) <<
" hit: r " << globalHitPos.perp() <<
" z " << globalHitPos.z()
164 <<
" mclink " << particleLink <<
"Kinetic energy " << hitKineticEnergy);
165 ATH_MSG_VERBOSE(
"Total hits passed to digitize: " << hitsToDigit.size());
167 if(digitizedHits.empty()) {
170 ATH_MSG_VERBOSE(
"Hit produced " << digitizedHits.size() <<
" digits." );
172 for (std::unique_ptr<sTgcDigit>& digit : digitizedHits) {
182 double digitTime = digit->time();
185 if(digitChType == ReadoutChannelType::Strip) {
192 uint16_t digitBCTag =
bcTagging(digitTime + bunchTime);
195 double digitCharge = digit->charge();
197 int eventId = hit.eventId();
198 bool isDead{
false}, isPileup{eventId != 0};
199 ATH_MSG_VERBOSE(
"Hit is from the main signal subevent if eventId is zero, eventId = "
200 << eventId <<
" newDigit time: " << digitTime);
201 auto newDigitPtr = std::make_unique<sTgcDigit>(digitId, digitBCTag, digitTime, digitCharge, isDead, isPileup);
202 if (digitChType == ReadoutChannelType::Strip) {
204 <<
" BC tag = " << newDigitPtr->bcTag()
205 <<
" digitTime = " << newDigitPtr->time()
206 <<
" charge = " << newDigitPtr->charge());
208 simDigitsByChType[digitChType].emplace_back(std::move(hit), std::move(newDigitPtr));
211 if (!simDigitsByChType[ReadoutChannelType::Strip].empty()) {
214 if (!simDigitsByChType[ReadoutChannelType::Pad].empty()) {
217 if (!simDigitsByChType[ReadoutChannelType::Wire].empty()) {
220 }
while (viewer.
next());
224 return StatusCode::SUCCESS;
230 const double vmmDeadTime,
231 const bool isNeighbourOn,
236 if (digitsInChamber.empty()) {
237 ATH_MSG_WARNING(
"Failed to obtain the digitized hits for VMM Simulation" );
238 return StatusCode::SUCCESS;
242 digitsInChamber, isNeighbourOn);
244 if (mergedDigits.empty()) {
245 return StatusCode::SUCCESS;
251 bool acceptDigit{
true};
252 float chargeAfterSmearing = merged.getDigit().charge();
262 if (idHelper.
channelType(merged.identify()) == ReadoutChannelType::Strip &&
263 chargeAfterSmearing < 0.001) {
266 std::unique_ptr<sTgcDigit> finalDigit = std::make_unique<sTgcDigit>(std::move(merged.getDigit()));
268 finalDigit->set_charge(chargeAfterSmearing);
271 " BC tag = " << finalDigit->bcTag()<<
272 " digitTime = " << finalDigit->time() <<
273 " charge = " << finalDigit->charge());
279 double globalHitTime = sdoHit->
globalTime() + merged.getSimHit().eventTime();
284 outColl->
push_back(std::move(finalDigit));
286 return StatusCode::SUCCESS;
291 const double vmmDeadTime,
293 const bool isNeighbourOn)
const {
300 const int layA = idHelper.gasGap(a.identify());
301 const int layB = idHelper.gasGap(b.identify());
302 if (layA != layB) return layA < layB;
303 const int chA = idHelper.channel(a.identify());
304 const int chB = idHelper.channel(b.identify());
305 if (chA != chB) return chA < chB;
306 return a.time() < b.time();
311 premerged.reserve(unmergedDigits.size());
312 savedDigits.reserve(premerged.capacity());
315 if (!isNeighbourOn || savedDigits.empty())
return false;
316 if (savedDigits.back().identify() == candidate.identify() &&
317 std::abs(savedDigits.back().time() - candidate.time()) < vmmDeadTime) {
321 const Identifier digitId = candidate.identify();
322 const int channel = idHelper.
channel(digitId);
323 const int maxChannel = detMgr->getsTgcReadoutElement(digitId)->numChannels(digitId);
324 for (
int neighbour : {std::max(1, channel -1), std::min(maxChannel, channel+1)}) {
326 if (neighbour == channel)
continue;
334 return known.identify() == neighbourId &&
335 known.getDigit().charge() > threshold &&
336 std::abs(known.time() - candidate.time()) < m_hitTimeMergeThreshold;
337 }) != savedDigits.end())
return true;
345 for (sTgcSimDigitVec::iterator merge_me = unmergedDigits.begin(); merge_me!= unmergedDigits.end(); ++merge_me) {
351 sTgcDigit& digit1{(*merge_me).getDigit()};
352 double totalCharge = digit1.
charge();
353 double weightedTime = digit1.
time();
355 sTgcSimDigitVec::iterator merge_with = merge_me + 1;
356 for ( ; merge_with!= unmergedDigits.end(); ++merge_with) {
358 if ((*merge_with).identify() != (*merge_me).identify()) {
361 const sTgcDigit& mergeDigit{(*merge_with).getDigit()};
367 weightedTime = (weightedTime * totalCharge + mergeDigit.
time() * mergeDigit.
charge())
368 / (totalCharge + mergeDigit.
charge());
370 totalCharge += mergeDigit.
charge();
375 if (!savedDigits.empty() &&
376 savedDigits.back().identify() == digit1.
identify() &&
377 std::abs(savedDigits.back().time() - digit1.
time()) <= vmmDeadTime)
continue;
379 savedDigits.emplace_back(std::move(mergedHit));
380 }
else if (isNeighbourOn) {
381 premerged.emplace_back(std::move(mergedHit));
384 std::copy_if(std::make_move_iterator(premerged.begin()),
385 std::make_move_iterator(premerged.end()),
386 std::back_inserter(savedDigits), passNeigbourLogic);
387 if(savedDigits.empty() && !unmergedDigits.empty()) {
Scalar theta() const
theta method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
ATLAS-specific HepMC functions.
value_type push_back(value_type pElem)
Add an element to the end of the collection.
a link optimized in size for a GenParticle in a McEventCollection
Identifier identify() const
const Amg::Transform3D & localToGlobalTrans(const ActsTrk::GeometryContext &ctx) const
Returns the local to global transformation into the ATLAS coordinate system.
size_type module_hash_max() const
the maximum hash value
bool getThreshold(const Identifier &, float &) const
digitMode
Constructor initializing digitization parameters.
void set_time(float newTime)
void set_charge(float newCharge)
int multilayer(const Identifier &id) const
int channelType(const Identifier &id) const
int channel(const Identifier &id) const override
int gasGap(const Identifier &id) const override
get the hashes
Identifier channelID(int stationName, int stationEta, int stationPhi, int multilayer, int gasGap, int channelType, int channel) const
bool next() noexcept
Loads the hits from the next chamber.
std::size_t size() const noexcept
Returns how many hits are in the current chamber.
void setGlobalTime(const float time)
Sets the time of the traversing particle.
float globalTime() const
Returns the time ellapsed since the collision of the traversing particle.
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Eigen::Matrix< double, 3, 1 > Vector3D
bool isElectron(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.
void stable_sort(DataModel_detail::iterator< DVL > beg, DataModel_detail::iterator< DVL > end)
Specialization of stable_sort for DataVector/List.
MuonSimHit_v1 MuonSimHit
Defined the version of the MuonSimHit.
MuonSimHitContainer_v1 MuonSimHitContainer
Define the version of the pixel cluster container.
const NswCalibDbThresholdData * thresholdData
const MuonGM::MuonDetectorManager * detMgr
CLHEP::HepRandomEngine * rndEngine
#define THROW_EXCEPTION(MESSAGE)