ATLAS Offline Software
MuonNSWSegmentFinderTool.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 
18 #include "TrkTrack/Track.h"
21 
22 #include "CxxUtils/inline_hints.h"
23 
24 namespace {
25  using MuonSegmentVec = std::vector<std::unique_ptr<Muon::MuonSegment>>;
26  const MuonGM::MuonChannelDesign* getDesign(const Muon::MuonClusterOnTrack* cl) {
27  const Trk::TrkDetElementBase* ele = cl->detectorElement();
29  return static_cast<const MuonGM::MMReadoutElement*>(ele)->getDesign(cl->identify());
31  return static_cast<const MuonGM::sTgcReadoutElement*>(ele)->getDesign(cl->identify());
32  return nullptr;
33  }
34 
35  int clusterSize(const Muon::MuonClusterOnTrack* cl) {
36  const Trk::PrepRawData* prd = cl->prepRawData();
38  return static_cast<const Muon::MMPrepData*>(prd)->stripNumbers().size();
39  }
41  return static_cast<const Muon::sTgcPrepData*>(prd)->stripNumbers().size();
42  }
43  return -1;
44  }
45 
46  std::string to_string(const Amg::Vector3D& v) {
47  std::stringstream sstr{};
48  sstr<<"[x,y,z]="<<Amg::toString(v, 2)<<" [theta/eta/phi]=("<<(v.theta() / Gaudi::Units::degree)<<","<<v.eta()<<","<<(v.phi()/ Gaudi::Units::degree)<<")";
49  return sstr.str();
50  }
52  constexpr double minEtaNSW = 1.2;
53  constexpr double maxEtaNSW = 2.8;
54 
55 } // namespace
56 namespace Muon {
82 
94 
104  m_cl{cl},
105  m_dir{cl->detectorElement()->transform(cl->identify()).linear() * Amg::Vector3D::UnitY()} {}
106 
107  NSWSeed::NSWSeed(const MuonNSWSegmentFinderTool* parent, const std::array<SeedMeasurement, 4>& seed,
108  const std::array<double,2>& lengths) :
109  m_parent{parent},
110  m_pos{seed[0].pos() + lengths[0] * seed[0].dir()} {
111 
112  const Amg::Vector3D un_dir = (seed[1].pos() + lengths[1] *seed[1].dir() - m_pos);
113  m_dir = un_dir.unit()*(un_dir.z() * seed[0].pos().z() > 0 ? 1 : -1);
114 
115  if (m_parent->msgLvl(MSG::VERBOSE))
116  m_parent->msgStream() << MSG::VERBOSE << m_parent->printSeed(seed)<<" is a valid seed "<<to_string(m_pos) <<" pointing to "<<to_string(m_dir)<<"."<<endmsg;
117 
119  for (const SeedMeasurement& cl : seed) {
120  insert(cl);
121  m_width = std::hypot(m_width, Amg::error(cl->localCovariance(), Trk::locX));
122  }
123  m_width /= std::sqrt(3);
124  }
126  const SeedMeasurement& second) :
127  m_parent{parent}, m_pos{first.pos()} {
128  m_dir = (second.pos() - m_pos).unit();
129  m_width = std::hypot(Amg::error(first->localCovariance(), Trk::locX),
130  Amg::error(second->localCovariance(), Trk::locX)) / std::sqrt(2);
131  insert(first);
132  insert(second);
133  }
135  m_parent{parent}, m_pos{seg.globalPosition()}, m_dir{seg.globalDirection()} {
136  for (const Trk::MeasurementBase* meas : seg.containedMeasurements()) {
137  const Muon::MuonClusterOnTrack* clus = dynamic_cast<const Muon::MuonClusterOnTrack*>(meas);
138  if (!clus) continue;
139  insert(clus);
140  m_width = std::hypot(m_width, Amg::error(clus->localCovariance(), Trk::locX));
141  }
142  m_width /= std::sqrt(size());
143  }
145  m_parent{parent}, m_pos{pos}, m_dir{dir}, m_size{1} {}
146  int NSWSeed::channel(const SeedMeasurement& meas) const {return m_parent->channel(meas);}
147  double NSWSeed::distance(const SeedMeasurement& meas) const {
148  const Amg::Vector3D& A = pos();
149  const Amg::Vector3D& B = dir();
150  const Amg::Vector3D& C = meas.pos();
151  const Amg::Vector3D& D = meas.dir();
152  const double BdotD = B.dot(D);
153  const double divisor = (1. - std::pow(BdotD, 2));
154  const Amg::Vector3D diff = C - A;
155  if (std::abs(divisor) < std::numeric_limits<double>::epsilon()) return diff.mag();
156  const double beta = (diff.dot(B) - diff.dot(D) * BdotD) / divisor;
157  const double delta = (diff.dot(B) * BdotD - diff.dot(D)) / divisor;
158  return (beta * B - delta * D - diff).mag();
159  }
160  bool NSWSeed::add(SeedMeasurement meas, double max_uncert) {
161  if (!size() || !meas) return false;
162  if (find(meas)) return true;
164  Amg::Vector2D lpos_seed{Amg::Vector2D::Zero()};
165  if (!meas->associatedSurface().globalToLocal(intersect.position, dir(), lpos_seed)) return false;
166  // Dont allow seeds outside of active areas to create seeds
167  // Happens rarely but is good protection to reduce wrong channel to track association
168  if (!meas->associatedSurface().insideBounds(lpos_seed)) return false;
169 
170  // Dont save sTGC wires in inner Q1
171  if (m_parent->isWire(meas)) {
172  const sTgcPrepData* prd = static_cast<const sTgcPrepData*>(meas->prepRawData());
173  if (prd->detectorElement()->isEtaZero(prd->identify(), lpos_seed)) return false;
174  }
175 
176  if (m_parent->isPad(meas)) {
177  const sTgcPrepData* prd = dynamic_cast<const sTgcPrepData*>(meas->prepRawData());
178  if (!prd) return false;
179  const MuonGM::MuonPadDesign* design = prd->detectorElement()->getPadDesign(prd->identify());
180  if (!design) return false;
181  Amg::Vector2D padDist = design->distanceToPad(lpos_seed, channel(meas));
182  const double dist = std::hypot(padDist.x(), padDist.y());
183  meas.setDistance(dist);
184  const double uncertD = std::max(1., m_width);
185  return (meas.distance() / uncertD < max_uncert) && insert(meas);
186  }
187  meas.setDistance(distance(meas));
188  const double uncertD = std::max(1.,std::hypot(m_width, Amg::error(meas->localCovariance(), Trk::locX)));
189  if (m_parent->msgLvl(MSG::VERBOSE)) {
190  m_parent->msgStream() << MSG::VERBOSE << m_parent->print(meas) << " is separated from "
191  << to_string(pos())<<" + lambda " <<to_string(dir())<<" " << meas.distance()
192  << ". covariance: " << (meas.distance() / uncertD) << endmsg;
193  }
194  return (meas.distance() / uncertD < max_uncert) && insert(meas);
195  }
198  unsigned int only_th{0}, only_oth{0};
199  for (size_t m = 0; m < m_measurements.size(); ++m) {
200  if (m_measurements[m]== other.m_measurements[m] &&
201  m_phiMeasurements[m] == other.m_phiMeasurements[m])
202  continue;
204  if (!m_measurements[m]) ++only_oth;
205  if (!m_phiMeasurements[m]) ++only_oth;
206  if (!other.m_measurements[m]) ++only_th;
207  if (!other.m_phiMeasurements[m]) ++only_th;
208  }
209  if (only_oth && !only_th) return SeedOR::SubSet;
210  if (only_th && !only_oth) return SeedOR::SuperSet;
211  return res;
212  }
214  MeasVec meas;
215  meas.reserve(size());
216  for (size_t m = 0; m < m_measurements.size(); ++m) {
217  if (m_measurements[m]) meas.push_back(m_measurements[m]);
218  if (m_phiMeasurements[m]) meas.push_back(m_phiMeasurements[m]);
219  if (m_padMeasurements[m]) meas.push_back(m_padMeasurements[m]);
220  }
221  std::sort(meas.begin(), meas.end(), [](const SeedMeasurement& a, const SeedMeasurement& b) {
222  return std::abs(a->globalPosition().z()) < std::abs(b->globalPosition().z());
223  });
224  return meas;
225  }
227  SeedMeasurement meas{cl};
228  meas.setDistance(distance(meas));
229  return insert(std::move(meas));
230  }
232  SeedMeasCache& seed_vec = m_parent->idHelper()->measuresPhi(meas->identify()) ?
234  SeedMeasurement& seed = seed_vec[m_parent->layerNumber(meas)];
235  if (!seed || meas.distance() < seed.distance()) {
236  m_size += !seed;
237  m_chi2 += meas.distance() / Amg::error(meas->localCovariance(), Trk::locX);
238  // From this point the measurement is now the old one
239  std::swap(seed, meas);
240  if (meas) m_chi2 -= meas.distance() / Amg::error(meas->localCovariance(), Trk::locX);
241  return true;
242  }
243  return false;
244  }
245  const Muon::MuonClusterOnTrack* NSWSeed::newCalibClust(std::unique_ptr<const Muon::MuonClusterOnTrack> new_clust) {
246  return m_calibClust.emplace(std::move(new_clust)).first->get();
247  }
248  bool NSWSeed::find(const SeedMeasurement& meas) const {
249  const int lay = m_parent->layerNumber(meas);
250  if (m_parent->isPad(meas)) return m_padMeasurements[lay] == meas;
251  if (m_parent->idHelper()->measuresPhi(meas->identify())) return m_phiMeasurements[lay] == meas;
252  return m_measurements[lay] == meas;
253  }
254 
255  //============================================================================
256  MuonNSWSegmentFinderTool::MuonNSWSegmentFinderTool(const std::string& type, const std::string& name, const IInterface* parent) :
258  declareInterface<IMuonNSWSegmentFinderTool>(this);
259  }
260 
261  //============================================================================
263  ATH_CHECK(m_slTrackFitter.retrieve());
264  ATH_CHECK(m_printer.retrieve());
265  ATH_CHECK(m_edmHelperSvc.retrieve());
266  ATH_CHECK(m_ambiTool.retrieve());
267  ATH_CHECK(m_trackToSegmentTool.retrieve());
268  ATH_CHECK(m_idHelperSvc.retrieve());
269  ATH_CHECK(m_trackCleaner.retrieve());
270  ATH_CHECK(m_trackSummary.retrieve());
271  ATH_CHECK(m_muonClusterCreator.retrieve());
273  ATH_MSG_FATAL("The muon should come from the IP && horizontally from the Calo..."<<
274  "We need to place a very good basball player at the calo exit to deflect the muon horizontally.");
275  return StatusCode::FAILURE;
276  }
277  ATH_MSG_DEBUG(" Max cut " << m_maxClustDist);
278  return StatusCode::SUCCESS;
279  }
280 
282  //============================================================================
283  void MuonNSWSegmentFinderTool::find(const EventContext& ctx, SegmentMakingCache& cache) const {
284 
285  std::vector<const Muon::MuonClusterOnTrack*> muonClusters{};
286  muonClusters.reserve(cache.inputClust.size());
287  std::transform(cache.inputClust.begin(), cache.inputClust.end(), std::back_inserter(muonClusters),
288  [](const std::unique_ptr<const MuonClusterOnTrack>& cl){return cl.get();});
289  ATH_MSG_DEBUG("Entering MuonNSWSegmentFinderTool with " << muonClusters.size() << " clusters to be fit");
290 
291  // Find segments using the MM strips as a seed
292  MuonSegmentVec out_segments{};
293  {
294  MuonSegmentVec stereoSegs = findStereoSegments(ctx, muonClusters, 0);
295  ATH_MSG_VERBOSE("Found " << stereoSegs.size() << " MMG stereo seeded segments");
296  out_segments.insert(out_segments.end(), std::make_move_iterator(stereoSegs.begin()),
297  std::make_move_iterator(stereoSegs.end()));
298  }
299 
300  // Push back mm seded segments and cache used hits
301  auto dump_output = [&]() {
302  cache.constructedSegs.reserve(cache.constructedSegs.size() + out_segments.size());
303  for (std::unique_ptr<Muon::MuonSegment>& seg : out_segments) {
304  for (const Trk::MeasurementBase* meas : seg->containedMeasurements()) {
305  const Muon::MuonClusterOnTrack* clus = dynamic_cast<const Muon::MuonClusterOnTrack*>(meas);
306  if (clus) cache.usedHits.insert(clus->identify());
307  }
308  cache.constructedSegs.push_back(std::move(seg));
309  }
310  };
311 
312  std::vector<const Muon::MuonClusterOnTrack*> clustPostStereo{};
314  std::array<std::set<Identifier>, 16> masked_segs{};
315  for (std::unique_ptr<Muon::MuonSegment>& seg : out_segments) {
316  for (const Trk::MeasurementBase* meas : seg->containedMeasurements()) {
317  const Muon::MuonClusterOnTrack* clus = dynamic_cast<const Muon::MuonClusterOnTrack*>(meas);
318  if (clus) masked_segs[layerNumber(clus)].insert(clus->identify());
319  }
320  }
321 
322  // Create new vector of clusters excluding the ones used in the mm seeded segments
323  if (!out_segments.empty()) {
324  clustPostStereo.reserve(muonClusters.size());
325  for (const Muon::MuonClusterOnTrack* clus : muonClusters) {
326  if (!masked_segs[layerNumber(clus)].count(clus->identify())) clustPostStereo.push_back(clus);
327  }
328  }
329 
330  // If we did not find any mm seeded segments use the full hit vector to build stgc seeded segments
331  // otherwise use the ones that did not make it onto a segment yet
332  const std::vector<const Muon::MuonClusterOnTrack*>& segmentInput = !out_segments.empty() ? clustPostStereo : muonClusters;
333 
335  {
336  MuonSegmentVec etaSegs = findStgcPrecisionSegments(ctx, segmentInput);
337  ATH_MSG_VERBOSE("Found " << etaSegs.size() << " stgc seeded eta segments");
338  MuonSegmentVec precSegs = find3DSegments(ctx, segmentInput, etaSegs);
339  ATH_MSG_VERBOSE("Found " << precSegs.size() << " 3D segments");
340  out_segments.insert(out_segments.end(),
341  std::make_move_iterator(precSegs.begin()),
342  std::make_move_iterator(precSegs.end()));
343  }
344 
345 
346 
347  if (!cache.buildQuads) {
348  dump_output();
349  return;
350  }
352  for (std::unique_ptr<Muon::MuonSegment>& seg : out_segments) {
353  std::vector<const MuonClusterOnTrack*> seg_hits{};
354  seg_hits.reserve(seg->containedMeasurements().size());
355  for (const Trk::MeasurementBase* meas : seg->containedMeasurements()) {
356  const Muon::MuonClusterOnTrack* clus = dynamic_cast<const Muon::MuonClusterOnTrack*>(meas);
357  if (clus) seg_hits.push_back(clus);
358  }
360  for (int iWedge{1}; iWedge<=4 ; ++iWedge) {
361  MeasVec quad_hits = cleanClusters(seg_hits, HitType::Eta | HitType::Phi, iWedge);
363  if ( quad_hits.size () < 2 || ((iWedge == 2 || iWedge == 3) && quad_hits.size() < 4)) continue;
364  std::vector<const Trk::MeasurementBase*> fit_meas{};
365  std::unique_ptr<Trk::PseudoMeasurementOnTrack> pseudoVtx{ipConstraint(ctx)};
366  if (pseudoVtx) fit_meas.push_back(pseudoVtx.get());
367  std::copy(quad_hits.begin(), quad_hits.end(), std::back_inserter(fit_meas));
369  const Trk::Surface& surf = quad_hits.front()->associatedSurface();
370  Trk::Intersection intersect = surf.straightLineIntersection(seg->globalPosition(), seg->globalDirection(), false, false);
371  const Amg::Vector3D& gpos_seg = intersect.position;
372  Amg::Vector3D gdir_seg{seg->globalDirection()};
373  Amg::Vector3D perpos = gpos_seg - 10 * gdir_seg.unit();
374  if (perpos.dot(gdir_seg) < 0) gdir_seg *= -1;
375  Trk::Perigee startpar{perpos, gdir_seg, 0, perpos};
377  std::unique_ptr<Trk::Track> segtrack = fit(ctx, fit_meas, startpar);
378  if (!segtrack) continue;
379 
380  std::unique_ptr<MuonSegment> seg{m_trackToSegmentTool->convert(ctx, *segtrack)};
381  if (seg) {
382  ATH_MSG_VERBOSE(" adding new quad segment " << m_printer->print(*seg) << std::endl
383  <<"position: "<<to_string(seg->globalPosition())<< std::endl
384  <<"direction: "<<to_string(seg->globalDirection())<< std::endl
385  << m_printer->print(seg->containedMeasurements()));
386  seg->setAuthor(Trk::Segment::NswQuadAlign);
387  cache.quadSegs.emplace_back(std::move(seg));
388  }
389  }
390  }
391  dump_output();
392  }
393  MuonSegmentVec MuonNSWSegmentFinderTool::findStereoSegments(const EventContext& ctx,
394  const std::vector<const Muon::MuonClusterOnTrack*>& allClusts,
395  int singleWedge) const {
396 
397  if (!m_useStereoSeeding){
398  ATH_MSG_VERBOSE("MMStereoSeeding disabled!");
399  return {};
400  }
401 
402  ATH_MSG_VERBOSE("Running MMStereoSeeding");
404  LayerMeasVec orderedClust =
405  classifyByLayer(cleanClusters(allClusts, HitType::Eta | HitType::Phi, singleWedge), HitType::Wire | HitType::Pad);
406 
407  for (MeasVec& hitsInLayer : orderedClust) hitsInLayer = vetoBursts(std::move(hitsInLayer));
408  orderedClust.erase(std::remove_if(orderedClust.begin(), orderedClust.end(),
409  [](const MeasVec& vec) { return vec.empty(); }),
410  orderedClust.end());
411  if (orderedClust.empty()) return {};
412 
413 
414  std::vector<NSWSeed> seeds = segmentSeedFromMM(orderedClust);
415  ATH_MSG_DEBUG("Retrieved " << seeds.size() << " seeds in the MMStereoAlg after the ambiguity resolution" );
416 
417  if (seeds.empty()) return {};
420  for (NSWSeed& seed : seeds) {
423  std::vector<const Trk::MeasurementBase*> fit_meas{};
424 
425  std::unique_ptr<Trk::PseudoMeasurementOnTrack> pseudoVtx{ipConstraint(ctx)};
426  if (pseudoVtx) fit_meas.push_back(pseudoVtx.get());
427  MeasVec calib_clust = getCalibratedClusters(seed);
428  std::copy(calib_clust.begin(), calib_clust.end(), std::back_inserter(fit_meas));
430  const Trk::Surface& surf = calib_clust.front()->associatedSurface();
431 
432  Trk::Intersection intersect = surf.straightLineIntersection(seed.pos(), seed.dir(), false, false);
433  const Amg::Vector3D& gpos_seg = intersect.position;
434  Amg::Vector3D gdir_seg{seed.dir()};
435  Amg::Vector3D perpos = gpos_seg - 10 * gdir_seg.unit();
436  if (perpos.dot(gdir_seg) < 0) gdir_seg *= -1;
437 
438  Trk::Perigee startpar{perpos, gdir_seg, 0, perpos};
439 
441  std::unique_ptr<Trk::Track> segtrack = fit(ctx, fit_meas, startpar);
442  if (segtrack) trackSegs.push_back(std::move(segtrack));
443  }
444  return resolveAmbiguities(ctx, trackSegs, Trk::Segment::Author::NswStereoSeeded);
445  }
446 
447  std::unique_ptr<Trk::Track> MuonNSWSegmentFinderTool::fit(const EventContext& ctx,
448  const std::vector<const Trk::MeasurementBase*>& fit_meas,
449  const Trk::TrackParameters& perigee) const {
450  ATH_MSG_DEBUG("Fit segment from (" << to_string(perigee.position())<< " pointing to " <<
451  to_string(perigee.momentum())<<". Contained measurements in candidate: " << std::endl
452  << m_printer->print(fit_meas));
453  std::unique_ptr<Trk::Track> segtrack = m_slTrackFitter->fit(ctx, fit_meas, perigee, false, Trk::nonInteracting);
454  if (!segtrack) {
455  ATH_MSG_DEBUG("Fit failed");
456  return nullptr;
457  }
458  ATH_MSG_VERBOSE("--> Fit succeeded");
459  std::unique_ptr<Trk::Track> cleanedTrack = m_trackCleaner->clean(*segtrack, ctx);
460  if (cleanedTrack && cleanedTrack->perigeeParameters() != segtrack->perigeeParameters()) { segtrack.swap(cleanedTrack); }
461  // quality criteria
462  if (!m_edmHelperSvc->goodTrack(*segtrack, 10)) {
463  if (segtrack->fitQuality()) {
464  ATH_MSG_DEBUG("Segment fit with chi^2/nDoF = " << segtrack->fitQuality()->chiSquared() << "/"
465  << segtrack->fitQuality()->numberDoF());
466  }
467  return nullptr;
468  }
469  // update the track summary and add the track to the collection
470  m_trackSummary->updateTrack(ctx, *segtrack);
471  ATH_MSG_DEBUG("Segment accepted with chi^2/nDoF = " << segtrack->fitQuality()->chiSquared() << "/"
472  << segtrack->fitQuality()->numberDoF());
473  return segtrack;
474  }
475 
476  //============================================================================
477  // find the precision (eta) segments
478  MuonSegmentVec MuonNSWSegmentFinderTool::findStgcPrecisionSegments(const EventContext& ctx,
479  const std::vector<const Muon::MuonClusterOnTrack*>& muonClusters,
480  int singleWedge) const {
481 
482  if (!m_usesTGCSeeding){
483  ATH_MSG_VERBOSE("2D sTGC seeding disabled!");
484  return {};
485  }
486 
487  ATH_MSG_VERBOSE("Running 2D sTGC seeding");
488 
489 
490  // clean the muon clusters; select only the eta hits.
491  // in single-wedge mode the eta seeds are retrieved from the specific wedge
492 
493  ATH_MSG_DEBUG("Cleaning eta clusters in stgc seeded 2D segments ");
494  MeasVec clusters = cleanClusters(muonClusters, HitType::Eta, singleWedge); // eta hits only
495  ATH_MSG_VERBOSE(" After hit cleaning, there are " << clusters.size() << " precision 2D clusters");
496 
497  // classify eta clusters by layer
498  LayerMeasVec orderedClusters = classifyByLayer(clusters, 0);
499 
500  if (orderedClusters.size() < 4) return {}; // at least four layers with eta hits (MM and sTGC)
501 
502  // create segment seeds
503  std::vector<NSWSeed> seeds = segmentSeedFromStgc(orderedClusters, false);
504  ATH_MSG_DEBUG(" Found " << seeds.size() << " 2D seeds");
505  // Loop on seeds: find all clusters near the seed and try to fit
506  MeasVec etaHitVec, phiHitVec;
507  TrackCollection segTrkColl{SG::OWN_ELEMENTS};
508 
509  for (NSWSeed& seed : seeds) {
510  if (seed.size() < 4){
511  ATH_MSG_VERBOSE(__func__<<" :"<<__LINE__<< " - Seed size: " << seed.size() << " is below the cut (4)");
512  continue;
513  }
514 
515  etaHitVec = seed.measurements();
516  const Trk::PlaneSurface& surf = static_cast<const Trk::PlaneSurface&>(etaHitVec.front()->associatedSurface());
517  // calculate start parameters for the fit
518  // local position and direction of the eta-seed on the surface of the first cluster
519  Trk::Intersection intersect = surf.straightLineIntersection(seed.pos(), seed.dir(), false, false);
520  Amg::Vector2D lpos_seed{Amg::Vector2D::Zero()};
521  Trk::LocalDirection ldir_seed{};
522  surf.globalToLocal(intersect.position, intersect.position, lpos_seed);
523  surf.globalToLocalDirection(seed.dir(), ldir_seed);
524 
525  // use the seed info to generate start parameters (dummy values for phi)
526  Amg::Vector2D lpos(lpos_seed[Trk::locX], 0.);
527  Trk::LocalDirection ldir(ldir_seed.angleXZ(), -M_PI_2);
528  Amg::Vector3D gpos_seg{Amg::Vector3D::Zero()}, gdir_seg{Amg::Vector3D::Zero()};
529  surf.localToGlobal(lpos, gpos_seg, gpos_seg);
530  surf.localToGlobalDirection(ldir, gdir_seg);
531 
532  Amg::Vector3D perpos = gpos_seg - 10 * gdir_seg.unit();
533  if (perpos.dot(gdir_seg) < 0) gdir_seg *= -1;
534  const auto startpar = Trk::Perigee(perpos, gdir_seg, 0, perpos);
535  ATH_MSG_VERBOSE(" start parameter " << perpos << " pp " << startpar.position() << " gd " << gdir_seg.unit() << " pp "
536  << startpar.momentum().unit());
537 
538  // fit the hits
539  hitsToTrack(ctx, etaHitVec, phiHitVec, startpar, segTrkColl);
540  }
542  return resolveAmbiguities(ctx, segTrkColl, Trk::Segment::Author::NswStgcSeeded);
543  }
544  MuonSegmentVec MuonNSWSegmentFinderTool::resolveAmbiguities(const EventContext& ctx,
545  const TrackCollection& segTrkColl,
546  const Trk::Segment::Author a) const {
547  if (msgLvl(MSG::DEBUG)) {
548  ATH_MSG_DEBUG("Tracks before ambi solving: ");
549  for (const Trk::Track* trk : segTrkColl) {
550  ATH_MSG_DEBUG(m_printer->print(*trk));
551  const DataVector<const Trk::MeasurementBase>* meas = trk->measurementsOnTrack();
552  if (meas) ATH_MSG_DEBUG(m_printer->print(meas->stdcont()));
553  }
554  }
555 
556  MuonSegmentVec segments{};
557  std::unique_ptr<const TrackCollection> resolvedTracks(m_ambiTool->process(&segTrkColl));
558  ATH_MSG_DEBUG("Resolved track candidates: old size " << segTrkColl.size() << " new size " << resolvedTracks->size());
559 
560  // store the resolved segments
561  for (const Trk::Track* trk : *resolvedTracks) {
562  const auto* measurements = trk->measurementsOnTrack();
563  const bool has_eta = std::find_if(measurements->begin(), measurements->end(),
564  [this](const Trk::MeasurementBase* meas) {
565  Identifier id = m_edmHelperSvc->getIdentifier(*meas);
566  return id.is_valid() && !m_idHelperSvc->measuresPhi(id);
567  }) != trk->measurementsOnTrack()->end();
568  if (!has_eta) continue;
569  std::unique_ptr<MuonSegment> seg{m_trackToSegmentTool->convert(ctx, *trk)};
570  if (seg) {
571  ATH_MSG_DEBUG(" adding " << m_printer->print(*seg) << std::endl << m_printer->print(seg->containedMeasurements()));
572  seg->setAuthor(a);
573  segments.emplace_back(std::move(seg));
574  } else {
575  ATH_MSG_VERBOSE("Segment conversion failed, no segment created. ");
576  }
577  }
578  return segments;
579  }
580  //============================================================================
581  MuonSegmentVec MuonNSWSegmentFinderTool::find3DSegments(const EventContext& ctx,
582  const std::vector<const Muon::MuonClusterOnTrack*>& muonClusters,
583  MuonSegmentVec& etaSegs,
584  int singleWedge) const {
585  MuonSegmentVec segments{};
586  // cluster cleaning #1; select only phi hits (must be from all wedges, in order to phi-seed)
587 
588  ATH_MSG_DEBUG("Cleaning phi clusters in stgc seeded 3D segments ");
589  MeasVec phiClusters = cleanClusters(muonClusters, HitType::Phi | HitType::Wire, singleWedge);
590  ATH_MSG_DEBUG("After hit cleaning, there are " << phiClusters.size() << " phi clusters to be fit");
591 
592 
593  // classify the phi clusters by layer
594  LayerMeasVec orderedWireClusters = classifyByLayer(phiClusters, HitType::Wire);
595  LayerMeasVec orderedPadClusters = classifyByLayer(phiClusters, HitType::Pad); // pads only
596  if (orderedWireClusters.size() + orderedPadClusters.size() < 2) {
597  ATH_MSG_DEBUG("Not enough phi hits present, cannot perform the 3D fit!");
598  segments.insert(segments.end(), std::make_move_iterator(etaSegs.begin()), std::make_move_iterator(etaSegs.end()));
599  return segments;
600  }
601 
602  // cluster cleaning #2; select only eta hits
603  ATH_MSG_DEBUG("Cleaning eta clusters in stgc seeded 3D segments ");
604  MeasVec etaClusters = cleanClusters(muonClusters, HitType::Eta, singleWedge);
605  LayerMeasVec orderedEtaClusters = classifyByLayer(etaClusters, HitType::Eta);
606 
607  // loop on eta segments
608  bool triedWireSeed{false}; // wire seeds need to be retrieved only once (the first time they are needed)
609  std::vector<NSWSeed> seeds_WiresSTGC;
610  TrackCollection segTrkColl{SG::OWN_ELEMENTS};
611  // Loop on eta segments
612  for (std::unique_ptr<Muon::MuonSegment>& etaSeg : etaSegs) {
613  bool is3Dseg{false};
614  NSWSeed seed2D{this, *etaSeg};
615  getClustersOnSegment(orderedEtaClusters, seed2D, {}); // eta clusters
616 
617  std::vector<NSWSeed> seeds;
620  if (std::abs(etaSeg->globalPosition().eta()) < 2.4) {
621  if (!triedWireSeed) {
622  // wire seeds need to be retrieved only once (they don't depend on the eta segment)
623  triedWireSeed = true;
624  seeds_WiresSTGC = segmentSeedFromStgc(orderedWireClusters, true);
625  }
626 
627  if (!seeds_WiresSTGC.empty()) {
628  seeds = seeds_WiresSTGC;
629  ATH_MSG_DEBUG(" Seeding from sTGC wires");
630  }
631  }
632 
633  // 3 - last resort, try sTGC pads
634  if (seeds.empty() ) {
635 
636  // only perform seeding with layers that have less than m_maxInputPads hits
637  LayerMeasVec orderedPadClustersForSeeding;
638  std::ranges::copy_if(orderedPadClusters,
639  std::back_inserter(orderedPadClustersForSeeding),
640  [this](const MeasVec& vec) { return vec.size() < m_maxInputPads; });
641 
642  seeds = segmentSeedFromPads(orderedPadClustersForSeeding, *etaSeg);
643  ATH_MSG_DEBUG(" Seeding from sTGC pads");
644  }
645 
646  // Loop on phi seeds
647  MeasVec phiHitVec;
648  const Trk::PlaneSurface& etaSegSurf = etaSeg->associatedSurface();
649  double etaSegLocX = etaSeg->localParameters()[Trk::locX];
650  double etaSegLocXZ = etaSeg->localDirection().angleXZ();
651 
652  for (NSWSeed& seed : seeds) {
653  // calculate start parameters for the fit
654  // combine the local position and direction of the eta-seed (segment)
655  // and local position and direction of the phi-seed to generate 3D starting parameters
656  Trk::Intersection intersect = etaSegSurf.straightLineIntersection(seed.pos(), seed.dir(), false, false);
657  Amg::Vector2D lpos_seed{Amg::Vector2D::Zero()};
658  Trk::LocalDirection ldir_seed{};
659  etaSegSurf.globalToLocal(intersect.position, intersect.position, lpos_seed);
660  etaSegSurf.globalToLocalDirection(seed.dir(), ldir_seed);
661 
662  Amg::Vector2D lpos_seg(etaSegLocX, lpos_seed[Trk::locY]);
663  Trk::LocalDirection ldir_seg(etaSegLocXZ, ldir_seed.angleYZ());
664 
665  Amg::Vector3D gpos_seg{Amg::Vector3D::Zero()}, gdir_seg{Amg::Vector3D::Zero()};
666  etaSegSurf.localToGlobal(lpos_seg, gpos_seg, gpos_seg);
667  etaSegSurf.localToGlobalDirection(ldir_seg, gdir_seg);
668 
669  Amg::Vector3D perpos = gpos_seg - 10 * gdir_seg.unit();
670  if (perpos.dot(gdir_seg) < 0) gdir_seg *= -1;
671  const Trk::Perigee startpar{perpos, gdir_seg, 0, perpos};
672 
673  NSWSeed seed3D{this, perpos, gdir_seg};
674 
675  // gather phi hits aligned with the segment
676  int nPhiHits = getClustersOnSegment(orderedPadClusters, seed3D,{}); // add pad hits (from the requested wedge if any)
677  nPhiHits += getClustersOnSegment(orderedWireClusters, seed3D, {}); // add wire hits (from the requested wedge if any)
678  if (nPhiHits < 2) continue; // at least two phi hits
679 
680  MeasVec phiHitVec = seed3D.measurements();
681  // calibrate the eta hits
682  MeasVec etaHitsCalibrated = getCalibratedClusters(seed2D);
683 
684  // fit
685  if (hitsToTrack(ctx, etaHitsCalibrated, phiHitVec, startpar, segTrkColl)) {
686  is3Dseg = true;
687  ATH_MSG_VERBOSE("Segment successfully fitted for wedge "<<singleWedge<<std::endl<<
688  m_printer->print(*segTrkColl.back()));
689  }
690  } // end loop on phi seeds
691 
692  // if we failed to combine the eta segment with phi measurements,
693  // just add the eta segment to the collection.
694  if (!is3Dseg) { segments.push_back(std::move(etaSeg)); }
695  } // end loop on precision plane segments
696  MuonSegmentVec new_segs = resolveAmbiguities(ctx, segTrkColl, Trk::Segment::NswStgcSeeded);
697  segments.insert(segments.end(), std::make_move_iterator(new_segs.begin()), std::make_move_iterator(new_segs.end()));
698  return segments;
699  }
700 
701  std::unique_ptr<Trk::PseudoMeasurementOnTrack> MuonNSWSegmentFinderTool::caloConstraint(const Trk::TrackParameters& startpar) const {
702  if (!m_caloConstraint) return nullptr;
703  constexpr double errVtx{1.*Gaudi::Units::m};
704  Amg::MatrixX covVtx(2,2);
705  covVtx.setIdentity();
706  covVtx = errVtx * errVtx * covVtx;
707  const Amg::Vector3D parPos{startpar.position()};
708  Amg::Vector3D projection{parPos.x(), parPos.y(), 0};
709  // project
710  Trk::PerigeeSurface perVtx(projection);
711  return std::make_unique<Trk::PseudoMeasurementOnTrack>(Trk::LocalParameters(Trk::DefinedParameter(0, Trk::locX),
713  std::move(covVtx),
714  std::move(perVtx));
715 
716  }
717 
718  std::unique_ptr<Trk::PseudoMeasurementOnTrack> MuonNSWSegmentFinderTool::ipConstraint(const EventContext& /*ctx*/) const {
719  if (!m_ipConstraint) return nullptr;
720  constexpr double errVtx{10.*Gaudi::Units::cm};
721  Amg::MatrixX covVtx(1, 1);
722  covVtx(0, 0) = errVtx * errVtx;
725  return std::make_unique<Trk::PseudoMeasurementOnTrack>(Trk::LocalParameters(Trk::DefinedParameter(0, Trk::locX)), std::move(covVtx),
726  std::move(perVtx));
727  }
729  const Identifier id = clust->identify();
730  return m_idHelperSvc->issTgc(id) && m_idHelperSvc->stgcIdHelper().channelType(id) == sTgcIdHelper::Pad;
731  }
733  const Identifier id = clust->identify();
734  return m_idHelperSvc->issTgc(id) && m_idHelperSvc->stgcIdHelper().channelType(id) == sTgcIdHelper::Strip;
735  }
737  const Identifier id = clust->identify();
738  return m_idHelperSvc->issTgc(id) && m_idHelperSvc->stgcIdHelper().channelType(id) == sTgcIdHelper::Wire;
739  }
740  //============================================================================
741  bool MuonNSWSegmentFinderTool::hitsToTrack(const EventContext& ctx,
742  const MeasVec& etaHitVec,
743  const MeasVec& phiHitVec,
744  const Trk::TrackParameters& startpar,
745  TrackCollection& segTrkColl) const {
746  // vector of hits for the fit
747  std::vector<const Trk::MeasurementBase*> vecFitPts;
748  unsigned int nHitsEta = etaHitVec.size();
749  unsigned int nHitsPhi = phiHitVec.size();
750  vecFitPts.reserve(nHitsEta + nHitsPhi + 2 + m_ipConstraint + m_caloConstraint);
751 
752  std::unique_ptr<Trk::PseudoMeasurementOnTrack> pseudoVtx{ipConstraint(ctx)},
753  pseudoVtxCalo{caloConstraint(startpar)},
754  pseudoPhi1{nullptr}, pseudoPhi2{nullptr};
755  // is chosen, add a pseudo measurement as vtx at the center of ATLAS
756  if (pseudoVtx) { vecFitPts.push_back(pseudoVtx.get()); }
757  if (pseudoVtxCalo) { vecFitPts.push_back(pseudoVtxCalo.get()); }
758 
759  if (!nHitsPhi) {
760  // generate two pseudo phi measurements for the fit,
761  // one on the first hit surface and one on the last hit surface.
762 
763  Amg::MatrixX cov(1, 1);
764  constexpr double pseudoPrecision = 100 * Gaudi::Units::micrometer;
765  cov(0, 0) = pseudoPrecision;
766  static const Trk::LocalParameters loc_pseudopars{Trk::DefinedParameter(0, Trk::locY)};
767  pseudoPhi1 = std::make_unique<Trk::PseudoMeasurementOnTrack>(Trk::LocalParameters(loc_pseudopars),
768  Amg::MatrixX(cov),
769  etaHitVec.front()->associatedSurface());
770  pseudoPhi2 = std::make_unique<Trk::PseudoMeasurementOnTrack>(Trk::LocalParameters(loc_pseudopars),
771  Amg::MatrixX(cov),
772  etaHitVec.back()->associatedSurface());
773 
774  // add the first pseudo phi hit, the hit vector, and the second pseudo phi hit
775  vecFitPts.push_back(pseudoPhi1.get());
776  std::copy(etaHitVec.begin(), etaHitVec.end(), std::back_inserter(vecFitPts));
777  vecFitPts.push_back(pseudoPhi2.get());
778  ATH_MSG_DEBUG("Fitting a 2D-segment track with " << nHitsEta << " Eta hits");
779 
780  } else {
781  // sorted eta and sorted phi hits combined (sorted by their the z-coordinate)
782  std::merge(phiHitVec.begin(), phiHitVec.end(), etaHitVec.begin(), etaHitVec.end(), std::back_inserter(vecFitPts),
784  double z1 = std::abs(c1->detectorElement()->center(c1->identify()).z());
785  double z2 = std::abs(c2->detectorElement()->center(c2->identify()).z());
786  return z1 < z2;
787  });
788  ATH_MSG_DEBUG("Fitting a 3D-segment track with " << nHitsEta << " Eta hits and " << nHitsPhi << " Phi hits");
789  }
790 
791  // fit the hits and generate the Trk::Track
792  std::unique_ptr<Trk::Track> segtrack = fit(ctx, vecFitPts, startpar);
793  if (!segtrack) return false;
794  segTrkColl.push_back(std::move(segtrack));
795  return true;
796  }
797 
798  //============================================================================
800  const std::vector<const Muon::MuonClusterOnTrack*>& muonClusters, int hit_sel, int singleWedge /*= 0*/) const {
801  // Keep only eta (MM && sTGC) or phi (sTGC) clusters
802  // In single-wedge mode keep only clusters from the requested wedge
804  clusters.reserve(muonClusters.size());
805  for (const Muon::MuonClusterOnTrack* cluster : muonClusters) {
806  if (!cluster) continue;
807  if (singleWedge && singleWedge != wedgeNumber(cluster)) continue;
808  const Identifier id = cluster->identify();
809  if (((hit_sel & HitType::Eta) && !m_idHelperSvc->measuresPhi(id)) ||
810  ((hit_sel & HitType::Phi) && m_idHelperSvc->measuresPhi(id)))
811  clusters.emplace_back(cluster);
812  }
813 
814  ATH_MSG_VERBOSE(" After hit cleaning, there are " << clusters.size() );
815  return clusters;
816  }
817 
818  //============================================================================
820  const MeasVec& clusters, int hit_sel) const {
821  // Classifies clusters by layer, starting from the layer closest to the IP and moving outwards.
822  // "clusters" is expected to contain only eta (MM+sTGC strip) or only phi hits (sTGC pads XOR wires).
823  // The returned vector contains only layers that have hits.
824 
825  LayerMeasVec orderedClusters(16);
826  std::array<std::set<Identifier>,16> used_hits{};
827  int nBad{0};
828  for (const Muon::MuonClusterOnTrack* hit : clusters) {
829  const int iorder = layerNumber(hit);
830  if (iorder < 0) {
831  ++nBad;
832  continue;
833  }
834  const Identifier id = hit->identify();
835  if (m_idHelperSvc->issTgc(id)) {
836  const int channelType = m_idHelperSvc->stgcIdHelper().channelType(id);
837  // skip sTGC pads if using wires, or skip wires if using pads
838  if (!(hit_sel & HitType::Pad) && channelType == sTgcIdHelper::Pad) continue;
839  if (!(hit_sel & HitType::Wire) && channelType == sTgcIdHelper::Wire) continue;
840  }
841  std::set<Identifier>& lay_hits = used_hits[iorder];
842  if (lay_hits.count(id)) continue;
843  lay_hits.insert(id);
844  orderedClusters[iorder].emplace_back(hit);
845  }
846  if (nBad) ATH_MSG_WARNING("Unable to classify " << nBad << " clusters by their layer since they are neither MM nor sTGC");
847 
848  // Erase layers without hits
849  orderedClusters.erase(std::remove_if(orderedClusters.begin(), orderedClusters.end(),
850  [](const MeasVec& vec) { return vec.empty(); }),
851  orderedClusters.end());
852 
853 
854  for( MeasVec& lays: orderedClusters){
855  std::sort(lays.begin(),lays.end(), [this](const SeedMeasurement& a, const SeedMeasurement& b){
856  return channel(a) < channel(b);
857  });
858  ATH_MSG_DEBUG("Found in layer "<<m_idHelperSvc->toStringDetEl(lays[0]->identify())<<" "<<lays.size()<<" clusters");
859 
860 
861  }
862  ATH_MSG_VERBOSE("Collected clusters "<<print(orderedClusters));
863 
864  return orderedClusters;
865  }
866 
867  //============================================================================
868  std::vector<NSWSeed> MuonNSWSegmentFinderTool::segmentSeedFromStgc(const LayerMeasVec& orderedClusters,
869  bool usePhi) const {
870  std::vector<NSWSeed> seeds;
871 
872  // oderedClusters should contain either eta clusters (MM and sTGC)
873  // or sTGC phi hits. For MM phi, use the dedicated function.
874  if (orderedClusters.size() < 4) return seeds;
875 
876  // Create seeds using each pair of hits on the two most distant layers (that containing hits).
877  // m_nOfSeedLayers (default = 1) dictates whether we want to also use hits from inner layers.
878 
879  // Loop on layers to get the first seed point
880  int seedingLayersL{0};
881  for (unsigned int ilayerL{0}; (ilayerL < orderedClusters.size() && seedingLayersL < m_nOfSeedLayers); ++ilayerL) {
882  bool usedLayerL{false};
883  for (const SeedMeasurement& hitL : orderedClusters[ilayerL]) {
885  if (usePhi != m_idHelperSvc->measuresPhi(hitL->identify())) continue;
886  else if(m_idHelperSvc->isMM(hitL->identify())) break;
887 
888 
889  // For the second point, loop on layers in reverse to be as far as possible from the first.
890  int seedingLayersR{0};
891  for (unsigned int ilayerR = orderedClusters.size() - 1; (ilayerR > ilayerL && seedingLayersR < m_nOfSeedLayers);
892  --ilayerR) {
893  bool usedLayerR{false};
894  for (const SeedMeasurement& hitR : orderedClusters[ilayerR]) {
895  if (usePhi != m_idHelperSvc->measuresPhi(hitR->identify())) continue;
896  else if (m_idHelperSvc->isMM(hitR->identify())) break;
897  NSWSeed seed{this,hitL, hitR};
898  if (!usePhi && m_ipConstraint) {
899  const double eta = seed.dir().perp() > std::numeric_limits<float>::epsilon() ? std::abs(seed.dir().eta()): FLT_MAX;
900  if (eta < minEtaNSW || eta > maxEtaNSW) {
901  continue;
902  }
903  } else if (usePhi && m_ipConstraint) {
904  // first make sure that the wires are in the same or neigbouring quads
905  if(std::abs(std::abs(m_idHelperSvc->stationEta(hitL->identify())) - std::abs(m_idHelperSvc->stationEta(hitR->identify()))) > 1) {
906  continue;
907  }
908  // project the hit in the first layer assuming the track comes from the IP
909  Trk::Intersection intersect = hitR->detectorElement()->surface(hitR->identify()).straightLineIntersection(hitL->globalPosition(),hitL->globalPosition().unit(), false, false);
910  Amg::Vector2D lpos_intersect{Amg::Vector2D::Zero()};
911  hitR->detectorElement()->surface(hitR->identify()).globalToLocal(intersect.position, intersect.position, lpos_intersect);
912 
913  Amg::Vector2D lPosR;
914  hitR->detectorElement()->surface(hitR->identify()).globalToLocal(hitR->globalPosition(), hitR->globalPosition(), lPosR);
915 
916 
917  if(std::abs(lpos_intersect.x() - lPosR.x()) > 87.5 ) continue; // reject seed if the projection is more than 2.5 wire groups away
918  }
919 
920  usedLayerR = true;
921  usedLayerL = true;
922  getClustersOnSegment(orderedClusters, seed, {ilayerL, ilayerR}, false);
923  seeds.emplace_back(std::move(seed));
924 
925  }
926  if (usedLayerR) ++seedingLayersR;
927  }
928  }
929  if (usedLayerL) ++seedingLayersL;
930  }
931 
932  return resolveAmbiguities(std::move(seeds));
933  }
934 
935  //============================================================================
937  if (m_idHelperSvc->isMM(cluster->identify()))
938  return m_idHelperSvc->mmIdHelper().multilayer(cluster->identify()) + 1; // [IP:2, HO:3]
939  if (m_idHelperSvc->issTgc(cluster->identify()))
940  return 3 * (m_idHelperSvc->stgcIdHelper().multilayer(cluster->identify()) - 1) + 1; // [IP:1, HO:4];
941  return -1;
942  }
944  // Internal logic. Initialize with 16 layers:
945  // [0-3] for the four sTGC IP layers
946  // [4-11] for the eight MM IP+HO layers (empty when phi hits are requested)
947  // [12-15] for the four sTGC HO layers
948  int layer{0};
949  if (m_idHelperSvc->isMM(cluster->identify())) layer = m_idHelperSvc->mmIdHelper().gasGap(cluster->identify());
950  if (m_idHelperSvc->issTgc(cluster->identify())) layer = m_idHelperSvc->stgcIdHelper().gasGap(cluster->identify());
951  return 4 * (wedgeNumber(cluster) - 1) + layer - 1;
952  }
954  if (m_idHelperSvc->isMM(cluster->identify())) return m_idHelperSvc->mmIdHelper().channel(cluster->identify());
955  if (m_idHelperSvc->issTgc(cluster->identify())) return m_idHelperSvc->stgcIdHelper().channel(cluster->identify());
956  return -1;
957  }
958 
959  //============================================================================
961  NSWSeed& seed, const std::set<unsigned int>& exclude, bool useStereo) const {
962  ATH_MSG_VERBOSE(" getClustersOnSegment: layers " << orderedclusters.size());
963  int nHitsAdded{0};
964 
965  for (const MeasVec& surfHits : orderedclusters) {
966  if (exclude.count(layerNumber(surfHits[0]))) continue;
967  // get the best hit candidate on this layer
968 
969  for (const SeedMeasurement& hit : surfHits) {
970 
971  const Identifier id = hit->identify();
972  const MuonGM::MuonChannelDesign* design = getDesign(hit);
973 
974  //In case of the 2D eta stgc seeding we don't want the MMG stereo hits on the segment
975  if ( !useStereo && m_idHelperSvc->isMM(id) && design->hasStereoAngle() ) continue;
976 
977  nHitsAdded += seed.add(hit, m_maxClustDist);
978  }
979  }
980  ATH_MSG_VERBOSE(" getClustersOnSegment: returning " << nHitsAdded << " hits ");
981  return nHitsAdded;
982  }
983 
984  //============================================================================
986  const LayerMeasVec& orderedClusters, const Muon::MuonSegment& etaSeg) const {
987  std::vector<NSWSeed> seeds;
989  if (orderedClusters.empty()) return seeds;
990 
991  std::vector<std::vector<const Muon::sTgcPrepData*>> sTgcIP(4); // IP: layers nearest to the IP will be added first
992  std::vector<std::vector<const Muon::sTgcPrepData*>> sTgcHO(4); // HO: layers furthest from the IP will be added first
993 
994  // Process clusters separately for each multilayer
995  for (int iml : {1, 2}) {
996  int il = (iml == 1) ? 0 : orderedClusters.size() - 1;
997  int iend = (iml == 1) ? orderedClusters.size() : -1;
998  int idir = (iml == 1) ? 1 : -1;
999  unsigned int nLayersWithHitMatch{0};
1000 
1001  // Loop on layers (reverse loop for HO)
1002  for (; il != iend; il += idir) {
1003  double lastDistance{1000.};
1004  if (nLayersWithHitMatch >= sTgcIP.size()) {
1005  sTgcIP.resize(nLayersWithHitMatch + 1);
1006  sTgcHO.resize(nLayersWithHitMatch + 1);
1007  }
1008  std::vector<const Muon::sTgcPrepData*>& matchedHits =
1009  (iml == 1) ? sTgcIP.at(nLayersWithHitMatch) : sTgcHO.at(nLayersWithHitMatch);
1010 
1011  // Loop on the hits on this layer. Find the one closest (in eta) to the segment intersection.
1012  for (const Muon::MuonClusterOnTrack* rio : orderedClusters[il]) {
1013  const sTgcPrepData* padHit = dynamic_cast<const sTgcPrepData*>(rio->prepRawData());
1014  if (!padHit) continue;
1015 
1016  // check the multilayer the hit is on
1017  if (m_idHelperSvc->stgcIdHelper().multilayer(padHit->identify()) != iml) continue;
1018 
1019  const MuonGM::MuonPadDesign* design = padHit->detectorElement()->getPadDesign(padHit->identify());
1020  if (!design) continue;
1021 
1022  // local position of the segment intersection with the plane
1023  const Trk::Surface& surf = padHit->detectorElement()->surface(padHit->identify());
1025  surf.straightLineIntersection(etaSeg.globalPosition(), etaSeg.globalDirection(), false, false);
1026  Amg::Vector2D segLocPosOnSurf{Amg::Vector2D::Zero()};
1027  surf.globalToLocal(intersect.position, intersect.position, segLocPosOnSurf);
1028 
1029  // eta distance between the hit and the segment intersection with the plane
1030  // check that it's no more than half of the pad eta-pitch.
1031  double chWidth = design->channelWidth(padHit->localPosition(), false);
1032  double etaDistance = std::abs(padHit->localPosition().y() - segLocPosOnSurf[1]);
1033  if (etaDistance > 0.5 * chWidth) continue;
1034  ATH_MSG_DEBUG(" etaDistance " << etaDistance << " between pad center and position on the pad.");
1035 
1036  if (matchedHits.empty()) {
1037  // first hit
1038  matchedHits.push_back(padHit);
1039  ATH_MSG_DEBUG(" best etaDistance: " << etaDistance);
1040  } else if (std::abs(etaDistance - lastDistance) < 0.001) {
1041  // competing hit pad, keep both (all hit pads of the same eta row will be candidates)
1042  matchedHits.push_back(padHit);
1043  ATH_MSG_DEBUG(" added etaDistance: " << etaDistance << " size " << matchedHits.size());
1044  } else if (etaDistance < lastDistance) {
1045  // found a better hit; clear the old ones (possible only for clustered pad hits)
1046  matchedHits.clear();
1047  matchedHits.push_back(padHit);
1048  ATH_MSG_DEBUG(" replacing best etaDistance with: " << etaDistance);
1049  } else {
1050  continue;
1051  }
1052  lastDistance = etaDistance;
1053  } // end of loop on hits
1054 
1055  if (!matchedHits.empty()) ++nLayersWithHitMatch;
1056 
1057  } // end of loop on layers
1058 
1059  // need at least one hit in each multilayer to create a seed
1060  if (!nLayersWithHitMatch) return seeds;
1061 
1062  } // end of loop on multilayers
1063 
1064  // get refined phi ranges on each ml, by taking into account pad staggering
1065  std::vector<std::pair<double, double>> sTgcIP_phiRanges = getPadPhiOverlap(sTgcIP);
1066  std::vector<std::pair<double, double>> sTgcHO_phiRanges = getPadPhiOverlap(sTgcHO);
1067 
1068  // reference prds on the outermost hit surfaces
1069  const sTgcPrepData* prdL1 = sTgcIP.front().front();
1070  const sTgcPrepData* prdL2 = sTgcHO.front().front();
1071  const auto& surfPrdL1 = prdL1->detectorElement()->surface();
1072  const auto& surfPrdL2 = prdL2->detectorElement()->surface();
1073 
1074  // create a seed for each combination of IP and HO points
1075  for (const std::pair<double, double>& range1 : sTgcIP_phiRanges) {
1076  double midPhi1 = 0.5 * (range1.first + range1.second);
1077  Amg::Vector2D lp1(midPhi1, prdL1->localPosition().y());
1079  surfPrdL1.localToGlobal(lp1, gpL1, gpL1);
1080 
1081  Amg::Vector2D lp1_lowPhi{range1.first, prdL1->localPosition().y()};
1082  Amg::Vector2D lp1_highPhi{range1.second, prdL1->localPosition().y()};
1083 
1084  Amg::Vector3D gp1_lowPhi{Amg::Vector3D::Zero()};
1085  Amg::Vector3D gp1_highPhi{Amg::Vector3D::Zero()};
1086 
1087  surfPrdL1.localToGlobal(lp1_lowPhi, gp1_lowPhi, gp1_lowPhi);
1088  surfPrdL1.localToGlobal(lp1_highPhi, gp1_highPhi, gp1_highPhi);
1089 
1090  Trk::Intersection intersect_lowPhi = surfPrdL2.straightLineIntersection(gp1_lowPhi, gp1_lowPhi, false, false);
1091  Trk::Intersection intersect_highPhi = surfPrdL2.straightLineIntersection(gp1_highPhi, gp1_highPhi, false, false);
1092 
1093  Amg::Vector2D lpIntersect_lowPhi{Amg::Vector2D::Zero()};
1094  Amg::Vector2D lpIntersect_highPhi{Amg::Vector2D::Zero()};
1095 
1096  surfPrdL2.globalToLocal(intersect_lowPhi.position, intersect_lowPhi.position, lpIntersect_lowPhi);
1097  surfPrdL2.globalToLocal(intersect_highPhi.position, intersect_highPhi.position, lpIntersect_highPhi);
1098 
1099  for (const std::pair<double, double>& range2 : sTgcHO_phiRanges) {
1100  double midPhi2 = 0.5 * (range2.first + range2.second);
1101  // let's check that the phi ranges in the two multilayer overlap
1102  if( lpIntersect_highPhi.x() - range2.first < 0 || range2.second - lpIntersect_lowPhi.x() < 0) {
1103  ATH_MSG_DEBUG(" segmentSeedFromPads: skipping seed with non-overlapping phi ranges");
1104  continue;
1105  }
1106 
1107  Amg::Vector2D lp2(midPhi2, prdL2->localPosition().y());
1109  surfPrdL2.localToGlobal(lp2, gpL2, gpL2);
1110  // create the seed taking the average position (w.r.t. IP)
1111  // as global direction (as for an infinite momentum track).
1112  Amg::Vector3D gDir = (gpL2 + gpL1).unit();
1113  seeds.emplace_back(this, gpL1, gDir);
1114  }
1115  }
1116 
1117  ATH_MSG_DEBUG(" segmentSeedFromPads: seeds.size() " << seeds.size());
1118  return seeds;
1119  }
1120 
1121  //============================================================================
1123  const LayerMeasVec& orderedClusters) const {
1124  std::vector<NSWSeed> seeds;
1125  std::array<unsigned int, 4> layers{};
1126  unsigned int trials{0}, used_layers{0};
1128  constexpr size_t lastMMLay = 11;
1129  std::vector<NSWSeed> laySeeds;
1130 
1132  std::stringstream sstr{};
1133  for (int e4 = std::min(lastMMLay, orderedClusters.size() -1); e4 >= 3 ; --e4) {
1134  layers[3] = e4;
1135  for (int e3 = e4 -1 ; e3 >= 2; --e3) {
1136  layers[2] = e3;
1137  for (int e2 = 1 ; e2 < e3; ++e2) {
1138  layers[1] = e2;
1139  for (int e1= 0; e1< e2; ++e1) {
1140  layers[0] = e1;
1141  const unsigned int old_trials = trials;
1142  laySeeds = segmentSeedFromMM(orderedClusters,layers, trials);
1143  if (old_trials == trials) continue;
1144 
1145  used_layers += !laySeeds.empty();
1146  seeds.insert(seeds.end(), std::make_move_iterator(laySeeds.begin()),
1147  std::make_move_iterator(laySeeds.end()));
1148 
1149  if (msgLvl(MSG::VERBOSE)) {
1150  sstr<<" Attempts thus far "<<old_trials<<" attempts now "<<trials<<" --- "<<e1<<","<<e2<<","<<e3<<","<<e4<<std::endl;
1151  for (int lay : layers) {
1152  sstr<<"Layer: "<<lay<<" number of measurements "<<orderedClusters[lay].size()<<std::endl;
1153  for (const SeedMeasurement& meas : orderedClusters[lay] ){
1154  sstr<<" **** "<< print(meas)<<std::endl;
1155  }
1156  sstr<<std::endl<<std::endl<<std::endl;
1157  }
1158  }
1159  }
1160  }
1161  }
1162  }
1163  if (trials > 100000) {
1164  ATH_MSG_VERBOSE(sstr.str());
1165  }
1166  ATH_MSG_VERBOSE("Out of "<<trials<<" possible seeds, "<<seeds.size()<<" were finally built. Used in total "<<used_layers<<" layers");
1167  return resolveAmbiguities(std::move(seeds));
1168  }
1169 
1170  #if defined(FLATTEN)
1171  ATH_FLATTEN
1172  #endif
1173  inline std::vector<NSWSeed> MuonNSWSegmentFinderTool::segmentSeedFromMM(const LayerMeasVec& orderedClusters,
1174  std::array<unsigned int,4> selLayers,
1175  unsigned int& trial_counter) const {
1176  std::vector<NSWSeed> seeds{};
1177 
1178  std::array<unsigned int, 4> lay_ord{};
1179  for (size_t s = 0; s < selLayers.size(); ++s) {
1180  unsigned int lay = selLayers[s];
1181  const SeedMeasurement& seed = orderedClusters[lay].front();
1182  const Identifier id = seed->identify();
1183  if (!m_idHelperSvc->isMM(id)) return seeds;
1184  const MuonGM::MuonChannelDesign* design = getDesign(seed);
1186  if (!design->hasStereoAngle()) lay_ord[s] = 1;
1187  else if (design->stereoAngle() >0.) lay_ord[s] = 2;
1188  else lay_ord[s] = 3;
1189  }
1190  auto swap_strips = [&selLayers, &lay_ord] (unsigned int i, unsigned j){
1191  std::swap(lay_ord[i], lay_ord[j]);
1192  std::swap(selLayers[i],selLayers[j]);
1193  };
1195  if (lay_ord[0] == lay_ord[1]){
1196  if (lay_ord[1] != lay_ord[2]) swap_strips(1,2);
1197  else if (lay_ord[1] != lay_ord[3]) swap_strips(1,3);
1198  else {
1199  ATH_MSG_VERBOSE("Strips are all parallel.");
1200  return seeds;
1201  }
1202  }
1204  if (lay_ord[2] == lay_ord[3]) {
1205  // Check if the last hit can be exchanged by the first one.
1206  // But also ensure that the second and fourth are not the same
1207  if (lay_ord[3] != lay_ord[0] && lay_ord[3] != lay_ord[1]) swap_strips(3,0);
1208  else {
1209  ATH_MSG_VERBOSE("No way to rearrange the strips such that the latter two strips cross.");
1210  return seeds;
1211  }
1212  }
1214  std::array<SeedMeasurement, 4> base_seed{};
1215  for (size_t s = 0; s < selLayers.size(); ++s) {
1216  unsigned int lay = selLayers[s];
1217  base_seed[s] = orderedClusters[lay].front();
1218  }
1219 
1220  const double A = (base_seed[1].pos().z() - base_seed[0].pos().z());
1221  const double G = (base_seed[2].pos().z() - base_seed[0].pos().z());
1222  const double K = (base_seed[3].pos().z() - base_seed[0].pos().z());
1223 
1224  AmgSymMatrix(2) diamond{AmgSymMatrix(2)::Zero()};
1225  diamond.block<2, 1>(0, 1) = ((A - G) * base_seed[3].dirDot(base_seed[1]) * base_seed[1].dir() + G * base_seed[3].dirDot(base_seed[0]) * base_seed[0].dir() - A * base_seed[3].dir()).block<2, 1>(0, 0);
1226  diamond.block<2, 1>(0, 0) = ((K - A) * base_seed[2].dirDot(base_seed[1]) * base_seed[1].dir() - K * base_seed[2].dirDot(base_seed[0]) * base_seed[0].dir() + A * base_seed[2].dir()).block<2, 1>(0, 0);
1227 
1228  if (std::abs(diamond.determinant()) < std::numeric_limits<float>::epsilon()) {
1229  ATH_MSG_VERBOSE(" The seed built from " << printSeed(base_seed) << " cannot constrain phi as " << std::endl
1230  << diamond << std::endl
1231  << " is singular " << diamond.determinant() << " with rank "
1232  << (Eigen::FullPivLU<AmgSymMatrix(2)>{diamond}.rank()));
1233 
1234  return seeds;
1235  }
1236  ATH_MSG_VERBOSE("The combination of " << printSeed(base_seed) << " to " << std::endl
1237  << diamond << std::endl
1238  << "May give a couple of stereo seeds " << diamond.determinant());
1239 
1241  const AmgSymMatrix(2) seed_builder = diamond.inverse();
1243  const double KmG = K-G;
1244  const double KmA = K-A;
1245  const double AmG = A-G;
1246 
1247  const double TwoDotZero = base_seed[2].dirDot(base_seed[0]);
1248  const double ThreeDotZero = base_seed[3].dirDot(base_seed[0]);
1249  const double ThreeDotOne = base_seed[3].dirDot(base_seed[1]);
1250  const double TwoDotOne = base_seed[2].dirDot(base_seed[1]);
1251 
1252  auto estimate_muon = [&] () -> std::optional<std::array<double,2>> {
1253  const Amg::Vector3D Y0 = K * base_seed[2].pos() - G * base_seed[3].pos() - KmG * base_seed[0].pos();
1254  const Amg::Vector3D Y1 = AmG * base_seed[3].pos() - KmG * base_seed[1].pos() + KmA * base_seed[2].pos();
1255  const double Y0dotE0 = base_seed[0].dirDot(Y0);
1256  const double Y1dotE1 = base_seed[1].dirDot(Y1);
1257 
1258  const AmgVector(2) centers = (KmG * (base_seed[0].pos() - base_seed[1].pos()) +
1259  Y0dotE0 * base_seed[0].dir() +
1260  A * (base_seed[3].pos() - base_seed[2].pos()) -
1261  Y1dotE1 * base_seed[1].dir())
1262  .block<2, 1>(0, 0);
1263 
1264  const AmgVector(2) sol_pars = seed_builder * centers;
1265  const std::array<double, 4> lengths{(Y0dotE0 + K * sol_pars[0] * TwoDotZero - G * sol_pars[1] * ThreeDotZero) / KmG,
1266  (Y1dotE1 + AmG * sol_pars[1] *ThreeDotOne + KmA * sol_pars[0] * TwoDotOne) / KmG, sol_pars[0], sol_pars[1]};
1267  bool accept{true};
1268  ATH_MSG_VERBOSE("Check intersections of "<<printSeed(base_seed));
1269  constexpr double tolerance = 10.* Gaudi::Units::mm;
1270  std::optional<Amg::Vector3D> seg_pos{std::nullopt}, seg_dir{std::nullopt};
1271  for (unsigned int i = 0; i < base_seed.size(); ++i) {
1272  const MuonGM::MuonChannelDesign* design = getDesign(base_seed[i]);
1273  const double halfLength = design->channelHalfLength(channel(base_seed[i]), true);
1274  accept &= (halfLength + tolerance > std::abs(lengths[i]));
1275  if (msgLvl(MSG::VERBOSE)) {
1276  if (!seg_pos) {
1277  seg_pos = std::make_optional<Amg::Vector3D>(base_seed[0].pos() +
1278  lengths[0] * base_seed[0].dir());
1279  ATH_MSG_VERBOSE("Position "<<to_string(*seg_pos));
1280  }
1281  if (!seg_dir){
1282  seg_dir = std::make_optional<Amg::Vector3D>((base_seed[1].pos() +
1283  lengths[1] *base_seed[1].dir() - (*seg_pos)).unit());
1284  ATH_MSG_VERBOSE("Direction "<<to_string(*seg_dir));
1285  }
1286  std::optional<double> mu_crossing = Amg::intersect<3>(*seg_pos, *seg_dir, base_seed[i].pos(),base_seed[i].dir());
1287  ATH_MSG_VERBOSE(" ----- "<<(i+1)<<" at "<<to_string(base_seed[i].pos() + lengths[i]*base_seed[i].dir())
1288  << " ("<< std::string( halfLength > std::abs(lengths[i]) ? "inside" : "outside")<<" wedge) "
1289  << halfLength <<" vs. "<<std::abs(lengths[i])<<" crossing point: "<<std::abs(*mu_crossing));
1290  } else if (!accept) return std::nullopt;
1291  }
1292  if (!accept) return std::nullopt;
1293  return std::make_optional<std::array<double,2>>({lengths[0], lengths[1]});
1294  };
1295 
1297  seeds.reserve(200);
1298  MeasVec::const_iterator begin2{orderedClusters[selLayers[1]].begin()};
1299  MeasVec::const_iterator begin3{orderedClusters[selLayers[2]].begin()};
1300  MeasVec::const_iterator begin4{orderedClusters[selLayers[3]].begin()};
1301 
1302  const MeasVec::const_iterator end2{orderedClusters[selLayers[1]].end()};
1303  const MeasVec::const_iterator end3{orderedClusters[selLayers[2]].end()};
1304  const MeasVec::const_iterator end4{orderedClusters[selLayers[3]].end()};
1305 
1306  for (const SeedMeasurement& lay1 : orderedClusters[selLayers[0]]) {
1307  base_seed[0] = lay1;
1308  for (MeasVec::const_iterator lay2 = begin2; lay2 != end2; ++lay2) {
1309 
1310  base_seed[1] = *lay2;
1311  ChannelConstraint chCheck = compatiblyFromIP(lay1, *lay2);
1314  if (chCheck == ChannelConstraint::TooNarrow) {
1315  begin2 = lay2 + 1;
1316  continue;
1317  }
1319  else if (chCheck == ChannelConstraint::TooWide) {
1320  break;
1321  }
1323  for (MeasVec::const_iterator lay3 = begin3; lay3 != end3; ++lay3) {
1324  chCheck = compatiblyFromIP(lay1, *lay3);
1325  const ChannelConstraint chCheck1 = compatiblyFromIP(*lay2, *lay3);
1326  if (chCheck == ChannelConstraint::TooNarrow && chCheck1 == ChannelConstraint::TooNarrow) {
1327  begin3 = lay3 + 1;
1328  continue;
1329  } else if (chCheck == ChannelConstraint::TooWide && chCheck1 == ChannelConstraint::TooWide) {
1330  break;
1331  }
1332  base_seed[2] = *lay3;
1334  for (MeasVec::const_iterator lay4 = begin4 ; lay4 != end4; ++lay4) {
1335  chCheck = compatiblyFromIP(*lay3, *lay4);
1336  if (chCheck == ChannelConstraint::TooNarrow) {
1337  begin4 = lay4 + 1;
1338  continue;
1339  } else if (chCheck == ChannelConstraint::TooWide) {
1340  break;
1341  }
1342 
1343  base_seed[3] = (*lay4);
1344  std::optional<std::array<double, 2>> isects = estimate_muon();
1345  ++trial_counter;
1346  if (!isects) continue;
1347  NSWSeed seed{this, base_seed, *isects};
1348 
1349  if (seed.size() < 4) continue;
1350  if (m_ipConstraint) {
1351  const double eta = std::abs(seed.dir().eta());
1352  if (eta < minEtaNSW || eta > maxEtaNSW) {
1353  continue;
1354  }
1355  if (seed.dir().block<2,1>(0,0).dot(seed.pos().block<2,1>(0,0)) < 0.) continue;
1357  static const Muon::MuonSectorMapping sector_mapping{};
1358  const double deltaPhi = std::abs(seed.dir().deltaPhi(seed.pos()));
1359  if (deltaPhi > sector_mapping.sectorWidth(m_idHelperSvc->sector(base_seed[0]->identify()))) continue;
1360  }
1361  getClustersOnSegment(orderedClusters, seed, {selLayers[0], selLayers[1],selLayers[2], selLayers[3]});
1362  seeds.emplace_back(std::move(seed));
1363  }
1364  }
1365  }
1366  }
1367  return seeds;
1368  }
1372 
1373  // For a given dZ the measurements can only be separated by a certain dR such that the
1375  const double dZ = std::abs(meas2->globalPosition().z()) -
1376  std::abs(meas1->globalPosition().z());
1377 
1381  static const double minTanTheta = 0.75 / std::sinh(maxEtaNSW);
1382  static const double maxTanTheta = 1.25 / std::sinh(minEtaNSW);
1383 
1384  const double minDR = minTanTheta * std::abs(dZ);
1385  const double maxDR = maxTanTheta * std::abs(dZ);
1386 
1387  const std::pair<double, double> rad1 = coveredRadii(meas1);
1388  const std::pair<double, double> rad2 = coveredRadii(meas2);
1390  const double dlR = rad2.first - rad1.first;
1391  const double drR = rad2.second - rad1.second;
1392  ATH_MSG_VERBOSE("compatiblyFromIP() -- Measurements "<<std::endl
1393  <<print(meas1)<<std::endl<<print(meas2)
1394  <<std::endl<<". Separation in dR (left/right) "<<dlR<<"/"<<drR<<", dZ "<<dZ
1395  <<" --> dR has to be in "<<minDR<<" "<<maxDR);
1396  if ((std::abs(dlR) < minDR && std::abs(drR) < minDR) ||
1397  (dZ > 0 && dlR <0 && drR <0) || (dZ < 0 && dlR >0 && drR > 0)) {
1399  } if (std::abs(dlR) > maxDR && std::abs(drR) > maxDR && dlR * drR > 0.){
1401  }
1403  }
1404  inline std::pair<double, double> MuonNSWSegmentFinderTool::coveredRadii(const SeedMeasurement& meas) const {
1405  const MuonGM::MuonChannelDesign* design = getDesign(meas);
1406  const int chNum = channel(meas);
1408  design->leftEdge(chNum, left);
1409  design->rightEdge(chNum, right);
1410  const double radLeft{meas->associatedSurface().localToGlobal(left).perp()};
1411  const double radRight{meas->associatedSurface().localToGlobal(right).perp()};
1412  return std::make_pair(radLeft, radRight);
1413  }
1414  std::vector<NSWSeed> MuonNSWSegmentFinderTool::resolveAmbiguities(std::vector<NSWSeed>&& unresolved) const {
1415  std::vector<NSWSeed> seeds;
1416  seeds.reserve(unresolved.size());
1417  std::sort(unresolved.begin(), unresolved.end(),[](const NSWSeed& a, const NSWSeed& b){
1418  return a.chi2() < b.chi2();
1419  });
1420  for (NSWSeed& seed : unresolved) {
1421  bool add_seed{true};
1422  for (NSWSeed& good : seeds) {
1423  NSWSeed::SeedOR ov = good.overlap(seed);
1424  if (ov == NSWSeed::SeedOR::SubSet) {
1425  std::swap(seed, good);
1426  add_seed = false;
1427  break;
1428  } else if (ov == NSWSeed::SeedOR::Same || ov == NSWSeed::SeedOR::SuperSet) {
1429  add_seed = false;
1430  break;
1431  }
1432  }
1433  if (add_seed) seeds.push_back(std::move(seed));
1434  }
1435  ATH_MSG_VERBOSE(seeds.size()<<" out of "<<unresolved.size()<<" passed the overlap removal");
1436  return seeds;
1437  }
1438 
1439  //============================================================================
1440  std::vector<std::pair<double, double>> MuonNSWSegmentFinderTool::getPadPhiOverlap(
1441  const std::vector<std::vector<const Muon::sTgcPrepData*>>& pads) const {
1442  // 'pads' contains segment hit candidates, classified in four layers (IP or HO).
1443  // Layers are ordered; for IP, the layer with hits that is nearest to
1444  // the IP is first, while for HO, the one furthest from the IP is first.
1445 
1446  std::vector<std::vector<double>> padsPhiL, padsPhiR;
1447  std::vector<double> padsPhiC;
1448 
1449  // Loop on layers
1450  for (const std::vector<const Muon::sTgcPrepData*>& surfHits : pads) {
1451  // Loop on layer hits
1452  std::vector<double> surfPadsPhiL, surfPadsPhiR;
1453  for (const Muon::sTgcPrepData* prd : surfHits) {
1454  const Identifier id = prd->identify();
1455  const MuonGM::MuonPadDesign* design = prd->detectorElement()->getPadDesign(id);
1456  if (!design) {
1457  ATH_MSG_WARNING("No design available for " << m_idHelperSvc->toString(id));
1458  continue;
1459  }
1460 
1461  // Phi boundaries of this pad in local coordinates
1462  const double halfWidthX = 0.5 * design->channelWidth(prd->localPosition(), true);
1463  const double hitPadX = prd->localPosition().x(); // x is in the phi direction
1464 
1465  // Reject hit candidates on pads too close (in phi) to any pad kept so far
1466  // (pad fuzziness) to constrain the number of combinations.
1467  bool samePhi = std::find_if(padsPhiC.begin(), padsPhiC.end(), [&hitPadX, &halfWidthX](const double prevPadPhi) {
1468  return std::abs(hitPadX - prevPadPhi) < 0.9 * halfWidthX;
1469  }) != padsPhiC.end();
1470 
1471  if (samePhi) continue;
1472 
1473  // Store the new pad candidate
1474  surfPadsPhiL.push_back(hitPadX - halfWidthX);
1475  surfPadsPhiR.push_back(hitPadX + halfWidthX);
1476  padsPhiC.push_back(hitPadX);
1477  ATH_MSG_DEBUG(" keep pad id " << m_idHelperSvc->toString(id) << " local x: " << hitPadX << " width: " << halfWidthX);
1478  }
1479 
1480  padsPhiL.push_back(std::move(surfPadsPhiL));
1481  padsPhiR.push_back(std::move(surfPadsPhiR));
1482  }
1483 
1484  unsigned int nSurf = padsPhiR.size();
1485 
1486  // number of combinations we can make out of pads in different layers
1487  // we want to keep combinations of overlapping pads.
1488  unsigned int nCombos{1};
1489  for (const std::vector<double>& surfPadsPhiR : padsPhiR) {
1490  if (!surfPadsPhiR.empty()) nCombos *= surfPadsPhiR.size();
1491  }
1492 
1493  std::vector<std::pair<double, double>> phiOverlap;
1494  phiOverlap.reserve(nCombos);
1495 
1496  if (nCombos <= 100) {
1497  unsigned int N{nCombos};
1498  for (unsigned int isurf{0}; isurf < nSurf; ++isurf) {
1499  if (padsPhiR[isurf].empty()) continue;
1500  unsigned int nSurfHits = padsPhiR[isurf].size();
1501  N /= nSurfHits;
1502 
1503  for (unsigned int icombo{0}; icombo < nCombos; ++icombo) {
1504  // index of the pad that corresponds to this combination
1505  unsigned int padIdx = (icombo / N) % nSurfHits;
1506  if (isurf == 0) {
1507  // first surface: just add the range of each hit pad
1508  phiOverlap.emplace_back(padsPhiL[isurf][padIdx], padsPhiR[isurf][padIdx]);
1509  } else {
1510  // subsequent surfaces: use staggering to narrow the phi ranges
1511  phiOverlap[icombo].first = std::max(padsPhiL[isurf][padIdx], phiOverlap[icombo].first);
1512  phiOverlap[icombo].second = std::min(padsPhiR[isurf][padIdx], phiOverlap[icombo].second);
1513  }
1514  }
1515  }
1516 
1517  // delete bad combinations with xmin > xmax (indicates non overlapping pads)
1518  phiOverlap.erase(std::remove_if(phiOverlap.begin(), phiOverlap.end(),
1519  [](std::pair<double, double>& range) { return range.first >= range.second; }),
1520  phiOverlap.end());
1521  ATH_MSG_DEBUG("Pad seeding - #combinations initial: " << nCombos
1522  << ", after cleaning for non overlapping pads: " << phiOverlap.size());
1523 
1524  } else {
1525  // in case combinations are too many, store the phi ranges of individual pads
1526  for (unsigned int isurf{0}; isurf < nSurf; ++isurf) {
1527  unsigned int nSurfHits = padsPhiR[isurf].size();
1528  for (unsigned int ihit{0}; ihit < nSurfHits; ++ihit) {
1529  phiOverlap.emplace_back(padsPhiL[isurf][ihit], padsPhiR[isurf][ihit]);
1530  }
1531  }
1532  ATH_MSG_DEBUG("Pad seeding - #combinations: " << nCombos << " is too large. Seeding from" << phiOverlap.size()
1533  << " individual pads.");
1534  }
1535 
1536  return phiOverlap;
1537  }
1538 
1539  //============================================================================
1541 
1542  MeasVec calibratedClusters;
1543  MeasVec clusters = seed.measurements();
1544 
1545  // loop on the segment clusters and use the phi of the seed to correct them
1546  for (const SeedMeasurement& clus : clusters) {
1547  std::unique_ptr<const Muon::MuonClusterOnTrack> newClus;
1548 
1549  // get the intercept of the seed direction with the cluster surface
1550  const Identifier hitID = clus->identify();
1551  const Trk::Surface& surf = clus->associatedSurface();
1552  Trk::Intersection intersect = surf.straightLineIntersection(seed.pos(), seed.dir(), false, false);
1553 
1554  if (m_idHelperSvc->isMM(hitID)) {
1555  // build a new MM cluster on track with correct position
1556  std::unique_ptr<const Muon::MuonClusterOnTrack> newClus {m_muonClusterCreator->correct(*clus->prepRawData(), intersect.position, seed.dir())};
1557  calibratedClusters.emplace_back(seed.newCalibClust(std::move(newClus)));
1558  } else if (m_idHelperSvc->issTgc(hitID)) {
1559  // build a new sTGC cluster on track with correct position
1560  std::unique_ptr<const Muon::MuonClusterOnTrack> newClus {m_muonClusterCreator->correct(*clus->prepRawData(), intersect.position, seed.dir())};
1561  calibratedClusters.emplace_back(seed.newCalibClust(std::move(newClus)));
1562  }
1563  }
1564 
1565  return calibratedClusters;
1566  }
1567 
1568  //============================================================================
1569  template <size_t N>
1570  std::string MuonNSWSegmentFinderTool::printSeed(const std::array<SeedMeasurement, N>& seed) const {
1571  std::stringstream sstr{};
1572  sstr << std::endl;
1573  for (const SeedMeasurement& cl : seed) sstr << " *** " << print(cl) << std::endl;
1574  return sstr.str();
1575  }
1576 
1577  //============================================================================
1579  std::stringstream sstr{};
1580  sstr << m_idHelperSvc->toString(cl->identify()) << " at " <<to_string(cl.pos())
1581  <<" pointing to (" <<to_string(cl.dir())<<" cluster size: "<<clusterSize(cl);
1582 
1583  return sstr.str();
1584  }
1585  std::string MuonNSWSegmentFinderTool::print(const MeasVec& measurements) const {
1586  std::stringstream sstr{};
1587  for (const SeedMeasurement& cl : measurements){
1588  sstr<<" *** "<<print(cl)<<std::endl;
1589  }
1590  return sstr.str();
1591  }
1592  std::string MuonNSWSegmentFinderTool::print(const LayerMeasVec& sortedVec) const {
1593  std::stringstream sstr{};
1594  unsigned int lay{0};
1595  for (const MeasVec& clusts: sortedVec){
1596  sstr<<"Clusters in Layer: "<<(lay+1)<<std::endl;
1597  sstr<<"#################################################"<<std::endl;
1598  sstr<<print(clusts);
1599  ++lay;
1600  }
1601  return sstr.str();
1602  }
1603 
1605  if (clustInLay.size() < m_ocupMmNumPerBin || m_idHelperSvc->issTgc(clustInLay[0]->identify())) return clustInLay;
1611  MeasVec prunedMeas{};
1612  prunedMeas.reserve(clustInLay.size());
1613  const unsigned int firstCh = channel(clustInLay[0]);
1614  const unsigned int lastCh = channel(clustInLay[clustInLay.size() -1]);
1616  const unsigned int deltaCh = lastCh - firstCh;
1617  const unsigned int nBins = deltaCh / m_ocupMmBinWidth + (deltaCh % m_ocupMmBinWidth > 0);
1618  ATH_MSG_VERBOSE("Clusters in layer "<<print(clustInLay)<<" lowest channel: "<<
1619  firstCh<<", highest channel: "<<lastCh<<" bin width: "<<m_ocupMmBinWidth<<" number of bins"<<nBins);
1620 
1621  LayerMeasVec occupancyHisto{};
1622  occupancyHisto.resize(nBins);
1623  for (MeasVec& bin : occupancyHisto) {
1624  bin.reserve(clustInLay.size());
1625  }
1626  ATH_MSG_VERBOSE("Clusters sorted into bins "<<print(occupancyHisto));
1628  for (SeedMeasurement& meas : clustInLay){
1629  unsigned int bin = (channel(meas) - firstCh) % nBins;
1630  occupancyHisto[bin].push_back(std::move(meas));
1631  }
1633  for (MeasVec& bin : occupancyHisto) {
1634  if(bin.size() >= m_ocupMmNumPerBin){
1635  ATH_MSG_VERBOSE("The micromegas are slobbering. Detected too many clusters "<<bin.size()<<std::endl<<print(bin));
1636  bin.clear();
1637  }
1638  }
1640  for (unsigned int i = 0; i < occupancyHisto.size() -1; ++i) {
1641  if (occupancyHisto[i].size() + occupancyHisto[i+1].size() >= m_ocupMmNumPerPair){
1642  ATH_MSG_VERBOSE("The two neighbouring bins "<<i<<"&"<<(i+1)<<" have too many clusters "<<std::endl<<
1643  print(occupancyHisto[i])<<std::endl<<print(occupancyHisto[i+1]));
1644  occupancyHisto[i].clear();
1645  occupancyHisto[i+1].clear();
1646  }
1647  }
1649  for (MeasVec& bin : occupancyHisto){
1650  std::copy(std::make_move_iterator(bin.begin()),
1651  std::make_move_iterator(bin.end()),
1652  std::back_inserter(prunedMeas));
1653  }
1654 
1655  ATH_MSG_VERBOSE("Number of measurements before pruning "<<clustInLay.size()<<" number of measurments survived the pruning "<<prunedMeas.size());
1656  return prunedMeas;
1657 
1658  }
1659 } // namespace Muon
Trk::Segment::Author
Author
enum to identify who created the segment.
Definition: Tracking/TrkEvent/TrkSegment/TrkSegment/Segment.h:63
ReadFromCoolCompare.ov
ov
Definition: ReadFromCoolCompare.py:230
PlotCalibFromCool.il
il
Definition: PlotCalibFromCool.py:381
Muon::MuonNSWSegmentFinderTool::coveredRadii
std::pair< double, double > coveredRadii(const SeedMeasurement &meas) const
Returns the minimal & maximal radial distance of a measurement.
Definition: MuonNSWSegmentFinderTool.cxx:1404
Trk::LocalParameters
Definition: LocalParameters.h:98
Muon::MuonNSWSegmentFinderTool::printSeed
std::string printSeed(const std::array< SeedMeasurement, N > &seed) const
Definition: MuonNSWSegmentFinderTool.cxx:1570
Trk::PlaneSurface::globalToLocal
virtual bool globalToLocal(const Amg::Vector3D &glob, const Amg::Vector3D &mom, Amg::Vector2D &loc) const override final
Specified for PlaneSurface: GlobalToLocal method without dynamic memory allocation - boolean checks i...
Definition: PlaneSurface.cxx:209
Trk::PlaneSurface::localToGlobalDirection
void localToGlobalDirection(const Trk::LocalDirection &locdir, Amg::Vector3D &globdir) const
This method transforms a local direction wrt the plane to a global direction.
Definition: PlaneSurface.cxx:238
MuonGM::MuonPadDesign
Parameters defining the design of the readout sTGC pads.
Definition: MuonPadDesign.h:40
Muon::MuonNSWSegmentFinderTool::print
std::string print(const SeedMeasurement &meas) const
Definition: MuonNSWSegmentFinderTool.cxx:1578
Muon::NSWSeed::measurements
MeasVec measurements() const
Definition: MuonNSWSegmentFinderTool.cxx:213
Muon::NSWSeed::m_parent
const MuonNSWSegmentFinderTool * m_parent
Definition: MuonNSWSegmentFinderTool.h:103
Muon::MuonNSWSegmentFinderTool::isPad
bool isPad(const Muon::MuonClusterOnTrack *clust) const
Definition: MuonNSWSegmentFinderTool.cxx:728
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
Muon::MuonNSWSegmentFinderTool::m_edmHelperSvc
ServiceHandle< IMuonEDMHelperSvc > m_edmHelperSvc
Definition: MuonNSWSegmentFinderTool.h:141
Muon::MMPrepData
Class to represent MM measurements.
Definition: MMPrepData.h:22
Trk::Track::fitQuality
const FitQuality * fitQuality() const
return a pointer to the fit quality const-overload
Amg::MatrixX
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > MatrixX
Dynamic Matrix - dynamic allocation.
Definition: EventPrimitives.h:27
Trk::Intersection
Definition: Intersection.h:24
inline_hints.h
m_dir
TDirectory & m_dir
The directory we need to return to.
Definition: OutputStreamData.cxx:41
python.SystemOfUnits.mm
float mm
Definition: SystemOfUnits.py:98
Muon::NSWSeed::SeedOR::SuperSet
@ SuperSet
TrackParameters.h
Muon::MuonNSWSegmentFinderTool::getPadPhiOverlap
std::vector< std::pair< double, double > > getPadPhiOverlap(const std::vector< std::vector< const Muon::sTgcPrepData * >> &pads) const
Definition: MuonNSWSegmentFinderTool.cxx:1440
Muon::MuonNSWSegmentFinderTool::m_ocupMmNumPerPair
Gaudi::Property< unsigned int > m_ocupMmNumPerPair
Definition: MuonNSWSegmentFinderTool.h:197
Muon::MuonClusterOnTrack::globalPosition
virtual const Amg::Vector3D & globalPosition() const override
Returns global position.
Definition: MuonClusterOnTrack.cxx:93
Trk::PrepRawDataType::MMPrepData
@ MMPrepData
Trk::locX
@ locX
Definition: ParamDefs.h:37
Trk::locY
@ locY
local cartesian
Definition: ParamDefs.h:38
Muon::MuonNSWSegmentFinderTool::m_trackToSegmentTool
ToolHandle< IMuonTrackToSegmentTool > m_trackToSegmentTool
Definition: MuonNSWSegmentFinderTool.h:158
Trk::Track
The ATLAS Track class.
Definition: Tracking/TrkEvent/TrkTrack/TrkTrack/Track.h:73
Trk::Surface::straightLineIntersection
Intersection straightLineIntersection(const T &pars, bool forceDir=false, const Trk::BoundaryCheck &bchk=false) const
fst straight line intersection schema - templated for charged and neutral parameters
Definition: Tracking/TrkDetDescr/TrkSurfaces/TrkSurfaces/Surface.h:352
egammaEnergyPositionAllSamples::e1
double e1(const xAOD::CaloCluster &cluster)
return the uncorrected cluster energy in 1st sampling
Muon::NSWSeed::m_dir
Amg::Vector3D m_dir
Seed direction.
Definition: MuonNSWSegmentFinderTool.h:115
Trk::PerigeeSurface
Definition: PerigeeSurface.h:43
sTgcReadoutElement.h
Trk::ParametersBase::position
const Amg::Vector3D & position() const
Access method for the position.
Amg::Vector2D
Eigen::Matrix< double, 2, 1 > Vector2D
Definition: GeoPrimitives.h:48
xAODP4Helpers.h
Muon::MuonNSWSegmentFinderTool::findStgcPrecisionSegments
std::vector< std::unique_ptr< Muon::MuonSegment > > findStgcPrecisionSegments(const EventContext &ctx, const std::vector< const Muon::MuonClusterOnTrack * > &MuonClusters, int singleWedge=0) const
Combines 2 sTgc strip layers to find 2D segments constraining the muon in the eta direction.
Definition: MuonNSWSegmentFinderTool.cxx:478
max
constexpr double max()
Definition: ap_fixedTest.cxx:33
Muon::MuonClusterOnTrack::prepRawData
virtual const MuonCluster * prepRawData() const override=0
Returns the Trk::PrepRawData - is a MuonCluster in this scope.
Trk::ParametersT
Dummy class used to allow special convertors to be called for surfaces owned by a detector element.
Definition: EMErrorDetail.h:25
xAOD::deltaPhi
setSAddress setEtaMS setDirPhiMS setDirZMS setBarrelRadius setEndcapAlpha setEndcapRadius setInterceptInner setEtaMap setEtaBin setIsTgcFailure setDeltaPt deltaPhi
Definition: L2StandAloneMuon_v1.cxx:161
min
constexpr double min()
Definition: ap_fixedTest.cxx:26
Muon::NSWSeed::SeedOR::NoOverlap
@ NoOverlap
CutsMETMaker::accept
StatusCode accept(const xAOD::Muon *mu)
Definition: CutsMETMaker.cxx:18
EventPrimitivesHelpers.h
extractSporadic.c1
c1
Definition: extractSporadic.py:133
Muon::MuonNSWSegmentFinderTool::ChannelConstraint
ChannelConstraint
Definition: MuonNSWSegmentFinderTool.h:298
Muon::MuonNSWSegmentFinderTool::m_idHelperSvc
ServiceHandle< IMuonIdHelperSvc > m_idHelperSvc
Definition: MuonNSWSegmentFinderTool.h:136
Muon::MuonNSWSegmentFinderTool::m_ocupMmNumPerBin
Gaudi::Property< unsigned int > m_ocupMmNumPerBin
Definition: MuonNSWSegmentFinderTool.h:195
Muon::MuonNSWSegmentFinderTool::m_printer
PublicToolHandle< MuonEDMPrinterTool > m_printer
Definition: MuonNSWSegmentFinderTool.h:163
Muon::NSWSeed::SeedMeasurement::dir
const Amg::Vector3D & dir() const
Definition: MuonNSWSegmentFinderTool.h:45
module_driven_slicing.layers
layers
Definition: module_driven_slicing.py:113
compute_lumi.divisor
divisor
Definition: compute_lumi.py:60
python.SystemOfUnits.second
float second
Definition: SystemOfUnits.py:135
Muon::MuonNSWSegmentFinderTool::segmentSeedFromMM
std::vector< NSWSeed > segmentSeedFromMM(const LayerMeasVec &orderedClusters) const
Definition: MuonNSWSegmentFinderTool.cxx:1122
plotBeamSpotVxVal.cov
cov
Definition: plotBeamSpotVxVal.py:200
bin
Definition: BinsDiffFromStripMedian.h:43
MuonGM::sTgcReadoutElement::getDesign
const MuonChannelDesign * getDesign(const Identifier &id) const
returns the MuonChannelDesign class for the given identifier
Definition: MuonDetDescr/MuonReadoutGeometry/MuonReadoutGeometry/sTgcReadoutElement.h:279
mc.diff
diff
Definition: mc.SFGenPy8_MuMu_DD.py:14
sTgcIdHelper::Strip
@ Strip
Definition: sTgcIdHelper.h:190
AthCommonMsg::msgLvl
bool msgLvl(const MSG::Level lvl) const
Definition: AthCommonMsg.h:30
Muon::MuonNSWSegmentFinderTool::hitsToTrack
bool hitsToTrack(const EventContext &ctx, const MeasVec &etaHitVec, const MeasVec &phiHitVec, const Trk::TrackParameters &startpar, TrackCollection &segTrkColl) const
Definition: MuonNSWSegmentFinderTool.cxx:741
Muon::MuonNSWSegmentFinderTool
Definition: MuonNSWSegmentFinderTool.h:126
MuonGM::sTgcReadoutElement::isEtaZero
bool isEtaZero(const Identifier &id, const Amg::Vector2D &localPosition) const
is eta=0 of QL1 or QS1? Support for Strip and Pad cathodes is valid when the Strip,...
Definition: MuonDetDescr/MuonReadoutGeometry/MuonReadoutGeometry/sTgcReadoutElement.h:382
Muon::MuonNSWSegmentFinderTool::MuonNSWSegmentFinderTool
MuonNSWSegmentFinderTool(const std::string &type, const std::string &name, const IInterface *parent)
default constructor
Definition: MuonNSWSegmentFinderTool.cxx:256
Muon::NSWSeed::m_measurements
SeedMeasCache m_measurements
Cache the eta measurements.
Definition: MuonNSWSegmentFinderTool.h:107
Trk::TrkDetElementBase
Definition: TrkDetElementBase.h:52
Phi
@ Phi
Definition: RPCdef.h:8
JetTiledMap::N
@ N
Definition: TiledEtaPhiMap.h:44
vec
std::vector< size_t > vec
Definition: CombinationsGeneratorTest.cxx:9
exclude
std::set< std::string > exclude
list of directories to be excluded
Definition: hcg.cxx:95
Muon::IMuonIdHelperSvc::measuresPhi
virtual bool measuresPhi(const Identifier &id) const =0
returns whether channel measures phi or not
Muon::MuonNSWSegmentFinderTool::cleanClusters
MeasVec cleanClusters(const std::vector< const Muon::MuonClusterOnTrack * > &MuonClusters, int hit_sel, int singleWedge) const
Definition: MuonNSWSegmentFinderTool.cxx:799
Muon::NSWSeed::m_width
double m_width
seed width
Definition: MuonNSWSegmentFinderTool.h:117
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
Muon
NRpcCablingAlg reads raw condition data and writes derived condition data to the condition store.
Definition: TrackSystemController.h:45
Muon::MuonNSWSegmentFinderTool::compatiblyFromIP
ChannelConstraint compatiblyFromIP(const SeedMeasurement &meas1, const SeedMeasurement &meas2) const
Checks whether the two measurements are compatible within the IP constraint
Definition: MuonNSWSegmentFinderTool.cxx:1370
Muon::NSWSeed::SeedMeasurement::setDistance
void setDistance(double d)
Definition: MuonNSWSegmentFinderTool.h:51
Trk::Perigee
ParametersT< TrackParametersDim, Charged, PerigeeSurface > Perigee
Definition: Tracking/TrkEvent/TrkParameters/TrkParameters/TrackParameters.h:33
MuonGM::MuonChannelDesign::hasStereoAngle
double hasStereoAngle() const
returns whether the stereo angle is non-zero
Definition: MuonChannelDesign.h:78
Muon::NSWSeed::SeedMeasurement::pos
const Amg::Vector3D & pos() const
Definition: MuonNSWSegmentFinderTool.h:46
MuonGM::MuonClusterReadoutElement::surface
virtual const Trk::PlaneSurface & surface() const override
access to chamber surface (phi orientation), uses the first gas gap
Definition: MuonClusterReadoutElement.h:123
Muon::NSWSeed::NSWSeed
NSWSeed()=default
AmgSymMatrix
#define AmgSymMatrix(dim)
Definition: EventPrimitives.h:50
python.CaloAddPedShiftConfig.type
type
Definition: CaloAddPedShiftConfig.py:42
XMLtoHeader.count
count
Definition: XMLtoHeader.py:84
Trk::TrkDetElementBase::detectorType
virtual DetectorElemType detectorType() const =0
Return the Detector element type.
Trk::DefinedParameter
std::pair< double, ParamDefs > DefinedParameter
Definition: DefinedParameter.h:27
Muon::IMuonNSWSegmentFinderTool::SegmentMakingCache::quadSegs
std::vector< std::unique_ptr< Muon::MuonSegment > > quadSegs
Output vector to which the quadruplet segments are pushed back.
Definition: IMuonNSWSegmentFinderTool.h:37
Muon::NSWSeed::SeedMeasCache
std::array< SeedMeasurement, 16 > SeedMeasCache
Helper pair to cache the measurements with the respective distances.
Definition: MuonNSWSegmentFinderTool.h:105
Track.h
m_width
PixelDiodeTree::Vector2D m_width
Definition: PixelDiodeTreeBuilder.cxx:54
sTgcPrepData.h
cm
const double cm
Definition: Simulation/ISF/ISF_FastCaloSim/ISF_FastCaloSimParametrization/tools/FCAL_ChannelMap.cxx:25
python.setupRTTAlg.size
int size
Definition: setupRTTAlg.py:39
Muon::NSWSeed::pos
const Amg::Vector3D & pos() const
Returns the position of the seed.
Definition: MuonNSWSegmentFinderTool.h:77
Muon::NSWSeed::SeedMeasurement::SeedMeasurement
SeedMeasurement()=default
A
Muon::MuonNSWSegmentFinderTool::ipConstraint
std::unique_ptr< Trk::PseudoMeasurementOnTrack > ipConstraint(const EventContext &ctx) const
creates the IP constraint
Definition: MuonNSWSegmentFinderTool.cxx:718
Muon::MuonNSWSegmentFinderTool::classifyByLayer
LayerMeasVec classifyByLayer(const MeasVec &clusters, int hit_sel) const
Definition: MuonNSWSegmentFinderTool.cxx:819
Amg::toString
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Definition: GeoPrimitivesToStringConverter.h:40
Muon::MuonNSWSegmentFinderTool::vetoBursts
MeasVec vetoBursts(MeasVec &&clustInLay) const
Removes clusters from high activity areas in the detector.
Definition: MuonNSWSegmentFinderTool.cxx:1604
CheckAppliedSFs.e3
e3
Definition: CheckAppliedSFs.py:264
EventPrimitivesToStringConverter.h
lumiFormat.i
int i
Definition: lumiFormat.py:85
SG::OWN_ELEMENTS
@ OWN_ELEMENTS
this data object owns its elements
Definition: OwnershipPolicy.h:17
MuonPrepDataCollection.h
PixelAthClusterMonAlgCfg.e4
e4
Definition: PixelAthClusterMonAlgCfg.py:332
Muon::MuonNSWSegmentFinderTool::find
void find(const EventContext &ctx, SegmentMakingCache &cache) const override
Definition: MuonNSWSegmentFinderTool.cxx:283
ATH_FLATTEN
#define ATH_FLATTEN
Definition: inline_hints.h:52
G
#define G(x, y, z)
Definition: MD5.cxx:113
python.SystemOfUnits.micrometer
float micrometer
Definition: SystemOfUnits.py:80
Muon::MeasVec
NSWSeed::MeasVec MeasVec
Stereo seeds can be formed using hits from 4 independent layers by solving the following system of eq...
Definition: MuonNSWSegmentFinderTool.cxx:102
endmsg
#define endmsg
Definition: AnalysisConfig_Ntuple.cxx:63
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
sTgcIdHelper::Wire
@ Wire
Definition: sTgcIdHelper.h:190
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
AmgVector
AmgVector(4) T2BSTrackFilterTool
Definition: T2BSTrackFilterTool.cxx:114
TRT::Hit::layer
@ layer
Definition: HitInfo.h:79
Muon::NSWSeed::m_calibClust
std::set< std::shared_ptr< const Muon::MuonClusterOnTrack > > m_calibClust
Garbage container per seed.
Definition: MuonNSWSegmentFinderTool.h:123
Muon::MuonNSWSegmentFinderTool::m_trackCleaner
ToolHandle< IMuonTrackCleaner > m_trackCleaner
Definition: MuonNSWSegmentFinderTool.h:168
MuonGM::sTgcReadoutElement
An sTgcReadoutElement corresponds to a single STGC module; therefore typicaly a barrel muon station c...
Definition: MuonDetDescr/MuonReadoutGeometry/MuonReadoutGeometry/sTgcReadoutElement.h:30
Trk::PrepRawData::type
virtual bool type(PrepRawDataType type) const
Interface method checking the type.
Definition: PrepRawData.h:133
Muon::MuonNSWSegmentFinderTool::isWire
bool isWire(const Muon::MuonClusterOnTrack *clust) const
Definition: MuonNSWSegmentFinderTool.cxx:736
MMPrepData.h
res
std::pair< std::vector< unsigned int >, bool > res
Definition: JetGroupProductTest.cxx:11
Amg::transform
Amg::Vector3D transform(Amg::Vector3D &v, Amg::Transform3D &tr)
Transform a point from a Trasformation3D.
Definition: GeoPrimitivesHelpers.h:156
plotBeamSpotVxVal.range
range
Definition: plotBeamSpotVxVal.py:194
PseudoMeasurementOnTrack.h
test_pyathena.parent
parent
Definition: test_pyathena.py:15
AnalysisUtils::copy_if
Out copy_if(In first, const In &last, Out res, const Pred &p)
Definition: IFilterUtils.h:30
Muon::NSWSeed::newCalibClust
const Muon::MuonClusterOnTrack * newCalibClust(std::unique_ptr< const Muon::MuonClusterOnTrack > new_clust)
Adds a calibrated cluster to the garbage collection.
Definition: MuonNSWSegmentFinderTool.cxx:245
Muon::MuonNSWSegmentFinderTool::m_nOfSeedLayers
Gaudi::Property< int > m_nOfSeedLayers
Definition: MuonNSWSegmentFinderTool.h:186
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
Muon::NSWSeed::SeedMeasurement
Struct caching the MuonClusterOnTrack and providing the orientation of the strip in addtion.
Definition: MuonNSWSegmentFinderTool.h:33
Muon::MuonNSWSegmentFinderTool::channel
int channel(const Muon::MuonClusterOnTrack *cluster) const
Returns the channel of the measurement on the layer.
Definition: MuonNSWSegmentFinderTool.cxx:953
Trk::PlaneSurface::globalToLocalDirection
void globalToLocalDirection(const Amg::Vector3D &glodir, Trk::LocalDirection &locdir) const
This method transforms the global direction to a local direction wrt the plane.
Definition: PlaneSurface.cxx:256
Muon::MuonNSWSegmentFinderTool::m_ocupMmBinWidth
Gaudi::Property< unsigned int > m_ocupMmBinWidth
Protection against slobbering Micromega events.
Definition: MuonNSWSegmentFinderTool.h:193
Trk::ParametersBase
Definition: ParametersBase.h:55
MuonReadoutElement.h
Trk::Intersection::position
Amg::Vector3D position
Definition: Intersection.h:25
Muon::NSWSeed::dir
const Amg::Vector3D & dir() const
Returns the direction of the seed.
Definition: MuonNSWSegmentFinderTool.h:79
DataVector< Trk::Track >
Trk::LocalDirection
represents the three-dimensional global direction with respect to a planar surface frame.
Definition: LocalDirection.h:81
WriteCalibToCool.swap
swap
Definition: WriteCalibToCool.py:94
MuonGM::MuonPadDesign::channelWidth
double channelWidth(const Amg::Vector2D &pos, bool measPhi, bool preciseMeas=false) const
calculate local channel width
Definition: MuonPadDesign.h:142
Muon::MuonNSWSegmentFinderTool::m_maxClustDist
Gaudi::Property< double > m_maxClustDist
Definition: MuonNSWSegmentFinderTool.h:185
Muon::MuonNSWSegmentFinderTool::ChannelConstraint::TooNarrow
@ TooNarrow
Muon::NSWSeed::distance
double distance(const SeedMeasurement &meas) const
Calculates the minimal distance between seed and measurement.
Definition: MuonNSWSegmentFinderTool.cxx:147
Trk::MeasurementBase::localCovariance
const Amg::MatrixX & localCovariance() const
Interface method to get the localError.
Definition: MeasurementBase.h:138
Muon::NSWSeed::overlap
SeedOR overlap(const NSWSeed &other) const
Definition: MuonNSWSegmentFinderTool.cxx:196
beamspotman.dir
string dir
Definition: beamspotman.py:621
Muon::IMuonNSWSegmentFinderTool::SegmentMakingCache::buildQuads
bool buildQuads
Toggle whether quad segments should be built or not.
Definition: IMuonNSWSegmentFinderTool.h:35
Muon::MuonNSWSegmentFinderTool::m_trackSummary
ToolHandle< Trk::ITrackSummaryTool > m_trackSummary
Definition: MuonNSWSegmentFinderTool.h:173
Trk::PrepRawData
Definition: PrepRawData.h:62
tolerance
Definition: suep_shower.h:17
Muon::NSWSeed::add
bool add(SeedMeasurement meas, double max_uncert)
Tries to add the measurement to the seeds. Returns false if the measurement is incompatible with the ...
Definition: MuonNSWSegmentFinderTool.cxx:160
Muon::MuonNSWSegmentFinderTool::findStereoSegments
std::vector< std::unique_ptr< Muon::MuonSegment > > findStereoSegments(const EventContext &ctx, const std::vector< const Muon::MuonClusterOnTrack * > &allClusts, int singleWedge=0) const
Runs the NSW segment maker by combining 4 Micromega layers to a stereo seed.
Definition: MuonNSWSegmentFinderTool.cxx:393
Muon::NSWSeed::m_padMeasurements
SeedMeasCache m_padMeasurements
Cache the sTGC pad measurements.
Definition: MuonNSWSegmentFinderTool.h:111
Trk::MeasurementBase
Definition: MeasurementBase.h:58
Trk::PrepRawData::identify
Identifier identify() const
return the identifier
Muon::MuonNSWSegmentFinderTool::LayerMeasVec
std::vector< MeasVec > LayerMeasVec
Definition: MuonNSWSegmentFinderTool.h:204
Muon::MuonNSWSegmentFinderTool::m_ambiTool
ToolHandle< Trk::ITrackAmbiguityProcessorTool > m_ambiTool
Tool for ambiguity solving.
Definition: MuonNSWSegmentFinderTool.h:148
Trk::DetectorElemType::sTgc
@ sTgc
Muon::MuonNSWSegmentFinderTool::segmentSeedFromStgc
std::vector< NSWSeed > segmentSeedFromStgc(const LayerMeasVec &orderedClusters, bool usePhi) const
Definition: MuonNSWSegmentFinderTool.cxx:868
Trk::Track::perigeeParameters
const Perigee * perigeeParameters() const
return Perigee.
Definition: Tracking/TrkEvent/TrkTrack/src/Track.cxx:163
dumpTgcDigiJitter.nBins
list nBins
Definition: dumpTgcDigiJitter.py:29
Muon::NSWSeed::channel
int channel(const SeedMeasurement &meas) const
Returns the channel of the measurement on the layer.
Definition: MuonNSWSegmentFinderTool.cxx:146
Muon::MuonNSWSegmentFinderTool::ChannelConstraint::InWindow
@ InWindow
Muon::MuonNSWSegmentFinderTool::m_maxInputPads
Gaudi::Property< uint > m_maxInputPads
Definition: MuonNSWSegmentFinderTool.h:199
MuonPadDesign.h
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
Muon::MuonNSWSegmentFinderTool::idHelper
const IMuonIdHelperSvc * idHelper() const
Definition: MuonNSWSegmentFinderTool.cxx:281
ActsTrk::to_string
std::string to_string(const DetectorType &type)
Definition: GeometryDefs.h:34
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:76
Amg::error
double error(const Amg::MatrixX &mat, int index)
return diagonal error of the matrix caller should ensure the matrix is symmetric and the index is in ...
Definition: EventPrimitivesHelpers.h:40
Muon::NSWSeed::insert
bool insert(const Muon::MuonClusterOnTrack *cl)
Definition: MuonNSWSegmentFinderTool.cxx:226
Trk::PrepRawData::localPosition
const Amg::Vector2D & localPosition() const
return the local position reference
plotBeamSpotVxVal.bin
int bin
Definition: plotBeamSpotVxVal.py:82
Trk::nonInteracting
@ nonInteracting
Definition: ParticleHypothesis.h:28
Trk::PrepRawDataType::sTgcPrepData
@ sTgcPrepData
DataVector::push_back
value_type push_back(value_type pElem)
Add an element to the end of the collection.
Muon::NSWSeed::size
size_t size() const
Returns the number of measurements.
Definition: MuonNSWSegmentFinderTool.h:75
Muon::IMuonNSWSegmentFinderTool::SegmentMakingCache::inputClust
std::vector< std::unique_ptr< const Muon::MuonClusterOnTrack > > inputClust
Input vector containing all muon cluster on track.
Definition: IMuonNSWSegmentFinderTool.h:39
Trk::Surface::insideBounds
virtual bool insideBounds(const Amg::Vector2D &locpos, double tol1=0., double tol2=0.) const =0
virtual methods to be overwritten by the inherited surfaces
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
Muon::NSWSeed::m_phiMeasurements
SeedMeasCache m_phiMeasurements
Cache the phi measurements.
Definition: MuonNSWSegmentFinderTool.h:109
Trk::PlaneSurface::straightLineIntersection
virtual Intersection straightLineIntersection(const Amg::Vector3D &pos, const Amg::Vector3D &dir, bool forceDir, Trk::BoundaryCheck bchk) const override final
fast straight line intersection schema - standard: provides closest intersection and (signed) path le...
Definition: PlaneSurface.cxx:219
Muon::MuonNSWSegmentFinderTool::segmentSeedFromPads
std::vector< NSWSeed > segmentSeedFromPads(const LayerMeasVec &orderedClusters, const Muon::MuonSegment &etaSeg) const
Definition: MuonNSWSegmentFinderTool.cxx:985
python.LumiBlobConversion.pos
pos
Definition: LumiBlobConversion.py:16
Muon::NSWSeed::m_size
size_t m_size
Added measurements on track.
Definition: MuonNSWSegmentFinderTool.h:121
Muon::MuonNSWSegmentFinderTool::ChannelConstraint::TooWide
@ TooWide
MuonGM::MuonChannelDesign::channelHalfLength
double channelHalfLength(int st, bool left) const
STRIPS ONLY: calculate channel length on the given side of the x axis (for MM stereo strips)
Definition: MuonChannelDesign.h:376
python.PyAthena.v
v
Definition: PyAthena.py:154
Muon::MuonNSWSegmentFinderTool::m_slTrackFitter
ToolHandle< Trk::ITrackFitter > m_slTrackFitter
Definition: MuonNSWSegmentFinderTool.h:153
DataVector::stdcont
const PtrVector & stdcont() const
Return the underlying std::vector of the container.
MuonGM::MuonChannelDesign::rightEdge
bool rightEdge(int channel, Amg::Vector2D &pos) const
STRIPS ONLY: Returns the right edge of the strip.
Definition: MuonChannelDesign.h:493
Trk::ParametersBase::momentum
const Amg::Vector3D & momentum() const
Access method for the momentum.
MuonGM::MuonChannelDesign
Definition: MuonChannelDesign.h:24
Muon::sTgcPrepData::detectorElement
virtual const MuonGM::sTgcReadoutElement * detectorElement() const override final
Returns the detector element corresponding to this PRD.
Definition: sTgcPrepData.h:138
python.DataFormatRates.c2
c2
Definition: DataFormatRates.py:123
MuonNSWSegmentFinderTool.h
ReadBchFromCool.good
good
Definition: ReadBchFromCool.py:433
MuonSectorMapping.h
Trk::DetectorElemType::MM
@ MM
a
TList * a
Definition: liststreamerinfos.cxx:10
InDetDD::other
@ other
Definition: InDetDD_Defs.h:16
Trk::Surface::globalToLocal
virtual bool globalToLocal(const Amg::Vector3D &glob, const Amg::Vector3D &mom, Amg::Vector2D &loc) const =0
Specified by each surface type: GlobalToLocal method without dynamic memory allocation - boolean chec...
Muon::NSWSeed
Definition: MuonNSWSegmentFinderTool.h:29
egammaEnergyPositionAllSamples::e2
double e2(const xAOD::CaloCluster &cluster)
return the uncorrected cluster energy in 2nd sampling
Amg::intersect
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.
Definition: GeoPrimitivesHelpers.h:347
Muon::NSWSeed::MeasVec
std::vector< SeedMeasurement > MeasVec
Returns the contained measurements.
Definition: MuonNSWSegmentFinderTool.h:82
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
Muon::IMuonNSWSegmentFinderTool::SegmentMakingCache::constructedSegs
std::vector< std::unique_ptr< Muon::MuonSegment > > constructedSegs
Output vector to which the constructed segments are pushed_back.
Definition: IMuonNSWSegmentFinderTool.h:33
Trk::PlaneSurface
Definition: PlaneSurface.h:64
sTgcIdHelper::Pad
@ Pad
Definition: sTgcIdHelper.h:190
Muon::NSWSeed::SeedOR
SeedOR
Definition: MuonNSWSegmentFinderTool.h:89
unit
const PlainObject unit() const
This is a plugin that makes Eigen look like CLHEP & defines some convenience methods.
Definition: AmgMatrixBasePlugin.h:21
DeMoScan.first
bool first
Definition: DeMoScan.py:534
Trk::RIO_OnTrack::identify
Identifier identify() const
return the identifier -extends MeasurementBase
Definition: RIO_OnTrack.h:152
DEBUG
#define DEBUG
Definition: page_access.h:11
MuonGM::MuonChannelDesign::stereoAngle
double stereoAngle() const
returns the stereo angle
Definition: MuonChannelDesign.h:73
Muon::IMuonNSWSegmentFinderTool::SegmentMakingCache
Helper struct to parse the data around.
Definition: IMuonNSWSegmentFinderTool.h:31
Muon::MuonNSWSegmentFinderTool::layerNumber
int layerNumber(const Muon::MuonClusterOnTrack *cluster) const
Definition: MuonNSWSegmentFinderTool.cxx:943
Muon::NSWSeed::find
bool find(const SeedMeasurement &meas) const
Checks whether the measurement is already part of the seed.
Definition: MuonNSWSegmentFinderTool.cxx:248
RunTileMonitoring.clusters
clusters
Definition: RunTileMonitoring.py:133
Muon::MuonNSWSegmentFinderTool::wedgeNumber
int wedgeNumber(const Muon::MuonClusterOnTrack *cluster) const
Definition: MuonNSWSegmentFinderTool.cxx:936
python.utility.LHE.merge
def merge(input_file_pattern, output_file)
Merge many input LHE files into a single output file.
Definition: LHE.py:29
MuonGM::MMReadoutElement
An MMReadoutElement corresponds to a single STGC module; therefore typicaly a barrel muon station con...
Definition: MMReadoutElement.h:25
Muon::MuonNSWSegmentFinderTool::find3DSegments
std::vector< std::unique_ptr< Muon::MuonSegment > > find3DSegments(const EventContext &ctx, const std::vector< const Muon::MuonClusterOnTrack * > &MuonClusters, std::vector< std::unique_ptr< Muon::MuonSegment >> &etaSegs, int singleWedge=0) const
Definition: MuonNSWSegmentFinderTool.cxx:581
Muon::IMuonIdHelperSvc
Interface for Helper service that creates muon Identifiers and can be used to print Identifiers.
Definition: IMuonIdHelperSvc.h:27
python.SystemOfUnits.s
float s
Definition: SystemOfUnits.py:147
Muon::NSWSeed::SeedOR::Same
@ Same
m_pos
PixelDiodeTree::Vector2D m_pos
Definition: PixelDiodeTreeBuilder.cxx:53
Muon::MuonNSWSegmentFinderTool::getClustersOnSegment
int getClustersOnSegment(const LayerMeasVec &orderedclusters, NSWSeed &seed, const std::set< unsigned int > &exclude, bool useStereo=true) const
Definition: MuonNSWSegmentFinderTool.cxx:960
Trk::FitQuality::chiSquared
double chiSquared() const
returns the of the overall track fit
Definition: FitQuality.h:56
Muon::MuonNSWSegmentFinderTool::m_muonClusterCreator
ToolHandle< IMuonClusterOnTrackCreator > m_muonClusterCreator
Definition: MuonNSWSegmentFinderTool.h:179
Muon::MuonSectorMapping
Definition: MuonSectorMapping.h:20
Muon::MuonNSWSegmentFinderTool::caloConstraint
std::unique_ptr< Trk::PseudoMeasurementOnTrack > caloConstraint(const Trk::TrackParameters &startpar) const
Definition: MuonNSWSegmentFinderTool.cxx:701
Trk::FitQuality::numberDoF
int numberDoF() const
returns the number of degrees of freedom of the overall track or vertex fit as integer
Definition: FitQuality.h:60
ReadBchFromCool.nBad
nBad
Definition: ReadBchFromCool.py:455
Muon::MuonSegment::globalPosition
virtual const Amg::Vector3D & globalPosition() const override final
global position
Definition: MuonSpectrometer/MuonReconstruction/MuonRecEvent/MuonSegment/MuonSegment/MuonSegment.h:157
Trk::RIO_OnTrack::associatedSurface
virtual const Surface & associatedSurface() const override=0
returns the surface for the local to global transformation
Muon::MuonNSWSegmentFinderTool::m_ipConstraint
Gaudi::Property< bool > m_ipConstraint
Definition: MuonNSWSegmentFinderTool.h:181
Muon::MuonNSWSegmentFinderTool::fit
std::unique_ptr< Trk::Track > fit(const EventContext &ctx, const std::vector< const Trk::MeasurementBase * > &fit_meas, const Trk::TrackParameters &perigee) const
Definition: MuonNSWSegmentFinderTool.cxx:447
Trk::Segment::NswQuadAlign
@ NswQuadAlign
Definition: Tracking/TrkEvent/TrkSegment/TrkSegment/Segment.h:79
calibdata.copy
bool copy
Definition: calibdata.py:26
MuonGM::sTgcReadoutElement::getPadDesign
const MuonPadDesign * getPadDesign(const Identifier &id) const
returns the MuonChannelDesign class for the given identifier
Definition: MuonDetDescr/MuonReadoutGeometry/MuonReadoutGeometry/sTgcReadoutElement.h:285
python.Constants.VERBOSE
int VERBOSE
Definition: Control/AthenaCommon/python/Constants.py:13
Muon::MuonSegment
Definition: MuonSpectrometer/MuonReconstruction/MuonRecEvent/MuonSegment/MuonSegment/MuonSegment.h:45
AthAlgTool
Definition: AthAlgTool.h:26
Trk::PlaneSurface::localToGlobal
virtual void localToGlobal(const Amg::Vector2D &locp, const Amg::Vector3D &mom, Amg::Vector3D &glob) const override final
Specified for PlaneSurface: LocalToGlobal method without dynamic memory allocation.
Definition: PlaneSurface.cxx:198
Trk::Segment::NswStgcSeeded
@ NswStgcSeeded
Definition: Tracking/TrkEvent/TrkSegment/TrkSegment/Segment.h:77
Muon::IMuonNSWSegmentFinderTool::SegmentMakingCache::usedHits
std::set< Identifier > usedHits
Set of all hits used in the segment making.
Definition: IMuonNSWSegmentFinderTool.h:41
MuonParameters::beta
@ beta
Definition: MuonParamDefs.h:144
Muon::MuonNSWSegmentFinderTool::m_caloConstraint
Gaudi::Property< bool > m_caloConstraint
Use a virtual point at the calorimeter exit with same Z as constraint...
Definition: MuonNSWSegmentFinderTool.h:184
FitQuality.h
Muon::MuonNSWSegmentFinderTool::m_usesTGCSeeding
Gaudi::Property< bool > m_usesTGCSeeding
Definition: MuonNSWSegmentFinderTool.h:190
Trk::Surface
Definition: Tracking/TrkDetDescr/TrkSurfaces/TrkSurfaces/Surface.h:79
Muon::NSWSeed::m_chi2
double m_chi2
Chi2.
Definition: MuonNSWSegmentFinderTool.h:119
pow
constexpr int pow(int base, int exp) noexcept
Definition: ap_fixedTest.cxx:15
MuonGM::MuonPadDesign::distanceToPad
Amg::Vector2D distanceToPad(const Amg::Vector2D &pos, int channel) const
Definition: MuonPadDesign.cxx:118
Muon::sTgcPrepData
Class to represent sTgc measurements.
Definition: sTgcPrepData.h:20
Muon::MuonNSWSegmentFinderTool::getCalibratedClusters
MeasVec getCalibratedClusters(NSWSeed &seed) const
Definition: MuonNSWSegmentFinderTool.cxx:1540
dq_make_web_display.cl
cl
print [x.__class__ for x in toList(dqregion.getSubRegions()) ]
Definition: dq_make_web_display.py:25
DataVector::size
size_type size() const noexcept
Returns the number of elements in the collection.
Muon::MuonNSWSegmentFinderTool::initialize
virtual StatusCode initialize() override
Definition: MuonNSWSegmentFinderTool.cxx:262
Muon::MuonNSWSegmentFinderTool::resolveAmbiguities
std::vector< NSWSeed > resolveAmbiguities(std::vector< NSWSeed > &&unresolved) const
Definition: MuonNSWSegmentFinderTool.cxx:1414
Muon::MuonNSWSegmentFinderTool::isStrip
bool isStrip(const Muon::MuonClusterOnTrack *clust) const
Definition: MuonNSWSegmentFinderTool.cxx:732
python.SystemOfUnits.degree
tuple degree
Definition: SystemOfUnits.py:121
Muon::MuonNSWSegmentFinderTool::m_useStereoSeeding
Gaudi::Property< bool > m_useStereoSeeding
Definition: MuonNSWSegmentFinderTool.h:189
Trk::Surface::localToGlobal
virtual void localToGlobal(const Amg::Vector2D &locp, const Amg::Vector3D &mom, Amg::Vector3D &glob) const =0
Specified by each surface type: LocalToGlobal method without dynamic memory allocation.
Eta
@ Eta
Definition: RPCdef.h:8
Muon::MuonClusterOnTrack
Base class for Muon cluster RIO_OnTracks.
Definition: MuonClusterOnTrack.h:34
Muon::MuonSegment::globalDirection
const Amg::Vector3D & globalDirection() const
global direction
Definition: MuonSpectrometer/MuonReconstruction/MuonRecEvent/MuonSegment/MuonSegment/MuonSegment.h:163
python.SystemOfUnits.m
float m
Definition: SystemOfUnits.py:106
generate::Zero
void Zero(TH1D *hin)
Definition: generate.cxx:32
MuonGM::MuonChannelDesign::leftEdge
bool leftEdge(int channel, Amg::Vector2D &pos) const
STRIPS ONLY: Returns the left edge of the strip.
Definition: MuonChannelDesign.h:486
Trk::PrepRawData::detectorElement
virtual const TrkDetElementBase * detectorElement() const =0
return the detector element corresponding to this PRD The pointer will be zero if the det el is not d...
Muon::NSWSeed::SeedMeasurement::distance
double distance() const
Definition: MuonNSWSegmentFinderTool.h:52
Identifier
Definition: IdentifierFieldParser.cxx:14
Muon::MuonNSWSegmentFinderTool::MeasVec
NSWSeed::MeasVec MeasVec
Definition: MuonNSWSegmentFinderTool.h:203
Muon::NSWSeed::SeedOR::SubSet
@ SubSet