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>
19using namespace MCTruthPartClassifier;
20namespace {
21
22 // Only reject muons from light quark deays
23 const std::set<int> bad_origins{
24 ParticleOrigin ::LightMeson, // 23
25 ParticleOrigin ::StrangeMeson, // 24
26 ParticleOrigin ::LightBaryon, // 30
27 ParticleOrigin ::StrangeBaryon, // 31
28 ParticleOrigin ::PionDecay, // 34
29 ParticleOrigin ::NucReact, // 41
30 ParticleOrigin ::PiZero, // 42
31 };
32
33} // namespace
34
35namespace Muon {
36 using namespace MuonStationIndex;
37 // Initialize method:
39 ATH_CHECK(m_muonTruth.initialize());
40
42 ATH_CHECK(m_SDO_TruthNames.initialize());
44
45 ATH_CHECK(m_detMgrKey.initialize());
46 ATH_CHECK(m_idHelperSvc.retrieve());
47
48 ATH_CHECK(m_truthOriginKey.initialize());
50 if(m_idHelperSvc->hasRPC()) {m_truthHitsKeyArray.emplace_back(m_muonTruth, "truthRpcHits");}
51 if(m_idHelperSvc->hasTGC()) {m_truthHitsKeyArray.emplace_back(m_muonTruth, "truthTgcHits");}
52 if(m_idHelperSvc->hasMDT()) {m_truthHitsKeyArray.emplace_back(m_muonTruth, "truthMdtHits");}
53 if(m_idHelperSvc->hasMM()) {m_truthHitsKeyArray.emplace_back(m_muonTruth, "truthMMHits");}
54 if(m_idHelperSvc->hasSTGC()) {m_truthHitsKeyArray.emplace_back(m_muonTruth, "truthStgcHits");}
55 if(m_idHelperSvc->hasCSC()) {m_truthHitsKeyArray.emplace_back(m_muonTruth, "truthCscHits");}
56 ATH_CHECK(m_truthHitsKeyArray.initialize());
57 return StatusCode::SUCCESS;
58 }
59
60 // Execute method:
61 StatusCode MuonTruthSegmentCreationAlg::execute(const EventContext& ctx) const {
62
63 const xAOD::TruthParticleContainer* muonTruthContainer{nullptr};
64 ATH_CHECK(SG::get(muonTruthContainer, m_muonTruth, ctx));
65
67 ATH_CHECK(truthOrigin.isPresent());
69 ATH_CHECK(truthClassification.isPresent()); // May need to comment this out initially
70
71 // create output container
73 ATH_CHECK(segmentContainer.record(std::make_unique<xAOD::MuonSegmentContainer>(),
74 std::make_unique<xAOD::MuonSegmentAuxContainer>()));
75 ATH_MSG_DEBUG("Recorded MuonSegmentContainer with key: " << segmentContainer.name());
76
77 size_t itr = 0;
78 for (const xAOD::TruthParticle* truthParticle : *muonTruthContainer) {
79 // TODO adapt the logic in this loop to use truthClassification rather than truthOrigin
80 const int iOrigin = truthOrigin(*truthParticle);
81 bool goodMuon = bad_origins.find(iOrigin) == bad_origins.end();
82
83 // create segments
84 if (goodMuon) {
85 ElementLink<xAOD::TruthParticleContainer> truthLink(*muonTruthContainer, itr);
86 truthLink.toPersistent();
87
88 ChamberIdMap ids{};
89 ATH_CHECK(fillChamberIdMap(ctx, *truthParticle, ids));
90 ATH_CHECK(createSegments(ctx, truthLink, ids, *segmentContainer));
91 }
92 itr++;
93 }
94
95 ATH_MSG_DEBUG("Registered " << segmentContainer->size() << " truth muon segments ");
96
97 return StatusCode::SUCCESS;
98 }
99
100 StatusCode MuonTruthSegmentCreationAlg::fillChamberIdMap(const EventContext& ctx,
101 const xAOD::TruthParticle& truthParticle,
102 ChamberIdMap& ids) const{
103
104 for (SG::ReadDecorHandle<xAOD::TruthParticleContainer, std::vector<unsigned long long>>& hitCollection : m_truthHitsKeyArray.makeHandles(ctx)){
105 for (const unsigned long long& hit_compID : hitCollection(truthParticle)){
106 const Identifier id{hit_compID};
107 if (m_idHelperSvc->isTgc(id)) { // TGCS should be added to both EIL and EIS
108 if (m_idHelperSvc->phiIndex(id) == PhiIndex::T4) {
109 ids[ChIndex::EIS].push_back(id);
110 ids[ChIndex::EIL].push_back(id);
111 } else {
112 ids[ChIndex::EMS].push_back(id);
113 ids[ChIndex::EML].push_back(id);
114 }
115 } else {
116 ids[m_idHelperSvc->chamberIndex(id) ].push_back(id);
117 }
118 }
119 }
120 return StatusCode::SUCCESS;
121 }
122
123 StatusCode MuonTruthSegmentCreationAlg::createSegments(const EventContext& ctx,
125 const ChamberIdMap& ids,
126 xAOD::MuonSegmentContainer& segmentContainer) const {
127
128 const MuonGM::MuonDetectorManager* detMgr{nullptr};
129 ATH_CHECK(SG::get(detMgr, m_detMgrKey, ctx));
130
131 constexpr unsigned techMax = toInt(TechnologyIndex::TechnologyIndexMax);
132 std::array<const MuonSimDataCollection*, techMax> sdoCollections{};
133 bool useSDO = !m_CSC_SDO_TruthNames.empty();
135 const MuonSimDataCollection* coll{nullptr};
136 ATH_CHECK(SG::get(coll, k, ctx));
137 if (coll->empty()) {
138 continue;
139 }
140 Identifier id = coll->begin()->first;
141 sdoCollections[toInt(m_idHelperSvc->technologyIndex(id))] = coll;
142 useSDO = true;
143 }
144 // loop over chamber layers
145 for (const auto& [chIdx, assocIds] : ids) {
146 // skip empty layers
147 Amg::Vector3D firstPos{Amg::Vector3D::Zero()}, secondPos{Amg::Vector3D::Zero()};
148 bool firstPosSet{false}, secondPosSet{false};
149 Identifier chId{};
150 int index = -1;
151 uint8_t nprecLayers{0}, nphiLayers{0}, ntrigEtaLayers{0};
152 std::unordered_set<int> phiLayers{}, etaLayers{}, precLayers{};
153 ATH_MSG_DEBUG(" new chamber layer " << Muon::MuonStationIndex::chName(chIdx) << " hits " << assocIds.size());
154 // loop over hits
155 for (const auto& id : assocIds) {
156 ATH_MSG_VERBOSE(" hit " << m_idHelperSvc->toString(id));
157 bool measPhi = m_idHelperSvc->measuresPhi(id);
158 bool isCsc = m_idHelperSvc->isCsc(id);
159 bool isMM = m_idHelperSvc->isMM(id);
160 bool isTrig = m_idHelperSvc->isTrigger(id);
161 bool isEndcap = m_idHelperSvc->isEndcap(id);
162 if (measPhi) {
163 phiLayers.insert(m_idHelperSvc->gasGap(id));
164 } else {
165 if (!isTrig) {
166 if (!chId.is_valid()) chId = id; // use first precision hit in list
167 if (isCsc || isMM) {
168 precLayers.insert(m_idHelperSvc->gasGap(id));
169 } else {
170 int iid = 10 * m_idHelperSvc->mdtIdHelper().multilayer(id) + m_idHelperSvc->mdtIdHelper().tubeLayer(id);
171 precLayers.insert(iid);
172 // ATH_MSG_VERBOSE("iid " << iid << " precLayers size " << precLayers.size() );
173 }
174 } else {
175 etaLayers.insert(m_idHelperSvc->gasGap(id));
176 }
177 }
178 // use SDO to look-up truth position of the hit
179 if (!useSDO) {
180 continue;
181 }
182 Amg::Vector3D gpos{Amg::Vector3D::Zero()};
183 if (!isCsc) {
184 bool ok = false;
185 TechnologyIndex techIdx = m_idHelperSvc->technologyIndex(id);
186 if (sdoCollections[toInt(techIdx)]) {
187 auto pos = sdoCollections[toInt(techIdx)]->find(id);
188 if (pos != sdoCollections[toInt(techIdx)]->end()) {
189 gpos = pos->second.globalPosition();
190 if (gpos.perp() > 0.1) ok = true; // sanity check
191 }
192 }
193 // look up successful, calculate
194 if (!ok) continue;
195
196 // small comparison function
197 auto isSmaller = [isEndcap](const Amg::Vector3D& p1, const Amg::Vector3D& p2) {
198 if (isEndcap)
199 return std::abs(p1.z()) < std::abs(p2.z());
200 else
201 return p1.perp() < p2.perp();
202 };
203 if (!firstPosSet) {
204 firstPos = gpos;
205 firstPosSet = true;
206 } else if (!secondPosSet) {
207 secondPos = gpos;
208 secondPosSet = true;
209 if (isSmaller(secondPos, firstPos)) std::swap(firstPos, secondPos);
210 } else {
211 // update position if we can increase the distance between the two positions
212 if (isSmaller(gpos, firstPos))
213 firstPos = gpos;
214 else if (isSmaller(secondPos, gpos))
215 secondPos = gpos;
216 }
217 } else {
218 SG::ReadHandle cscCollection(m_CSC_SDO_TruthNames, ctx);
219 ATH_CHECK(cscCollection.isPresent());
220 auto pos = cscCollection->find(id);
221 if (pos == cscCollection->end()) {
222 continue;
223 }
224 const MuonGM::CscReadoutElement* descriptor = detMgr->getCscReadoutElement(id);
225 ATH_MSG_DEBUG("found csc sdo with " << pos->second.getdeposits().size() << " deposits");
226 Amg::Vector3D locpos(0, pos->second.getdeposits()[0].second.ypos(), pos->second.getdeposits()[0].second.zpos());
227 gpos = descriptor->localToGlobalCoords(locpos, m_idHelperSvc->cscIdHelper().elementID(id));
228 ATH_MSG_DEBUG("got CSC global position " << gpos);
229 if (!firstPosSet) {
230 firstPos = gpos;
231 firstPosSet = true;
232 } else if (!secondPosSet) {
233 secondPos = gpos;
234 secondPosSet = true;
235 if (secondPos.perp() < firstPos.perp()) std::swap(firstPos, secondPos);
236 } else {
237 if (gpos.perp() < firstPos.perp())
238 firstPos = gpos;
239 else if (secondPos.perp() < gpos.perp())
240 secondPos = gpos;
241 }
242 }
243 }
244 if (precLayers.size() > 2) {
245 if (!phiLayers.empty()) nphiLayers = phiLayers.size();
246 ntrigEtaLayers = etaLayers.size();
247 nprecLayers = precLayers.size();
248 ATH_MSG_DEBUG(" total counts: precision " << static_cast<int>(nprecLayers) << " phi layers " << static_cast<int>(nphiLayers)
249 << " eta trig layers " << static_cast<int>(ntrigEtaLayers)
250 << " associated reco muon " << index << " unique ID " << HepMC::uniqueID(*truthLink)
251 << " truthLink " << truthLink);
252 xAOD::MuonSegment* segment = segmentContainer.push_back(std::make_unique<xAOD::MuonSegment>());
253
254 segment->setNHits(nprecLayers, nphiLayers, ntrigEtaLayers);
256 truthParticleLinkAcc("truthParticleLink");
257 truthParticleLinkAcc(*segment) = truthLink;
258 if (chId.is_valid()) { //we should always enter here if we have precision measurements
259 int eta = m_idHelperSvc->stationEta(chId);
260 int sector = m_idHelperSvc->sector(chId);
261 MuonStationIndex::TechnologyIndex technology = m_idHelperSvc->technologyIndex(chId);
262 MuonStationIndex::ChIndex chIndex = m_idHelperSvc->chamberIndex(chId);
263 segment->setIdentifier(sector, chIndex, eta, technology);
264 }
265 if (firstPosSet && secondPosSet) {
266 Amg::Vector3D gpos = (firstPos + secondPos) / 2.;
267 Amg::Vector3D gdir = (firstPos - secondPos).unit();
268 ATH_MSG_DEBUG(" got position : r " << gpos.perp() << " z " << gpos.z() << " and direction: theta " << gdir.theta()
269 << " phi " << gdir.phi());
270 segment->setPosition(gpos.x(), gpos.y(), gpos.z());
271 segment->setDirection(gdir.x(), gdir.y(), gdir.z());
272 }
273 }
274 }
275 return StatusCode::SUCCESS;
276 }
277
278
279
280} // 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(const std::uint8_t nPrecisionHits, const std::uint8_t nPhiLayers, const std::uint8_t nTrigEtaLayers)
Assign the segment hit summary.
void setPosition(float x, float y, float z)
Sets the global position.
void setIdentifier(const std::uint8_t sector, const ::Muon::MuonStationIndex::ChIndex chamberIndex, const std::int8_t etaIndex, const ::Muon::MuonStationIndex::TechnologyIndex technology)
Set the Identifier fields of the Segment.
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.