19#include "GaudiKernel/PhysicalConstants.h"
21#include <unordered_map>
24 constexpr double c_inv = 1./Gaudi::Units::c_light;
34 ATH_MSG_ERROR(
"No simulated hit containers have been parsed to build the segments from ");
35 return StatusCode::FAILURE;
53 return StatusCode::SUCCESS;
57 switch (
const auto techIdx =
m_idHelperSvc->technologyIndex(hitId)) {
65 const double driftTime = rtCalib->tr()->driftTime(hit.
localPosition().perp()).value_or(rtCalib->tr()->maxRadius());
66 return rtCalib->rtRes()->resolution(driftTime);
68 const auto*
re =
m_detMgr->getRpcReadoutElement(hitId);
69 return re->stripEtaPitch() / std::sqrt(12.);
71 const auto*
re =
m_detMgr->getTgcReadoutElement(hitId);
73 const auto& design =
re->wireGangLayout(measHash);
74 return design.stripPitch() / std::sqrt(12.);
84 if (techIdx ==
STGC) {
99 return link->momentum().perp();
102 return std::sqrt(std::max(e*e - m*m, 0.f)) * std::sin(globDir.theta());
119 ATH_MSG_VERBOSE(
"Assemble segments from "<<simHits.size()<<
" background hits.");
120 std::vector<char> alreadyUsed(simHits.size(), 0);
121 for (std::size_t
h = 0 ;
h < simHits.size(); ++
h) {
122 if (alreadyUsed[
h]) {
125 const auto& [refHit, refPos, refDir] = simHits[
h];
129 <<
", pt: "<<
muonPt(*refHit, locToGlob.linear()* refDir)/ Gaudi::Units::GeV <<
" [GeV].");
130 std::vector<std::size_t> indicesOnSeg{
h};
131 for (std::size_t h1 =
h +1; h1 < simHits.size(); ++h1) {
132 if (alreadyUsed[h1]) {
135 const auto&[testHit, testPos, testDir] = simHits[h1];
138 if (std::abs(refHit->kineticEnergy() - testHit->kineticEnergy()) >
m_pileUpHitELoss) {
144 const double angleDir =
Amg::angle(testDir, refDir);
148 <<
", E: "<<testHit->kineticEnergy() / (Gaudi::Units::GeV)<<
", angle: "
149 <<(angleDir / Gaudi::Units::deg) <<
", distance: "<<hitSep<<
".");
154 indicesOnSeg.push_back(h1);
160 globPos, globDir).value_or(0.) * globDir;
161 ATH_MSG_VERBOSE(
"Found "<<indicesOnSeg.size()<<
" matching hits. Closest perigee "
164 std::ranges::transform(indicesOnSeg,
165 std::back_inserter(hitsOnSeg),
166 [&simHits](
const auto idx) {
171 std::ranges::for_each(indicesOnSeg,
172 [&alreadyUsed](
const auto idx) {
173 alreadyUsed[idx] = 1;
185 auto refHit_itr = std::ranges::min_element(simHits,
187 return std::abs(std::get<1>(
a).
z()) <std::abs(std::get<1>(b).
z());
190 const auto [simHit, localPos, chamberDir] = (*refHit_itr);
192 " pdgId: "<<simHit->pdgId()<<
", energy: "<<simHit->kineticEnergy()
193 <<
", genParticle: "<<simHit->genParticleLink().cptr());
197 const double distance =
Amg::intersect<3>(localPos, chamberDir, Amg::Vector3D::UnitZ(), 0.).value_or(0.);
198 const Amg::Vector3D chamberPos = localPos + distance*chamberDir;
201 const Amg::Vector3D globDir = locToGlob.linear() * chamberDir;
203 unsigned nMdt{0}, nRpcEta{0}, nRpcPhi{0}, nTgcEta{0}, nTgcPhi{0};
204 unsigned nMm{0}, nStgcEta{0}, nStgcPhi{0};
207 for (
const auto& [assocMe, pos, dir] : simHits) {
216 if (castRE->nEtaStrips()) ++nRpcEta;
217 if (castRE->nPhiStrips()) ++nRpcPhi;
222 if (castRE->numStrips(gapHash)){
225 if (castRE->numWireGangs(gapHash)) {
240 <<
" pdgId: "<<assocMe->pdgId()<<
", energy: "<<assocMe->kineticEnergy()
241 <<
", genParticle: "<<assocMe->genParticleLink().cptr()<<
", beta: "<<simHit->beta()
242 <<
" global time: "<<simHit->globalTime()<<
", pos: "<<
Amg::toString(pos)
245 associatedHits.push_back(std::move(link));
247 int nPrecisionHits = nMdt + nMm + nStgcEta;
248 int nPhiLayers = nTgcPhi + nRpcPhi + nStgcPhi;
250 if (nPrecisionHits < 3) {
254 xAOD::MuonSegment* truthSegment = out.segments.push_back(std::make_unique<xAOD::MuonSegment>());
255 out.ptDecor(*truthSegment) =
muonPt(*simHit, globDir);
256 out.chargeDecor(*truthSegment) =
MC::charge(simHit);
257 SegPars_t& locPars{out.paramDecor(*truthSegment)};
258 locPars[Acts::toUnderlying(ParamDefs::x0)] = chamberPos.x();
259 locPars[Acts::toUnderlying(ParamDefs::y0)] = chamberPos.y();
260 constexpr float betaLowLimit = 1.e-6;
261 locPars[Acts::toUnderlying(ParamDefs::t0)] = simHit->globalTime() + distance *c_inv / std::max(simHit->beta(), betaLowLimit);
262 locPars[Acts::toUnderlying(ParamDefs::theta)] = chamberDir.theta();
263 locPars[Acts::toUnderlying(ParamDefs::phi)] = chamberDir.phi();
265 truthSegment->
setPosition(globPos.x(), globPos.y(), globPos.z());
266 truthSegment->
setDirection(globDir.x(), globDir.y(), globDir.z());
267 truthSegment->
setT0Error(locPars[Acts::toUnderlying(ParamDefs::t0)], 0.);
269 truthSegment->
setNHits(nPrecisionHits, nPhiLayers, nTgcEta + nRpcEta);
275 if (nPhiLayers == 0){
278 truthSegment->
setFitQuality(
chi2, (nPrecisionHits + nPhiLayers + nTgcEta + nRpcEta - 5));
280 out.hitLinkDecor(*truthSegment) = std::move(associatedHits);
288 using HitsPerParticle = std::unordered_map<HepMC::ConstGenParticlePtr, SimHitVec_t>;
289 using HitCollector = std::unordered_map<const MuonGMR4::SpectrometerSector*, HitsPerParticle>;
290 HitCollector hitCollector{};
298 auto genLink = simHit->genParticleLink();
300 if (genLink.isValid()){
301 genParticle = genLink.cptr();
306 " pdgId: "<<simHit->pdgId()<<
", energy: "<<simHit->kineticEnergy()
307 <<
", genParticle: "<<genParticle);
311 hitCollector[id][genParticle].emplace_back(simHit,
312 toChTrf *xAOD::toEigen(simHit->localPosition()),
313 toChTrf.linear()* xAOD::toEigen(simHit->localDirection()));
318 ATH_CHECK(writeHandle.
record(std::make_unique<xAOD::MuonSegmentContainer>(),
319 std::make_unique<xAOD::MuonSegmentAuxContainer>()));
323 for (
auto& [chamber, collectedParts] : hitCollector) {
325 for (
auto& [particle, simHits]: collectedParts) {
328 return std::get<1>(
a).z() < std::get<1>(b).z();
338 ATH_MSG_DEBUG(
"Constructed "<<writeHandle->size()<<
" truth segments in total ");
339 return StatusCode::SUCCESS;
345 std::unordered_map<const SG::AuxVectorData*, DecorHandle_t> handleMap{};
347 DecorHandle_t decorHandle{decorKey, ctx};
348 if (decorHandle->empty()) {
349 ATH_MSG_DEBUG(
"Don't setup a decoration handle for "<<decorKey.fullKey());
352 decorHandle(*decorHandle->front()) =
SegLink_t{};
353 handleMap.insert(std::make_pair(decorHandle.cptr(), std::move(decorHandle)));
356 SegLink_t segLink{&segments, segment->index()};
358 handleMap.at(simHit->container())(*simHit) = segLink;
361 return StatusCode::SUCCESS;
const boost::regex re(r_e)
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
ATLAS-specific HepMC functions.
virtual DetectorType detectorType() const =0
Returns the detector element type.
const ServiceHandle< StoreGateSvc > & detStore() const
Header file for AthHistogramAlgorithm.
ElementLink implementation for ROOT usage.
This is a "hash" representation of an Identifier.
const MdtFullCalibData * getCalibData(const Identifier &measId, MsgStream &msg) const
Returns the calibration data associated with this station.
MuonReadoutElement is an abstract class representing the geometry of a muon detector.
const Amg::Transform3D & localToGlobalTransform(const ActsTrk::GeometryContext &ctx) const
Returns the transformation from the local coordinate system of the readout element into the global AT...
const SpectrometerSector * msSector() const
Returns the pointer to the envelope volume enclosing all chambers in the sector.
virtual IdentifierHash measurementHash(const Identifier &measId) const =0
The measurement hash is a continous numbering schema of all readout channels described by the specifi...
virtual IdentifierHash layerHash(const Identifier &measId) const =0
The layer hash removes the bits from the IdentifierHash corresponding to the measurement's channel nu...
A spectrometer sector forms the envelope of all chambers that are placed in the same MS sector & laye...
Amg::Transform3D globalToLocalTransform(const ActsTrk::GeometryContext &gctx) const
Returns the global -> local transformation from the ATLAS global.
SG::WriteDecorHandleKey< xAOD::MuonSegmentContainer > m_locParKey
Decoration key of the local parameters.
std::vector< HitPosTuple_t > SimHitVec_t
Gaudi::Property< float > m_pileUpHitMinE
Minimum energy threshold for pile up hits to be converted.
SG::ReadHandleKey< ActsTrk::GeometryContext > m_geoCtxKey
Key to the geometry context.
StatusCode execute(const EventContext &ctx) const override
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
IdHelperSvc to decode the Identifiers.
Gaudi::Property< float > m_pileUpHitAngleCone
Maximum scattering angle between two pile-up hits.
Gaudi::Property< float > m_idCylinderR
ID / ITk cylinder radius.
Amg::Transform3D toChamber(const ActsTrk::GeometryContext &gctx, const Identifier &chanId) const
Returns the transform from the local simHit frame -> chamber frame.
const MuonGMR4::MuonDetectorManager * m_detMgr
Pointer to the muon readout geometry.
StatusCode initialize() override final
SG::WriteDecorHandleKey< xAOD::MuonSegmentContainer > m_eleLinkKey
Decoration key of the associated sim hit links.
SG::ReadCondHandleKey< MuonCalib::MdtCalibDataContainer > m_mdtCalibKey
Data dependency on the Mdt calibration container to calculate the uncertainty.
ElementLink< xAOD::MuonSimHitContainer > EleLink_t
Gaudi::Property< float > m_pileUpHitELoss
Maximum energy loss between two pile-up hits.
std::vector< EleLink_t > HitLinkVec_t
Gaudi::Property< float > m_idCylinderHalfZ
ID / Itk cylinder half length.
SG::WriteDecorHandleKey< xAOD::MuonSegmentContainer > m_qKey
Decoration key of the muon charge.
xAOD::MuonSegment * constructSegmentFromHits(const EventContext &ctx, const Amg::Transform3D &locToGlob, const SimHitVec_t &hits, WriteDecorHolder &writeShip) const
Takes a list of related sim hits and transforms them into a truth segment.
SG::WriteDecorHandleKey< xAOD::MuonSegmentContainer > m_ptKey
Decoration key of the associated particle pt.
Gaudi::Property< bool > m_useOnlyMuonHits
Build segments from muon hits only.
SG::WriteDecorHandleKeyArray< xAOD::MuonSimHitContainer > m_segLinkKeys
Decorate the truth segment link to the simHit.
Gaudi::Property< std::string > m_segLinkKey
Name of the link to the truth segment.
void buildSegmentsFromBkg(const EventContext &ctx, const Amg::Transform3D &locToGlob, const SimHitVec_t &simHits, WriteDecorHolder &writeShip) const
Attempts to assemble truth segments from a list of loose sim hits, i.e., the hits are stemming from a...
std::tuple< const xAOD::MuonSimHit *, Amg::Vector3D, Amg::Vector3D > HitPosTuple_t
Tuple consisting out of pointer to the sim hit and the position & direction expressed in the chamber'...
xAOD::MeasVector< Acts::toUnderlying(SegmentFit::ParamDefs::nPars)> SegPars_t
SG::WriteHandleKey< xAOD::MuonSegmentContainer > m_segmentKey
Key under which the segment Container will be recorded in StoreGate.
SG::ReadCondHandleKey< NswErrorCalibData > m_nswUncertKey
Data dependency on the Nsw calibration container to estimate the uncertaintys.
Gaudi::Property< bool > m_includePileUpHits
Construct segments from pile-up hits without GenParticleLink.
Gaudi::Property< float > m_pileUpHitDistance
Maximum separation between two pile-up hits.
float hitUncertainty(const EventContext &ctx, const xAOD::MuonSimHit &hit) const
Evaluates the hit uncertainty.
float muonPt(const xAOD::MuonSimHit &hit, const Amg::Vector3D &globDir) const
Returns the muon pt from the sim hit.
StatusCode linkSegmentsToHits(const EventContext &ctx, const xAOD::MuonSegmentContainer &segments) const
Establish the link from the simulated hit -> truth segment.
SG::ReadHandleKeyArray< xAOD::MuonSimHitContainer > m_readKeys
List of sim hit containers from which the truth segments shall be retrieved.
double clusterUncertainty(const Input &clustInfo) const
Property holding a SG store/key/clid from which a ReadHandle is made.
Handle class for adding a decoration to an object.
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
void setDirection(float px, float py, float pz)
Sets the direction.
void setFitQuality(float chiSquared, float numberDoF)
Set the 'Fit Quality' information.
void setNHits(int nPrecisionHits, int nPhiLayers, int nTrigEtaLayers)
Set the number of hits/layers.
void setT0Error(float t0, float t0Error)
Sets the time error.
void setIdentifier(int sector, ::Muon::MuonStationIndex::ChIndex chamberIndex, int etaIndex, ::Muon::MuonStationIndex::TechnologyIndex technology)
Set the identifier.
void setPosition(float x, float y, float z)
Sets the global position.
ConstVectorMap< 3 > localDirection() const
Returns the local direction of the traversing particle.
float mass() const
Returns the rest-mass of the traversing particle.
Identifier identify() const
Returns the global ATLAS identifier of the SimHit.
ConstVectorMap< 3 > localPosition() const
Returns the local postion of the traversing particle.
const HepMcParticleLink & genParticleLink() const
Returns the link to the HepMC particle producing this hit.
float kineticEnergy() const
Returns the kinetic energy of the traversing particle.
double chi2(TH1 *h0, TH1 *h1)
@ Mm
Maybe not needed in the migration.
@ Tgc
Resitive Plate Chambers.
@ Rpc
Monitored Drift Tubes.
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.
double signedDistance(const Amg::Vector3D &posA, const Amg::Vector3D &dirA, const Amg::Vector3D &posB, const Amg::Vector3D &dirB)
Calculates the signed distance between two lines in 3D space.
double angle(const Amg::Vector3D &v1, const Amg::Vector3D &v2)
calculates the opening angle between two vectors
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 3, 1 > Vector3D
const GenParticle * ConstGenParticlePtr
double charge(const T &p)
This header ties the generic definitions in this package.
std::unordered_set< const xAOD::MuonSimHit * > getMatchingSimHits(const xAOD::MuonSegment &segment)
: Returns all sim hits matched to a xAOD::MuonSegment
ElementLink< MuonR4::SegmentContainer > SegLink_t
Abrivation of the link to the reco segment container.
TechnologyIndex
enum to classify the different layers in the muon spectrometer
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
MuonSimHitContainer_v1 MuonSimHitContainer
Define the version of the pixel cluster container.
MuonSegmentContainer_v1 MuonSegmentContainer
Definition of the current "MuonSegment container version".
MuonSimHit_v1 MuonSimHit
Defined the version of the MuonSimHit.
MuonSegment_v1 MuonSegment
Reference the current persistent version:
Helper struct to ship the write DecorHandles and the reference to the output segment container throug...
#define THROW_EXCEPTION(MESSAGE)