ATLAS Offline Software
Loading...
Searching...
No Matches
MuonTruthSegmentCreationAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6
8#include "Identifier/Identifier.h"
16#include <cstddef>
17#include <memory>
19namespace {
20
21 // Only reject muons from light quark deays
22 const std::set<int> bad_origins{
23 ParticleOrigin ::LightMeson, // 23
24 ParticleOrigin ::StrangeMeson, // 24
25 ParticleOrigin ::LightBaryon, // 30
26 ParticleOrigin ::StrangeBaryon, // 31
27 ParticleOrigin ::PionDecay, // 34
28 ParticleOrigin ::NucReact, // 41
29 ParticleOrigin ::PiZero, // 42
30 };
31
32} // namespace
33
34namespace Muon {
35 using namespace MuonStationIndex;
36 // Initialize method:
38 ATH_CHECK(m_muonTruth.initialize());
39
41 ATH_CHECK(m_SDO_TruthNames.initialize());
43
44 ATH_CHECK(m_detMgrKey.initialize());
45 ATH_CHECK(m_idHelperSvc.retrieve());
46
47 ATH_CHECK(m_truthOriginKey.initialize());
49 if(m_idHelperSvc->hasRPC()) {m_truthHitsKeyArray.emplace_back(m_muonTruth, "truthRpcHits");}
50 if(m_idHelperSvc->hasTGC()) {m_truthHitsKeyArray.emplace_back(m_muonTruth, "truthTgcHits");}
51 if(m_idHelperSvc->hasMDT()) {m_truthHitsKeyArray.emplace_back(m_muonTruth, "truthMdtHits");}
52 if(m_idHelperSvc->hasMM()) {m_truthHitsKeyArray.emplace_back(m_muonTruth, "truthMMHits");}
53 if(m_idHelperSvc->hasSTGC()) {m_truthHitsKeyArray.emplace_back(m_muonTruth, "truthStgcHits");}
54 if(m_idHelperSvc->hasCSC()) {m_truthHitsKeyArray.emplace_back(m_muonTruth, "truthCscHits");}
55 ATH_CHECK(m_truthHitsKeyArray.initialize());
56 return StatusCode::SUCCESS;
57 }
58
59 // Execute method:
60 StatusCode MuonTruthSegmentCreationAlg::execute(const EventContext& ctx) const {
61
62 const xAOD::TruthParticleContainer* muonTruthContainer{nullptr};
63 ATH_CHECK(SG::get(muonTruthContainer, m_muonTruth, ctx));
64
66 ATH_CHECK(truthOrigin.isPresent());
68 ATH_CHECK(truthClassification.isPresent()); // May need to comment this out initially
69
70 // create output container
72 ATH_CHECK(segmentContainer.record(std::make_unique<xAOD::MuonSegmentContainer>(),
73 std::make_unique<xAOD::MuonSegmentAuxContainer>()));
74 ATH_MSG_DEBUG("Recorded MuonSegmentContainer with key: " << segmentContainer.name());
75
76 size_t itr = 0;
77 for (const xAOD::TruthParticle* truthParticle : *muonTruthContainer) {
78 // TODO adapt the logic in this loop to use truthClassification rather than truthOrigin
79 const int iOrigin = truthOrigin(*truthParticle);
80 bool goodMuon = bad_origins.find(iOrigin) == bad_origins.end();
81
82 // create segments
83 if (goodMuon) {
84 ElementLink<xAOD::TruthParticleContainer> truthLink(*muonTruthContainer, itr);
85 truthLink.toPersistent();
86
87 ChamberIdMap ids{};
88 ATH_CHECK(fillChamberIdMap(ctx, *truthParticle, ids));
89 ATH_CHECK(createSegments(ctx, truthLink, ids, *segmentContainer));
90 }
91 itr++;
92 }
93
94 ATH_MSG_DEBUG("Registered " << segmentContainer->size() << " truth muon segments ");
95
96 return StatusCode::SUCCESS;
97 }
98
99 StatusCode MuonTruthSegmentCreationAlg::fillChamberIdMap(const EventContext& ctx,
100 const xAOD::TruthParticle& truthParticle,
101 ChamberIdMap& ids) const{
102
103 for (SG::ReadDecorHandle<xAOD::TruthParticleContainer, std::vector<unsigned long long>>& hitCollection : m_truthHitsKeyArray.makeHandles(ctx)){
104 for (const unsigned long long& hit_compID : hitCollection(truthParticle)){
105 const Identifier id{hit_compID};
106 if (m_idHelperSvc->isTgc(id)) { // TGCS should be added to both EIL and EIS
107 if (m_idHelperSvc->phiIndex(id) == PhiIndex::T4) {
108 ids[ChIndex::EIS].push_back(id);
109 ids[ChIndex::EIL].push_back(id);
110 } else {
111 ids[ChIndex::EMS].push_back(id);
112 ids[ChIndex::EML].push_back(id);
113 }
114 } else {
115 ids[m_idHelperSvc->chamberIndex(id) ].push_back(id);
116 }
117 }
118 }
119 return StatusCode::SUCCESS;
120 }
121
122 StatusCode MuonTruthSegmentCreationAlg::createSegments(const EventContext& ctx,
124 const ChamberIdMap& ids,
125 xAOD::MuonSegmentContainer& segmentContainer) const {
126
127 const MuonGM::MuonDetectorManager* detMgr{nullptr};
128 ATH_CHECK(SG::get(detMgr, m_detMgrKey, ctx));
129
130 constexpr unsigned techMax = toInt(TechnologyIndex::TechnologyIndexMax);
131 std::array<const MuonSimDataCollection*, techMax> sdoCollections{};
132 bool useSDO = !m_CSC_SDO_TruthNames.empty();
134 const MuonSimDataCollection* coll{nullptr};
135 ATH_CHECK(SG::get(coll, k, ctx));
136 if (coll->empty()) {
137 continue;
138 }
139 Identifier id = coll->begin()->first;
140 sdoCollections[toInt(m_idHelperSvc->technologyIndex(id))] = coll;
141 useSDO = true;
142 }
143 // loop over chamber layers
144 for (const auto& [chIdx, assocIds] : ids) {
145 // skip empty layers
146 Amg::Vector3D firstPos{Amg::Vector3D::Zero()}, secondPos{Amg::Vector3D::Zero()};
147 bool firstPosSet{false}, secondPosSet{false};
148 Identifier chId{};
149 int index = -1;
150 uint8_t nprecLayers{0}, nphiLayers{0}, ntrigEtaLayers{0};
151 std::unordered_set<int> phiLayers{}, etaLayers{}, precLayers{};
152 ATH_MSG_DEBUG(" new chamber layer " << Muon::MuonStationIndex::chName(chIdx) << " hits " << assocIds.size());
153 // loop over hits
154 for (const auto& id : assocIds) {
155 ATH_MSG_VERBOSE(" hit " << m_idHelperSvc->toString(id));
156 bool measPhi = m_idHelperSvc->measuresPhi(id);
157 bool isCsc = m_idHelperSvc->isCsc(id);
158 bool isMM = m_idHelperSvc->isMM(id);
159 bool isTrig = m_idHelperSvc->isTrigger(id);
160 bool isEndcap = m_idHelperSvc->isEndcap(id);
161 if (measPhi) {
162 phiLayers.insert(m_idHelperSvc->gasGap(id));
163 } else {
164 if (!isTrig) {
165 if (!chId.is_valid()) chId = id; // use first precision hit in list
166 if (isCsc || isMM) {
167 precLayers.insert(m_idHelperSvc->gasGap(id));
168 } else {
169 int iid = 10 * m_idHelperSvc->mdtIdHelper().multilayer(id) + m_idHelperSvc->mdtIdHelper().tubeLayer(id);
170 precLayers.insert(iid);
171 // ATH_MSG_VERBOSE("iid " << iid << " precLayers size " << precLayers.size() );
172 }
173 } else {
174 etaLayers.insert(m_idHelperSvc->gasGap(id));
175 }
176 }
177 // use SDO to look-up truth position of the hit
178 if (!useSDO) {
179 continue;
180 }
181 Amg::Vector3D gpos{Amg::Vector3D::Zero()};
182 if (!isCsc) {
183 bool ok = false;
184 TechnologyIndex techIdx = m_idHelperSvc->technologyIndex(id);
185 if (sdoCollections[toInt(techIdx)]) {
186 auto pos = sdoCollections[toInt(techIdx)]->find(id);
187 if (pos != sdoCollections[toInt(techIdx)]->end()) {
188 gpos = pos->second.globalPosition();
189 if (gpos.perp() > 0.1) ok = true; // sanity check
190 }
191 }
192 // look up successful, calculate
193 if (!ok) continue;
194
195 // small comparison function
196 auto isSmaller = [isEndcap](const Amg::Vector3D& p1, const Amg::Vector3D& p2) {
197 if (isEndcap)
198 return std::abs(p1.z()) < std::abs(p2.z());
199 else
200 return p1.perp() < p2.perp();
201 };
202 if (!firstPosSet) {
203 firstPos = gpos;
204 firstPosSet = true;
205 } else if (!secondPosSet) {
206 secondPos = gpos;
207 secondPosSet = true;
208 if (isSmaller(secondPos, firstPos)) std::swap(firstPos, secondPos);
209 } else {
210 // update position if we can increase the distance between the two positions
211 if (isSmaller(gpos, firstPos))
212 firstPos = gpos;
213 else if (isSmaller(secondPos, gpos))
214 secondPos = gpos;
215 }
216 } else {
217 SG::ReadHandle cscCollection(m_CSC_SDO_TruthNames, ctx);
218 ATH_CHECK(cscCollection.isPresent());
219 auto pos = cscCollection->find(id);
220 if (pos == cscCollection->end()) {
221 continue;
222 }
223 const MuonGM::CscReadoutElement* descriptor = detMgr->getCscReadoutElement(id);
224 ATH_MSG_DEBUG("found csc sdo with " << pos->second.getdeposits().size() << " deposits");
225 Amg::Vector3D locpos(0, pos->second.getdeposits()[0].second.ypos(), pos->second.getdeposits()[0].second.zpos());
226 gpos = descriptor->localToGlobalCoords(locpos, m_idHelperSvc->cscIdHelper().elementID(id));
227 ATH_MSG_DEBUG("got CSC global position " << gpos);
228 if (!firstPosSet) {
229 firstPos = gpos;
230 firstPosSet = true;
231 } else if (!secondPosSet) {
232 secondPos = gpos;
233 secondPosSet = true;
234 if (secondPos.perp() < firstPos.perp()) std::swap(firstPos, secondPos);
235 } else {
236 if (gpos.perp() < firstPos.perp())
237 firstPos = gpos;
238 else if (secondPos.perp() < gpos.perp())
239 secondPos = gpos;
240 }
241 }
242 }
243 if (precLayers.size() > 2) {
244 if (!phiLayers.empty()) nphiLayers = phiLayers.size();
245 ntrigEtaLayers = etaLayers.size();
246 nprecLayers = precLayers.size();
247 ATH_MSG_DEBUG(" total counts: precision " << static_cast<int>(nprecLayers) << " phi layers " << static_cast<int>(nphiLayers)
248 << " eta trig layers " << static_cast<int>(ntrigEtaLayers)
249 << " associated reco muon " << index << " unique ID " << HepMC::uniqueID(*truthLink)
250 << " truthLink " << truthLink);
251 xAOD::MuonSegment* segment = segmentContainer.push_back(std::make_unique<xAOD::MuonSegment>());
252
253 segment->setNHits(nprecLayers, nphiLayers, ntrigEtaLayers);
255 truthParticleLinkAcc("truthParticleLink");
256 truthParticleLinkAcc(*segment) = truthLink;
257 if (chId.is_valid()) { //we should always enter here if we have precision measurements
258 int eta = m_idHelperSvc->stationEta(chId);
259 int sector = m_idHelperSvc->sector(chId);
260 MuonStationIndex::TechnologyIndex technology = m_idHelperSvc->technologyIndex(chId);
261 MuonStationIndex::ChIndex chIndex = m_idHelperSvc->chamberIndex(chId);
262 segment->setIdentifier(sector, chIndex, eta, technology);
263 }
264 if (firstPosSet && secondPosSet) {
265 Amg::Vector3D gpos = (firstPos + secondPos) / 2.;
266 Amg::Vector3D gdir = (firstPos - secondPos).unit();
267 ATH_MSG_DEBUG(" got position : r " << gpos.perp() << " z " << gpos.z() << " and direction: theta " << gdir.theta()
268 << " phi " << gdir.phi());
269 segment->setPosition(gpos.x(), gpos.y(), gpos.z());
270 segment->setDirection(gdir.x(), gdir.y(), gdir.z());
271 }
272 }
273 }
274 return StatusCode::SUCCESS;
275 }
276
277
278
279} // namespace Muon
Scalar eta() const
pseudorapidity method
const PlainObject unit() const
This is a plugin that makes Eigen look like CLHEP & defines some convenience methods.
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_DEBUG(x)
Handle class for reading a decoration on an object.
value_type push_back(value_type pElem)
Add an element to the end of the collection.
bool is_valid() const
Check if id is in a valid state.
Amg::Vector3D localToGlobalCoords(const Amg::Vector3D &x, const Identifier &id) const
localToGlobalCoords and Transf connect the Gas Gap Frame (defined as a Sensitive Detector) to the Glo...
The MuonDetectorManager stores the transient representation of the Muon Spectrometer geometry and pro...
const CscReadoutElement * getCscReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
SG::ReadDecorHandleKey< xAOD::TruthParticleContainer > m_truthOriginKey
FIXME ReadDecorHandle should not be used to access dynamic variables applied by the algorithm which c...
virtual StatusCode execute(const EventContext &ctx) const override
StatusCode fillChamberIdMap(const EventContext &ctx, const xAOD::TruthParticle &truthParticle, ChamberIdMap &ids) const
This function uses the 6 vectors, contained in.
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
Handle for the muonIdHelper service.
SG::ReadDecorHandleKeyArray< xAOD::TruthParticleContainer, std::vector< unsigned long long > > m_truthHitsKeyArray
Keys of the truth muon decorations that we need to read to (re-)fill the chamberIdMap.
std::map< Muon::MuonStationIndex::ChIndex, std::vector< Identifier > > ChamberIdMap
This map contains all the hits corresponding to truth muons classified by chamber layer that recorded...
SG::ReadCondHandleKey< MuonGM::MuonDetectorManager > m_detMgrKey
MuonDetectorManager from the conditions store.
SG::WriteHandleKey< xAOD::MuonSegmentContainer > m_muonTruthSegmentContainerName
Key for segment container that will be populated with segments.
SG::ReadHandleKey< CscSimDataCollection > m_CSC_SDO_TruthNames
StatusCode createSegments(const EventContext &ctx, const ElementLink< xAOD::TruthParticleContainer > &truthLink, const ChamberIdMap &ids, xAOD::MuonSegmentContainer &segmentContainer) const
This function performs, for each truth muon, the actual segment creation and stores segments into a n...
SG::ReadHandleKey< xAOD::TruthParticleContainer > m_muonTruth
Key for the truth muon container and muon origin decoration.
SG::ReadHandleKeyArray< MuonSimDataCollection > m_SDO_TruthNames
Keys for all çontainers of muon hit simulation data, classified by detector technology.
SG::ReadDecorHandleKey< xAOD::TruthParticleContainer > m_truthClassificationKey
Helper class to provide type-safe access to aux data.
Handle class for reading a decoration on an object.
Property holding a SG store/key/clid from which a ReadHandle is made.
bool isPresent() const
Is the referenced object present in SG?
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.
void setDirection(float px, float py, float pz)
Sets the direction.
void setNHits(int nPrecisionHits, int nPhiLayers, int nTrigEtaLayers)
Set the number of hits/layers.
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.
Eigen::Matrix< double, 3, 1 > Vector3D
int uniqueID(const T &p)
ChIndex chIndex(const std::string &index)
convert ChIndex name string to enum
TechnologyIndex
enum to classify the different layers in the muon spectrometer
constexpr int toInt(const EnumType enumVal)
const std::string & chName(ChIndex index)
convert ChIndex into a string
ChIndex
enum to classify the different chamber layers in the muon spectrometer
NRpcCablingAlg reads raw condition data and writes derived condition data to the condition store.
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
Definition index.py:1
void swap(ElementLinkVector< DOBJ > &lhs, ElementLinkVector< DOBJ > &rhs)
MuonSegmentContainer_v1 MuonSegmentContainer
Definition of the current "MuonSegment container version".
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.