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;
251 const CondType* & condPtr)
const{
253 ATH_MSG_DEBUG(
"No key has been configured for object "<<
typeid(CondType).name()<<
". Clear pointer");
255 return StatusCode::SUCCESS;
259 ATH_MSG_FATAL(
"Failed to load conditions object "<<key.fullKey()<<
".");
260 return StatusCode::FAILURE;
262 condPtr = readHandle.
cptr();
263 return StatusCode::SUCCESS;
282 ATH_MSG_DEBUG (
"sTgcDigitContainer recorded in StoreGate." );
286 ATH_CHECK(sdoContainer.
record(std::make_unique<MuonSimDataCollection>()));
293 sTgcSimDigitCont unmergedPadDigits{}, unmergedStripDigits{}, unmergedWireDigits{};
298 double earliestEventTime = 9999;
301 while(
m_thpcsTGC->nextDetectorElement(i, e)) {
305 ATH_MSG_VERBOSE(
"Looping over hit " << nhits+1 <<
" on this Detector Element." );
316 if(eventTime < earliestEventTime) earliestEventTime = eventTime;
328 if (hit_kineticEnergy > 0.) {
331 ATH_MSG_DEBUG(
"Skip electron hit with kinetic energy " << hit_kineticEnergy
341 ATH_MSG_VERBOSE(
"Skip hit with a direction perpendicular to the beam line, ie z-component is less than 0.00001 mm.");
347 ATH_MSG_DEBUG(
"Updated hit global time to include off set of " << eventTime <<
" ns from OOT bunch.");
353 const int idHit = hit.
sTGCId();
361 bool acceptHit =
true;
398 const double scale =
Amg::intersect<3>(LPOS, LOCDIRE, Amg::Vector3D::UnitZ(), 0.).value_or(0);
408 ATH_MSG_DEBUG(
"sTgcDigitizationTool::doDigitization hits mapped");
421 double globalHitTime = temp_hit.
globalTime() + eventTime;
423 double bunchTime = globalHitTime - tof;
427 if (digiHits.empty()) {
431 for( std::unique_ptr<sTgcDigit>& digit : digiHits) {
441 double newTime = digit->time();
442 int newChannelType = idHelper.
channelType(newDigitId);
447 newTime += timeJitterElectronicsStrip;
449 newTime += timeJitterElectronicsPad;
450 uint16_t newBcTag =
bcTagging(newTime+bunchTime);
453 newTime += bunchTime;
455 newTime += globalHitTime;
457 double newCharge = digit->charge();
459 bool isDead{
false}, isPileup{eventId != 0};
460 ATH_MSG_VERBOSE(
"Hit is from the main signal subevent if eventId is zero, eventId = " << eventId <<
" newTime: " << newTime);
464 sTgcDigit newDigit(newDigitId, newBcTag, newTime, newCharge, isDead, isPileup);
466 <<
" BC tag = " << newDigit.
bcTag()
467 <<
" digitTime = " << newDigit.
time()
468 <<
" charge = " << newDigit.
charge()) ;
473 std::vector<MuonSimData::Deposit> deposits;
474 deposits.push_back(std::move(deposit));
479 simData.setPosition(glob_hitOnSurf_wire);
480 simData.setTime(globalHitTime);
481 const unsigned int modHash =
static_cast<unsigned>(
m_idHelperSvc->detElementHash(newDigitId));
485 if (contToPush.size() <= modHash) contToPush.resize(modHash + 1);
486 contToPush[modHash].emplace_back(std::move(
simData), std::move(newDigit));
517 false, outputDigits, *sdoContainer));
522 false, outputDigits, *sdoContainer));
527 if (digits.empty())
continue;
530 std::unique_ptr<sTgcDigitCollection> collection = std::make_unique<sTgcDigitCollection>(elemID, modHash);
531 collection->insert(collection->end(), std::make_move_iterator(digits.begin()),
532 std::make_move_iterator(digits.end()));
533 ATH_CHECK(digitContainer->addCollection(collection.release(), modHash));
535 return StatusCode::SUCCESS;
544 if(digitTime > 0) bunchInteger = (int)(abs(digitTime/25.0));
545 else bunchInteger = (int)(abs(digitTime/25.0)) + 1;
546 bctag = (bctag | bunchInteger);
547 if(digitTime < 0) bctag = ~bctag;
557 std::optional<float> elecThrsld = thresholdData.
getThreshold(channelID);
560 THROW_EXCEPTION(
"Cannot find retrieve VMM threshold from conditions data base!");
570 std::string rngName = name()+streamName;
571 rngWrapper->
setSeed( rngName, ctx );
572 CLHEP::HepRandomEngine* engine = rngWrapper->
getEngine(ctx);
580 const double vmmDeadTime,
581 const bool isNeighbourOn,
589 if (digitsInCham.empty())
continue;
592 digitsInCham, isNeighbourOn);
594 if (mergedDigits.empty())
continue;
597 const unsigned int hashIdx =
static_cast<unsigned>(hash);
599 if (hash >= outDigitContainer.size()) {
600 outDigitContainer.resize(hash + 1);
604 outSdoContainer.insert(std::make_pair(merged.identify(), std::move(merged.getSimData())));
606 bool acceptDigit{
true};
607 float chargeAfterSmearing = merged.getDigit().charge();
618 chargeAfterSmearing < 0.001) {
621 std::unique_ptr<sTgcDigit> finalDigit = std::make_unique<sTgcDigit>(std::move(merged.getDigit()));
623 finalDigit->set_charge(chargeAfterSmearing);
626 " BC tag = " << finalDigit->bcTag()<<
627 " digitTime = " << finalDigit->time() <<
628 " charge = " << finalDigit->charge());
629 outDigitContainer[hashIdx].push_back(std::move(finalDigit));
632 return StatusCode::SUCCESS;
636 const double vmmDeadTime,
638 const bool isNeighborOn)
const {
645 const int layA = idHelper.gasGap(a.identify());
646 const int layB = idHelper.gasGap(b.identify());
647 if (layA != layB) return layA < layB;
648 const int chA = idHelper.channel(a.identify());
649 const int chB = idHelper.channel(b.identify());
650 if (chA != chB) return chA < chB;
651 return a.time() < b.time();
655 premerged.reserve(unmergedDigits.size());
656 savedDigits.reserve(premerged.capacity());
660 if (!isNeighborOn || savedDigits.empty())
return false;
661 if (savedDigits.back().identify() == candidate.identify() &&
662 std::abs(savedDigits.back().time() - candidate.time()) < vmmDeadTime) {
666 const Identifier digitId = candidate.identify();
667 const int channel = idHelper.
channel(digitId);
669 for (
int neighbour : {std::max(1, channel -1), std::min(maxChannel, channel+1)}) {
671 if (neighbour == channel)
continue;
679 return known.identify() == neighbourId &&
680 known.getDigit().charge() > threshold &&
681 std::abs(known.time() - candidate.time()) < m_hitTimeMergeThreshold;
682 }) != savedDigits.end())
return true;
690 for (sTgcSimDigitVec::iterator merge_me = unmergedDigits.begin(); merge_me!= unmergedDigits.end(); ++merge_me) {
696 sTgcDigit& digit1{(*merge_me).getDigit()};
697 double totalCharge = digit1.
charge();
698 double weightedTime = digit1.
time();
700 sTgcSimDigitVec::iterator merge_with = merge_me + 1;
701 for ( ; merge_with!= unmergedDigits.end(); ++merge_with) {
703 if ((*merge_with).identify() != (*merge_me).identify()) {
706 const sTgcDigit& mergeDigit{(*merge_with).getDigit()};
712 weightedTime = (weightedTime * totalCharge + mergeDigit.
time() * mergeDigit.
charge())
713 / (totalCharge + mergeDigit.
charge());
715 totalCharge += mergeDigit.
charge();
720 if (!savedDigits.empty() &&
721 savedDigits.back().identify() == digit1.
identify() &&
722 std::abs(savedDigits.back().time() - digit1.
time()) <= vmmDeadTime)
continue;
724 savedDigits.emplace_back(std::move(mergedHit));
725 }
else if (isNeighborOn) {
726 premerged.emplace_back(std::move(mergedHit));
729 std::copy_if(std::make_move_iterator(premerged.begin()),
730 std::make_move_iterator(premerged.end()),
731 std::back_inserter(savedDigits), passNeigbourLogic);
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(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
const_pointer_type cptr()
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.
const Amg::Vector3D & globalPrePosition() const
double globalTime() const
const Amg::Vector3D & globalDirection() const
double kineticEnergy() const
const Amg::Vector3D & globalPosition() const
const HepMcParticleLink & particleLink() const
int particleEncoding() const
double depositEnergy() 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.
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)