ATLAS Offline Software
Loading...
Searching...
No Matches
SpacePointMakerAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
5
11#include <GaudiKernel/IMessageSvc.h>
12#include <memory>
13#include <sstream>
14#include <algorithm>
15#include <ranges>
16#include <optional>
17#include <type_traits>
24
25
26#include "Acts/Surfaces/detail/LineHelper.hpp"
27namespace {
28 using CovIdx = MuonR4::SpacePoint::CovIdx;
29
30 inline std::vector<std::shared_ptr<unsigned>> matchCountVec(unsigned n) {
31 std::vector<std::shared_ptr<unsigned>> out{};
32 out.reserve(n);
33 for (unsigned p = 0; p < n ;++p) {
34 out.emplace_back(std::make_shared<unsigned>(0));
35 }
36 return out;
37 }
43 template<class MeasType>
44 #if defined(FLATTEN)
45 // We compile this package with optimization, even in debug builds; otherwise,
46 // the heavy use of Eigen makes it too slow. However, from here we may call
47 // to out-of-line Eigen code that is linked from other DSOs; in that case,
48 // it would not be optimized. Avoid this by forcing all Eigen code
49 // to be inlined here if possible.
51 #endif
52 Amg::Transform3D toChamberTransform(const ActsTrk::GeometryContext& gctx,
53 const Amg::Transform3D& sectorTrans,
54 const MeasType& meas) {
55 const MuonGMR4::MuonReadoutElement* reEle{meas.readoutElement()};
56 if constexpr(std::is_same_v<MeasType, xAOD::MdtDriftCircle>) {
57 return sectorTrans * reEle->localToGlobalTransform(gctx, meas.measurementHash());
58 } else {
59 return sectorTrans * reEle->localToGlobalTransform(gctx, meas.layerHash());
60 }
61 }
64 template <typename PrdType>
65 double sensorHalfLength(const PrdType& prd) {
66 const auto* re = prd.readoutElement();
67 if constexpr(std::is_same_v<PrdType, xAOD::MdtDriftCircle>) {
68 return 0.5 * re->activeTubeLength(prd.measurementHash());
69 } else if constexpr(std::is_same_v<PrdType, xAOD::RpcMeasurement>) {
70 return 0.5*(prd.measuresPhi() ? re->stripPhiLength() : re->stripEtaLength());
71 } else if constexpr(std::is_same_v<PrdType, xAOD::TgcStrip>) {
72 return 0.5 * re->sensorLayout(prd.layerHash())->design(prd.measuresPhi()).stripLength(prd.channelNumber());
73 } else if constexpr(std::is_same_v<PrdType, xAOD::MMCluster>) {
74 return 0.5* re->stripLayer(prd.layerHash()).design().stripLength(prd.channelNumber());
75 } else if constexpr(std::is_same_v<PrdType, xAOD::sTgcMeasurement>) {
76 return 0.5* re->stripLayer(prd.layerHash()).design().stripLength(prd.channelNumber());
77 }
78 return 0.;
79 }
84 inline double covElement(const xAOD::sTgcMeasurement& m,
85 const CovIdx covIdx) {
86 if (m.numDimensions() == 2) {
87 const unsigned i = (covIdx != CovIdx::etaCov);
88 return m.localCovariance<2>()(i,i);
89 }
90 return m.localCovariance<1>()[0];
91 }
92
97bool wildcardMatch(const std::string_view pattern,
98 const std::string_view value) {
99 std::size_t patternPos = 0;
100 std::size_t valuePos = 0;
101 std::size_t wildcardPos = std::string_view::npos;
102 std::size_t wildcardValuePos = 0;
103
104 while (valuePos < value.size()) {
105 if (patternPos < pattern.size() &&
106 pattern[patternPos] == value[valuePos]) {
107 ++patternPos;
108 ++valuePos;
109 } else if (patternPos < pattern.size() &&
110 pattern[patternPos] == '*') {
111 wildcardPos = patternPos++;
112 wildcardValuePos = valuePos;
113 } else if (wildcardPos != std::string_view::npos) {
114 patternPos = wildcardPos + 1;
115 valuePos = ++wildcardValuePos;
116 } else {
117 return false;
118 }
119 }
120
121 while (patternPos < pattern.size() &&
122 pattern[patternPos] == '*') {
123 ++patternPos;
124 }
125 return patternPos == pattern.size();
126}
127
128
129
130}
131
132namespace MuonR4 {
133
138 if (techIdx != other.techIdx) {
139 return static_cast<int>(techIdx) < static_cast<int>(other.techIdx);
140 }
141 if (stIdx != other.stIdx) {
142 return static_cast<int>(stIdx) < static_cast<int>(other.stIdx);
143 }
144 return eta < other.eta;
145}
151
152void SpacePointMakerAlg::SpacePointStatistics::addToStat(const std::vector<SpacePoint>& spacePoints){
153 std::lock_guard guard{m_mutex};
154 for (const SpacePoint& sp : spacePoints){
155 FieldKey key{};
156 key.stIdx = m_idHelperSvc->stationIndex(sp.identify());
157 key.techIdx = m_idHelperSvc->technologyIndex(sp.identify());
158 key.eta = m_idHelperSvc->stationEta(sp.identify());
159 StatField & stats = m_map[key];
160 if (sp.measuresEta() && sp.measuresPhi()) {
161 ++stats.measEtaPhi;
162 } else {
163 stats.measEta += sp.measuresEta();
164 stats.measPhi += sp.measuresPhi();
165 }
166 }
167}
169 using KeyVal = std::pair<FieldKey, StatField>;
170 std::vector<KeyVal> sortedstats{};
171 sortedstats.reserve(m_map.size());
173 for (const auto & [key, stats] : m_map){
174 sortedstats.emplace_back(std::make_pair(key, stats));
175 }
176 std::stable_sort(sortedstats.begin(), sortedstats.end(), [](const KeyVal& a, const KeyVal&b) {
177 return a.second.allHits() > b.second.allHits();
178 });
179 msg<<MSG::ALWAYS<<"###########################################################################"<<endmsg;
180 for (const auto & [key, stats] : sortedstats) {
181 msg<<MSG::ALWAYS<<" "<<Muon::MuonStationIndex::technologyName(key.techIdx)
182 <<" "<<Muon::MuonStationIndex::stName(key.stIdx)
183 <<" "<<std::abs(key.eta)<<(key.eta < 0 ? "A" : "C")
184 <<" "<<std::setw(8)<<stats.measEtaPhi
185 <<" "<<std::setw(8)<<stats.measEta
186 <<" "<<std::setw(8)<<stats.measPhi<<endmsg;
187 }
188 msg<<MSG::ALWAYS<<"###########################################################################"<<endmsg;
189
190}
191
195 if (m_statCounter) {
196 m_statCounter->dumpStatisics(msgStream());
197 }
198 return StatusCode::SUCCESS;
199}
201 ATH_CHECK(m_geoCtxKey.initialize());
202 ATH_CHECK(m_mdtKey.initialize(!m_mdtKey.empty()));
203 ATH_CHECK(m_rpcKey.initialize(!m_rpcKey.empty()));
204 ATH_CHECK(m_tgcKey.initialize(!m_tgcKey.empty()));
205 ATH_CHECK(m_mmKey.initialize(!m_mmKey.empty()));
206 ATH_CHECK(m_stgcKey.initialize(!m_stgcKey.empty()));
207 ATH_CHECK(m_idHelperSvc.retrieve());
208 ATH_CHECK(m_writeKey.initialize());
209 if (m_doStat) {
210 m_statCounter = std::make_unique<SpacePointStatistics>(m_idHelperSvc.get());
211 }
212
213
214 //Initialize the chamber-based bucket windows and max bucket lengths
216 .spacePointWindow = m_spacePointWindow.value(),
217 .maxBucketLength = m_maxBucketLength.value(),
218 .spacePointOverlap= m_spacePointOverlap.value()
219 };
220
221
222 ATH_CHECK(detStore()->retrieve(m_detMgr));
223 const auto chambers = m_detMgr->getAllChambers();
224
225 m_bucketParameters.reserve(chambers.size());
226 for (const MuonGMR4::Chamber* chamber : chambers) {
227 const std::optional<BucketParameters> parameters = resolveBucketParameters(*chamber);
228
229 //Fill only the chambers for which we have at least one match, the rest will be filled with the default parameters on demand
230 if (!parameters) {
231 continue;
232 }
233
234 m_bucketParameters.emplace( chamber, *parameters);
235 }
236
237 ATH_MSG_DEBUG( "Configured chamber-dependent bucket parameters for " << m_bucketParameters.size() << " chambers out of " << chambers.size() << " the rest has the following default bucket parameters: "
238 << " maxBucketLength=" << m_defaultBucketParameters.maxBucketLength
239 << " spacePointWindow=" << m_defaultBucketParameters.spacePointWindow
240 << " spacePointOverlap=" << m_defaultBucketParameters.spacePointOverlap);
241
242 return StatusCode::SUCCESS;
243}
244
245template <>
247 const PrdVec_t<const xAOD::TgcStrip*>& phiHits) const {
248 if (etaHits.empty() || phiHits.empty()) {
249 return false;
250 }
251 const MuonGMR4::TgcReadoutElement* re = etaHits[0]->readoutElement();
252 ATH_MSG_VERBOSE("Collected "<<etaHits.size()<<"/"<<phiHits.size()<<" hits in "<<m_idHelperSvc->toStringGasGap(etaHits[0]->identify()));
253 return ((1.*etaHits.size()) / ((1.*re->numChannels(etaHits[0]->measurementHash())))) < m_maxOccTgcEta &&
254 ((1.*phiHits.size()) / ((1.*re->numChannels(phiHits[0]->measurementHash())))) < m_maxOccTgcPhi;
255 }
256template <>
258 const PrdVec_t<const xAOD::RpcMeasurement*>& phiHits) const {
259 if (etaHits.empty() || phiHits.empty()) {
260 return false;
261 }
262 const MuonGMR4::RpcReadoutElement* re = etaHits[0]->readoutElement();
263 ATH_MSG_VERBOSE("Collected "<<etaHits.size()<<"/"<<phiHits.size()<<" hits in "<<m_idHelperSvc->toStringGasGap(etaHits[0]->identify()));
264 return ((1.*etaHits.size()) / (1.*re->nEtaStrips())) < m_maxOccRpcEta &&
265 ((1.*phiHits.size()) / (1.*re->nPhiStrips())) < m_maxOccRpcPhi;
266 }
267
268template <>
270 const PrdVec_t<const xAOD::MMCluster*>& /*phiHits*/) const {
271 return false;
272 }
273template <typename PrdType>
275 const Amg::Transform3D& sectorTrans,
276 const PrdVec_t<const PrdType*>& prdsToFill,
277 std::vector<SpacePoint>& outColl) const {
278 if (prdsToFill.empty()) {
279 return;
280 }
281 const PrdType* refMeas = prdsToFill.front();
282 bool allSpArePhi{false};
283
284 const Amg::Transform3D toSectorTrans = toChamberTransform(gctx, sectorTrans, *refMeas);
286 Amg::Vector3D sensorDir{Amg::Vector3D::Zero()}, toNextSen{Amg::Vector3D::Zero()};
288 if constexpr(std::is_same_v<PrdType, xAOD::RpcMeasurement> ||
289 std::is_same_v<PrdType, xAOD::TgcStrip>) {
290 allSpArePhi = refMeas->measuresPhi();
291 const auto& stripLayout = refMeas->readoutElement()->sensorLayout(refMeas->layerHash());
292 const auto& design = stripLayout->design(allSpArePhi);
293 sensorDir = toSectorTrans.linear() * stripLayout->to3D(design.stripDir(), allSpArePhi);
294 toNextSen = toSectorTrans.linear() * stripLayout->to3D(design.stripNormal(), allSpArePhi);
295 ATH_MSG_VERBOSE("Fill space points for "<<m_idHelperSvc->toString(refMeas->identify())
296 <<" -> sensor: "<<Amg::toString(sensorDir)<<", "<<Amg::toString(toNextSen));
297 } else if constexpr (std::is_same_v<PrdType, xAOD::sTgcMeasurement>){
298 allSpArePhi = refMeas->channelType() == xAOD::sTgcMeasurement::sTgcChannelTypes::Wire;
299 const auto& stripLayout = refMeas->readoutElement()->stripLayer(refMeas->measurementHash());
300 const auto& design = stripLayout.design(allSpArePhi);
301 sensorDir = toSectorTrans.linear() * stripLayout.to3D(design.stripDir(), allSpArePhi);
302 toNextSen = toSectorTrans.linear() * stripLayout.to3D(design.stripNormal(), allSpArePhi);
303 } else {
304 sensorDir = toSectorTrans.linear().col(Amg::y);
305 toNextSen = toSectorTrans.linear().col(Amg::x);
306 }
307 outColl.reserve(outColl.size() + prdsToFill.size());
308 for (const PrdType* prd: prdsToFill) {
309 SpacePoint& newSp = outColl.emplace_back(prd);
310 if constexpr (std::is_same_v<PrdType, xAOD::TgcStrip>) {
311 if (allSpArePhi) {
312 const auto& stripLayout = refMeas->readoutElement()->sensorLayout(refMeas->layerHash());
313 const auto& radialDesign = static_cast<const MuonGMR4::RadialStripDesign&>(stripLayout->design(allSpArePhi));
314 toNextSen = toSectorTrans.linear() * stripLayout->to3D(radialDesign.stripNormal(prd->channelNumber()), allSpArePhi);
315 sensorDir = toSectorTrans.linear() * stripLayout->to3D(radialDesign.stripDir(prd->channelNumber()), allSpArePhi);
316 }
317 }
318 newSp.setPosition(toSectorTrans * prd->localMeasurementPos());
319 newSp.setDirection(sensorDir, toNextSen);
320 auto cov = Acts::filledArray<double,3>(0.);
321 if (prd->numDimensions() == 2) {
322 cov[Acts::toUnderlying(CovIdx::etaCov)] = prd->template localCovariance<2>()(0,0);
323 cov[Acts::toUnderlying(CovIdx::phiCov)] = prd->template localCovariance<2>()(1,1);
324 } else {
326 auto covIdx{Acts::toUnderlying(CovIdx::etaCov)},
327 lenIdx{Acts::toUnderlying(CovIdx::phiCov)};
328 if (!newSp.measuresEta()) {
329 std::swap(covIdx, lenIdx);
330 }
331 cov[covIdx] = prd->template localCovariance<1>()[0];
332 cov[lenIdx] = Acts::square(sensorHalfLength(*prd));
333 }
334 newSp.setCovariance(std::move(cov));
335 }
336}
337
338
339template <typename ContType>
342 std::vector<EtaPhi2DHits<typename ContType::const_value_type>> hitsPerGasGap{};
343 for (const auto& prd : viewer) {
344 ATH_MSG_VERBOSE("Create space point from "<<m_idHelperSvc->toString(prd->identify())
345 <<", hash: "<<prd->identifierHash());
346
347 unsigned gapIdx = prd->gasGap() -1;
348 if constexpr (std::is_same_v<ContType, xAOD::RpcMeasurementContainer>) {
349 gapIdx = prd->readoutElement()->createHash(0, prd->gasGap(), prd->doubletPhi(), false);
350 }
351 if (hitsPerGasGap.size() <= gapIdx) {
352 hitsPerGasGap.resize(gapIdx + 1);
353 }
354 bool measPhi{false};
355 if constexpr(std::is_same_v<ContType, xAOD::sTgcMeasContainer>) {
357 measPhi = prd->channelType() == sTgcIdHelper::sTgcChannelTypes::Wire;
358 } else if constexpr(!std::is_same_v<ContType, xAOD::MMClusterContainer>) {
360 measPhi = prd->measuresPhi();
361 }
362
363 if (prd->numDimensions() == 2) {
364 hitsPerGasGap[gapIdx][2].push_back(prd);
365 continue;
366 }
368 auto& toPush = hitsPerGasGap[gapIdx][measPhi];
369 if (toPush.capacity() == toPush.size()) {
370 toPush.reserve(toPush.size() + m_capacityBucket);
371 }
372 toPush.push_back(prd);
373 }
374 return hitsPerGasGap;
375}
376
377template <typename ContType>
378 StatusCode SpacePointMakerAlg::loadContainerAndSort(const EventContext& ctx,
380 PreSortedSpacePointMap& fillContainer) const {
381 const ContType* measurementCont{nullptr};
382 ATH_CHECK(SG::get(measurementCont, key, ctx));
383 if (!measurementCont || measurementCont->empty()){
384 ATH_MSG_DEBUG("nothing to do");
385 return StatusCode::SUCCESS;
386 }
387 const ActsTrk::GeometryContext* gctx{nullptr};
388 ATH_CHECK(SG::get(gctx, m_geoCtxKey, ctx));
389
390 xAOD::ChamberViewer viewer{*measurementCont};
391
392 do {
393 SpacePointsPerChamber& pointsInChamb = fillContainer[viewer.at(0)->readoutElement()->msSector()];
394 const Amg::Transform3D sectorTrans = viewer.at(0)->readoutElement()->msSector()->globalToLocalTransform(*gctx);
395 ATH_MSG_DEBUG("Fill space points for chamber "<<m_idHelperSvc->toStringDetEl(viewer.at(0)->identify()));
396 if constexpr( std::is_same_v<ContType, xAOD::MdtDriftCircleContainer>) {
397 pointsInChamb.etaHits.reserve(pointsInChamb.etaHits.capacity() + viewer.size());
398 for (const auto& prd : viewer) {
399 Amg::Transform3D toChamberTrans{toChamberTransform(*gctx, sectorTrans, *prd)};
400 SpacePoint& sp{pointsInChamb.etaHits.emplace_back(prd)};
401 sp.setPosition(toChamberTrans*prd->localMeasurementPos());
402 sp.setDirection(toChamberTrans.linear().col(Amg::z),
403 toChamberTrans.linear().col(Amg::y));
404 std::array<double, 3> cov{Acts::filledArray<double,3>(0.)};
405 cov[Acts::toUnderlying(CovIdx::etaCov)] = prd->driftRadiusCov();
406 cov[Acts::toUnderlying(CovIdx::phiCov)] = Acts::square(sensorHalfLength(*prd));
407 if (ATH_UNLIKELY(prd->numDimensions() == 2)){
408 cov[Acts::toUnderlying(CovIdx::phiCov)] = static_cast<const xAOD::MdtTwinDriftCircle*>(prd)->posAlongWireCov();
409 }
410 sp.setCovariance(std::move(cov));
411 }
412 } else {
414 for (auto& [etaHits, phiHits, two2DHits] : splitHitsPerGasGap(viewer)) {
415 ATH_MSG_DEBUG("Found "<<etaHits.size()<<"/"<<phiHits.size()
416 <<" 1D and "<<two2DHits.size()<<" 2D hits in chamber "
417 <<m_idHelperSvc->toStringDetEl(viewer.at(0)->identify()));
419 fillUncombinedSpacePoints(*gctx, sectorTrans, two2DHits, pointsInChamb.etaHits);
421 // Check if we do not have 2D occupancy (missing phi or eta hits)
422 if (!passOccupancy2D(etaHits, phiHits)) {
423 fillUncombinedSpacePoints(*gctx, sectorTrans, etaHits, pointsInChamb.etaHits);
424 fillUncombinedSpacePoints(*gctx, sectorTrans, phiHits, pointsInChamb.phiHits);
425 continue;
426 }
427
428 std::vector<std::shared_ptr<unsigned>> etaCounts{matchCountVec(etaHits.size())},
429 phiCounts{matchCountVec(phiHits.size())};
430
431 pointsInChamb.etaHits.reserve(pointsInChamb.etaHits.size() + etaHits.size()*phiHits.size());
433 const auto& firstEta{etaHits.front()};
434 const Amg::Transform3D toSectorTrans = toChamberTransform(*gctx, sectorTrans, *firstEta);
435
436 Amg::Vector3D toNextDir{Amg::Vector3D::Zero()}, sensorDir{Amg::Vector3D::Zero()};
437 if constexpr (std::is_same_v<xAOD::RpcMeasurementContainer, ContType> ||
438 std::is_same_v<xAOD::TgcStripContainer, ContType>) {
439 const auto& stripLayout = firstEta->readoutElement()->sensorLayout(firstEta->layerHash());
440 const auto& design = stripLayout->design();
441 sensorDir = toSectorTrans.linear() * stripLayout->to3D(design.stripDir(), false);
442 toNextDir = toSectorTrans.linear() * stripLayout->to3D(design.stripNormal(), false);
443 } else if constexpr (std::is_same_v<xAOD::sTgcMeasContainer, ContType>){
444 const auto& stripLayout = firstEta->readoutElement()->stripLayer(firstEta->measurementHash());
445 const auto& design = stripLayout.design(false);
446 sensorDir = toSectorTrans.linear() * stripLayout.to3D(design.stripDir(), false);
447 toNextDir = toSectorTrans.linear() * stripLayout.to3D(design.stripNormal(), false);
448 } else {
449 ATH_MSG_ERROR("Unsupported container type");
450 return StatusCode::FAILURE;
451 }
452
453 using namespace Acts::detail::LineHelper;
454 for (unsigned etaP = 0; etaP < etaHits.size(); ++etaP) {
456 for (unsigned phiP = 0; phiP < phiHits.size(); ++ phiP) {
458 if constexpr(std::is_same_v<xAOD::TgcStripContainer, ContType>) {
459 if (!(etaHits[etaP]->bcBitMap() & phiHits[phiP]->bcBitMap())){
460 continue;
461 }
462 const auto& stripLay = phiHits[phiP]->readoutElement()->sensorLayout(phiHits[phiP]->layerHash());
463 const auto& radialDesign = static_cast<const MuonGMR4::RadialStripDesign&>(stripLay->design(true));
464 toNextDir = toSectorTrans.linear() * stripLay->to3D(radialDesign.stripDir(phiHits[phiP]->channelNumber()), true);
465 }
466
467 SpacePoint& newSp = pointsInChamb.etaHits.emplace_back(etaHits[etaP], phiHits[phiP]);
468 newSp.setInstanceCounts(etaCounts[etaP], phiCounts[phiP]);
469
470 auto spIsect = lineIntersect(toSectorTrans*etaHits[etaP]->localMeasurementPos(), sensorDir,
471 toSectorTrans*phiHits[phiP]->localMeasurementPos(), toNextDir);
472 newSp.setPosition(spIsect.position());
473 newSp.setDirection(sensorDir, toNextDir);
474 auto cov = Acts::filledArray<double, 3>(0.);
475 cov[Acts::toUnderlying(CovIdx::etaCov)] = etaHits[etaP]->template localCovariance<1>()[0];
476 cov[Acts::toUnderlying(CovIdx::phiCov)] = phiHits[phiP]->template localCovariance<1>()[0];
478 if constexpr(std::is_same_v<xAOD::TgcStripContainer, ContType>) {
479 const auto& stripLay = phiHits[phiP]->readoutElement()->sensorLayout(phiHits[phiP]->layerHash());
480 const auto& radialDesign = static_cast<const MuonGMR4::RadialStripDesign&>(stripLay->design(true));
481 const Amg::Vector2D planePos = stripLay->to2D(toSectorTrans.inverse()*spIsect.position(), true);
482 cov[Acts::toUnderlying(CovIdx::phiCov)] =
483 Acts::square(radialDesign.stripPitch(phiHits[phiP]->channelNumber(), planePos)) / 12.;
484 }
485
486 newSp.setCovariance(std::move(cov));
487 ATH_MSG_VERBOSE("Created new space point "<<newSp);
488 }
489 }
490 }
491 }
492 } while (viewer.next());
493 return StatusCode::SUCCESS;
494}
495
496template<>
497StatusCode SpacePointMakerAlg::loadContainerAndSort(const EventContext& ctx,
499 PreSortedSpacePointMap& fillContainer) const {
500
501 const xAOD::sTgcMeasContainer* measurementCont{nullptr};
502 ATH_CHECK(SG::get(measurementCont, key, ctx));
503 if (!measurementCont || measurementCont->empty()){
504 ATH_MSG_DEBUG("nothing to do");
505 return StatusCode::SUCCESS;
506 }
507 const ActsTrk::GeometryContext* gctx{nullptr};
508 ATH_CHECK(SG::get(gctx, m_geoCtxKey, ctx));
509 xAOD::ChamberViewer viewer{*measurementCont};
510 using namespace Acts::detail::LineHelper;
511 do {
512 SpacePointsPerChamber& pointsInChamb = fillContainer[viewer.at(0)->readoutElement()->msSector()];
513 const Amg::Transform3D sectorTrans = viewer.at(0)->readoutElement()->msSector()->globalToLocalTransform(*gctx);
514 ATH_MSG_DEBUG(__func__<<"() "<<__LINE__<<" - Fill space points for multiplet "<<m_idHelperSvc->toStringDetEl(viewer.at(0)->identify()));
515 for(auto& HitColls: splitHitsPerGasGap(viewer)){
516 auto& [etaHits, phiHits, two2DHits] = HitColls;
517 std::array<std::vector<std::shared_ptr<unsigned>>, 3> instanceCounts{matchCountVec(etaHits.size()),
518 matchCountVec(phiHits.size()),
519 matchCountVec(two2DHits.size())};
520
521 //loop through the Prds and try to combine according` to the hierarchy
522 // Strip+Wire
523 // Strip+Pad
524 // Wire+Pad
525 // Pad
533 auto combineMe = [&](const std::size_t collIdxA,
534 const std::size_t collIdxB,
535 const std::function<bool(const xAOD::sTgcMeasurement*,
536 const xAOD::sTgcMeasurement*)>& combFunc) {
537 std::vector<char> combinedFlagsA{}, combinedFlagsB{};
538 std::ranges::transform(instanceCounts[collIdxA], std::back_inserter(combinedFlagsA),
539 [](const std::shared_ptr<unsigned>& countPtr){
540 return (*countPtr) == 0;
541 });
542 std::ranges::transform(instanceCounts[collIdxB], std::back_inserter(combinedFlagsB),
543 [](const std::shared_ptr<unsigned>& countPtr){
544 return (*countPtr) == 0;
545 });
546
547 const auto& collA = HitColls[collIdxA];
548 const auto& collB = HitColls[collIdxB];
549
551 if(collA.empty() || collB.empty()) {
552 ATH_MSG_DEBUG(__func__<<"() "<<__LINE__<<" - Skipping combination: both collections empty");
553 return;
554 }
555
557 const xAOD::sTgcMeasurement* firstHit = collB.front();
558 const Amg::Transform3D toSectorTrans = toChamberTransform(*gctx, sectorTrans, *firstHit);
559
560 for(std::size_t idxA = 0; idxA < collA.size(); ++idxA) {
562 if(!combinedFlagsA[idxA]) {
563 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - Hit "<<m_idHelperSvc->toString(collA[idxA]->identify())
564 <<" has been used in previous iteration");
565 continue;
566 }
567 for(std::size_t idxB = 0; idxB < collB.size(); ++idxB) {
568 if(!combinedFlagsB[idxB] || !combFunc(collA[idxA], collB[idxB])){
569 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - Hit "<<m_idHelperSvc->toString(collB[idxB]->identify())
570 <<" has been used in previous iteration. Or is incompatible with "
571 <<m_idHelperSvc->toString(collA[idxA]->identify()));
572 continue;
573 }
574 //create space point
575 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - Combine sTgc measurements "
576 <<m_idHelperSvc->toString(collA[idxA]->identify())<<" and "
577 <<m_idHelperSvc->toString(collB[idxB]->identify())<< "with local positions"
578 << Amg::toString(collA[idxA]->localMeasurementPos()) << " and "
579 << Amg::toString(collB[idxB]->localMeasurementPos())
580 <<" to new space point");
581
582 SpacePoint& newSp = pointsInChamb.etaHits.emplace_back(collB[idxB], collA[idxA]);
583 auto crossPoint = lineIntersect<3>(collA[idxA]->localMeasurementPos(),
584 Amg::Vector3D::UnitX(),
585 collB[idxB]->localMeasurementPos(),
586 Amg::Vector3D::UnitY());
587
588 newSp.setPosition(toSectorTrans*crossPoint.position());
589 newSp.setDirection(Amg::Vector3D::UnitX(), Amg::Vector3D::UnitY());
590 auto cov = Acts::filledArray<double, 3>(0.);
591 cov[Acts::toUnderlying(CovIdx::phiCov)] = covElement(*collA[idxA], CovIdx::phiCov);
592 cov[Acts::toUnderlying(CovIdx::etaCov)] = covElement(*collB[idxB], CovIdx::etaCov);
593 newSp.setCovariance(std::move(cov));
594 newSp.setInstanceCounts(instanceCounts[collIdxB][idxB], instanceCounts[collIdxA][idxA]);
595 ATH_MSG_VERBOSE("Created new space point "<<newSp);
596 }
597 }
598 };
599
600 //try to combine strip with wire measurements first
601 combineMe(1, 0, [&](const xAOD::sTgcMeasurement* wire,
603 // do not combine the strips with the wire that are in the etaZero region
604 const MuonGMR4::sTgcReadoutElement* readoutElement = strip->readoutElement();
605 if(readoutElement->isEtaZero(strip->measurementHash(),
606 strip->localMeasurementPos().block<2,1>(0,0))){
607 return false;
608 }
609 //ignore combinations where the wire and the strip are not crossing
610 //check if the projection of the crossing point is within the bounds of the layer
611 Amg::Vector3D crossPoint = strip->localMeasurementPos() + wire->localMeasurementPos();
612 const Acts::Surface& surf = readoutElement->surface(strip->layerHash());
613 return surf.insideBounds(crossPoint.block<2,1>(0,0));
614 });
615
616 //combine strip and pad measurements
617 combineMe(2, 0, [&](const xAOD::sTgcMeasurement* pad,
619 // do not combine the strips with the pads that are not overlayed
620 const MuonGMR4::sTgcReadoutElement* readoutElement = pad ->readoutElement();
621 const MuonGMR4::PadDesign& padDesign = readoutElement->padDesign(pad->measurementHash());
622 double padHeight = padDesign.padHeight();
623 const Amg::Vector3D padCenter = pad->localMeasurementPos();
624
625 return std::abs(strip->localMeasurementPos().x() - padCenter.x()) < 0.5*padHeight;
626 });
627
628 //finally combine wire and pad measurements
629 combineMe(1, 2, [&](const xAOD::sTgcMeasurement* wire,
630 const xAOD::sTgcMeasurement* pad){
631 // do not combine the wires with the pads that are not overlayed
632 const MuonGMR4::sTgcReadoutElement* readoutElement = pad ->readoutElement();
633 const std::array<Amg::Vector2D, 4> localPadCorners = readoutElement->localPadCorners(pad->measurementHash());
634 auto [min,max] = std::ranges::minmax_element(localPadCorners.begin(), localPadCorners.end(),
635 [](const Amg::Vector2D& a, const Amg::Vector2D& b){
636 return a.y() < b.y();
637 });
638 return (wire->localMeasurementPos().y() > min->y() || wire->localMeasurementPos().y() < max->y());
639
640 });
641
642 //fill uncombined strip, wire and pad measurements that have not been used in combination
643 for(std::size_t collIdx = 0; collIdx < HitColls.size(); ++collIdx){
644 const auto& hits = HitColls[collIdx];
645 std::vector<const xAOD::sTgcMeasurement*> unusedHits{};
646 unusedHits.reserve(hits.size());
647
648 for(std::size_t idx = 0; idx < hits.size(); ++idx){
649 if((*instanceCounts[collIdx][idx]) == 0){
650 unusedHits.push_back(hits[idx]);
651 }
652 }
653 fillUncombinedSpacePoints(*gctx, sectorTrans, unusedHits, pointsInChamb.etaHits);
654 }
655 }
656 } while (viewer.next());
657 return StatusCode::SUCCESS;
658}
659
660
661StatusCode SpacePointMakerAlg::execute(const EventContext& ctx) const {
662 PreSortedSpacePointMap preSortedContainer{};
663 ATH_CHECK(loadContainerAndSort(ctx, m_mdtKey, preSortedContainer));
664 ATH_CHECK(loadContainerAndSort(ctx, m_rpcKey, preSortedContainer));
665 ATH_CHECK(loadContainerAndSort(ctx, m_tgcKey, preSortedContainer));
666 ATH_CHECK(loadContainerAndSort(ctx, m_mmKey, preSortedContainer));
667 ATH_CHECK(loadContainerAndSort(ctx, m_stgcKey, preSortedContainer));
668 std::unique_ptr<SpacePointContainer> outContainer = std::make_unique<SpacePointContainer>();
669
670 for (auto &[chamber, hitsPerChamber] : preSortedContainer){
671 ATH_MSG_DEBUG("Fill space points for chamber "<<chamber->identString() << " with "<<hitsPerChamber.etaHits.size()
672 <<" primary and "<<hitsPerChamber.phiHits.size()<<" phi space points.");
673
674 distributePointsAndStore(std::move(hitsPerChamber), *outContainer);
675 }
676
677 ATH_MSG_DEBUG("Created a total of "<<outContainer->size()<<" space points in "<<preSortedContainer.size()<<" chambers");
678
679 SG::WriteHandle writeHandle{m_writeKey, ctx};
680 ATH_CHECK(writeHandle.record(std::move(outContainer)));
681 return StatusCode::SUCCESS;
682}
683
685 SpacePointContainer& finalContainer) const {
686 SpacePointBucketVec splittedHits{};
687 splittedHits.emplace_back();
688 if (m_statCounter){
689 m_statCounter->addToStat(hitsPerChamber.etaHits);
690 m_statCounter->addToStat(hitsPerChamber.phiHits);
691
692 }
693 distributePrimaryPoints(std::move(hitsPerChamber.etaHits), splittedHits);
694 splittedHits.erase(std::remove_if(splittedHits.begin(), splittedHits.end(),
695 [](const SpacePointBucket& bucket) {
696 return bucket.size() <= 1;
697 }), splittedHits.end());
698 distributePhiPoints(std::move(hitsPerChamber.phiHits), splittedHits);
699
700 std::size_t nBuckets{0};
701 std::size_t nSpacePointsInBuckets{0};
702 std::size_t maxBucketSize{0};
703 for (SpacePointBucket& bucket : splittedHits) {
704
705 std::ranges::sort(bucket, MuonR4::SpacePointPerLayerSorter{});
706
707 if (msgLvl(MSG::VERBOSE)){
708 std::stringstream spStr{};
709 for (const std::shared_ptr<SpacePoint>& sp : bucket){
710 spStr<<"SpacePoint: PrimaryMeas: " <<(*sp)<<std::endl;
711 }
712 ATH_MSG_VERBOSE("Created a bucket, printing all spacepoints..."<<std::endl<<spStr.str());
713 }
715
716 ++nBuckets;
717 nSpacePointsInBuckets += bucket.size();
718 maxBucketSize = std::max(maxBucketSize, bucket.size());
719 finalContainer.push_back(std::make_unique<SpacePointBucket>(std::move(bucket)));
720 }
721
722 ATH_MSG_DEBUG("Created "<<nBuckets<<" buckets with a total of "<<nSpacePointsInBuckets
723 <<" space points. Max bucket size: "<<maxBucketSize);
724
725}
726void SpacePointMakerAlg::distributePhiPoints(std::vector<SpacePoint>&& spacePoints,
727 SpacePointBucketVec& splittedContainer) const{
728 for (SpacePoint& sp : spacePoints) {
729 auto phiPoint = std::make_shared<SpacePoint>(std::move(sp));
730 const double dY = std::sqrt(phiPoint->covariance()[Acts::toUnderlying(CovIdx::etaCov)]);
731 const double minY = phiPoint->localPosition().y() - dY;
732 const double maxY = phiPoint->localPosition().y() + dY;
733 for (SpacePointBucket& bucket : splittedContainer){
736 if (! (maxY < bucket.coveredMin() || bucket.coveredMax() < minY) ) {
737 bucket.emplace_back(phiPoint);
738 }
739 }
740 }
741}
743 const double firstSpPos,
744 const SpacePointBucketVec& sortedPoints, const BucketParameters& bucketParams) const {
745
747 const double spY = spacePoint.localPosition().y();
748
749 if (spY - firstSpPos > bucketParams.maxBucketLength){
750 ATH_MSG_DEBUG("Splitting bucket based on maxLength. First space point Y=" << firstSpPos
751 << " current space point Y =" << spY
752 << " m_maxBucketLength=" << bucketParams.maxBucketLength );
753 return true;
754 }
755
756 if (sortedPoints.empty() || sortedPoints.back().empty()) {
757 return false;
758 }
759
760 const double gap = spY - sortedPoints.back().back()->localPosition().y();
761
762
763 if (gap > bucketParams.spacePointWindow){
764 ATH_MSG_DEBUG("Splitting bucket based on gap. Last space point Y=" << sortedPoints.back().back()->localPosition().y()
765 << " current space point Y =" << spY
766 << " gap=" << gap
767 << " window=" << bucketParams.spacePointWindow);
768 }
769
770 return gap > bucketParams.spacePointWindow;
771}
773 SpacePointBucketVec& sortedPoints,
774 const BucketParameters& bucketParams) const {
775 SpacePointBucket& newContainer = sortedPoints.emplace_back();
776 newContainer.setBucketId(sortedPoints.size() -1);
777
779 SpacePointBucket& overlap{sortedPoints[sortedPoints.size() - 2]};
780 overlap.setCoveredRange(overlap.front()->localPosition().y(),
781 overlap.back()->localPosition().y());
782
783 const double refBound = refSpacePoint.localPosition().y();
784
785
787 for (const std::shared_ptr<SpacePoint>& pointInBucket : overlap | std::views::reverse) {
788 const double overlapPos = pointInBucket->localPosition().y() +
789 std::sqrt(pointInBucket->covariance()[Acts::toUnderlying(CovIdx::etaCov)]);
790 if (refBound - overlapPos < bucketParams.spacePointOverlap) {
791 newContainer.insert(newContainer.begin(), pointInBucket);
792 } else {
793 break;
794 }
795 }
796
797}
798
799void SpacePointMakerAlg::distributePrimaryPoints(std::vector<SpacePoint>&& spacePoints,
800 SpacePointBucketVec& splittedHits) const {
801
802 if (spacePoints.empty()) return;
803
805 std::ranges::sort(spacePoints,
806 [] (const SpacePoint& a, const SpacePoint& b) {
807 return a.localPosition().y() < b.localPosition().y();
808 });
809
810 double firstPointPos = spacePoints.front().localPosition().y();
811
812 //Base the bucket parameters on the first space point in the chamber. This is a good approximation since all space points in the same chamber should have similar properties with the exception of the edge space points and overlapping chambers
813 const BucketParameters& bucketParams = getBucketParameters(spacePoints.front());
814
815 ATH_MSG_DEBUG("Distributing "<<spacePoints.size()<<" primary space points into buckets with parameters: "
816 << "maxBucketLength=" << bucketParams.maxBucketLength
817 << ", spacePointWindow=" << bucketParams.spacePointWindow
818 << ", spacePointOverlap=" << bucketParams.spacePointOverlap);
819
820 for (SpacePoint& toSort : spacePoints) {
821 ATH_MSG_VERBOSE("Add new primary space point "<<toSort);
822
823 if (splitBucket(toSort, firstPointPos, splittedHits, bucketParams)){
824 newBucket(toSort, splittedHits, bucketParams);
825 firstPointPos = splittedHits.back().empty() ? toSort.localPosition().y() : splittedHits.back().front()->localPosition().y();
826 ATH_MSG_VERBOSE("New bucket: id " << splittedHits.back().bucketId() << " Coverage: " << firstPointPos);
827 }
828 std::shared_ptr<SpacePoint> spacePoint = std::make_shared<SpacePoint>(std::move(toSort));
829 splittedHits.back().emplace_back(spacePoint);
830 }
831 SpacePointBucket& lastBucket{splittedHits.back()};
832 lastBucket.setCoveredRange(lastBucket.front()->localPosition().y(),
833 lastBucket.back()->localPosition().y());
834}
835
836
837std::string SpacePointMakerAlg::chamberConfigKey( const MuonGMR4::Chamber& chamber) const {
838 return std::format("{:}_eta{:}_phi{:}", Muon::MuonStationIndex::chName(chamber.chamberIndex()), chamber.stationEta(), chamber.stationPhi());
839}
840
842 const MuonGMR4::Chamber* chamber = spacePoint.chamber();
843
844 ATH_MSG_DEBUG("Resolving bucket parameters for chamber "<<chamber->identString());
845
846 if (const auto itr = m_bucketParameters.find(chamber);
847 itr != m_bucketParameters.end()) {
848 ATH_MSG_DEBUG("FOUNDPARAMS!" );
849 return itr->second;
850 }
851
853}
854
856 const std::string_view chamberKey,
857 const double defaultValue,
858 const BucketPatternMap& patterns) const {
859
860 // Exact match (e.g. BIL_eta-3_phi3) has the highest priority.
861 if (const auto exactItr = patterns.find(chamberKey);
862 exactItr != patterns.end()) {
863 return {
864 .value = exactItr->second,
865 .matched = true
866 };
867 }
868
869 double resolvedValue = defaultValue;
870 std::size_t bestSpecificity = 0;
871 bool matched = false;
872
873 // Otherwise select the most-specific matching wildcard (e.g. BIL_eta-3* or BIL* or BIL_eta*_phi3).
874 // If there are multiple patterns matching, the one with the most non-wildcard characters is selected.
875 for (const auto& [pattern, value] : patterns) {
876 if (pattern.find('*') == std::string::npos) {
877 continue;
878 }
879
880 if (!wildcardMatch(pattern, chamberKey)) {
881 continue;
882 }
883
884 // More non-wildcard characters means a more specific pattern.
885 const std::size_t specificity =
886 std::ranges::count_if(pattern, [](const char c) {
887 return c != '*';
888 });
889
890 if (!matched || specificity > bestSpecificity) {
891 bestSpecificity = specificity;
892 resolvedValue = value;
893 matched = true;
894 }
895 }
896
897 return {
898 .value = resolvedValue,
899 .matched = matched
900 };
901}
902
903
904
905std::optional<SpacePointMakerAlg::BucketParameters> SpacePointMakerAlg::resolveBucketParameters(
906 const MuonGMR4::Chamber& chamber) const {
907
908 const std::string chamberKey = chamberConfigKey(chamber);
909
910 const ResolvedParameter maxLength = resolveParameter(
911 chamberKey,
912 m_maxBucketLength.value(),
914
915 const ResolvedParameter hitWindow = resolveParameter(
916 chamberKey,
917 m_spacePointWindow.value(),
919
920 const ResolvedParameter overlap = resolveParameter(
921 chamberKey,
922 m_spacePointOverlap.value(),
924
925 // No chamber-dependent setting matched.
926 if (!maxLength.matched &&
927 !hitWindow.matched &&
928 !overlap.matched) {
929 return std::nullopt;
930 }
931
932 BucketParameters parameters{
933 .spacePointWindow = hitWindow.value,
934 .maxBucketLength = maxLength.value,
935 .spacePointOverlap = overlap.value
936 };
937
938
940 "Resolved bucket override for " << chamberKey
941 << ": maxBucketLength=" << parameters.maxBucketLength
942 << (maxLength.matched ? " [override]" : " [default]")
943 << ", spacePointWindow=" << parameters.spacePointWindow
944 << (hitWindow.matched ? " [override]" : " [default]")
945 << ", spacePointOverlap=" << parameters.spacePointOverlap
946 << (overlap.matched ? " [override]" : " [default]"));
947
948 return parameters;
949}
950
951
952}
const std::regex re(r_e)
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_DEBUG(x)
#define ATH_UNLIKELY(x)
static Double_t sp
static Double_t a
Handle class for reading from StoreGate.
Handle class for recording to StoreGate.
#define min(a, b)
Definition cfImp.cxx:40
#define max(a, b)
Definition cfImp.cxx:41
const ServiceHandle< StoreGateSvc > & detStore() const
bool msgLvl(const MSG::Level lvl) const
value_type push_back(value_type pElem)
Add an element to the end of the collection.
bool empty() const noexcept
Returns true if the collection is empty.
Chamber represent the volume enclosing a muon station.
Definition Chamber.h:29
MuonReadoutElement is an abstract class representing the geometry of a muon detector.
const Acts::Surface & surface() const
Returns the surface associated with the readout element.
const Amg::Transform3D & localToGlobalTransform(const ActsTrk::GeometryContext &ctx) const override final
Returns the transformation from the local coordinate system of the readout element into the global AT...
double padHeight() const
Returns the height of all the pads that are not adjacent to the bottom edge of the trapezoid active a...
const PadDesign & padDesign(const IdentifierHash &measHash) const
Retrieves the readoutElement Layer given the Identifier/Hash.
localCornerArray localPadCorners(const IdentifierHash &measHash) const
bool isEtaZero(const IdentifierHash &measurementHash, const Amg::Vector2D &localPosition) const
: The muon space point bucket represents a collection of points that will bre processed together in t...
void setCoveredRange(double min, double max)
set the range in the precision plane covered by the bucket
void setBucketId(unsigned int id)
sets the Identifier of the MuonSpacePointBucket in context of the associated muonChamber
SpacePointStatistics(const Muon::IMuonIdHelperSvc *idHelperSvc)
Standard constructor.
void addToStat(const std::vector< SpacePoint > &spacePoints)
Adds the vector of space points to the overall statistics.
void dumpStatisics(MsgStream &msg) const
Print the statistics table of the built space points per category into the log-file / console.
Gaudi::Property< double > m_maxOccRpcEta
BucketParameters m_defaultBucketParameters
Default bucket parameters used if no chamber-specific parameters are found, defaults into m_spacePoin...
Gaudi::Property< double > m_maxOccTgcEta
const MuonGMR4::MuonDetectorManager * m_detMgr
Gaudi::Property< double > m_maxOccTgcPhi
Gaudi::Property< double > m_spacePointWindow
Default space point window size (Max distance between the two eta hits).
Gaudi::Property< bool > m_doStat
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
std::vector< EtaPhi2DHits< T > > EtaPhi2DHitsVec
SG::ReadHandleKey< xAOD::TgcStripContainer > m_tgcKey
bool splitBucket(const SpacePoint &spacePoint, const double firstSpPos, const SpacePointBucketVec &sortedPoints, const BucketParameters &bucketParams) const
Returns whether the space point is beyond the bucket boundary.
void distributePhiPoints(std::vector< SpacePoint > &&spacePoints, SpacePointBucketVec &splittedContainer) const
Distributs the vector phi space points into the buckets.
Gaudi::Property< double > m_maxOccRpcPhi
Gaudi::Property< double > m_maxBucketLength
Default maximum bucket length (the width of the bucket in local y coordinate).
ResolvedParameter resolveParameter(const std::string_view chamberKey, const double defaultValue, const BucketPatternMap &patterns) const
Resolves a specific parameter for a given chamber key, based on the configured patterns.
SG::ReadHandleKey< xAOD::MMClusterContainer > m_mmKey
bool passOccupancy2D(const PrdVec_t< PrdType > &etaHits, const PrdVec_t< PrdType > &phiHits) const
: Check whether the occupancy cuts of hits in a gasGap are surpassed.
std::vector< SpacePointBucket > SpacePointBucketVec
Abrivation of a MuonSapcePoint bucket vector.
void fillUncombinedSpacePoints(const ActsTrk::GeometryContext &gctx, const Amg::Transform3D &sectorTrans, const PrdVec_t< const PrdType * > &prdsToFill, std::vector< SpacePoint > &outColl) const
Transform the uncombined space prd measurements to space points.
void newBucket(const SpacePoint &refSp, SpacePointBucketVec &sortedPoints, const BucketParameters &bucketParams) const
Closes the current processed bucket and creates a new one.
Gaudi::Property< BucketPatternMap > m_spacePointOverlapPatterns
Chamber-pattern dependent space point overlap.
SG::WriteHandleKey< SpacePointContainer > m_writeKey
StatusCode loadContainerAndSort(const EventContext &ctx, const SG::ReadHandleKey< ContType > &key, PreSortedSpacePointMap &fillContainer) const
Retrieve an uncalibrated measurement container <ContType> and fill the hits into the presorted space ...
SG::ReadHandleKey< xAOD::RpcMeasurementContainer > m_rpcKey
Gaudi::Property< double > m_spacePointOverlap
Default space point overlap (the margin around the edge of the bucket which is also coppied into anot...
StatusCode execute(const EventContext &ctx) const override
std::optional< BucketParameters > resolveBucketParameters(const MuonGMR4::Chamber &chamber) const
Resolves the bucket parameters for a given chamber, based on the chamber key and the configured patte...
std::vector< Prd_t > PrdVec_t
void distributePrimaryPoints(std::vector< SpacePoint > &&spacePoints, SpacePointBucketVec &splittedContainer) const
Distributes the vector of primary eta or eta + phi space points and fills them into the buckets.
StatusCode initialize() override
SG::ReadHandleKey< xAOD::sTgcMeasContainer > m_stgcKey
void distributePointsAndStore(SpacePointsPerChamber &&hitsPerChamber, SpacePointContainer &finalContainer) const
Distribute the premade spacepoints per chamber into their individual SpacePoint buckets.
EtaPhi2DHitsVec< typename ContType::const_value_type > splitHitsPerGasGap(xAOD::ChamberViewer< ContType > &viewer) const
Splits the chamber hits of the viewer per gas gap.
StatusCode finalize() override
########################################## SpacePointMakerAlg #######################################...
const BucketParameters & getBucketParameters(const SpacePoint &spacePoint) const
Returns the bucket parameters for a given space point.
Gaudi::Property< BucketPatternMap > m_maxBucketLengthPatterns
Chamber-pattern dependent maximum bucket length.
std::string chamberConfigKey(const MuonGMR4::Chamber &chamber) const
Returns a string key for a chamber, based on the space point identifier.
Gaudi::Property< BucketPatternMap > m_spacePointWindowPatterns
Chamber-pattern dependent space point window.
std::unordered_map< const MuonGMR4::SpectrometerSector *, SpacePointsPerChamber > PreSortedSpacePointMap
Container abrivation of the presorted space point container per MuonChambers.
Gaudi::Property< unsigned > m_capacityBucket
SG::ReadHandleKey< xAOD::MdtDriftCircleContainer > m_mdtKey
ActsTrk::GeoContextReadKey_t m_geoCtxKey
std::map< std::string, double, std::less<> > BucketPatternMap
std::unordered_map< const MuonGMR4::Chamber *, BucketParameters > m_bucketParameters
Map of bucket parameters for each chamber.
The SpacePointPerLayerSorter sort two given space points by their layer Identifier.
The muon space point is the combination of two uncalibrated measurements one of them measures the eta...
void setDirection(const Amg::Vector3D &sensorDir, const Amg::Vector3D &toNextSensor)
Setter for the direction of the measurement channel in the sector frame.
void setInstanceCounts(std::shared_ptr< unsigned > etaCounts, std::shared_ptr< unsigned > phiCounts)
Set the number of space points built with the same eta / phi prd.
const MuonGMR4::Chamber * chamber() const
: Pointer to the associated chamber
bool measuresEta() const
: Does the space point contain an eta measurement
Interface for Helper service that creates muon Identifiers and can be used to print Identifiers.
Property holding a SG store/key/clid from which a ReadHandle is made.
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
const_ref at(const std::size_t idx) const
Returns the i-the measurement from the current chamber.
std::size_t size() const noexcept
Returns how many hits are in the current chamber.
bool next()
Loads the hits from the next chamber.
const MuonGMR4::sTgcReadoutElement * readoutElement() const override final
Retrieve the associated sTgcReadoutElement.
IdentifierHash measurementHash() const override final
Returns the hash of the measurement channel w.r.t ReadoutElement.
Amg::Vector3D localMeasurementPos() const override final
Returns the local measurement position as 3-vector.
#define ATH_FLATTEN
std::vector< std::string > patterns
Definition listroot.cxx:187
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
This header ties the generic definitions in this package.
DataVector< SpacePointBucket > SpacePointContainer
Abrivation of the space point container type.
const std::string & stName(StIndex index)
convert StIndex into a string
const std::string & technologyName(TechnologyIndex index)
convert LayerIndex into a string
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.
void swap(ElementLinkVector< DOBJ > &lhs, ElementLinkVector< DOBJ > &rhs)
void stable_sort(DataModel_detail::iterator< DVL > beg, DataModel_detail::iterator< DVL > end)
Specialization of stable_sort for DataVector/List.
DataModel_detail::iterator< DVL > remove_if(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end, Predicate pred)
Specialization of remove_if for DataVector/List.
MdtTwinDriftCircle_v1 MdtTwinDriftCircle
sTgcMeasContainer_v1 sTgcMeasContainer
sTgcMeasurement_v1 sTgcMeasurement
Helper struct to define the bucket parameters for a given chamber.
Helper struct to store the resolved bucket parameters for a given chamber.
Helper struct to define the counting categories.
bool operator<(const FieldKey &other) const
################################################################ SpacePointStatistics ###############...
Helper struct to count the space-points in each detector category.
unsigned measEtaPhi
Number of space points measuring eta & phi.
unsigned measEta
Number of space points measuring eta only.
unsigned measPhi
Number of space points measuring phi only.
unsigned allHits() const
Helper method returning the sum of the three space point type counts.
: Helper struct to collect the space point per muon chamber, which are later sorted into the space po...
std::vector< SpacePoint > etaHits
Vector of all hits that contain an eta measurement including the ones which are combined with phi mea...
std::vector< SpacePoint > phiHits
Vector of all space points that are built from single phi hits.