8#include "AthLinks/ElementLink.h"
9#include "Identifier/Identifier.h"
15#include "Acts/Surfaces/PlaneSurface.hpp"
17#include <unordered_set>
20using namespace Acts::UnitLiterals;
23 using IdSet_t = std::unordered_set<Identifier>;
24 unsigned int countMatched(
const std::unordered_set<const xAOD::MuonSimHit*>& simHits,
25 const IdSet_t& matchIds) {
26 return std::ranges::count_if(simHits, [&matchIds](
const xAOD::MuonSimHit* hit) {
27 return matchIds.count(hit->
identify());
36 return Acts::Vector4::Zero();
56 return StatusCode::SUCCESS;
69 std::vector<IdDecorHandle_t> idDecorHandles{};
71 idDecorHandles.emplace_back(hitKey, ctx);
74 using IdSet_t = std::unordered_set<Identifier>;
75 using TruthTuple_t = std::tuple<const xAOD::TruthParticle*, IdSet_t>;
76 std::vector<TruthTuple_t> truthPartWithIds{};
78 std::vector<const xAOD::TruthParticle*> bkgMuons{};
79 truthPartWithIds.reserve(truthParticles->
size());
81 segLinkDecor(*truthMuon).clear();
83 ATH_MSG_DEBUG(__func__<<
"() "<<__LINE__<<
" - Truth muon "<<truthMuon->pt()<<
", eta: "<<truthMuon->eta()
84 <<
", phi: "<<(truthMuon->phi() / 1._degree)<<
", id: "<<
HepMC::uniqueID(truthMuon));
85 for (
const IdDecorHandle_t& hitDecor : idDecorHandles) {
86 std::ranges::transform(hitDecor(*truthMuon), std::inserter(assocIds, assocIds.begin()),
87 [
this](
unsigned long long rawId){
88 const Identifier id{rawId};
93 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Truth muon with pt: "<<(truthMuon->pt() / 1_GeV)
94 <<
", eta: "<<truthMuon->eta()<<
", phi: "<<truthMuon->phi()
95 <<
", uniqueID: "<<
HepMC::uniqueID(truthMuon)<<
", associated hits: "<<assocIds.size());
96 if (assocIds.empty()) {
97 bkgMuons.push_back(truthMuon);
99 truthPartWithIds.emplace_back(std::make_tuple(truthMuon, std::move(assocIds)));
107 TruthPartDecor_t truthLinkDecor{m_truthLinkKey, ctx};
109 std::vector<const xAOD::MuonSegment*> bkgSegments{};
113 ATH_MSG_DEBUG(__func__<<
"() "<<__LINE__<<
" - Reconstructed truth segment "
116 <<
", phi: "<<segment->sector()<<
", nPrecHits: "<<segment->nPrecisionHits()
117 <<
", nDoF: "<<segment->numberDoF()<<
" sim hits: "<<simHits.size());
118 if (msgLvl(MSG::VERBOSE)){
119 std::vector<const xAOD::MuonSimHit*> sortedHits{simHits.begin(), simHits.end()};
121 return a->identify() <
b->identify();
131 if (!(*simHits.begin())->genParticleLink().isValid()) {
132 bkgSegments.push_back(segment);
133 truthLinkDecor(*segment) = TruthPartLink_t{};
137 const auto best_itr = std::ranges::max_element(truthPartWithIds,
138 [&simHits](
const TruthTuple_t& truthTupleA,
139 const TruthTuple_t& truthTupleB) {
140 return countMatched(simHits, std::get<1>(truthTupleA)) <
143 if (best_itr == truthPartWithIds.end()) {
144 ATH_MSG_WARNING(__func__<<
"() "<<__LINE__<<
" - No truth particle matched the truth hits of the segment");
147 if (1.*
countMatched(simHits, std::get<1>(*best_itr)) < 0.5* simHits.size()) {
148 if (msgLvl(MSG::VERBOSE)) {
149 for (
const auto& [truthMuon, assocIds]: truthPartWithIds){
150 std::stringstream unMatchedStr{};
153 if (!assocIds.count(hit->
identify())){
154 unMatchedStr<<
" *** "<<m_idHelperSvc->toString(hit->
identify())<<std::endl;
164 <<counts<<
", unmatched: "<<std::endl<<unMatchedStr.str());
170 segLinkDecor(*truthPart).emplace_back(segments, segment->index());
171 truthLinkDecor(*segment) = TruthPartLink_t{truthParticles, truthPart->
index()};
180 std::ranges::sort(linkedSegs,[&pos, &dir](
const SegLink_t& linkA,
const SegLink_t& linkB){
181 return dir.dot((*linkA)->position() - pos) <
182 dir.dot((*linkB)->position() - pos);
185 return StatusCode::SUCCESS;
188 const std::vector<const xAOD::TruthParticle*>& pileUpMuons,
189 const std::vector<const xAOD::MuonSegment*>& pileUpSegments,
194 ATH_MSG_DEBUG(__func__<<
"() "<<__LINE__<<
" - Matching between pile-up segments & muons is disabled");
197 if (pileUpMuons.empty() || pileUpSegments.empty()) {
198 ATH_MSG_DEBUG(__func__<<
"() "<<__LINE__<<
" - Segments ("<<pileUpSegments.size()<<
") or muons ("
199 <<pileUpMuons.size()<<
") are empty -> nothing to do");
203 std::stringstream sstr{};
205 sstr<<
" *** pT: "<<(bkgMuon->pt() / 1_GeV)<<
", eta: "<<bkgMuon->eta()
206 <<
", phi: "<<(bkgMuon->phi() / 1_degree)<<
", pdgId: "<<bkgMuon->pdgId()
208 <<
", uid: "<<bkgMuon->uid() <<std::endl;
210 sstr<<
"\n To these segments: "<<std::endl;
211 unsigned int counter{0};
213 sstr<<
" "<<(counter++)<<
") "<<
Amg::toString(bkgSeg->position())
214 <<
", phi: "<<(bkgSeg->position().
phi() / 1_degree)<<
", eta: "<<(bkgSeg->position().
eta())
215 <<
", pT: "<< (acc_pt(*bkgSeg) / 1_GeV)
217 <<
", sector: "<<bkgSeg->sector()<<
", nPrecHits: "<<bkgSeg->nPrecisionHits()
218 <<
", chi2: "<<(bkgSeg->chiSquared() / std::max(bkgSeg->numberDoF(), 1.f))
219 <<
", nDoF: "<<bkgSeg->numberDoF()<<std::endl;
221 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - \nMatch the following muons "<<std::endl<<sstr.str());
223 std::vector<char> segmentMatched(pileUpSegments.size(), 0);
226 const Acts::GeometryContext tgContext = gctx.
context();
229 const Acts::Vector4 fourPos = vertexPos(*bkgMuon);
234 auto startSurf = Acts::Surface::makeShared<Acts::PlaneSurface>(
Amg::getTranslate3D(start));
237 Acts::BoundMatrix initialCov{Acts::BoundMatrix::Identity()};
239 auto initialPars = Acts::BoundTrackParameters::create(tgContext, startSurf, fourPos, threeMom.unit(),
240 bkgMuon->charge() / threeMom.mag(),
241 initialCov, Acts::ParticleHypothesis::muon());
242 if(!initialPars.ok()) {
243 ATH_MSG_WARNING(__func__<<
"() "<<__LINE__<<
" - Failed to create start parameters");
247 <<
Amg::toString(threeMom / 1_GeV) <<
", pT: "<<(threeMom.perp() / 1_GeV)
248 <<
", eta: "<<threeMom.eta()<<
", phi: "<<(threeMom.phi() / 1_degree)<<
", q: "<<bkgMuon->charge());
250 for (std::size_t sIdx =0 ; sIdx < pileUpSegments.size(); ++sIdx) {
252 if (segmentMatched[sIdx]) {
256 if (acc_q(*bkgSeg) != bkgMuon->charge()) {
257 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Segment charge does not match");
263 const double lDist = std::abs(
Amg::lineDistance(segPos, segDir, start, threeMom.unit()));
264 const double dPhi = std::abs(segPos.deltaPhi(threeMom));
266 <<
", "<<
Amg::toString(segDir) <<
", lDist: "<<lDist<<
", dPhi: "<<(dPhi / 1_degree));
274 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Extrapolation failed.");
278 const Amg::Vector2D dPosExtp = propPars->localPosition() - (sector->globalToLocalTrans(gctx) * segPos).segment<2>(0);
279 const double dThetaExtp = std::abs(segDir.theta() - propPars->theta());
280 const double dPhiExtp = std::abs(segDir.phi() - propPars->phi());
282 <<
", dTheta:"<<(dThetaExtp / 1._degree)<<
", dPhi: "<<(dPhiExtp / 1._degree));
287 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
" - Parameters differ too much. Cut values"
292 truthSegDecor(*bkgMuon).emplace_back(truthPartDecor.
cptr(), bkgSeg->
index());
293 segmentMatched[sIdx] =
true;
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi 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.
Handle class for reading a decoration on an object.
Handle class for adding a decoration to an object.
Acts::GeometryContext context() const
const ServiceHandle< StoreGateSvc > & detStore() const
bool msgLvl(const MSG::Level lvl) const
size_type size() const noexcept
Returns the number of elements in the collection.
ElementLink implementation for ROOT usage.
Gaudi::Property< std::vector< std::string > > m_simHitIds
List of simHit id decorations to read from the truth particle.
Gaudi::Property< bool > m_includePileUpObjs
Property checking whether a pile-up muons shall be matched to pile-up segments.
const MuonGMR4::MuonDetectorManager * m_detMgr
Pointer to the muon detector manager.
SG::WriteDecorHandleKey< xAOD::MuonSegmentContainer > m_truthLinkKey
Key of the truthParticleLink decorated onto the segment.
SG::WriteDecorHandle< xAOD::TruthParticleContainer, TruthSegLinkVec_t > TruthSegLinkDecor_t
ElementLink< xAOD::TruthParticleContainer > TruthPartLink_t
PublicToolHandle< ActsTrk::ITrackingGeometryTool > m_trackingGeometryTool
Tracking geometry tool.
virtual StatusCode initialize() override final
Gaudi::Property< double > m_pileUpObjExtpDthetaCut
Cut on the delta theta between the bkg segment and the extrapolated parameters.
SG::ReadHandleKey< xAOD::TruthParticleContainer > m_truthKey
Key to the truth particle container to associate.
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
IdHelperSvc to decode the Identifiers.
SG::WriteDecorHandleKey< xAOD::TruthParticleContainer > m_segLinkKey
Declaration of the segmentLink to the truth particle.
Gaudi::Property< double > m_pileUpObjDPhiCut
Delta phi cut between particle momentum & segment position to start the extrapolation.
Gaudi::Property< double > m_pileUpObjExtpDyCut
Cut on the delta y0 between the bkg segment and the extrapolated parameters.
void matchPileupSegments(const EventContext &ctx, const std::vector< const xAOD::TruthParticle * > &pileUpMuons, const std::vector< const xAOD::MuonSegment * > &pileUpSegments, TruthPartDecor_t &truthPartDecor, TruthSegLinkDecor_t &truthSegDecor) const
Match truth muons without any HEPMC link with truth segments reconstructed in the MS.
virtual StatusCode execute(const EventContext &ctx) const override final
Gaudi::Property< double > m_pileUpObjExtpDphiCut
Cut on the delta phi between the bkg segment and the extrapolated parameters.
SG::ReadHandleKey< xAOD::MuonSegmentContainer > m_segmentKey
Key to the truth segment container to associate.
SG::ReadDecorHandleKeyArray< xAOD::TruthParticleContainer > m_simHitKeys
Declaration of the dependency on the simHit decorations.
ToolHandle< ActsTrk::IExtrapolationTool > m_extrapolationTool
Track extrapolation tool.
SG::WriteDecorHandle< xAOD::MuonSegmentContainer, TruthPartLink_t > TruthPartDecor_t
Gaudi::Property< double > m_pileUpObjExtpDxCut
Cut on the delta x0 between the bkg segment and the extrapolated parameters.
size_t index() const
Return the index of this element within its container.
Helper class to provide constant type-safe access to aux data.
Property holding a SG store/key/clid/attr name from which a ReadDecorHandle is made.
Handle class for reading a decoration on an object.
const_pointer_type cptr()
Dereference the pointer.
Handle class for adding a decoration to an object.
Amg::Vector3D direction() const
Returns the direction as Amg::Vector.
::Muon::MuonStationIndex::ChIndex chamberIndex() const
Returns the chamber index.
Amg::Vector3D position() const
Returns the position as Amg::Vector.
int etaIndex() const
Returns the eta index, which corresponds to stationEta in the offline identifiers (and the ).
ConstVectorMap< 3 > localDirection() const
Returns the local direction 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.
bool hasProdVtx() const
Check for a production vertex on this particle.
const TruthVertex_v1 * prodVtx() const
The production vertex of this particle.
float z() const
Vertex longitudinal distance along the beam line form the origin.
float y() const
Vertex y displacement.
float t() const
Vertex time.
float x() const
Vertex x displacement.
std::pair< Amg::Vector3D, double > convertPosFromActs(const Acts::Vector4 &actsPos)
Converts an Acts 4-vector into a pair of an Athena spatial vector and the passed time.
Acts::Vector4 convertMomToActs(const Amg::Vector3D &threeMom, const double mass=0.)
Converts a three momentum vector from Athena together with the associated particle mass into an Acts ...
Acts::Vector4 convertPosToActs(const Amg::Vector3D &athenaPos, const double athenaTime=0.)
Converts a position vector & time from Athena units into Acts units.
Amg::Transform3D getTranslate3D(const double X, const double Y, const double Z)
: Returns a shift transformation along an arbitrary axis
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
double lineDistance(const AmgVector(N)&posA, const AmgVector(N)&dirA, const AmgVector(N)&posB, const AmgVector(N)&dirB)
: Calculates the shortest distance between two lines
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
Parameters localSegmentPars(const xAOD::MuonSegment &seg)
Returns the localSegPars decoration from a xAODMuon::Segment.
std::string toString(const Parameters &pars)
Dumps the parameters into a string with labels in front of each number.
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.
std::vector< SegLink_t > SegLinkVec_t
unsigned int countMatched(const simHitSet &truthHits, const simHitSet &recoHits)
const std::string & chName(ChIndex index)
convert ChIndex into a string
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
MuonSegmentContainer_v1 MuonSegmentContainer
Definition of the current "MuonSegment container version".
TruthVertex_v1 TruthVertex
Typedef to implementation.
MuonSimHit_v1 MuonSimHit
Defined the version of the MuonSimHit.
TruthParticle_v1 TruthParticle
Typedef to implementation.
MuonSegment_v1 MuonSegment
Reference the current persistent version:
TruthParticleContainer_v1 TruthParticleContainer
Declare the latest version of the truth particle container.