32#include "CLHEP/Random/RandGaussZiggurat.h"
64 return StatusCode::FAILURE;
99 ATH_MSG_ERROR(
"STGC run voltage must be in kV and within fit domain of 2.3 kV to 3.2 kV");
100 return StatusCode::FAILURE;
102 double meanGasGain = 2.15 * 1E-4 * std::exp(6.88*
m_runVoltage);
104 m_digitizer->setLevel(
static_cast<MSG::Level
>(msgLevel()));
111 return StatusCode::SUCCESS;
116 ATH_MSG_DEBUG(
"sTgcDigitizationTool::prepareEvent() called for " << nInputEvents <<
" input events" );
119 return StatusCode::SUCCESS;
126 ATH_MSG_DEBUG (
"sTgcDigitizationTool::in processBunchXing()" );
128 m_thpcsTGC = std::make_unique<TimedHitCollection<sTGCSimHit>>();
131 TimedHitCollList hitCollList;
134 bSubEvents, eSubEvents).isSuccess()) &&
135 hitCollList.empty()) {
137 return StatusCode::FAILURE;
139 ATH_MSG_VERBOSE(hitCollList.size() <<
" sTGCSimHitCollection with key " <<
143 TimedHitCollList::iterator iColl(hitCollList.begin());
144 TimedHitCollList::iterator endColl(hitCollList.end());
147 for( ; iColl != endColl; ++iColl){
149 auto hitCollPtr = std::make_unique<sTGCSimHitCollection>(*iColl->second);
152 ATH_MSG_DEBUG(
"sTGCSimHitCollection found with " << hitCollPtr->size() <<
" hits");
154 <<
" index: " << timeIndex.
index()
155 <<
" type: " << timeIndex.
type());
157 m_thpcsTGC->insert(timeIndex, hitCollPtr.get());
160 return StatusCode::SUCCESS;
173 if (!hitCollection.
isValid()) {
174 ATH_MSG_ERROR(
"Could not get sTGCSimHitCollection container " << hitCollection.
name() <<
" from store " << hitCollection.
store());
175 return StatusCode::FAILURE;
179 m_thpcsTGC = std::make_unique<TimedHitCollection<sTGCSimHit>>(1);
181 ATH_MSG_DEBUG(
"sTGCSimHitCollection found with " << hitCollection->size() <<
" hits");
182 return StatusCode::SUCCESS;
186 TimedHitCollList hitCollList;
190 return StatusCode::FAILURE;
192 if (hitCollList.empty()) {
194 return StatusCode::FAILURE;
202 m_thpcsTGC = std::make_unique<TimedHitCollection<sTGCSimHit>>();
205 return StatusCode::FAILURE;
209 TimedHitCollList::iterator iColl(hitCollList.begin());
210 TimedHitCollList::iterator endColl(hitCollList.end());
211 while (iColl != endColl) {
213 m_thpcsTGC->insert(iColl->first, p_collection);
214 ATH_MSG_DEBUG (
"sTGC SimHitCollection found with " << p_collection->
size() <<
" hits" );
218 return StatusCode::SUCCESS;
229 return StatusCode::SUCCESS;
237 ATH_MSG_DEBUG (
" sTgcDigitizationTool::processAllSubEvents()" );
246 return StatusCode::SUCCESS;
265 ATH_MSG_DEBUG (
"sTgcDigitContainer recorded in StoreGate." );
269 ATH_CHECK(sdoContainer.
record(std::make_unique<MuonSimDataCollection>()));
276 sTgcSimDigitCont unmergedPadDigits{}, unmergedStripDigits{}, unmergedWireDigits{};
281 double earliestEventTime = 9999;
284 while(
m_thpcsTGC->nextDetectorElement(i, e)) {
288 ATH_MSG_VERBOSE(
"Looping over hit " << nhits+1 <<
" on this Detector Element." );
299 if(eventTime < earliestEventTime) earliestEventTime = eventTime;
308 double hit_kineticEnergy =
hit.kineticEnergy();
311 if (hit_kineticEnergy > 0.) {
314 ATH_MSG_DEBUG(
"Skip electron hit with kinetic energy " << hit_kineticEnergy
323 if (std::abs(
hit.globalPosition().z() -
hit.globalPrePosition().z()) < 0.00001) {
324 ATH_MSG_VERBOSE(
"Skip hit with a direction perpendicular to the beam line, ie z-component is less than 0.00001 mm.");
330 ATH_MSG_DEBUG(
"Updated hit global time to include off set of " << eventTime <<
" ns from OOT bunch.");
336 const int idHit =
hit.sTGCId();
344 bool acceptHit =
true;
381 const double scale =
Amg::intersect<3>(LPOS, LOCDIRE, Amg::Vector3D::UnitZ(), 0.).value_or(0);
391 ATH_MSG_DEBUG(
"sTgcDigitizationTool::doDigitization hits mapped");
396 hit.particleEncoding(),
397 hit.globalDirection(),
404 double globalHitTime = temp_hit.
globalTime() + eventTime;
406 double bunchTime = globalHitTime - tof;
410 if (digiHits.empty()) {
414 for( std::unique_ptr<sTgcDigit>& digit : digiHits) {
424 double newTime = digit->time();
425 int newChannelType = idHelper.
channelType(newDigitId);
430 newTime += timeJitterElectronicsStrip;
432 newTime += timeJitterElectronicsPad;
433 uint16_t newBcTag =
bcTagging(newTime+bunchTime);
436 newTime += bunchTime;
438 newTime += globalHitTime;
440 double newCharge = digit->charge();
442 bool isDead{
false}, isPileup{eventId != 0};
443 ATH_MSG_VERBOSE(
"Hit is from the main signal subevent if eventId is zero, eventId = " << eventId <<
" newTime: " << newTime);
447 sTgcDigit newDigit(newDigitId, newBcTag, newTime, newCharge, isDead, isPileup);
449 <<
" BC tag = " << newDigit.
bcTag()
450 <<
" digitTime = " << newDigit.
time()
451 <<
" charge = " << newDigit.
charge()) ;
456 std::vector<MuonSimData::Deposit> deposits;
457 deposits.push_back(std::move(deposit));
462 simData.setPosition(glob_hitOnSurf_wire);
463 simData.setTime(globalHitTime);
464 const unsigned int modHash =
static_cast<unsigned>(
m_idHelperSvc->detElementHash(newDigitId));
468 if (contToPush.size() <= modHash) contToPush.resize(modHash + 1);
469 contToPush[modHash].emplace_back(std::move(
simData), std::move(newDigit));
500 false, outputDigits, *sdoContainer));
505 false, outputDigits, *sdoContainer));
510 if (digits.empty())
continue;
513 std::unique_ptr<sTgcDigitCollection> collection = std::make_unique<sTgcDigitCollection>(elemID, modHash);
514 collection->insert(collection->end(), std::make_move_iterator(digits.begin()),
515 std::make_move_iterator(digits.end()));
516 ATH_CHECK(digitContainer->addCollection(collection.release(), modHash));
518 return StatusCode::SUCCESS;
527 if(digitTime > 0) bunchInteger = (int)(abs(digitTime/25.0));
528 else bunchInteger = (int)(abs(digitTime/25.0)) + 1;
529 bctag = (bctag | bunchInteger);
530 if(digitTime < 0) bctag = ~bctag;
540 std::optional<float> elecThrsld = thresholdData.
getThreshold(channelID);
543 THROW_EXCEPTION(
"Cannot find retrieve VMM threshold from conditions data base!");
553 std::string rngName = name()+streamName;
554 rngWrapper->
setSeed( rngName, ctx );
555 CLHEP::HepRandomEngine* engine = rngWrapper->
getEngine(ctx);
563 const double vmmDeadTime,
564 const bool isNeighbourOn,
572 if (digitsInCham.empty())
continue;
575 digitsInCham, isNeighbourOn);
577 if (mergedDigits.empty())
continue;
580 const unsigned int hashIdx =
static_cast<unsigned>(hash);
582 if (hash >= outDigitContainer.size()) {
583 outDigitContainer.resize(hash + 1);
587 outSdoContainer.insert(std::make_pair(merged.identify(), std::move(merged.getSimData())));
589 bool acceptDigit{
true};
590 float chargeAfterSmearing = merged.getDigit().charge();
601 chargeAfterSmearing < 0.001) {
604 std::unique_ptr<sTgcDigit> finalDigit = std::make_unique<sTgcDigit>(std::move(merged.getDigit()));
606 finalDigit->set_charge(chargeAfterSmearing);
609 " BC tag = " << finalDigit->bcTag()<<
610 " digitTime = " << finalDigit->time() <<
611 " charge = " << finalDigit->charge());
612 outDigitContainer[hashIdx].push_back(std::move(finalDigit));
615 return StatusCode::SUCCESS;
619 const double vmmDeadTime,
621 const bool isNeighborOn)
const {
628 const int layA = idHelper.gasGap(a.identify());
629 const int layB = idHelper.gasGap(b.identify());
630 if (layA != layB) return layA < layB;
631 const int chA = idHelper.channel(a.identify());
632 const int chB = idHelper.channel(b.identify());
633 if (chA != chB) return chA < chB;
634 return a.time() < b.time();
638 premerged.reserve(unmergedDigits.size());
639 savedDigits.reserve(premerged.capacity());
643 if (!isNeighborOn || savedDigits.empty())
return false;
644 if (savedDigits.back().identify() == candidate.identify() &&
645 std::abs(savedDigits.back().time() - candidate.time()) < vmmDeadTime) {
649 const Identifier digitId = candidate.identify();
650 const int channel = idHelper.
channel(digitId);
652 for (
int neighbour : {std::max(1, channel -1), std::min(maxChannel, channel+1)}) {
654 if (neighbour == channel)
continue;
661 if (std::find_if(savedDigits.begin(), savedDigits.end(), [&](
const sTgcSimDigitData& known){
662 return known.identify() == neighbourId &&
663 known.getDigit().charge() > threshold &&
664 std::abs(known.time() - candidate.time()) < m_hitTimeMergeThreshold;
665 }) != savedDigits.end())
return true;
673 for (sTgcSimDigitVec::iterator merge_me = unmergedDigits.begin(); merge_me!= unmergedDigits.end(); ++merge_me) {
679 sTgcDigit& digit1{(*merge_me).getDigit()};
680 double totalCharge = digit1.
charge();
681 double weightedTime = digit1.
time();
683 sTgcSimDigitVec::iterator merge_with = merge_me + 1;
684 for ( ; merge_with!= unmergedDigits.end(); ++merge_with) {
686 if ((*merge_with).identify() != (*merge_me).identify()) {
689 const sTgcDigit& mergeDigit{(*merge_with).getDigit()};
695 weightedTime = (weightedTime * totalCharge + mergeDigit.
time() * mergeDigit.
charge())
696 / (totalCharge + mergeDigit.
charge());
698 totalCharge += mergeDigit.
charge();
703 if (!savedDigits.empty() &&
704 savedDigits.back().identify() == digit1.
identify() &&
705 std::abs(savedDigits.back().time() - digit1.
time()) <= vmmDeadTime)
continue;
707 savedDigits.emplace_back(std::move(mergedHit));
708 }
else if (isNeighborOn) {
709 premerged.emplace_back(std::move(mergedHit));
712 std::copy_if(std::make_move_iterator(premerged.begin()),
713 std::make_move_iterator(premerged.end()),
714 std::back_inserter(savedDigits), passNeigbourLogic);
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_VERBOSE(x,...)
#define ATH_MSG_INFO(x,...)
#define ATH_MSG_FATAL(x,...)
ATLAS-specific HepMC functions.
A wrapper class for event-slot-local random engines.
void setSeed(const std::string &algName, const EventContext &ctx)
Set the random seed using a string (e.g.
CLHEP::HepRandomEngine * getEngine(const EventContext &ctx) const
Retrieve the random engine corresponding to the provided EventContext.
a link optimized in size for a GenParticle in a McEventCollection
static HepMcParticleLink getRedirectedLink(const HepMcParticleLink &particleLink, uint32_t eventIndex, const EventContext &ctx)
Return a HepMcParticleLink pointing at the same particle, but in a different GenEvent.
This is a "hash" representation of an Identifier.
Identifier identify() const
virtual const Trk::PlaneSurface & surface() const override
access to chamber surface (phi orientation), uses the first gas gap
The MuonDetectorManager stores the transient representation of the Muon Spectrometer geometry and pro...
const sTgcReadoutElement * getsTgcReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
An sTgcReadoutElement corresponds to a single STGC module; therefore typicaly a barrel muon station c...
virtual int numberOfStrips(const Identifier &layerId) const override final
number of strips per layer
virtual int surfaceHash(const Identifier &id) const override final
returns the hash to be used to look up the surface and transform in the MuonClusterReadoutElement tra...
size_type module_hash_max() const
the maximum hash value
std::pair< HepMcParticleLink, MuonMCData > Deposit
Conditions data to model a channel dependent energy deposit threshold such that the electronics retur...
std::optional< float > getThreshold(const Identifier &channelId) const
virtual bool isValid() override final
Can the handle be successfully dereferenced?
const_pointer_type cptr()
Dereference the pointer.
std::string store() const
Return the name of the store holding the object we are proxying.
const std::string & name() const
Return the StoreGate ID for the referenced object.
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
TimedVector::const_iterator const_iterator
a smart pointer to a hit that also provides access to the extended timing info of the host event.
unsigned short eventId() const
the index of the component event in PileUpEventInfo.
float eventTime() const
t0 offset of the bunch xing containing the hit in ns.
Class for a planaer rectangular or trapezoidal surface in the ATLAS detector.
const Amg::Transform3D & transform() const
Returns HepGeom::Transform3D by reference.
const Amg::Vector3D & center() const
Returns the center position of the Surface.
double globalTime() const
const Amg::Vector3D & globalPosition() const
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
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, 3, 1 > Vector3D
Ensure that the Athena extensions are properly loaded.
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.
AtlasHitsVector< sTGCSimHit > sTGCSimHitCollection
std::list< value_t > type
type of the collection of timed data object
a struct encapsulating the identifier of a pile-up event
index_type index() const
the index of the component event in PileUpEventInfo
PileUpType type() const
the pileup type - minbias, cavern, beam halo, signal?
time_type time() const
bunch xing time in ns
Digitize a given hit, determining the time and charge spread on wires, pads and strips.
const Muon::DigitEffiData * efficiencies
CLHEP::HepRandomEngine * rndmEngine
const MuonGM::MuonDetectorManager * detMgr
const NswCalibDbThresholdData * thresholdData
Identifier convert(int simId) const
#define THROW_EXCEPTION(MESSAGE)