Loading [MathJax]/extensions/tex2jax.js
ATLAS Offline Software
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
MuonNSWSegmentFinderTool.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 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& _rightM) :
127  m_parent{parent}, m_pos{_leftM.pos()} {
128  m_dir = (_rightM.pos() - m_pos).unit();
129  m_width = std::hypot(Amg::error(_leftM->localCovariance(), Trk::locX),
130  Amg::error(_rightM->localCovariance(), Trk::locX)) / std::sqrt(2);
131  insert(_leftM);
132  insert(_rightM);
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  MuonSegmentVec out_segments{};
292  {
293  MuonSegmentVec stereoSegs = findStereoSegments(ctx, muonClusters, 0);
294  ATH_MSG_VERBOSE("Found " << stereoSegs.size() << " MMG stereo seeded segments");
295  out_segments.insert(out_segments.end(), std::make_move_iterator(stereoSegs.begin()),
296  std::make_move_iterator(stereoSegs.end()));
297  }
298 
299  auto dump_output = [&]() {
300  cache.constructedSegs.reserve(cache.constructedSegs.size() + out_segments.size());
301  for (std::unique_ptr<Muon::MuonSegment>& seg : out_segments) {
302  for (const Trk::MeasurementBase* meas : seg->containedMeasurements()) {
303  const Muon::MuonClusterOnTrack* clus = dynamic_cast<const Muon::MuonClusterOnTrack*>(meas);
304  if (clus) cache.usedHits.insert(clus->identify());
305  }
306  cache.constructedSegs.push_back(std::move(seg));
307  }
308  };
309 
310  std::vector<const Muon::MuonClusterOnTrack*> clustPostStereo{};
312  std::array<std::set<Identifier>, 16> masked_segs{};
313  for (std::unique_ptr<Muon::MuonSegment>& seg : out_segments) {
314  for (const Trk::MeasurementBase* meas : seg->containedMeasurements()) {
315  const Muon::MuonClusterOnTrack* clus = dynamic_cast<const Muon::MuonClusterOnTrack*>(meas);
316  if (clus) masked_segs[layerNumber(clus)].insert(clus->identify());
317  }
318  }
319 
320  if (!out_segments.empty()) {
321  clustPostStereo.reserve(muonClusters.size());
322  for (const Muon::MuonClusterOnTrack* clus : muonClusters) {
323  if (!masked_segs[layerNumber(clus)].count(clus->identify())) clustPostStereo.push_back(clus);
324  }
325  }
326  const std::vector<const Muon::MuonClusterOnTrack*>& segmentInput = !out_segments.empty() ? clustPostStereo : muonClusters;
327 
329  {
330  MuonSegmentVec etaSegs = findStgcPrecisionSegments(ctx, segmentInput);
331  ATH_MSG_VERBOSE("Found " << etaSegs.size() << " stgc seeded eta segments");
332  MuonSegmentVec precSegs = find3DSegments(ctx, segmentInput, etaSegs);
333  ATH_MSG_VERBOSE("Found " << precSegs.size() << " 3D segments");
334  out_segments.insert(out_segments.end(),
335  std::make_move_iterator(precSegs.begin()),
336  std::make_move_iterator(precSegs.end()));
337  }
338 
339 
340 
341  if (!cache.buildQuads) {
342  dump_output();
343  return;
344  }
346  for (std::unique_ptr<Muon::MuonSegment>& seg : out_segments) {
347  std::vector<const MuonClusterOnTrack*> seg_hits{};
348  seg_hits.reserve(seg->containedMeasurements().size());
349  for (const Trk::MeasurementBase* meas : seg->containedMeasurements()) {
350  const Muon::MuonClusterOnTrack* clus = dynamic_cast<const Muon::MuonClusterOnTrack*>(meas);
351  if (clus) seg_hits.push_back(clus);
352  }
354  for (int iWedge{1}; iWedge<=4 ; ++iWedge) {
355  MeasVec quad_hits = cleanClusters(seg_hits, HitType::Eta | HitType::Phi, iWedge);
357  if ( quad_hits.size () < 2 || ((iWedge == 2 || iWedge == 3) && quad_hits.size() < 4)) continue;
358  std::vector<const Trk::MeasurementBase*> fit_meas{};
359  std::unique_ptr<Trk::PseudoMeasurementOnTrack> pseudoVtx{ipConstraint(ctx)};
360  if (pseudoVtx) fit_meas.push_back(pseudoVtx.get());
361  std::copy(quad_hits.begin(), quad_hits.end(), std::back_inserter(fit_meas));
363  const Trk::Surface& surf = quad_hits.front()->associatedSurface();
364  Trk::Intersection intersect = surf.straightLineIntersection(seg->globalPosition(), seg->globalDirection(), false, false);
365  const Amg::Vector3D& gpos_seg = intersect.position;
366  Amg::Vector3D gdir_seg{seg->globalDirection()};
367  Amg::Vector3D perpos = gpos_seg - 10 * gdir_seg.unit();
368  if (perpos.dot(gdir_seg) < 0) gdir_seg *= -1;
369  Trk::Perigee startpar{perpos, gdir_seg, 0, perpos};
371  std::unique_ptr<Trk::Track> segtrack = fit(ctx, fit_meas, startpar);
372  if (!segtrack) continue;
373 
374  std::unique_ptr<MuonSegment> seg{m_trackToSegmentTool->convert(ctx, *segtrack)};
375  if (seg) {
376  ATH_MSG_VERBOSE(" adding new quad segment " << m_printer->print(*seg) << std::endl
377  <<"position: "<<to_string(seg->globalPosition())<< std::endl
378  <<"direction: "<<to_string(seg->globalDirection())<< std::endl
379  << m_printer->print(seg->containedMeasurements()));
380  seg->setAuthor(Trk::Segment::NswQuadAlign);
381  cache.quadSegs.emplace_back(std::move(seg));
382  }
383  }
384  }
385  dump_output();
386  }
387  MuonSegmentVec MuonNSWSegmentFinderTool::findStereoSegments(const EventContext& ctx,
388  const std::vector<const Muon::MuonClusterOnTrack*>& allClusts,
389  int singleWedge) const {
390 
391  if (!m_useStereoSeeding){
392  ATH_MSG_VERBOSE("MMStereoSeeding disabled!");
393  return {};
394  }
395 
396  ATH_MSG_VERBOSE("Running MMStereoSeeding");
398  LayerMeasVec orderedClust =
399  classifyByLayer(cleanClusters(allClusts, HitType::Eta | HitType::Phi, singleWedge), HitType::Wire | HitType::Pad);
400 
401  for (MeasVec& hitsInLayer : orderedClust) hitsInLayer = vetoBursts(std::move(hitsInLayer));
402  orderedClust.erase(std::remove_if(orderedClust.begin(), orderedClust.end(),
403  [](const MeasVec& vec) { return vec.empty(); }),
404  orderedClust.end());
405  if (orderedClust.empty()) return {};
406 
407 
408  std::vector<NSWSeed> seeds = segmentSeedFromMM(orderedClust);
409  ATH_MSG_VERBOSE("Retrieved " << seeds.size() << " seeds in the MMStereoAlg after the ambiguity resolution" );
410 
411  if (seeds.empty()) return {};
414  for (NSWSeed& seed : seeds) {
417  std::vector<const Trk::MeasurementBase*> fit_meas{};
418 
419  std::unique_ptr<Trk::PseudoMeasurementOnTrack> pseudoVtx{ipConstraint(ctx)};
420  if (pseudoVtx) fit_meas.push_back(pseudoVtx.get());
421  MeasVec calib_clust = getCalibratedClusters(seed);
422  std::copy(calib_clust.begin(), calib_clust.end(), std::back_inserter(fit_meas));
424  const Trk::Surface& surf = calib_clust.front()->associatedSurface();
425 
426  Trk::Intersection intersect = surf.straightLineIntersection(seed.pos(), seed.dir(), false, false);
427  const Amg::Vector3D& gpos_seg = intersect.position;
428  Amg::Vector3D gdir_seg{seed.dir()};
429  Amg::Vector3D perpos = gpos_seg - 10 * gdir_seg.unit();
430  if (perpos.dot(gdir_seg) < 0) gdir_seg *= -1;
431 
432  Trk::Perigee startpar{perpos, gdir_seg, 0, perpos};
433 
435  std::unique_ptr<Trk::Track> segtrack = fit(ctx, fit_meas, startpar);
436  if (segtrack) trackSegs.push_back(std::move(segtrack));
437  }
438  return resolveAmbiguities(ctx, trackSegs, Trk::Segment::Author::NswStereoSeeded);
439  }
440 
441  std::unique_ptr<Trk::Track> MuonNSWSegmentFinderTool::fit(const EventContext& ctx,
442  const std::vector<const Trk::MeasurementBase*>& fit_meas,
443  const Trk::TrackParameters& perigee) const {
444  ATH_MSG_VERBOSE("Fit segment from (" << to_string(perigee.position())<< " pointing to " <<
445  to_string(perigee.momentum())<<". Contained measurements in candidate: " << std::endl
446  << m_printer->print(fit_meas));
447  std::unique_ptr<Trk::Track> segtrack = m_slTrackFitter->fit(ctx, fit_meas, perigee, false, Trk::nonInteracting);
448  if (!segtrack) {
449  ATH_MSG_VERBOSE("Fit failed");
450  return nullptr;
451  }
452  ATH_MSG_VERBOSE("--> Fit succeeded");
453  std::unique_ptr<Trk::Track> cleanedTrack = m_trackCleaner->clean(*segtrack, ctx);
454  if (cleanedTrack && cleanedTrack->perigeeParameters() != segtrack->perigeeParameters()) { segtrack.swap(cleanedTrack); }
455  // quality criteria
456  if (!m_edmHelperSvc->goodTrack(*segtrack, 10)) {
457  if (segtrack->fitQuality()) {
458  ATH_MSG_DEBUG("Segment fit with chi^2/nDoF = " << segtrack->fitQuality()->chiSquared() << "/"
459  << segtrack->fitQuality()->numberDoF());
460  }
461  return nullptr;
462  }
463  // update the track summary and add the track to the collection
464  m_trackSummary->updateTrack(ctx, *segtrack);
465  ATH_MSG_VERBOSE("Segment accepted with chi^2/nDoF = " << segtrack->fitQuality()->chiSquared() << "/"
466  << segtrack->fitQuality()->numberDoF());
467  return segtrack;
468  }
469 
470  //============================================================================
471  // find the precision (eta) segments
472  MuonSegmentVec MuonNSWSegmentFinderTool::findStgcPrecisionSegments(const EventContext& ctx,
473  const std::vector<const Muon::MuonClusterOnTrack*>& muonClusters,
474  int singleWedge) const {
475 
476  if (!m_usesTGCSeeding){
477  ATH_MSG_VERBOSE("2D sTGC seeding disabled!");
478  return {};
479  }
480 
481  ATH_MSG_VERBOSE("Running 2D sTGC seeding");
482 
483 
484  // clean the muon clusters; select only the eta hits.
485  // in single-wedge mode the eta seeds are retrieved from the specific wedge
486 
487  ATH_MSG_DEBUG("Cleaning eta clusters in stgc seeded 2D segments ");
488  MeasVec clusters = cleanClusters(muonClusters, HitType::Eta, singleWedge); // eta hits only
489  ATH_MSG_VERBOSE(" After hit cleaning, there are " << clusters.size() << " precision 2D clusters");
490 
491  // classify eta clusters by layer
492  LayerMeasVec orderedClusters = classifyByLayer(clusters, 0);
493 
494  if (orderedClusters.size() < 4) return {}; // at least four layers with eta hits (MM and sTGC)
495 
496  // create segment seeds
497  std::vector<NSWSeed> seeds = segmentSeedFromStgc(orderedClusters, false);
498  ATH_MSG_DEBUG(" Found " << seeds.size() << " 2D seeds");
499  // Loop on seeds: find all clusters near the seed and try to fit
500  MeasVec etaHitVec, phiHitVec;
501  TrackCollection segTrkColl{SG::OWN_ELEMENTS};
502 
503  for (NSWSeed& seed : seeds) {
504  if (seed.size() < 4){
505  ATH_MSG_VERBOSE(__func__<<" :"<<__LINE__<< " - Seed size: " << seed.size() << " is below the cut (4)");
506  continue;
507  }
508 
509  etaHitVec = seed.measurements();
510  const Trk::PlaneSurface& surf = static_cast<const Trk::PlaneSurface&>(etaHitVec.front()->associatedSurface());
511  // calculate start parameters for the fit
512  // local position and direction of the eta-seed on the surface of the first cluster
513  Trk::Intersection intersect = surf.straightLineIntersection(seed.pos(), seed.dir(), false, false);
514  Amg::Vector2D lpos_seed{Amg::Vector2D::Zero()};
515  Trk::LocalDirection ldir_seed{};
516  surf.globalToLocal(intersect.position, intersect.position, lpos_seed);
517  surf.globalToLocalDirection(seed.dir(), ldir_seed);
518 
519  // use the seed info to generate start parameters (dummy values for phi)
520  Amg::Vector2D lpos(lpos_seed[Trk::locX], 0.);
521  Trk::LocalDirection ldir(ldir_seed.angleXZ(), -M_PI_2);
522  Amg::Vector3D gpos_seg{Amg::Vector3D::Zero()}, gdir_seg{Amg::Vector3D::Zero()};
523  surf.localToGlobal(lpos, gpos_seg, gpos_seg);
524  surf.localToGlobalDirection(ldir, gdir_seg);
525 
526  Amg::Vector3D perpos = gpos_seg - 10 * gdir_seg.unit();
527  if (perpos.dot(gdir_seg) < 0) gdir_seg *= -1;
528  const auto startpar = Trk::Perigee(perpos, gdir_seg, 0, perpos);
529  ATH_MSG_VERBOSE(" start parameter " << perpos << " pp " << startpar.position() << " gd " << gdir_seg.unit() << " pp "
530  << startpar.momentum().unit());
531 
532  // fit the hits
533  hitsToTrack(ctx, etaHitVec, phiHitVec, startpar, segTrkColl);
534  }
536  return resolveAmbiguities(ctx, segTrkColl, Trk::Segment::Author::NswStgcSeeded);
537  }
538  MuonSegmentVec MuonNSWSegmentFinderTool::resolveAmbiguities(const EventContext& ctx,
539  const TrackCollection& segTrkColl,
540  const Trk::Segment::Author a) const {
541  if (msgLvl(MSG::DEBUG)) {
542  ATH_MSG_DEBUG("Tracks before ambi solving: ");
543  for (const Trk::Track* trk : segTrkColl) {
544  ATH_MSG_DEBUG(m_printer->print(*trk));
545  const DataVector<const Trk::MeasurementBase>* meas = trk->measurementsOnTrack();
546  if (meas) ATH_MSG_DEBUG(m_printer->print(meas->stdcont()));
547  }
548  }
549 
550  MuonSegmentVec segments{};
551  std::unique_ptr<const TrackCollection> resolvedTracks(m_ambiTool->process(&segTrkColl));
552  ATH_MSG_DEBUG("Resolved track candidates: old size " << segTrkColl.size() << " new size " << resolvedTracks->size());
553 
554  // store the resolved segments
555  for (const Trk::Track* trk : *resolvedTracks) {
556  const auto* measurements = trk->measurementsOnTrack();
557  const bool has_eta = std::find_if(measurements->begin(), measurements->end(),
558  [this](const Trk::MeasurementBase* meas) {
559  Identifier id = m_edmHelperSvc->getIdentifier(*meas);
560  return id.is_valid() && !m_idHelperSvc->measuresPhi(id);
561  }) != trk->measurementsOnTrack()->end();
562  if (!has_eta) continue;
563  std::unique_ptr<MuonSegment> seg{m_trackToSegmentTool->convert(ctx, *trk)};
564  if (seg) {
565  ATH_MSG_DEBUG(" adding " << m_printer->print(*seg) << std::endl << m_printer->print(seg->containedMeasurements()));
566  seg->setAuthor(a);
567  segments.emplace_back(std::move(seg));
568  } else {
569  ATH_MSG_VERBOSE("Segment conversion failed, no segment created. ");
570  }
571  }
572  return segments;
573  }
574  //============================================================================
575  MuonSegmentVec MuonNSWSegmentFinderTool::find3DSegments(const EventContext& ctx,
576  const std::vector<const Muon::MuonClusterOnTrack*>& muonClusters,
577  MuonSegmentVec& etaSegs,
578  int singleWedge) const {
579  MuonSegmentVec segments{};
580  // cluster cleaning #1; select only phi hits (must be from all wedges, in order to phi-seed)
581 
582  ATH_MSG_DEBUG("Cleaning phi clusters in stgc seeded 3D segments ");
583  MeasVec phiClusters = cleanClusters(muonClusters, HitType::Phi | HitType::Wire, singleWedge);
584  ATH_MSG_DEBUG("After hit cleaning, there are " << phiClusters.size() << " phi clusters to be fit");
585 
586 
587  // classify the phi clusters by layer
588  LayerMeasVec orderedWireClusters = classifyByLayer(phiClusters, HitType::Wire);
589  LayerMeasVec orderedPadClusters = classifyByLayer(phiClusters, HitType::Pad); // pads only
590  if (orderedWireClusters.size() + orderedPadClusters.size() < 2) {
591  ATH_MSG_DEBUG("Not enough phi hits present, cannot perform the 3D fit!");
592  segments.insert(segments.end(), std::make_move_iterator(etaSegs.begin()), std::make_move_iterator(etaSegs.end()));
593  return segments;
594  }
595 
596  // cluster cleaning #2; select only eta hits
597  ATH_MSG_DEBUG("Cleaning eta clusters in stgc seeded 3D segments ");
598  MeasVec etaClusters = cleanClusters(muonClusters, HitType::Eta, singleWedge);
599  LayerMeasVec orderedEtaClusters = classifyByLayer(etaClusters, HitType::Eta);
600 
601  // loop on eta segments
602  bool triedWireSeed{false}; // wire seeds need to be retrieved only once (the first time they are needed)
603  std::vector<NSWSeed> seeds_WiresSTGC;
604  TrackCollection segTrkColl{SG::OWN_ELEMENTS};
605  // Loop on eta segments
606  for (std::unique_ptr<Muon::MuonSegment>& etaSeg : etaSegs) {
607  bool is3Dseg{false};
608  NSWSeed seed2D{this, *etaSeg};
609  getClustersOnSegment(orderedEtaClusters, seed2D, {}); // eta clusters
610 
611  std::vector<NSWSeed> seeds;
614  if (std::abs(etaSeg->globalPosition().eta()) < 2.4) {
615  if (!triedWireSeed) {
616  // wire seeds need to be retrieved only once (they don't depend on the eta segment)
617  triedWireSeed = true;
618  seeds_WiresSTGC = segmentSeedFromStgc(orderedWireClusters, true);
619  }
620 
621  if (!seeds_WiresSTGC.empty()) {
622  seeds = seeds_WiresSTGC;
623  ATH_MSG_DEBUG(" Seeding from sTGC wires");
624  }
625  }
626 
627  // 3 - last resort, try sTGC pads
628  if (seeds.empty()) {
629  seeds = segmentSeedFromPads(orderedPadClusters, *etaSeg);
630  ATH_MSG_DEBUG(" Seeding from sTGC pads");
631  }
632 
633  // Loop on phi seeds
634  MeasVec phiHitVec;
635  const Trk::PlaneSurface& etaSegSurf = etaSeg->associatedSurface();
636  double etaSegLocX = etaSeg->localParameters()[Trk::locX];
637  double etaSegLocXZ = etaSeg->localDirection().angleXZ();
638 
639  for (NSWSeed& seed : seeds) {
640  // calculate start parameters for the fit
641  // combine the local position and direction of the eta-seed (segment)
642  // and local position and direction of the phi-seed to generate 3D starting parameters
643  Trk::Intersection intersect = etaSegSurf.straightLineIntersection(seed.pos(), seed.dir(), false, false);
644  Amg::Vector2D lpos_seed{Amg::Vector2D::Zero()};
645  Trk::LocalDirection ldir_seed{};
646  etaSegSurf.globalToLocal(intersect.position, intersect.position, lpos_seed);
647  etaSegSurf.globalToLocalDirection(seed.dir(), ldir_seed);
648 
649  Amg::Vector2D lpos_seg(etaSegLocX, lpos_seed[Trk::locY]);
650  Trk::LocalDirection ldir_seg(etaSegLocXZ, ldir_seed.angleYZ());
651 
652  Amg::Vector3D gpos_seg{Amg::Vector3D::Zero()}, gdir_seg{Amg::Vector3D::Zero()};
653  etaSegSurf.localToGlobal(lpos_seg, gpos_seg, gpos_seg);
654  etaSegSurf.localToGlobalDirection(ldir_seg, gdir_seg);
655 
656  Amg::Vector3D perpos = gpos_seg - 10 * gdir_seg.unit();
657  if (perpos.dot(gdir_seg) < 0) gdir_seg *= -1;
658  const Trk::Perigee startpar{perpos, gdir_seg, 0, perpos};
659 
660  NSWSeed seed3D{this, perpos, gdir_seg};
661 
662  // gather phi hits aligned with the segment
663  int nPhiHits = getClustersOnSegment(orderedPadClusters, seed3D,{}); // add pad hits (from the requested wedge if any)
664  nPhiHits += getClustersOnSegment(orderedWireClusters, seed3D, {}); // add wire hits (from the requested wedge if any)
665  if (nPhiHits < 2) continue; // at least two phi hits
666 
667  MeasVec phiHitVec = seed3D.measurements();
668  // calibrate the eta hits
669  MeasVec etaHitsCalibrated = getCalibratedClusters(seed2D);
670 
671  // fit
672  if (hitsToTrack(ctx, etaHitsCalibrated, phiHitVec, startpar, segTrkColl)) {
673  is3Dseg = true;
674  ATH_MSG_VERBOSE("Segment successfully fitted for wedge "<<singleWedge<<std::endl<<
675  m_printer->print(*segTrkColl.back()));
676  }
677  } // end loop on phi seeds
678 
679  // if we failed to combine the eta segment with phi measurements,
680  // just add the eta segment to the collection.
681  if (!is3Dseg) { segments.push_back(std::move(etaSeg)); }
682  } // end loop on precision plane segments
683  MuonSegmentVec new_segs = resolveAmbiguities(ctx, segTrkColl, Trk::Segment::NswStgcSeeded);
684  segments.insert(segments.end(), std::make_move_iterator(new_segs.begin()), std::make_move_iterator(new_segs.end()));
685  return segments;
686  }
687 
688  std::unique_ptr<Trk::PseudoMeasurementOnTrack> MuonNSWSegmentFinderTool::caloConstraint(const Trk::TrackParameters& startpar) const {
689  if (!m_caloConstraint) return nullptr;
690  constexpr double errVtx{1.*Gaudi::Units::m};
691  Amg::MatrixX covVtx(2,2);
692  covVtx.setIdentity();
693  covVtx = errVtx * errVtx * covVtx;
694  const Amg::Vector3D parPos{startpar.position()};
695  Amg::Vector3D projection{parPos.x(), parPos.y(), 0};
696  // project
697  Trk::PerigeeSurface perVtx(projection);
698  return std::make_unique<Trk::PseudoMeasurementOnTrack>(Trk::LocalParameters(Trk::DefinedParameter(0, Trk::locX),
700  std::move(covVtx),
701  std::move(perVtx));
702 
703  }
704 
705  std::unique_ptr<Trk::PseudoMeasurementOnTrack> MuonNSWSegmentFinderTool::ipConstraint(const EventContext& /*ctx*/) const {
706  if (!m_ipConstraint) return nullptr;
707  constexpr double errVtx{10.*Gaudi::Units::cm};
708  Amg::MatrixX covVtx(1, 1);
709  covVtx(0, 0) = errVtx * errVtx;
712  return std::make_unique<Trk::PseudoMeasurementOnTrack>(Trk::LocalParameters(Trk::DefinedParameter(0, Trk::locX)), std::move(covVtx),
713  std::move(perVtx));
714  }
716  const Identifier id = clust->identify();
717  return m_idHelperSvc->issTgc(id) && m_idHelperSvc->stgcIdHelper().channelType(id) == sTgcIdHelper::Pad;
718  }
720  const Identifier id = clust->identify();
721  return m_idHelperSvc->issTgc(id) && m_idHelperSvc->stgcIdHelper().channelType(id) == sTgcIdHelper::Strip;
722  }
724  const Identifier id = clust->identify();
725  return m_idHelperSvc->issTgc(id) && m_idHelperSvc->stgcIdHelper().channelType(id) == sTgcIdHelper::Wire;
726  }
727  //============================================================================
728  bool MuonNSWSegmentFinderTool::hitsToTrack(const EventContext& ctx,
729  const MeasVec& etaHitVec,
730  const MeasVec& phiHitVec,
731  const Trk::TrackParameters& startpar,
732  TrackCollection& segTrkColl) const {
733  // vector of hits for the fit
734  std::vector<const Trk::MeasurementBase*> vecFitPts;
735  unsigned int nHitsEta = etaHitVec.size();
736  unsigned int nHitsPhi = phiHitVec.size();
737  vecFitPts.reserve(nHitsEta + nHitsPhi + 2 + m_ipConstraint + m_caloConstraint);
738 
739  std::unique_ptr<Trk::PseudoMeasurementOnTrack> pseudoVtx{ipConstraint(ctx)},
740  pseudoVtxCalo{caloConstraint(startpar)},
741  pseudoPhi1{nullptr}, pseudoPhi2{nullptr};
742  // is chosen, add a pseudo measurement as vtx at the center of ATLAS
743  if (pseudoVtx) { vecFitPts.push_back(pseudoVtx.get()); }
744  if (pseudoVtxCalo) { vecFitPts.push_back(pseudoVtxCalo.get()); }
745 
746  if (!nHitsPhi) {
747  // generate two pseudo phi measurements for the fit,
748  // one on the first hit surface and one on the last hit surface.
749 
750  Amg::MatrixX cov(1, 1);
751  constexpr double pseudoPrecision = 100 * Gaudi::Units::micrometer;
752  cov(0, 0) = pseudoPrecision;
753  static const Trk::LocalParameters loc_pseudopars{Trk::DefinedParameter(0, Trk::locY)};
754  pseudoPhi1 = std::make_unique<Trk::PseudoMeasurementOnTrack>(Trk::LocalParameters(loc_pseudopars),
755  Amg::MatrixX(cov),
756  etaHitVec.front()->associatedSurface());
757  pseudoPhi2 = std::make_unique<Trk::PseudoMeasurementOnTrack>(Trk::LocalParameters(loc_pseudopars),
758  Amg::MatrixX(cov),
759  etaHitVec.back()->associatedSurface());
760 
761  // add the first pseudo phi hit, the hit vector, and the second pseudo phi hit
762  vecFitPts.push_back(pseudoPhi1.get());
763  std::copy(etaHitVec.begin(), etaHitVec.end(), std::back_inserter(vecFitPts));
764  vecFitPts.push_back(pseudoPhi2.get());
765  ATH_MSG_VERBOSE("Fitting a 2D-segment track with " << nHitsEta << " Eta hits");
766 
767  } else {
768  // sorted eta and sorted phi hits combined (sorted by their the z-coordinate)
769  std::merge(phiHitVec.begin(), phiHitVec.end(), etaHitVec.begin(), etaHitVec.end(), std::back_inserter(vecFitPts),
771  double z1 = std::abs(c1->detectorElement()->center(c1->identify()).z());
772  double z2 = std::abs(c2->detectorElement()->center(c2->identify()).z());
773  return z1 < z2;
774  });
775  ATH_MSG_VERBOSE("Fitting a 3D-segment track with " << nHitsEta << " Eta hits and " << nHitsPhi << " Phi hits");
776  }
777 
778  // fit the hits and generate the Trk::Track
779  std::unique_ptr<Trk::Track> segtrack = fit(ctx, vecFitPts, startpar);
780  if (!segtrack) return false;
781  segTrkColl.push_back(std::move(segtrack));
782  return true;
783  }
784 
785  //============================================================================
787  const std::vector<const Muon::MuonClusterOnTrack*>& muonClusters, int hit_sel, int singleWedge /*= 0*/) const {
788  // Keep only eta (MM && sTGC) or phi (sTGC) clusters
789  // In single-wedge mode keep only clusters from the requested wedge
791  clusters.reserve(muonClusters.size());
792  for (const Muon::MuonClusterOnTrack* cluster : muonClusters) {
793  if (!cluster) continue;
794  if (singleWedge && singleWedge != wedgeNumber(cluster)) continue;
795  const Identifier id = cluster->identify();
796  if (((hit_sel & HitType::Eta) && !m_idHelperSvc->measuresPhi(id)) ||
797  ((hit_sel & HitType::Phi) && m_idHelperSvc->measuresPhi(id)))
798  clusters.emplace_back(cluster);
799  }
800 
801  ATH_MSG_VERBOSE(" After hit cleaning, there are " << clusters.size() );
802  return clusters;
803  }
804 
805  //============================================================================
807  const MeasVec& clusters, int hit_sel) const {
808  // Classifies clusters by layer, starting from the layer closest to the IP and moving outwards.
809  // "clusters" is expected to contain only eta (MM+sTGC strip) or only phi hits (sTGC pads XOR wires).
810  // The returned vector contains only layers that have hits.
811 
812  LayerMeasVec orderedClusters(16);
813  std::array<std::set<Identifier>,16> used_hits{};
814  int nBad{0};
815  for (const Muon::MuonClusterOnTrack* hit : clusters) {
816  const int iorder = layerNumber(hit);
817  if (iorder < 0) {
818  ++nBad;
819  continue;
820  }
821  const Identifier id = hit->identify();
822  if (m_idHelperSvc->issTgc(id)) {
823  const int channelType = m_idHelperSvc->stgcIdHelper().channelType(id);
824  // skip sTGC pads if using wires, or skip wires if using pads
825  if (!(hit_sel & HitType::Pad) && channelType == sTgcIdHelper::Pad) continue;
826  if (!(hit_sel & HitType::Wire) && channelType == sTgcIdHelper::Wire) continue;
827  }
828  std::set<Identifier>& lay_hits = used_hits[iorder];
829  if (lay_hits.count(id)) continue;
830  lay_hits.insert(id);
831  orderedClusters[iorder].emplace_back(hit);
832  }
833  if (nBad) ATH_MSG_WARNING("Unable to classify " << nBad << " clusters by their layer since they are neither MM nor sTGC");
834 
835  // Erase layers without hits
836  orderedClusters.erase(std::remove_if(orderedClusters.begin(), orderedClusters.end(),
837  [](const MeasVec& vec) { return vec.empty(); }),
838  orderedClusters.end());
839 
840 
841  for( MeasVec& lays: orderedClusters){
842  std::sort(lays.begin(),lays.end(), [this](const SeedMeasurement& a, const SeedMeasurement& b){
843  return channel(a) < channel(b);
844  });
845  ATH_MSG_DEBUG("Found in layer "<<m_idHelperSvc->toStringDetEl(lays[0]->identify())<<" "<<lays.size()<<" clusters");
846 
847 
848  }
849  ATH_MSG_VERBOSE("Collected clusters "<<print(orderedClusters));
850 
851  return orderedClusters;
852  }
853 
854  //============================================================================
855  std::vector<NSWSeed> MuonNSWSegmentFinderTool::segmentSeedFromStgc(const LayerMeasVec& orderedClusters,
856  bool usePhi) const {
857  std::vector<NSWSeed> seeds;
858 
859  // oderedClusters should contain either eta clusters (MM and sTGC)
860  // or sTGC phi hits. For MM phi, use the dedicated function.
861  if (orderedClusters.size() < 4) return seeds;
862 
863  // Create seeds using each pair of hits on the two most distant layers (that containing hits).
864  // m_nOfSeedLayers (default = 1) dictates whether we want to also use hits from inner layers.
865 
866  // Loop on layers to get the first seed point
867  int seedingLayersL{0};
868  for (unsigned int ilayerL{0}; (ilayerL < orderedClusters.size() && seedingLayersL < m_nOfSeedLayers); ++ilayerL) {
869  bool usedLayerL{false};
870  for (const SeedMeasurement& hitL : orderedClusters[ilayerL]) {
872  if (usePhi != m_idHelperSvc->measuresPhi(hitL->identify())) continue;
873  else if(m_idHelperSvc->isMM(hitL->identify())) break;
874 
875 
876  // For the second point, loop on layers in reverse to be as far as possible from the first.
877  int seedingLayersR{0};
878  for (unsigned int ilayerR = orderedClusters.size() - 1; (ilayerR > ilayerL && seedingLayersR < m_nOfSeedLayers);
879  --ilayerR) {
880  bool usedLayerR{false};
881  for (const SeedMeasurement& hitR : orderedClusters[ilayerR]) {
882  if (usePhi != m_idHelperSvc->measuresPhi(hitR->identify())) continue;
883  else if (m_idHelperSvc->isMM(hitR->identify())) break;
884  NSWSeed seed{this,hitL, hitR};
885  if (!usePhi && m_ipConstraint) {
886  const double eta = seed.dir().perp() > std::numeric_limits<float>::epsilon() ? std::abs(seed.dir().eta()): FLT_MAX;
887  if (eta < minEtaNSW || eta > maxEtaNSW) {
888  continue;
889  }
890  }
891  usedLayerR = true;
892  usedLayerL = true;
893  getClustersOnSegment(orderedClusters, seed, {ilayerL, ilayerR}, false);
894  seeds.emplace_back(std::move(seed));
895 
896  }
897  if (usedLayerR) ++seedingLayersR;
898  }
899  }
900  if (usedLayerL) ++seedingLayersL;
901  }
902 
903  return resolveAmbiguities(std::move(seeds));
904  }
905 
906  //============================================================================
908  if (m_idHelperSvc->isMM(cluster->identify()))
909  return m_idHelperSvc->mmIdHelper().multilayer(cluster->identify()) + 1; // [IP:2, HO:3]
910  if (m_idHelperSvc->issTgc(cluster->identify()))
911  return 3 * (m_idHelperSvc->stgcIdHelper().multilayer(cluster->identify()) - 1) + 1; // [IP:1, HO:4];
912  return -1;
913  }
915  // Internal logic. Initialize with 16 layers:
916  // [0-3] for the four sTGC IP layers
917  // [4-11] for the eight MM IP+HO layers (empty when phi hits are requested)
918  // [12-15] for the four sTGC HO layers
919  int layer{0};
920  if (m_idHelperSvc->isMM(cluster->identify())) layer = m_idHelperSvc->mmIdHelper().gasGap(cluster->identify());
921  if (m_idHelperSvc->issTgc(cluster->identify())) layer = m_idHelperSvc->stgcIdHelper().gasGap(cluster->identify());
922  return 4 * (wedgeNumber(cluster) - 1) + layer - 1;
923  }
925  if (m_idHelperSvc->isMM(cluster->identify())) return m_idHelperSvc->mmIdHelper().channel(cluster->identify());
926  if (m_idHelperSvc->issTgc(cluster->identify())) return m_idHelperSvc->stgcIdHelper().channel(cluster->identify());
927  return -1;
928  }
929 
930  //============================================================================
932  NSWSeed& seed, const std::set<unsigned int>& exclude, bool useStereo) const {
933  ATH_MSG_VERBOSE(" getClustersOnSegment: layers " << orderedclusters.size());
934  int nHitsAdded{0};
935 
936  for (const MeasVec& surfHits : orderedclusters) {
937  if (exclude.count(layerNumber(surfHits[0]))) continue;
938  // get the best hit candidate on this layer
939 
940  for (const SeedMeasurement& hit : surfHits) {
941 
942  const Identifier id = hit->identify();
943  const MuonGM::MuonChannelDesign* design = getDesign(hit);
944 
945  //In case of the 2D eta stgc seeding we don't want the MMG stereo hits on the segment
946  if ( !useStereo && m_idHelperSvc->isMM(id) && design->hasStereoAngle() ) continue;
947 
948  nHitsAdded += seed.add(hit, m_maxClustDist);
949  }
950  }
951  ATH_MSG_VERBOSE(" getClustersOnSegment: returning " << nHitsAdded << " hits ");
952  return nHitsAdded;
953  }
954 
955  //============================================================================
957  const LayerMeasVec& orderedClusters, const Muon::MuonSegment& etaSeg) const {
958  std::vector<NSWSeed> seeds;
960  if (orderedClusters.empty()) return seeds;
961 
962  std::vector<std::vector<const Muon::sTgcPrepData*>> sTgcIP(4); // IP: layers nearest to the IP will be added first
963  std::vector<std::vector<const Muon::sTgcPrepData*>> sTgcHO(4); // HO: layers furthest from the IP will be added first
964 
965  // Process clusters separately for each multilayer
966  for (int iml : {1, 2}) {
967  int il = (iml == 1) ? 0 : orderedClusters.size() - 1;
968  int iend = (iml == 1) ? orderedClusters.size() : -1;
969  int idir = (iml == 1) ? 1 : -1;
970  unsigned int nLayersWithHitMatch{0};
971 
972  // Loop on layers (reverse loop for HO)
973  for (; il != iend; il += idir) {
974  double lastDistance{1000.};
975  if (nLayersWithHitMatch >= sTgcIP.size()) {
976  sTgcIP.resize(nLayersWithHitMatch + 1);
977  sTgcHO.resize(nLayersWithHitMatch + 1);
978  }
979  std::vector<const Muon::sTgcPrepData*>& matchedHits =
980  (iml == 1) ? sTgcIP.at(nLayersWithHitMatch) : sTgcHO.at(nLayersWithHitMatch);
981 
982  // Loop on the hits on this layer. Find the one closest (in eta) to the segment intersection.
983  for (const Muon::MuonClusterOnTrack* rio : orderedClusters[il]) {
984  const sTgcPrepData* padHit = dynamic_cast<const sTgcPrepData*>(rio->prepRawData());
985  if (!padHit) continue;
986 
987  // check the multilayer the hit is on
988  if (m_idHelperSvc->stgcIdHelper().multilayer(padHit->identify()) != iml) continue;
989 
990  const MuonGM::MuonPadDesign* design = padHit->detectorElement()->getPadDesign(padHit->identify());
991  if (!design) continue;
992 
993  // local position of the segment intersection with the plane
994  const Trk::Surface& surf = padHit->detectorElement()->surface(padHit->identify());
996  surf.straightLineIntersection(etaSeg.globalPosition(), etaSeg.globalDirection(), false, false);
997  Amg::Vector2D segLocPosOnSurf{Amg::Vector2D::Zero()};
998  surf.globalToLocal(intersect.position, intersect.position, segLocPosOnSurf);
999 
1000  // eta distance between the hit and the segment intersection with the plane
1001  // check that it's no more than half of the pad eta-pitch.
1002  double chWidth = design->channelWidth(padHit->localPosition(), false);
1003  double etaDistance = std::abs(padHit->localPosition().y() - segLocPosOnSurf[1]);
1004  if (etaDistance > 0.5 * chWidth) continue;
1005  ATH_MSG_DEBUG(" etaDistance " << etaDistance << " between pad center and position on the pad.");
1006 
1007  if (matchedHits.empty()) {
1008  // first hit
1009  matchedHits.push_back(padHit);
1010  ATH_MSG_DEBUG(" best etaDistance: " << etaDistance);
1011  } else if (std::abs(etaDistance - lastDistance) < 0.001) {
1012  // competing hit pad, keep both (all hit pads of the same eta row will be candidates)
1013  matchedHits.push_back(padHit);
1014  ATH_MSG_DEBUG(" added etaDistance: " << etaDistance << " size " << matchedHits.size());
1015  } else if (etaDistance < lastDistance) {
1016  // found a better hit; clear the old ones (possible only for clustered pad hits)
1017  matchedHits.clear();
1018  matchedHits.push_back(padHit);
1019  ATH_MSG_DEBUG(" replacing best etaDistance with: " << etaDistance);
1020  } else {
1021  continue;
1022  }
1023  lastDistance = etaDistance;
1024  } // end of loop on hits
1025 
1026  if (!matchedHits.empty()) ++nLayersWithHitMatch;
1027 
1028  } // end of loop on layers
1029 
1030  // need at least one hit in each multilayer to create a seed
1031  if (!nLayersWithHitMatch) return seeds;
1032 
1033  } // end of loop on multilayers
1034 
1035  // get refined phi ranges on each ml, by taking into account pad staggering
1036  std::vector<std::pair<double, double>> sTgcIP_phiRanges = getPadPhiOverlap(sTgcIP);
1037  std::vector<std::pair<double, double>> sTgcHO_phiRanges = getPadPhiOverlap(sTgcHO);
1038 
1039  // reference prds on the outermost hit surfaces
1040  const sTgcPrepData* prdL1 = sTgcIP.front().front();
1041  const sTgcPrepData* prdL2 = sTgcHO.front().front();
1042  const auto& surfPrdL1 = prdL1->detectorElement()->surface();
1043  const auto& surfPrdL2 = prdL2->detectorElement()->surface();
1044 
1045  // create a seed for each combination of IP and HO points
1046  for (const std::pair<double, double>& range1 : sTgcIP_phiRanges) {
1047  double midPhi1 = 0.5 * (range1.first + range1.second);
1048  Amg::Vector2D lp1(midPhi1, prdL1->localPosition().y());
1050  surfPrdL1.localToGlobal(lp1, gpL1, gpL1);
1051 
1052  for (const std::pair<double, double>& range2 : sTgcHO_phiRanges) {
1053  double midPhi2 = 0.5 * (range2.first + range2.second);
1054  Amg::Vector2D lp2(midPhi2, prdL2->localPosition().y());
1056  surfPrdL2.localToGlobal(lp2, gpL2, gpL2);
1057  // create the seed taking the average position (w.r.t. IP)
1058  // as global direction (as for an infinite momentum track).
1059  Amg::Vector3D gDir = (gpL2 + gpL1).unit();
1060  seeds.emplace_back(this, gpL1, gDir);
1061  }
1062  }
1063 
1064  ATH_MSG_DEBUG(" segmentSeedFromPads: seeds.size() " << seeds.size());
1065  return seeds;
1066  }
1067 
1068  //============================================================================
1070  const LayerMeasVec& orderedClusters) const {
1071  std::vector<NSWSeed> seeds;
1072  std::array<unsigned int, 4> layers{};
1073  unsigned int trials{0}, used_layers{0};
1075  constexpr size_t lastMMLay = 11;
1076  std::vector<NSWSeed> laySeeds;
1077 
1079  std::stringstream sstr{};
1080  for (int e4 = std::min(lastMMLay, orderedClusters.size() -1); e4 >= 3 ; --e4) {
1081  layers[3] = e4;
1082  for (int e3 = e4 -1 ; e3 >= 2; --e3) {
1083  layers[2] = e3;
1084  for (int e2 = 1 ; e2 < e3; ++e2) {
1085  layers[1] = e2;
1086  for (int e1= 0; e1< e2; ++e1) {
1087  layers[0] = e1;
1088  const unsigned int old_trials = trials;
1089  laySeeds = segmentSeedFromMM(orderedClusters,layers, trials);
1090  if (old_trials == trials) continue;
1091 
1092  used_layers += !laySeeds.empty();
1093  seeds.insert(seeds.end(), std::make_move_iterator(laySeeds.begin()),
1094  std::make_move_iterator(laySeeds.end()));
1095 
1096  if (msgLvl(MSG::VERBOSE)) {
1097  sstr<<" Attempts thus far "<<old_trials<<" attempts now "<<trials<<" --- "<<e1<<","<<e2<<","<<e3<<","<<e4<<std::endl;
1098  for (int lay : layers) {
1099  sstr<<"Layer: "<<lay<<" number of measurements "<<orderedClusters[lay].size()<<std::endl;
1100  for (const SeedMeasurement& meas : orderedClusters[lay] ){
1101  sstr<<" **** "<< print(meas)<<std::endl;
1102  }
1103  sstr<<std::endl<<std::endl<<std::endl;
1104  }
1105  }
1106  }
1107  }
1108  }
1109  }
1110  if (trials > 100000) {
1111  ATH_MSG_VERBOSE(sstr.str());
1112  }
1113  ATH_MSG_VERBOSE("Out of "<<trials<<" possible seeds, "<<seeds.size()<<" were finally built. Used in total "<<used_layers<<" layers");
1114  return resolveAmbiguities(std::move(seeds));
1115  }
1116 
1117  #if defined(FLATTEN)
1118  ATH_FLATTEN
1119  #endif
1120  inline std::vector<NSWSeed> MuonNSWSegmentFinderTool::segmentSeedFromMM(const LayerMeasVec& orderedClusters,
1121  std::array<unsigned int,4> selLayers,
1122  unsigned int& trial_counter) const {
1123  std::vector<NSWSeed> seeds{};
1124 
1125  std::array<unsigned int, 4> lay_ord{};
1126  for (size_t s = 0; s < selLayers.size(); ++s) {
1127  unsigned int lay = selLayers[s];
1128  const SeedMeasurement& seed = orderedClusters[lay].front();
1129  const Identifier id = seed->identify();
1130  if (!m_idHelperSvc->isMM(id)) return seeds;
1131  const MuonGM::MuonChannelDesign* design = getDesign(seed);
1133  if (!design->hasStereoAngle()) lay_ord[s] = 1;
1134  else if (design->stereoAngle() >0.) lay_ord[s] = 2;
1135  else lay_ord[s] = 3;
1136  }
1137  auto swap_strips = [&selLayers, &lay_ord] (unsigned int i, unsigned j){
1138  std::swap(lay_ord[i], lay_ord[j]);
1139  std::swap(selLayers[i],selLayers[j]);
1140  };
1142  if (lay_ord[0] == lay_ord[1]){
1143  if (lay_ord[1] != lay_ord[2]) swap_strips(1,2);
1144  else if (lay_ord[1] != lay_ord[3]) swap_strips(1,3);
1145  else {
1146  ATH_MSG_VERBOSE("Strips are all parallel.");
1147  return seeds;
1148  }
1149  }
1151  if (lay_ord[2] == lay_ord[3]) {
1152  // Check if the last hit can be exchanged by the first one.
1153  // But also ensure that the second and fourth are not the same
1154  if (lay_ord[3] != lay_ord[0] && lay_ord[3] != lay_ord[1]) swap_strips(3,0);
1155  else {
1156  ATH_MSG_VERBOSE("No way to rearrange the strips such that the latter two strips cross.");
1157  return seeds;
1158  }
1159  }
1161  std::array<SeedMeasurement, 4> base_seed{};
1162  for (size_t s = 0; s < selLayers.size(); ++s) {
1163  unsigned int lay = selLayers[s];
1164  base_seed[s] = orderedClusters[lay].front();
1165  }
1166 
1167  const double A = (base_seed[1].pos().z() - base_seed[0].pos().z());
1168  const double G = (base_seed[2].pos().z() - base_seed[0].pos().z());
1169  const double K = (base_seed[3].pos().z() - base_seed[0].pos().z());
1170 
1171  AmgSymMatrix(2) diamond{AmgSymMatrix(2)::Zero()};
1172  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);
1173  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);
1174 
1175  if (std::abs(diamond.determinant()) < std::numeric_limits<float>::epsilon()) {
1176  ATH_MSG_VERBOSE(" The seed built from " << printSeed(base_seed) << " cannot constrain phi as " << std::endl
1177  << diamond << std::endl
1178  << " is singular " << diamond.determinant() << " with rank "
1179  << (Eigen::FullPivLU<AmgSymMatrix(2)>{diamond}.rank()));
1180 
1181  return seeds;
1182  }
1183  ATH_MSG_VERBOSE("The combination of " << printSeed(base_seed) << " to " << std::endl
1184  << diamond << std::endl
1185  << "May give a couple of stereo seeds " << diamond.determinant());
1186 
1188  const AmgSymMatrix(2) seed_builder = diamond.inverse();
1190  const double KmG = K-G;
1191  const double KmA = K-A;
1192  const double AmG = A-G;
1193 
1194  const double TwoDotZero = base_seed[2].dirDot(base_seed[0]);
1195  const double ThreeDotZero = base_seed[3].dirDot(base_seed[0]);
1196  const double ThreeDotOne = base_seed[3].dirDot(base_seed[1]);
1197  const double TwoDotOne = base_seed[2].dirDot(base_seed[1]);
1198 
1199  auto estimate_muon = [&] () -> std::optional<std::array<double,2>> {
1200  const Amg::Vector3D Y0 = K * base_seed[2].pos() - G * base_seed[3].pos() - KmG * base_seed[0].pos();
1201  const Amg::Vector3D Y1 = AmG * base_seed[3].pos() - KmG * base_seed[1].pos() + KmA * base_seed[2].pos();
1202  const double Y0dotE0 = base_seed[0].dirDot(Y0);
1203  const double Y1dotE1 = base_seed[1].dirDot(Y1);
1204 
1205  const AmgVector(2) centers = (KmG * (base_seed[0].pos() - base_seed[1].pos()) +
1206  Y0dotE0 * base_seed[0].dir() +
1207  A * (base_seed[3].pos() - base_seed[2].pos()) -
1208  Y1dotE1 * base_seed[1].dir())
1209  .block<2, 1>(0, 0);
1210 
1211  const AmgVector(2) sol_pars = seed_builder * centers;
1212  const std::array<double, 4> lengths{(Y0dotE0 + K * sol_pars[0] * TwoDotZero - G * sol_pars[1] * ThreeDotZero) / KmG,
1213  (Y1dotE1 + AmG * sol_pars[1] *ThreeDotOne + KmA * sol_pars[0] * TwoDotOne) / KmG, sol_pars[0], sol_pars[1]};
1214  bool accept{true};
1215  ATH_MSG_VERBOSE("Check intersections of "<<printSeed(base_seed));
1216  constexpr double tolerance = 10.* Gaudi::Units::mm;
1217  std::optional<Amg::Vector3D> seg_pos{std::nullopt}, seg_dir{std::nullopt};
1218  for (unsigned int i = 0; i < base_seed.size(); ++i) {
1219  const MuonGM::MuonChannelDesign* design = getDesign(base_seed[i]);
1220  const double halfLength = design->channelHalfLength(channel(base_seed[i]), true);
1221  accept &= (halfLength + tolerance > std::abs(lengths[i]));
1222  if (msgLvl(MSG::VERBOSE)) {
1223  if (!seg_pos) {
1224  seg_pos = std::make_optional<Amg::Vector3D>(base_seed[0].pos() +
1225  lengths[0] * base_seed[0].dir());
1226  ATH_MSG_VERBOSE("Position "<<to_string(*seg_pos));
1227  }
1228  if (!seg_dir){
1229  seg_dir = std::make_optional<Amg::Vector3D>((base_seed[1].pos() +
1230  lengths[1] *base_seed[1].dir() - (*seg_pos)).unit());
1231  ATH_MSG_VERBOSE("Direction "<<to_string(*seg_dir));
1232  }
1233  std::optional<double> mu_crossing = Amg::intersect<3>(*seg_pos, *seg_dir, base_seed[i].pos(),base_seed[i].dir());
1234  ATH_MSG_VERBOSE(" ----- "<<(i+1)<<" at "<<to_string(base_seed[i].pos() + lengths[i]*base_seed[i].dir())
1235  << " ("<< std::string( halfLength > std::abs(lengths[i]) ? "inside" : "outside")<<" wedge) "
1236  << halfLength <<" vs. "<<std::abs(lengths[i])<<" crossing point: "<<std::abs(*mu_crossing));
1237  } else if (!accept) return std::nullopt;
1238  }
1239  if (!accept) return std::nullopt;
1240  return std::make_optional<std::array<double,2>>({lengths[0], lengths[1]});
1241  };
1242 
1244  seeds.reserve(200);
1245  MeasVec::const_iterator begin2{orderedClusters[selLayers[1]].begin()};
1246  MeasVec::const_iterator begin3{orderedClusters[selLayers[2]].begin()};
1247  MeasVec::const_iterator begin4{orderedClusters[selLayers[3]].begin()};
1248 
1249  const MeasVec::const_iterator end2{orderedClusters[selLayers[1]].end()};
1250  const MeasVec::const_iterator end3{orderedClusters[selLayers[2]].end()};
1251  const MeasVec::const_iterator end4{orderedClusters[selLayers[3]].end()};
1252 
1253  for (const SeedMeasurement& lay1 : orderedClusters[selLayers[0]]) {
1254  base_seed[0] = lay1;
1255  for (MeasVec::const_iterator lay2 = begin2; lay2 != end2; ++lay2) {
1256 
1257  base_seed[1] = *lay2;
1258  ChannelConstraint chCheck = compatiblyFromIP(lay1, *lay2);
1261  if (chCheck == ChannelConstraint::TooNarrow) {
1262  begin2 = lay2 + 1;
1263  continue;
1264  }
1266  else if (chCheck == ChannelConstraint::TooWide) {
1267  break;
1268  }
1270  for (MeasVec::const_iterator lay3 = begin3; lay3 != end3; ++lay3) {
1271  chCheck = compatiblyFromIP(lay1, *lay3);
1272  const ChannelConstraint chCheck1 = compatiblyFromIP(*lay2, *lay3);
1273  if (chCheck == ChannelConstraint::TooNarrow && chCheck1 == ChannelConstraint::TooNarrow) {
1274  begin3 = lay3 + 1;
1275  continue;
1276  } else if (chCheck == ChannelConstraint::TooWide && chCheck1 == ChannelConstraint::TooWide) {
1277  break;
1278  }
1279  base_seed[2] = *lay3;
1281  for (MeasVec::const_iterator lay4 = begin4 ; lay4 != end4; ++lay4) {
1282  chCheck = compatiblyFromIP(*lay3, *lay4);
1283  if (chCheck == ChannelConstraint::TooNarrow) {
1284  begin4 = lay4 + 1;
1285  continue;
1286  } else if (chCheck == ChannelConstraint::TooWide) {
1287  break;
1288  }
1289 
1290  base_seed[3] = (*lay4);
1291  std::optional<std::array<double, 2>> isects = estimate_muon();
1292  ++trial_counter;
1293  if (!isects) continue;
1294  NSWSeed seed{this, base_seed, *isects};
1295 
1296  if (seed.size() < 4) continue;
1297  if (m_ipConstraint) {
1298  const double eta = std::abs(seed.dir().eta());
1299  if (eta < minEtaNSW || eta > maxEtaNSW) {
1300  continue;
1301  }
1302  if (seed.dir().block<2,1>(0,0).dot(seed.pos().block<2,1>(0,0)) < 0.) continue;
1304  static const Muon::MuonSectorMapping sector_mapping{};
1305  const double deltaPhi = std::abs(seed.dir().deltaPhi(seed.pos()));
1306  if (deltaPhi > sector_mapping.sectorWidth(m_idHelperSvc->sector(base_seed[0]->identify()))) continue;
1307  }
1308  getClustersOnSegment(orderedClusters, seed, {selLayers[0], selLayers[1],selLayers[2], selLayers[3]});
1309  seeds.emplace_back(std::move(seed));
1310  }
1311  }
1312  }
1313  }
1314  return seeds;
1315  }
1319 
1320  // For a given dZ the measurements can only be separated by a certain dR such that the
1322  const double dZ = std::abs(meas2->globalPosition().z()) -
1323  std::abs(meas1->globalPosition().z());
1324 
1328  static const double minTanTheta = 0.75 / std::sinh(maxEtaNSW);
1329  static const double maxTanTheta = 1.25 / std::sinh(minEtaNSW);
1330 
1331  const double minDR = minTanTheta * std::abs(dZ);
1332  const double maxDR = maxTanTheta * std::abs(dZ);
1333 
1334  const std::pair<double, double> rad1 = coveredRadii(meas1);
1335  const std::pair<double, double> rad2 = coveredRadii(meas2);
1337  const double dlR = rad2.first - rad1.first;
1338  const double drR = rad2.second - rad1.second;
1339  ATH_MSG_VERBOSE("compatiblyFromIP() -- Measurements "<<std::endl
1340  <<print(meas1)<<std::endl<<print(meas2)
1341  <<std::endl<<". Separation in dR (left/right) "<<dlR<<"/"<<drR<<", dZ "<<dZ
1342  <<" --> dR has to be in "<<minDR<<" "<<maxDR);
1343  if ((std::abs(dlR) < minDR && std::abs(drR) < minDR) ||
1344  (dZ > 0 && dlR <0 && drR <0) || (dZ < 0 && dlR >0 && drR > 0)) {
1346  } if (std::abs(dlR) > maxDR && std::abs(drR) > maxDR && dlR * drR > 0.){
1348  }
1350  }
1351  inline std::pair<double, double> MuonNSWSegmentFinderTool::coveredRadii(const SeedMeasurement& meas) const {
1352  const MuonGM::MuonChannelDesign* design = getDesign(meas);
1353  const int chNum = channel(meas);
1355  design->leftEdge(chNum, left);
1356  design->rightEdge(chNum, right);
1357  const double radLeft{meas->associatedSurface().localToGlobal(left).perp()};
1358  const double radRight{meas->associatedSurface().localToGlobal(right).perp()};
1359  return std::make_pair(radLeft, radRight);
1360  }
1361  std::vector<NSWSeed> MuonNSWSegmentFinderTool::resolveAmbiguities(std::vector<NSWSeed>&& unresolved) const {
1362  std::vector<NSWSeed> seeds;
1363  seeds.reserve(unresolved.size());
1364  std::sort(unresolved.begin(), unresolved.end(),[](const NSWSeed& a, const NSWSeed& b){
1365  return a.chi2() < b.chi2();
1366  });
1367  for (NSWSeed& seed : unresolved) {
1368  bool add_seed{true};
1369  for (NSWSeed& good : seeds) {
1370  NSWSeed::SeedOR ov = good.overlap(seed);
1371  if (ov == NSWSeed::SeedOR::SubSet) {
1372  std::swap(seed, good);
1373  add_seed = false;
1374  break;
1375  } else if (ov == NSWSeed::SeedOR::Same || ov == NSWSeed::SeedOR::SuperSet) {
1376  add_seed = false;
1377  break;
1378  }
1379  }
1380  if (add_seed) seeds.push_back(std::move(seed));
1381  }
1382  ATH_MSG_VERBOSE(seeds.size()<<" out of "<<unresolved.size()<<" passed the overlap removal");
1383  return seeds;
1384  }
1385 
1386  //============================================================================
1387  std::vector<std::pair<double, double>> MuonNSWSegmentFinderTool::getPadPhiOverlap(
1388  const std::vector<std::vector<const Muon::sTgcPrepData*>>& pads) const {
1389  // 'pads' contains segment hit candidates, classified in four layers (IP or HO).
1390  // Layers are ordered; for IP, the layer with hits that is nearest to
1391  // the IP is first, while for HO, the one furthest from the IP is first.
1392 
1393  std::vector<std::vector<double>> padsPhiL, padsPhiR;
1394  std::vector<double> padsPhiC;
1395 
1396  // Loop on layers
1397  for (const std::vector<const Muon::sTgcPrepData*>& surfHits : pads) {
1398  // Loop on layer hits
1399  std::vector<double> surfPadsPhiL, surfPadsPhiR;
1400  for (const Muon::sTgcPrepData* prd : surfHits) {
1401  const Identifier id = prd->identify();
1402  const MuonGM::MuonPadDesign* design = prd->detectorElement()->getPadDesign(id);
1403  if (!design) {
1404  ATH_MSG_WARNING("No design available for " << m_idHelperSvc->toString(id));
1405  continue;
1406  }
1407 
1408  // Phi boundaries of this pad in local coordinates
1409  const double halfWidthX = 0.5 * design->channelWidth(prd->localPosition(), true);
1410  const double hitPadX = prd->localPosition().x(); // x is in the phi direction
1411 
1412  // Reject hit candidates on pads too close (in phi) to any pad kept so far
1413  // (pad fuzziness) to constrain the number of combinations.
1414  bool samePhi = std::find_if(padsPhiC.begin(), padsPhiC.end(), [&hitPadX, &halfWidthX](const double prevPadPhi) {
1415  return std::abs(hitPadX - prevPadPhi) < 0.9 * halfWidthX;
1416  }) != padsPhiC.end();
1417 
1418  if (samePhi) continue;
1419 
1420  // Store the new pad candidate
1421  surfPadsPhiL.push_back(hitPadX - halfWidthX);
1422  surfPadsPhiR.push_back(hitPadX + halfWidthX);
1423  padsPhiC.push_back(hitPadX);
1424  ATH_MSG_DEBUG(" keep pad id " << m_idHelperSvc->toString(id) << " local x: " << hitPadX << " width: " << halfWidthX);
1425  }
1426 
1427  padsPhiL.push_back(std::move(surfPadsPhiL));
1428  padsPhiR.push_back(std::move(surfPadsPhiR));
1429  }
1430 
1431  unsigned int nSurf = padsPhiR.size();
1432 
1433  // number of combinations we can make out of pads in different layers
1434  // we want to keep combinations of overlapping pads.
1435  unsigned int nCombos{1};
1436  for (const std::vector<double>& surfPadsPhiR : padsPhiR) {
1437  if (!surfPadsPhiR.empty()) nCombos *= surfPadsPhiR.size();
1438  }
1439 
1440  std::vector<std::pair<double, double>> phiOverlap;
1441  phiOverlap.reserve(nCombos);
1442 
1443  if (nCombos <= 100) {
1444  unsigned int N{nCombos};
1445  for (unsigned int isurf{0}; isurf < nSurf; ++isurf) {
1446  if (padsPhiR[isurf].empty()) continue;
1447  unsigned int nSurfHits = padsPhiR[isurf].size();
1448  N /= nSurfHits;
1449 
1450  for (unsigned int icombo{0}; icombo < nCombos; ++icombo) {
1451  // index of the pad that corresponds to this combination
1452  unsigned int padIdx = (icombo / N) % nSurfHits;
1453  if (isurf == 0) {
1454  // first surface: just add the range of each hit pad
1455  phiOverlap.emplace_back(padsPhiL[isurf][padIdx], padsPhiR[isurf][padIdx]);
1456  } else {
1457  // subsequent surfaces: use staggering to narrow the phi ranges
1458  phiOverlap[icombo].first = std::max(padsPhiL[isurf][padIdx], phiOverlap[icombo].first);
1459  phiOverlap[icombo].second = std::min(padsPhiR[isurf][padIdx], phiOverlap[icombo].second);
1460  }
1461  }
1462  }
1463 
1464  // delete bad combinations with xmin > xmax (indicates non overlapping pads)
1465  phiOverlap.erase(std::remove_if(phiOverlap.begin(), phiOverlap.end(),
1466  [](std::pair<double, double>& range) { return range.first >= range.second; }),
1467  phiOverlap.end());
1468  ATH_MSG_DEBUG("Pad seeding - #combinations initial: " << nCombos
1469  << ", after cleaning for non overlapping pads: " << phiOverlap.size());
1470 
1471  } else {
1472  // in case combinations are too many, store the phi ranges of individual pads
1473  for (unsigned int isurf{0}; isurf < nSurf; ++isurf) {
1474  unsigned int nSurfHits = padsPhiR[isurf].size();
1475  for (unsigned int ihit{0}; ihit < nSurfHits; ++ihit) {
1476  phiOverlap.emplace_back(padsPhiL[isurf][ihit], padsPhiR[isurf][ihit]);
1477  }
1478  }
1479  ATH_MSG_DEBUG("Pad seeding - #combinations: " << nCombos << " is too large. Seeding from" << phiOverlap.size()
1480  << " individual pads.");
1481  }
1482 
1483  return phiOverlap;
1484  }
1485 
1486  //============================================================================
1488 
1489  MeasVec calibratedClusters;
1490  MeasVec clusters = seed.measurements();
1491 
1492  // loop on the segment clusters and use the phi of the seed to correct them
1493  for (const SeedMeasurement& clus : clusters) {
1494  std::unique_ptr<const Muon::MuonClusterOnTrack> newClus;
1495 
1496  // get the intercept of the seed direction with the cluster surface
1497  const Identifier hitID = clus->identify();
1498  const Trk::Surface& surf = clus->associatedSurface();
1499  Trk::Intersection intersect = surf.straightLineIntersection(seed.pos(), seed.dir(), false, false);
1500 
1501  if (m_idHelperSvc->isMM(hitID)) {
1502  // build a new MM cluster on track with correct position
1503  std::unique_ptr<const Muon::MuonClusterOnTrack> newClus {m_muonClusterCreator->correct(*clus->prepRawData(), intersect.position, seed.dir())};
1504  calibratedClusters.emplace_back(seed.newCalibClust(std::move(newClus)));
1505  } else if (m_idHelperSvc->issTgc(hitID)) {
1506  // build a new sTGC cluster on track with correct position
1507  std::unique_ptr<const Muon::MuonClusterOnTrack> newClus {m_muonClusterCreator->correct(*clus->prepRawData(), intersect.position, seed.dir())};
1508  calibratedClusters.emplace_back(seed.newCalibClust(std::move(newClus)));
1509  }
1510  }
1511 
1512  return calibratedClusters;
1513  }
1514 
1515  //============================================================================
1516  template <size_t N>
1517  std::string MuonNSWSegmentFinderTool::printSeed(const std::array<SeedMeasurement, N>& seed) const {
1518  std::stringstream sstr{};
1519  sstr << std::endl;
1520  for (const SeedMeasurement& cl : seed) sstr << " *** " << print(cl) << std::endl;
1521  return sstr.str();
1522  }
1523 
1524  //============================================================================
1526  std::stringstream sstr{};
1527  sstr << m_idHelperSvc->toString(cl->identify()) << " at " <<to_string(cl.pos())
1528  <<" pointing to (" <<to_string(cl.dir())<<" cluster size: "<<clusterSize(cl);
1529 
1530  return sstr.str();
1531  }
1532  std::string MuonNSWSegmentFinderTool::print(const MeasVec& measurements) const {
1533  std::stringstream sstr{};
1534  for (const SeedMeasurement& cl : measurements){
1535  sstr<<" *** "<<print(cl)<<std::endl;
1536  }
1537  return sstr.str();
1538  }
1539  std::string MuonNSWSegmentFinderTool::print(const LayerMeasVec& sortedVec) const {
1540  std::stringstream sstr{};
1541  unsigned int lay{0};
1542  for (const MeasVec& clusts: sortedVec){
1543  sstr<<"Clusters in Layer: "<<(lay+1)<<std::endl;
1544  sstr<<"#################################################"<<std::endl;
1545  sstr<<print(clusts);
1546  ++lay;
1547  }
1548  return sstr.str();
1549  }
1550 
1552  if (clustInLay.size() < m_ocupMmNumPerBin || m_idHelperSvc->issTgc(clustInLay[0]->identify())) return clustInLay;
1558  MeasVec prunedMeas{};
1559  prunedMeas.reserve(clustInLay.size());
1560  const unsigned int firstCh = channel(clustInLay[0]);
1561  const unsigned int lastCh = channel(clustInLay[clustInLay.size() -1]);
1563  const unsigned int deltaCh = lastCh - firstCh;
1564  const unsigned int nBins = deltaCh / m_ocupMmBinWidth + (deltaCh % m_ocupMmBinWidth > 0);
1565  ATH_MSG_VERBOSE("Clusters in layer "<<print(clustInLay)<<" lowest channel: "<<
1566  firstCh<<", highest channel: "<<lastCh<<" bin width: "<<m_ocupMmBinWidth<<" number of bins"<<nBins);
1567 
1568  LayerMeasVec occupancyHisto{};
1569  occupancyHisto.resize(nBins);
1570  for (MeasVec& bin : occupancyHisto) {
1571  bin.reserve(clustInLay.size());
1572  }
1573  ATH_MSG_VERBOSE("Clusters sorted into bins "<<print(occupancyHisto));
1575  for (SeedMeasurement& meas : clustInLay){
1576  unsigned int bin = (channel(meas) - firstCh) % nBins;
1577  occupancyHisto[bin].push_back(std::move(meas));
1578  }
1580  for (MeasVec& bin : occupancyHisto) {
1581  if(bin.size() >= m_ocupMmNumPerBin){
1582  ATH_MSG_VERBOSE("The micromegas are slobbering. Detected too many clusters "<<bin.size()<<std::endl<<print(bin));
1583  bin.clear();
1584  }
1585  }
1587  for (unsigned int i = 0; i < occupancyHisto.size() -1; ++i) {
1588  if (occupancyHisto[i].size() + occupancyHisto[i+1].size() >= m_ocupMmNumPerPair){
1589  ATH_MSG_VERBOSE("The two neighbouring bins "<<i<<"&"<<(i+1)<<" have too many clusters "<<std::endl<<
1590  print(occupancyHisto[i])<<std::endl<<print(occupancyHisto[i+1]));
1591  occupancyHisto[i].clear();
1592  occupancyHisto[i+1].clear();
1593  }
1594  }
1596  for (MeasVec& bin : occupancyHisto){
1597  std::copy(std::make_move_iterator(bin.begin()),
1598  std::make_move_iterator(bin.end()),
1599  std::back_inserter(prunedMeas));
1600  }
1601 
1602  ATH_MSG_VERBOSE("Number of measurements before pruning "<<clustInLay.size()<<" number of measurments survived the pruning "<<prunedMeas.size());
1603  return prunedMeas;
1604 
1605  }
1606 } // 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:1351
Trk::LocalParameters
Definition: LocalParameters.h:98
Muon::MuonNSWSegmentFinderTool::printSeed
std::string printSeed(const std::array< SeedMeasurement, N > &seed) const
Definition: MuonNSWSegmentFinderTool.cxx:1517
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:215
python.SystemOfUnits.second
int second
Definition: SystemOfUnits.py:120
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:244
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:1525
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:715
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
python.SystemOfUnits.s
int s
Definition: SystemOfUnits.py:131
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.m
int m
Definition: SystemOfUnits.py:91
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:1387
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:351
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:472
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:160
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:134
Muon::MuonNSWSegmentFinderTool::ChannelConstraint
ChannelConstraint
Definition: MuonNSWSegmentFinderTool.h:296
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:114
compute_lumi.divisor
divisor
Definition: compute_lumi.py:60
Muon::MuonNSWSegmentFinderTool::segmentSeedFromMM
std::vector< NSWSeed > segmentSeedFromMM(const LayerMeasVec &orderedClusters) const
Definition: MuonNSWSegmentFinderTool.cxx:1069
plotBeamSpotVxVal.cov
cov
Definition: plotBeamSpotVxVal.py:201
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:728
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::PrepRawData::type
virtual bool type(PrepRawDataType type) const =0
Interface method checking the type.
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:786
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:1317
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:85
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
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:705
Muon::MuonNSWSegmentFinderTool::classifyByLayer
LayerMeasVec classifyByLayer(const MeasVec &clusters, int hit_sel) const
Definition: MuonNSWSegmentFinderTool.cxx:806
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:1551
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
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
Muon::MuonNSWSegmentFinderTool::isWire
bool isWire(const Muon::MuonClusterOnTrack *clust) const
Definition: MuonNSWSegmentFinderTool.cxx:723
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:195
PseudoMeasurementOnTrack.h
test_pyathena.parent
parent
Definition: test_pyathena.py:15
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:924
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:262
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
python.SystemOfUnits.micrometer
int micrometer
Definition: SystemOfUnits.py:71
MuonReadoutElement.h
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:623
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:387
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:202
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:855
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
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:77
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:83
Trk::nonInteracting
@ nonInteracting
Definition: ParticleHypothesis.h:25
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:225
Muon::MuonNSWSegmentFinderTool::segmentSeedFromPads
std::vector< NSWSeed > segmentSeedFromPads(const LayerMeasVec &orderedClusters, const Muon::MuonSegment &etaSeg) const
Definition: MuonNSWSegmentFinderTool.cxx:956
python.LumiBlobConversion.pos
pos
Definition: LumiBlobConversion.py:18
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.SystemOfUnits.mm
int mm
Definition: SystemOfUnits.py:83
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:139
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:536
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:914
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:907
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:575
Muon::IMuonIdHelperSvc
Interface for Helper service that creates muon Identifiers and can be used to print Identifiers.
Definition: IMuonIdHelperSvc.h:27
Muon::NSWSeed::SeedOR::Same
@ Same
Muon::MuonNSWSegmentFinderTool::getClustersOnSegment
int getClustersOnSegment(const LayerMeasVec &orderedclusters, NSWSeed &seed, const std::set< unsigned int > &exclude, bool useStereo=true) const
Definition: MuonNSWSegmentFinderTool.cxx:931
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:688
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:441
Trk::Segment::NswQuadAlign
@ NswQuadAlign
Definition: Tracking/TrkEvent/TrkSegment/TrkSegment/Segment.h:79
calibdata.copy
bool copy
Definition: calibdata.py:27
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:204
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:75
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:1487
dq_make_web_display.cl
cl
print [x.__class__ for x in toList(dqregion.getSubRegions()) ]
Definition: dq_make_web_display.py:26
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:1361
Muon::MuonNSWSegmentFinderTool::isStrip
bool isStrip(const Muon::MuonClusterOnTrack *clust) const
Definition: MuonNSWSegmentFinderTool.cxx:719
python.SystemOfUnits.degree
tuple degree
Definition: SystemOfUnits.py:106
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
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:201
Muon::NSWSeed::SeedOR::SubSet
@ SubSet