ATLAS Offline Software
MaterialAllocator.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3  */
4 
5 /***************************************************************************
6  least squared fit to track hit data => PerigeeParameters with covariance
7  and fit quality.
8 ***************************************************************************/
9 
11 
12 #include <cmath>
13 #include <iomanip>
14 
15 #include "GaudiKernel/SystemOfUnits.h"
26 #include "TrkSurfaces/Surface.h"
27 #include "TrkTrack/Track.h"
33 
34 namespace Trk {
36  const std::string& name,
37  const IInterface* parent)
39  m_aggregateMaterial(true),
40  m_allowReordering(false),
41  m_useStepPropagator(1),
42  m_maxWarnings(10),
43  m_orderingTolerance(1. * Gaudi::Units::mm),
44  m_scattererMinGap(100. * Gaudi::Units::mm),
45  m_scatteringConstant(13.6 *
46  Gaudi::Units::MeV), // Coulomb scattering constant
47  m_scatteringLogCoeff(0.038), // Coulomb scattering constant
48  m_sectorMaxPhi(0.28),
49  m_stationMaxGap(0.6 * Gaudi::Units::meter),
50  m_calorimeterVolume(nullptr),
51  m_indetVolume(nullptr),
52  m_messageHelper(nullptr) {
53  m_messageHelper = std::make_unique<MessageHelper>(*this, 6);
54  declareInterface<IMaterialAllocator>(this);
55 
56  declareProperty("AggregateMaterial", m_aggregateMaterial);
57  declareProperty("AllowReordering", m_allowReordering);
58 
59  // m_useStepPropagator 0 means not used (so Intersector used)
60  // 1 Intersector not used and StepPropagator used with FullField
61  // 2 StepPropagator with FastField propagation
62  // 99 debug mode where both are ran with FullField
63 
64  declareProperty("UseStepPropagator", m_useStepPropagator);
65  declareProperty("OrderingTolerance", m_orderingTolerance);
66  declareProperty(
67  "MaxNumberOfWarnings", m_maxWarnings,
68  "Maximum number of permitted WARNING messages per message type.");
69 }
70 
72  // fill WARNING messages
73  m_messageHelper->setMaxNumberOfMessagesPrinted(m_maxWarnings);
74  m_messageHelper->setMessage(
75  0,
76  "leadingSpectrometerTSOS: missing TrackingGeometrySvc - no leading "
77  "material will be added");
78  m_messageHelper->setMessage(
79  1, "indetMaterial: extrapolateM finds no material on track");
80  m_messageHelper->setMessage(
81  2,
82  "spectrometerMaterial: missing TrackingGeometrySvc - no spectrometer "
83  "material added");
84  m_messageHelper->setMessage(3,
85  "spectrometerMaterial: did not find MS entrance "
86  "surface - no MS material taken into account");
87  m_messageHelper->setMessage(4, "spectrometerMaterial: failed extrapolation");
88  m_messageHelper->setMessage(
89  5, "spectrometerMaterial: extrapolateM finds no material on track");
90 
91  // retrieve the necessary Extrapolators (muon tracking geometry is very
92  // picky!)
93  ATH_CHECK(m_extrapolator.retrieve());
94  ATH_MSG_DEBUG("Retrieved tool " << m_extrapolator);
95 
96  ATH_CHECK(m_intersector.retrieve());
97  ATH_MSG_DEBUG("Retrieved tool " << m_intersector);
98 
99  // retrieve services
100  if (m_trackingGeometryReadKey.empty()) {
101  ATH_CHECK(m_trackingGeometrySvc.retrieve());
102  } else
103  ATH_CHECK(m_trackingGeometryReadKey.initialize());
104  // need to create the IndetExit and MuonEntrance TrackingVolumes
105  ATH_CHECK(m_trackingVolumesSvc.retrieve());
106  ATH_MSG_DEBUG("Retrieved Svc " << m_trackingVolumesSvc);
109  m_indetVolume = &(
111 
112  if (m_useStepPropagator > 0) {
113  ATH_CHECK(m_stepPropagator.retrieve());
114  }
115 
116  // Field for StepPropagator
118  if (m_useStepPropagator == 2)
120 
121  return StatusCode::SUCCESS;
122 }
123 
125  // summarize WARNINGs
126  m_messageHelper->printSummary();
127  return StatusCode::SUCCESS;
128 }
129 
131  std::vector<FitMeasurement*>& measurements,
132  ParticleHypothesis particleHypothesis, FitParameters& fitParameters,
133  Garbage_t& garbage) const {
134  const EventContext& ctx = Gaudi::Hive::currentContext();
135  // nothing to do if starting with vertex measurement
136  if (measurements.front()->isVertex()) {
137  return;
138  }
139 
140  if (msgLvl(MSG::DEBUG)) {
141  ATH_MSG_DEBUG(" start of addLeadingMaterial: ");
142  printMeasurements(measurements);
143  }
144 
145  // fitted momentum at perigee - ignoring leading material effects
146  double charge = 1.;
147  double qOverP = fitParameters.qOverP();
148  double p = 1. / qOverP;
149  if (p < 0.) {
150  charge = -1.;
151  p = -p;
152  }
153 
154  // check if leading scatterer(s) already present or need to be added (up to
155  // delimiter)
156  bool energyGain = false;
157  bool haveDelimiter = false;
158  std::optional<TrackSurfaceIntersection> intersection = std::nullopt;
159  int leadingScatterers = 0;
160  Trk::FitMeasurement* leadingScatterer = nullptr;
161  for (auto* measurement : measurements) {
162  if ((*measurement).isMaterialDelimiter()) {
163  haveDelimiter = true;
164  } else if ((*measurement).isScatterer()) {
165  // count unfitted scatterers
166  if (!(*measurement).numberDoF()) {
167  ++leadingScatterers;
168  leadingScatterer = measurement;
169  } else {
170  if (std::abs(1. / (*measurement).qOverP()) > p)
171  energyGain = true;
172  break;
173  }
174  }
175  }
176 
177  // need to allocate leading scatterers
178  if (haveDelimiter && !leadingScatterers) {
179  // find first measurement after delimiter
180  haveDelimiter = false;
181  Amg::Vector3D endPosition = fitParameters.vertex();
182  const Surface* firstMeasurementSurface = nullptr;
183  Trk::FitMeasurement* leadingOutlier = nullptr;
184  std::vector<Trk::FitMeasurement*> leadingOutliers;
185  const Surface* surface = nullptr;
186  for (auto* measurement : measurements) {
187  if ((*measurement).isMaterialDelimiter()) {
188  haveDelimiter = true;
189  endPosition = (*measurement).position();
190  surface = (*measurement).surface();
191  } else if ((*measurement).isPositionMeasurement()) {
192  if ((*measurement).isOutlier()) {
193  if (!firstMeasurementSurface)
194  leadingOutliers.push_back(measurement);
195  } else {
196  if (!firstMeasurementSurface && !intersection) {
197  firstMeasurementSurface = (*measurement).surface();
199  (*measurement).intersection(FittedTrajectory));
200  }
201  if (!haveDelimiter)
202  continue;
203  // surface = (**m).surface();
204  }
205  } else if ((*measurement).isScatterer()) {
206  if (!surface)
207  continue;
208  // FIXME: update p for Perigee in case of gain??
209  if (std::abs(1. / (*measurement).qOverP()) > p)
210  energyGain = true;
211  break;
212  }
213  }
214 
215  // leading material identified by outwards extrapolateM from perigee to
216  // delimiter
217  // FIXME: currently only for indet
218  // first create the fitted perigee (ignoring the leading material)
219  Perigee perigee(fitParameters.position(), p * fitParameters.direction(),
220  charge, fitParameters.vertex());
221  bool haveMaterial = false;
222  const std::vector<const TrackStateOnSurface*>* indetMaterial = nullptr;
223  if (haveDelimiter && intersection && surface &&
224  m_indetVolume->inside(endPosition)) {
225  // debug
226  if (msgLvl(MSG::VERBOSE)) {
227  const Amg::Vector3D& direction = intersection->direction();
228  const Amg::Vector3D& startPosition = intersection->position();
230  " addLeadingMaterial: using extrapolateM from distance "
231  << direction.dot(fitParameters.position() - startPosition));
232  }
233 
234  // extrapolateM from perigee to get leading material
236  alongMomentum, false,
237  particleHypothesis, garbage);
238 
239  // check material found (expected at least for leading measurement)
240  if (indetMaterial && !indetMaterial->empty()) {
241  std::vector<const TrackStateOnSurface*>::const_reverse_iterator r =
242  indetMaterial->rbegin();
243  for (; r != indetMaterial->rend(); ++r) {
244  // ignore trailing material
245  if (!(**r).trackParameters() || !(**r).materialEffectsOnTrack() ||
246  intersection->direction().dot(
247  (**r).trackParameters()->position() - endPosition) > 0.)
248  continue;
249 
250  haveMaterial = true;
251  }
252  }
253  } else {
254  haveDelimiter = false;
255  }
256 
257  // try again with back extrapolation if no leading material found
258  if (haveDelimiter && !haveMaterial) {
259  // debug
261  " no leading material found with forward extrapolation"
262  << ", try again with back extrapolation ");
263 
264  // clean up after previous attempt
265  deleteMaterial(indetMaterial, garbage);
266  indetMaterial = nullptr;
267 
268  std::vector<const TrackStateOnSurface*>* indetMaterialF = nullptr;
269  const std::vector<const TrackStateOnSurface*>* indetMaterialR = nullptr;
270  CurvilinearUVT uvt(intersection->direction());
271  Amg::Vector2D localPos;
272  PlaneSurface plane(intersection->position(), uvt);
273  if (plane.globalToLocal(intersection->position(),
274  intersection->direction(), localPos)) {
275  AtaPlane parameters(localPos[locR], localPos[locZ],
276  intersection->direction().phi(),
277  intersection->direction().theta(), qOverP, plane);
278 
279  indetMaterialR = extrapolatedMaterial(
281  oppositeMomentum, false, particleHypothesis, garbage);
282 
283  if (indetMaterialR && !indetMaterialR->empty()) {
284  indetMaterialF = new std::vector<const TrackStateOnSurface*>;
285  indetMaterialF->reserve(indetMaterialR->size());
286 
287  std::vector<const TrackStateOnSurface*>::const_reverse_iterator r =
288  indetMaterialR->rbegin();
289  for (; r != indetMaterialR->rend(); ++r) {
290  indetMaterialF->push_back(*r);
291  }
292 
293  for (r = indetMaterialF->rbegin(); r != indetMaterialF->rend(); ++r) {
294  // ignore trailing material
295  if (!(**r).trackParameters() || !(**r).materialEffectsOnTrack() ||
296  intersection->direction().dot(
297  (**r).trackParameters()->position() - endPosition) > 0.)
298  continue;
299 
300  haveMaterial = true;
301  }
302  indetMaterial = indetMaterialF;
303  indetMaterialF = nullptr;
304  }
305  }
306  delete indetMaterialR;
307  }
308 
309  // create scatterer FitMeasurement's corresponding to leading material
310  // (intersector running inwards to give parameters with qOverP update)
311  FitMeasurement* leadingMeas = nullptr;
312  if (indetMaterial && !indetMaterial->empty()) {
313  std::vector<const TrackStateOnSurface*>::const_reverse_iterator r =
314  indetMaterial->rbegin();
315  for (; r != indetMaterial->rend(); ++r) {
316  // ignore trailing material
317  if (!(**r).trackParameters() || !(**r).materialEffectsOnTrack() ||
318  intersection->direction().dot((**r).trackParameters()->position() -
319  endPosition) > 0.)
320  continue;
321 
322  // intersect material surface
323  double eLoss = 0.;
324  const MaterialEffectsOnTrack* materialEffects =
325  dynamic_cast<const MaterialEffectsOnTrack*>(
326  (**r).materialEffectsOnTrack());
327  if (materialEffects) {
328  eLoss = std::abs(materialEffects->energyLoss()->deltaE());
329  if (energyGain)
330  eLoss = -eLoss;
331  }
332 
333  if (leadingScatterers++ || !firstMeasurementSurface) {
334  if (m_useStepPropagator == 99) {
335  std::optional<TrackSurfaceIntersection> newIntersectionSTEP =
336  m_stepPropagator->intersectSurface(
337  ctx, (**r).trackParameters()->associatedSurface(),
340  intersection = m_intersector->intersectSurface(
341  (**r).trackParameters()->associatedSurface(), *intersection,
342  qOverP);
343  } else {
344  intersection =
346  ? m_stepPropagator->intersectSurface(
347  ctx, (**r).trackParameters()->associatedSurface(),
349  : m_intersector->intersectSurface(
350  (**r).trackParameters()->associatedSurface(),
351  *intersection, qOverP);
352  }
353 
354  // quit if tracking problem
355  if (!intersection) {
356  intersection =
357  measurements.front()->intersection(FittedTrajectory);
358  break;
359  }
360  leadingMeas =
361  new FitMeasurement((**r).materialEffectsOnTrack(),
362  Trk::ParticleMasses::mass[particleHypothesis],
363  intersection->position());
364  } else {
365  // remove leadingOutliers - they will be reinserted wrt the
366  // leadingScatterers
367  for (std::vector<Trk::FitMeasurement*>::const_iterator l =
368  leadingOutliers.begin();
369  l != leadingOutliers.end(); ++l) {
370  leadingOutlier = leadingOutliers.back();
371  measurements.erase(
372  std::remove(measurements.begin(), measurements.end(), *l),
373  measurements.end());
374  }
375  leadingMeas = new FitMeasurement(
376  (**r).materialEffectsOnTrack()->thicknessInX0(), -eLoss,
377  Trk::ParticleMasses::mass[particleHypothesis],
378  intersection->position(), intersection->direction(), qOverP,
379  firstMeasurementSurface);
380  leadingScatterer = leadingMeas;
381  }
383  leadingMeas->qOverP(qOverP);
384 
385  // put corresponding scatterer FitMeasurement at front of list,
386  // after re-inserting any intermediate leadingOutliers
387  if (leadingOutlier) {
388  double radius =
389  leadingMeas->intersection(FittedTrajectory).position().perp();
390  while (
391  leadingOutlier &&
392  leadingOutlier->intersection(FittedTrajectory).position().perp() >
393  radius) {
394  leadingOutliers.pop_back();
395  measurements.insert(measurements.begin(), leadingOutlier);
396  if (!leadingOutliers.empty()) {
397  leadingOutlier = leadingOutliers.back();
398  } else {
399  leadingOutlier = nullptr;
400  }
401  }
402  }
403 
404  ATH_MSG_DEBUG(" push_front(leadingMeas) ");
405 
406  measurements.insert(measurements.begin(), leadingMeas);
407 
408  // update momentum for energy loss
409  if (materialEffects) {
410  if (charge > 0.) {
411  qOverP = 1. / (1. / qOverP + eLoss);
412  } else {
413  qOverP = 1. / (1. / qOverP - eLoss);
414  }
415  }
416  }
417  }
418 
419  // final step to give intersection at perigee surface plus memory management
420  if (leadingMeas) {
421  if (m_useStepPropagator == 99) {
422  std::optional<TrackSurfaceIntersection> newIntersectionSTEP =
423  m_stepPropagator->intersectSurface(
424  ctx, perigee.associatedSurface(), *intersection, qOverP,
426  intersection = m_intersector->intersectSurface(
427  perigee.associatedSurface(), *intersection, qOverP);
428  } else {
429  intersection =
431  ? m_stepPropagator->intersectSurface(
432  ctx, perigee.associatedSurface(), *intersection, qOverP,
434  : m_intersector->intersectSurface(perigee.associatedSurface(),
435  *intersection, qOverP);
436  }
437  } else {
438  intersection = std::nullopt;
439  }
440  deleteMaterial(indetMaterial, garbage);
441  indetMaterial = nullptr;
442  }
443 
444  // integrate X0, energy loss and contribution to covariance (from leading
445  // scatterer towards perigee)
446  AmgSymMatrix(5) leadingCovariance;
447  leadingCovariance.setZero();
448  if (leadingScatterers) {
449  double leadingScattering = 0.;
450  double previousScattering = 0.;
451  double leadingX0Integral = 0.;
452  std::vector<Trk::FitMeasurement*>::reverse_iterator m =
453  measurements.rbegin();
454  while (*m != leadingScatterer)
455  ++m;
456  for (; m != measurements.rend(); ++m) {
457  if (!(**m).isScatterer())
458  continue;
459  const MaterialEffectsOnTrack* materialEffects =
460  dynamic_cast<const MaterialEffectsOnTrack*>((**m).materialEffects());
461  if (!materialEffects)
462  continue;
463 
464  // set the scattering angle and X0Integral
465  leadingX0Integral += (**m).materialEffects()->thicknessInX0();
466  double logTerm = 1.0 + m_scatteringLogCoeff * std::log(leadingX0Integral);
467  leadingScattering = leadingX0Integral * logTerm * logTerm;
468  double scatteringAngle =
470  std::sqrt(leadingScattering - previousScattering);
471  previousScattering = leadingScattering;
472  (**m).scatteringAngle(scatteringAngle, leadingX0Integral);
473 
474  // the scattering contribution to the covariance at perigee
475  double angleSquared = 1. / (**m).weight();
476  double deltaR = ((**m).intersection(FittedTrajectory).position() -
477  fitParameters.vertex())
478  .perp();
479  double sinThetaSquared =
480  (**m).intersection(FittedTrajectory).direction().perp2();
481  angleSquared *= angleSquared / sinThetaSquared;
482 
483  // transverse projection
484  leadingCovariance(0, 0) += deltaR * deltaR * angleSquared;
485  leadingCovariance(0, 2) -= deltaR * angleSquared;
486  leadingCovariance(2, 0) = leadingCovariance(0, 2);
487  leadingCovariance(2, 2) += angleSquared;
488 
489  // longitudinal projection (to get z: remember dcotTh/dTh = -1/sin*sin)
490  leadingCovariance(1, 1) +=
491  deltaR * deltaR * angleSquared / sinThetaSquared;
492  leadingCovariance(1, 3) += deltaR * angleSquared;
493  leadingCovariance(3, 1) = leadingCovariance(1, 3);
494  leadingCovariance(3, 3) += angleSquared * sinThetaSquared;
495  }
496  }
497 
498  // if leading material has just been added
499  if (intersection) {
500  fitParameters.update(intersection->position(), intersection->direction(),
501  qOverP, leadingCovariance);
502  }
503  // or pre-existing leading material
504  else {
505  fitParameters.update(fitParameters.position(), fitParameters.direction(),
506  qOverP, leadingCovariance);
507  }
508 
509  // debug
510  if (msgLvl(MSG::DEBUG)) {
511  if (!haveDelimiter)
512  ATH_MSG_VERBOSE(" addLeadingMaterial: ");
513  printMeasurements(measurements);
514  }
515 }
516 
518  std::vector<FitMeasurement*>& measurements,
519  ParticleHypothesis particleHypothesis, FitParameters& fitParameters,
520  const TrackParameters& startParameters, Garbage_t& garbage) const {
521  // different strategies used for indet and muon spectrometer
522  indetMaterial(measurements, particleHypothesis, startParameters, garbage);
523  if (!m_extrapolator.empty())
524  spectrometerMaterial(measurements, particleHypothesis, fitParameters,
525  startParameters, garbage);
526 
527  // debug
528  if (msgLvl(MSG::VERBOSE)) {
529  ATH_MSG_VERBOSE(" allocateMaterial: ");
530  printMeasurements(measurements);
531  }
532 }
533 
535  std::vector<FitMeasurement*>& measurements) const {
536  // loop over scatterers to include log term corresponding to integral
537  // thickness
538  bool integrate = false;
539  double previousScattering = 0.;
540  double X0Integral = 0.;
541 
542  std::vector<Trk::FitMeasurement*>::iterator m = measurements.begin();
543 
544  // start integration after any leading material
545  while (!(**m).isPositionMeasurement() || (**m).isOutlier())
546  ++m;
547 
548  for (; m != measurements.end(); ++m) {
549  if (integrate && (**m).isPositionMeasurement() && !(**m).isOutlier()) {
550  // restart integration for log term
551  integrate = false;
552  previousScattering = 0.;
553  X0Integral = 0.;
554  }
555  if ((**m).isScatterer()) {
556  if (integrate) {
557  // reset if measurement closely following
559  if (++next != measurements.end() && !(**next).hitOnTrack() &&
560  (**next).isPositionMeasurement() && !(**next).isOutlier()) {
561  Amg::Vector3D position =
562  (**next).intersection(FittedTrajectory).position();
563  if (((**m).intersection(FittedTrajectory).position() - position)
564  .mag() < 1. * Gaudi::Units::mm)
565  integrate = false;
566  }
567 
568  if (!integrate) {
569  // restart integration for log term
570  previousScattering = 0.;
571  X0Integral = 0.;
572  }
573  }
574 
575  integrate = true;
576  double thicknessInX0 = (**m).materialEffects()->thicknessInX0();
577  if ((**m).materialEffects()->thicknessInX0() < 0.) {
578  ATH_MSG_WARNING("thicknessInX0 smaller or equal to zero "
579  << (**m).materialEffects()->thicknessInX0() << " "
580  << *(**m).materialEffects());
581  thicknessInX0 = 1e-6;
582  }
583  X0Integral += thicknessInX0;
584  double logTerm = 1.;
585  if (X0Integral > 0.) {
586  logTerm = 1.0 + m_scatteringLogCoeff * std::log(X0Integral);
587  } else {
588  ATH_MSG_WARNING("X0Integral smaller or equal to zero "
589  << X0Integral << " thicknessInX0 "
590  << (**m).materialEffects()->thicknessInX0() << " "
591  << *(**m).materialEffects());
592  X0Integral = 1e-6;
593  }
594  double scattering = X0Integral * logTerm * logTerm;
595  double angle =
596  m_scatteringConstant * std::sqrt(scattering - previousScattering);
597  previousScattering = scattering;
598  (**m).numberDoF(2);
599  (**m).scatteringAngle(angle, X0Integral);
600  }
601  }
602 }
603 
604 std::vector<const TrackStateOnSurface*>*
606  const TrackParameters& spectrometerParameters, Garbage_t& garbage) const {
607  const EventContext& ctx = Gaudi::Hive::currentContext();
608  const Trk::TrackingVolume* spectrometerEntrance = getSpectrometerEntrance();
609  if (!spectrometerEntrance)
610  return nullptr;
611  // check input parameters are really in the spectrometer
612  if (m_calorimeterVolume->inside(spectrometerParameters.position()))
613  return nullptr;
614 
615  std::unique_ptr<const TrackParameters> entranceParameters(
616  m_extrapolator->extrapolateToVolume(ctx, spectrometerParameters,
617  *spectrometerEntrance, anyDirection,
619  if (!entranceParameters) {
621  std::setiosflags(std::ios::fixed)
622  << "leadingSpectrometerTSOS: no material found from RZ" << std::setw(9)
623  << std::setprecision(3) << spectrometerParameters.position().perp()
624  << std::setw(10) << std::setprecision(3)
625  << spectrometerParameters.position().z() << " with p " << std::setw(8)
626  << std::setprecision(3)
627  << spectrometerParameters.momentum().mag() / Gaudi::Units::GeV);
628  return nullptr;
629  }
630 
631  const Surface& entranceSurface = entranceParameters->associatedSurface();
632  std::unique_ptr<const std::vector<const TrackStateOnSurface*>>
633  extrapolatedTSOS(extrapolatedMaterial(
634  m_extrapolator, spectrometerParameters, entranceSurface, anyDirection,
635  false, Trk::muon, garbage));
636 
637  if (!extrapolatedTSOS || extrapolatedTSOS->empty() ||
638  !extrapolatedTSOS->front()->trackParameters()) {
640  std::setiosflags(std::ios::fixed)
641  << "leadingSpectrometerTSOS: no material found from RZ" << std::setw(9)
642  << std::setprecision(3) << spectrometerParameters.position().perp()
643  << std::setw(10) << std::setprecision(3)
644  << spectrometerParameters.position().z() << " with p " << std::setw(8)
645  << std::setprecision(3)
646  << spectrometerParameters.momentum().mag() / Gaudi::Units::GeV);
647  return nullptr;
648  }
649 
650  std::vector<std::unique_ptr<FitMeasurement>> leadingMeasurements;
651  std::unique_ptr<std::vector<const TrackStateOnSurface*>> leadingTSOS =
652  std::make_unique<std::vector<const TrackStateOnSurface*>>();
653  leadingTSOS->reserve(extrapolatedTSOS->size());
654  double outgoingEnergy = spectrometerParameters.momentum().mag();
655  double particleMass = Trk::ParticleMasses::mass[Trk::muon];
656  for (const auto* s : *extrapolatedTSOS) {
657  if (!(*s).trackParameters())
658  continue;
659  std::unique_ptr<FitMeasurement> measurement(
660  measurementFromTSOS(*s, outgoingEnergy, particleMass));
661  outgoingEnergy = (*s).trackParameters()->momentum().mag();
662 
663  if (measurement) {
664  leadingMeasurements.emplace(leadingMeasurements.begin(),
665  std::move(measurement));
666  } else {
667  leadingTSOS->push_back((*s).clone());
668  }
669  }
670 
671  // convert back to TSOS
672  for (const auto& m : leadingMeasurements)
673  leadingTSOS->emplace_back(new TrackStateOnSurface(
674  nullptr, nullptr, m->materialEffects()->uniqueClone()));
675 
676  deleteMaterial(extrapolatedTSOS.release(), garbage);
677 
678  // debug
679  if (msgLvl(MSG::VERBOSE) && !leadingTSOS->empty()) {
681  std::setiosflags(std::ios::fixed)
682  << "leadingSpectrometerTSOS: from RZ" << std::setw(9)
683  << std::setprecision(3) << spectrometerParameters.position().perp()
684  << std::setw(10) << std::setprecision(3)
685  << spectrometerParameters.position().z() << " with p " << std::setw(8)
686  << std::setprecision(3)
687  << spectrometerParameters.momentum().mag() / Gaudi::Units::GeV);
688  // printMeasurements(leadingMeasurements);
689  }
690  return leadingTSOS.release();
691 }
692 
694  std::vector<FitMeasurement*>& measurements, Amg::Vector3D startDirection,
695  Amg::Vector3D startPosition) const {
696  // order measurements
697  ATH_MSG_VERBOSE(" measurement ordering with startDirection phi "
698  << startDirection.phi() << " theta "
699  << startDirection.theta());
700 
701  // note: preserve original order for close double measurements (such as
702  // crossed eta/phi)
703  double previousDistance = -m_orderingTolerance;
704  std::vector<std::pair<double, FitMeasurement*>> measurementOrder;
705  std::vector<std::pair<double, FitMeasurement*>> originalOrder;
706  for (auto* measurement : measurements) {
707  double distance = startDirection.dot(
708  (*measurement).intersection(FittedTrajectory).position() -
709  startPosition);
710  if (distance < previousDistance)
712  previousDistance = distance - m_orderingTolerance;
713  measurementOrder.emplace_back(distance, measurement);
714  originalOrder.emplace_back(distance, measurement);
715  }
716  std::sort(measurementOrder.begin(), measurementOrder.end(),
717  compareByDistance());
718  std::vector<std::pair<double, FitMeasurement*>>::const_iterator orig =
719  originalOrder.begin();
720  bool shouldReorder = false;
721  if (m_allowReordering)
722  measurements.erase(measurements.begin(), measurements.end());
723 
724  for (std::vector<std::pair<double, FitMeasurement*>>::const_iterator order =
725  measurementOrder.begin();
726  order != measurementOrder.end(); ++order, ++orig) {
727  if (m_allowReordering) {
728  measurements.push_back((*order).second);
729  }
730 
731  // signal if reordering would help
732  // FIXME add tolerance
733  if ((*order).second == (*orig).second ||
734  std::abs((*order).first - (*orig).first) < m_orderingTolerance)
735  continue;
736  shouldReorder = true;
737  // ATH_MSG_INFO( " reorder distance " << (*order).first - (*orig).first );
738  }
739 
740  if (shouldReorder) {
741  if (m_allowReordering) {
742  ATH_MSG_DEBUG(" measurements have been reordered ");
743  } else {
744  ATH_MSG_DEBUG(" measurement reordering would improve the track fit ");
745  }
746  }
747 }
748 
750  std::vector<FitMeasurement*>& measurements, FitParameters& parameters,
751  Garbage_t& garbage) const {
752  ATH_MSG_DEBUG(" reallocateSpectrometerMaterial ");
753 
754  int n = 0;
755  for (auto& measurement : measurements) {
756  if (!(*measurement).isMaterialDelimiter())
757  continue;
758 
759  double distance =
760  ((*measurement).intersection(FittedTrajectory).position() -
761  (*measurement).position())
762  .mag();
763  ATH_MSG_INFO(
764  std::setiosflags(std::ios::fixed)
765  << std::setw(5) << ++n << std::setw(10) << std::setprecision(3)
766  << distance << " " << (*measurement).type() << std::setw(10)
767  << std::setprecision(1)
768  << (*measurement).intersection(FittedTrajectory).position().perp()
769  << std::setw(9) << std::setprecision(4)
770  << (*measurement).intersection(FittedTrajectory).position().phi()
771  << std::setw(10) << std::setprecision(1)
772  << (*measurement).intersection(FittedTrajectory).position().z());
773  }
774 
775  // put iterator at MS entrance
776  double qOverP = 0;
777  ATH_MSG_INFO("qOverP " << qOverP);
778 
779  std::vector<Trk::FitMeasurement*>::iterator m = measurements.begin();
780  for (; m != measurements.end(); ++m) {
781  if (m_calorimeterVolume->inside((**m).position())) {
782  // save qOverP for following use with spectrometer
783  if ((**m).materialEffects())
784  qOverP = (**m).qOverP();
785  if ((**m).isMaterialDelimiter())
786  ATH_MSG_INFO(" at material delimiter");
787  ATH_MSG_INFO("qOverP " << qOverP);
788  } else {
789  if ((**m).isMaterialDelimiter())
790  ATH_MSG_INFO(" at material delimiter");
791  break;
792  }
793  }
794 
795  // allocate material from outside inwards
797  MsgStream log(msgSvc(), name());
798  const TrackParameters* trackParameters =
799  parameters.trackParameters(log, *measurements.back());
800 
801  // protect the momentum to avoid excessive Eloss
802  Amg::VectorX parameterVector = trackParameters->parameters();
803  double Emax = 50000.;
804  if (parameterVector[Trk::qOverP] == 0.) {
805  parameterVector[Trk::qOverP] = 1. / Emax;
806  } else {
807  if (std::abs(parameterVector[Trk::qOverP]) * Emax < 1)
808  parameterVector[Trk::qOverP] = trackParameters->charge() / Emax;
809  }
810 
811  // correct track parameters for high momentum track (otherwise Eloss is too
812  // large)
813  trackParameters =
814  (trackParameters->associatedSurface())
815  .createUniqueTrackParameters(
816  parameterVector[Trk::loc1], parameterVector[Trk::loc2],
817  parameterVector[Trk::phi], parameterVector[Trk::theta],
818  parameterVector[Trk::qOverP], std::nullopt)
819  .release();
820 
821  for (std::vector<Trk::FitMeasurement*>::reverse_iterator r =
822  measurements.rbegin();
823  r != measurements.rend(); ++r) {
824  if (!(**r).isMaterialDelimiter())
825  continue;
826  const std::vector<const TrackStateOnSurface*>* spectrometerMaterial =
827  extrapolatedMaterial(m_extrapolator, *trackParameters, *(**r).surface(),
828  oppositeMomentum, false, Trk::muon, garbage);
829 
830  if (spectrometerMaterial && !spectrometerMaterial->empty()) {
831  // for (std::vector<const
832  // TrackStateOnSurface*>::const_reverse_iterator s =
833  // spectrometerMaterial->rbegin();
834  // s != spectrometerMaterial->rend();
835  // ++s)
836  // {
837  // if (! (**s).trackParameters() || ! (**s).materialEffectsOnTrack())
838  // continue; ATH_MSG_INFO( " material " <<
839  // (**s).trackParameters()->position() );
840  // }
841 
842  std::pair<FitMeasurement*, FitMeasurement*> fms =
844  delete fms.first;
845  delete fms.second;
846  // ATH_MSG_INFO( " delete TSOS " );
847 
848  for (const auto* s : *spectrometerMaterial)
849  delete s;
850  }
851  // ATH_MSG_INFO( " delete material " );
852  delete spectrometerMaterial;
853  delete trackParameters;
854 
855  MsgStream log(msgSvc(), name());
856  trackParameters = parameters.trackParameters(log, **r);
857  }
858 
859  delete trackParameters;
860 
861  // erase materialDelimiters
862  for (m = measurements.begin(); m != measurements.end(); ++m) {
863  if (!(**m).isMaterialDelimiter())
864  continue;
865  delete *m;
867  --m;
868  measurements.erase(n);
869  }
870 
871  return true;
872 }
873 
875  std::vector<FitMeasurement*>& measurements) const {
876  // insert delimiters representing station limits for later material
877  // aggregation
878  // preBreak: put delimiter upstream of measurement
879  // postBreak: put delimiter downstream of previous measurement
880  // FIXME: modify aggregation function: no aggregation in EC toroid region
881  // (~11m)
882  // FIXME: single scatterer in outer delimited pair
883  // printMeasurements(measurements);
884  FitMeasurement* previous = nullptr;
885  double previousDistance = 0.;
886 
887  Amg::Vector3D startDirection;
888  Amg::Vector3D startPosition;
889  Amg::Vector3D referenceDirection;
890  Amg::Vector3D referencePosition;
891  double referencePhi = 0.;
892  int index = 1;
893  for (std::vector<FitMeasurement*>::iterator m = measurements.begin();
894  m != measurements.end(); ++m, ++index) {
895  // skip 'non'-measurements
896  if (!(**m).isPositionMeasurement() || (**m).isPseudo())
897  continue;
898 
899  // material delimiters in MS follow the entrance break which should be
900  // already present
901  Amg::Vector3D position = (**m).position();
902  if (m_calorimeterVolume->inside(position))
903  continue;
904 
905  // break can be before measurement or after previous measurement
906  bool preBreak = false;
907  bool postBreak = false;
908  double distance = 0.;
909  if (!previous) {
910  // preBreak at first measurement in MS
911  preBreak = true;
912  referenceDirection = (**m).intersection(FittedTrajectory).direction();
913  referencePosition = (**m).intersection(FittedTrajectory).position();
914  referencePhi = position.phi();
915  startDirection = referenceDirection;
916  startPosition = referencePosition;
917  } else {
918  // post and pre breaks for cluster/drift transition,
919  // large gap between measurements,
920  // sector overlap
921  distance = referenceDirection.dot(
922  (**m).intersection(FittedTrajectory).position() - referencePosition);
923  if (((**m).isDrift() && !previous->isDrift()) ||
924  (!(**m).isDrift() && previous->isDrift()) ||
926  ((**m).isDrift() &&
927  std::abs(position.phi() - referencePhi) > m_sectorMaxPhi)) {
928  preBreak = true;
929  if (distance > previousDistance + m_scattererMinGap)
930  postBreak = true;
931  }
932  }
933 
934  if (!(preBreak || postBreak)) {
935  previous = *m;
936  previousDistance = distance;
937  continue;
938  }
939 
940  // ///////
941  // msg(MSG::INFO) << std::setiosflags(std::ios::fixed)
942  // << " index" << std::setw(3) << index+1
943  // << " at " << std::setw(10) << std::setprecision(1)
944  // << startDirection.dot(
945  // (**m).intersection(FittedTrajectory).position() -
946  // startPosition)
947  // << std::setw(10) << std::setprecision(1) << distance
948  // << std::setw(9) << std::setprecision(4)
949  // << std::abs(position.phi() - referencePhi);
950  // if (preBreak) msg() << " preBreak ";
951  // if (postBreak) msg() << " postBreak ";
952  // if ((**m).isDrift()) msg() << " isDrift ";
953  // msg() << endmsg;
954  // ///////
955 
956  if (postBreak && previous) {
957  // if (distance < offset) offset = 0.5*distance;
959  while (*m != previous)
960  --m;
962  (**m).intersection(FittedTrajectory), 0.5 * m_scattererMinGap);
963  m = measurements.insert(++m, delimiter);
964  while (*m != current)
965  ++m;
966  }
967  if (preBreak) {
968  double offset = -0.5 * m_scattererMinGap;
969  if (distance - previousDistance < m_scattererMinGap)
970  offset = 0.5 * (previousDistance - distance);
971 
973  new FitMeasurement((**m).intersection(FittedTrajectory), offset);
974  m = measurements.insert(m, delimiter);
975  ++m;
976  }
977  previous = *m;
978  previousDistance = 0.;
979  referenceDirection = (**m).intersection(FittedTrajectory).direction();
980  referencePosition = (**m).intersection(FittedTrajectory).position();
981  referencePhi = position.phi();
982  }
983  // orderMeasurements(measurements,startDirection,startPosition);
984  // printMeasurements(measurements);
985 }
986 
988  const std::vector<const TrackStateOnSurface*>* material,
989  Garbage_t& garbage) {
990  if (material) {
991  for (const TrackStateOnSurface* m : *material) {
992  garbage.push_back(std::unique_ptr<const TrackStateOnSurface>(m));
993  }
994  delete material;
995  }
996 }
997 
998 const std::vector<const TrackStateOnSurface*>*
1000  const ToolHandle<IExtrapolator>& extrapolator,
1001  const TrackParameters& parameters, const Surface& surface,
1002  PropDirection dir, const BoundaryCheck& boundsCheck,
1003  ParticleHypothesis particleHypothesis, Garbage_t& garbage) const {
1004  const EventContext& ctx = Gaudi::Hive::currentContext();
1005  // fix up material duplication appearing after recent TrackingGeometry
1006  // speed-up
1007  const std::vector<const TrackStateOnSurface*>* TGMaterial =
1008  extrapolator->extrapolateM(ctx, parameters, surface, dir, boundsCheck,
1009  particleHypothesis);
1010 
1011  if (!TGMaterial || TGMaterial->empty())
1012  return TGMaterial;
1013 
1014  std::vector<const TrackStateOnSurface*>* duplicates = nullptr;
1015  std::vector<const TrackStateOnSurface*>* material =
1016  new std::vector<const TrackStateOnSurface*>;
1017  material->reserve(TGMaterial->size());
1018  std::vector<const TrackStateOnSurface*>::const_iterator tg =
1019  TGMaterial->begin();
1020  material->push_back(*tg);
1021  ++tg;
1022  for (; tg != TGMaterial->end(); ++tg) {
1023  const TrackStateOnSurface* TSOS = material->back();
1024  double separation = 0.;
1025  if (TSOS->trackParameters())
1026  separation = (TSOS->trackParameters()->position() -
1027  (**tg).trackParameters()->position())
1028  .mag();
1029 
1030  if (separation > 0.001 * Gaudi::Units::mm) {
1031  material->push_back(*tg);
1032  } else {
1034  std::setiosflags(std::ios::fixed)
1035  << " duplicate: RZ" << std::setw(9) << std::setprecision(3)
1036  << (**tg).trackParameters()->position().perp() << std::setw(10)
1037  << std::setprecision(3) << (**tg).trackParameters()->position().z());
1038  if (!duplicates)
1039  duplicates = new std::vector<const TrackStateOnSurface*>;
1040  duplicates->push_back(*tg);
1041  }
1042  }
1043 
1044  delete TGMaterial;
1045  if (duplicates)
1046  deleteMaterial(duplicates, garbage);
1047  return material;
1048 }
1049 
1051  std::vector<FitMeasurement*>& measurements,
1052  ParticleHypothesis particleHypothesis,
1053  const TrackParameters& startParameters, Garbage_t& garbage) const {
1054  const EventContext& ctx = Gaudi::Hive::currentContext();
1055  // gather material between first and last measurements inside indet volume
1056  // allow a few mm radial tolerance around first&last measurements for their
1057  // associated material
1058  double tolerance =
1059  10. * Gaudi::Units::mm / startParameters.momentum().unit().perp();
1060 
1061  // loop over measurements to define portions of track needing indet material
1062  double endIndetDistance = 0.;
1063  FitMeasurement* endIndetMeasurement = nullptr;
1064  double qOverP = startParameters.charge() / startParameters.momentum().mag();
1065 
1066  Amg::Vector3D startDirection = startParameters.momentum().unit();
1067  Amg::Vector3D startPosition = startParameters.position();
1068  const TrackParameters* parameters = &startParameters;
1069  std::unique_ptr<AtaPlane> newParameters;
1070 
1071  std::vector<Trk::FitMeasurement*>::iterator m = measurements.begin();
1072  if ((**m).isVertex())
1073  ++m;
1074  for (; m != measurements.end(); ++m) {
1075  if ((**m).isOutlier())
1076  continue;
1077  if (m_indetVolume->inside((**m).position())) {
1078  // quit if pre-existing indet material
1079  if ((**m).isScatterer()) {
1080  return;
1081  }
1082 
1083  // use first measurement at a plane surface to create starting parameters
1084  if (!(**m).isPositionMeasurement())
1085  continue;
1086  if (!endIndetMeasurement && (**m).hasIntersection(FittedTrajectory) &&
1087  ((**m).surface()->type() == Trk::SurfaceType::Plane ||
1088  (**m).surface()->type() == Trk::SurfaceType::Disc)) {
1089  std::optional<TrackSurfaceIntersection> intersection =
1090  (**m).intersection(FittedTrajectory);
1091  Amg::Vector3D offset = intersection->direction() * tolerance;
1092  CurvilinearUVT uvt(intersection->direction());
1093  PlaneSurface plane(intersection->position() - offset, uvt);
1094 
1095  if (m_useStepPropagator == 99) {
1096  std::optional<TrackSurfaceIntersection> newIntersectionSTEP =
1097  m_stepPropagator->intersectSurface(
1098  ctx, plane, *intersection, qOverP,
1100  intersection =
1101  m_intersector->intersectSurface(plane, *intersection, qOverP);
1102  if (newIntersectionSTEP && intersection) {
1103  // double dist =
1104  // 1000.*(newIntersectionSTEP->position()-intersection->position()).mag();
1105  // std::cout << " iMat 3 distance STEP and
1106  // Intersector " << dist << std::endl;
1107  // if(dist>10.) std::cout << " iMat 3 ALARM
1108  // distance STEP and Intersector " << dist <<
1109  // std::endl;
1110  } else {
1111  // if(intersection) std::cout << " iMat 3 ALARM
1112  // STEP did not intersect! " << std::endl;
1113  }
1114  } else {
1116  ? m_stepPropagator->intersectSurface(
1117  ctx, plane, *intersection, qOverP,
1119  : m_intersector->intersectSurface(
1120  plane, *intersection, qOverP);
1121  }
1122  Amg::Vector2D localPos;
1123  if (intersection &&
1124  plane.globalToLocal(intersection->position(),
1125  intersection->direction(), localPos)) {
1126  newParameters = std::make_unique<AtaPlane>(
1127  localPos[locR], localPos[locZ], intersection->direction().phi(),
1128  intersection->direction().theta(), qOverP, plane);
1129  parameters = newParameters.get();
1130  startDirection = intersection->direction();
1131  startPosition = intersection->position();
1132  }
1133  }
1134 
1135  // save the last indet measurement, signal any out-of-order meas
1136  double distance = startDirection.dot(
1137  (**m).intersection(FittedTrajectory).position() - startPosition);
1138  if (!endIndetMeasurement || distance > endIndetDistance) {
1139  endIndetDistance = distance;
1140  endIndetMeasurement = *m;
1141  }
1142  } else { // outside indet
1143  break;
1144  }
1145  }
1146  if (!endIndetMeasurement) {
1147  return;
1148  }
1149 
1150  ATH_MSG_DEBUG(" indetMaterial: ALARM no material found on track");
1151 
1152  // allocate indet material from TrackingGeometry
1153  Amg::Vector3D endPosition =
1154  endIndetMeasurement->intersection(FittedTrajectory).position();
1155  startDirection = (endPosition - startPosition).unit();
1156  endIndetDistance =
1157  startDirection.dot(endPosition - startPosition) + tolerance;
1158  ATH_MSG_VERBOSE(" indetMaterial: using extrapolateM out to distance "
1159  << endIndetDistance);
1160  const std::vector<const TrackStateOnSurface*>* indetMaterial =
1162  *endIndetMeasurement->surface(), alongMomentum,
1163  false, particleHypothesis, garbage);
1164 
1165  if (!indetMaterial || indetMaterial->empty()) {
1166  deleteMaterial(indetMaterial, garbage);
1167  return;
1168  }
1169 
1170  // insert the material into the measurement list
1171  // ignore trailing material - with a few mm radial tolerance
1172  std::vector<const Surface*> surfaces;
1173  surfaces.reserve(indetMaterial->size());
1174  std::vector<const TrackStateOnSurface*>::const_iterator indetMaterialEnd =
1175  indetMaterial->begin();
1176  int trailing = indetMaterial->size();
1177  for (std::vector<const TrackStateOnSurface*>::const_iterator s =
1178  indetMaterial->begin();
1179  s != indetMaterial->end(); ++s, --trailing) {
1180  if ((**s).trackParameters()) {
1181  if (startDirection.dot((**s).trackParameters()->position() -
1182  startPosition) < endIndetDistance) {
1183  indetMaterialEnd = s;
1184  ++indetMaterialEnd;
1185  } else {
1186  ATH_MSG_VERBOSE(" indetMaterial: "
1187  << trailing
1188  << " trailing TSOS (after last measurement)");
1189  break;
1190  }
1191  }
1192  }
1193 
1194  // return in case of extrapolateM problem
1195  if (indetMaterialEnd == indetMaterial->begin()) {
1196  // extrapolateM finds no material on track !!
1197  m_messageHelper->printWarning(1);
1198  deleteMaterial(indetMaterial, garbage);
1199  return;
1200  }
1201 
1202  // debug
1203  if (msgLvl(MSG::VERBOSE)) {
1204  double p1 = indetMaterial->front()->trackParameters()->momentum().mag();
1205 
1206  for (std::vector<const TrackStateOnSurface*>::const_iterator s =
1207  indetMaterial->begin();
1208  s != indetMaterialEnd; ++s) {
1209  if (!(**s).trackParameters())
1210  continue;
1211  double distance = startDirection.dot((**s).trackParameters()->position() -
1212  startPosition);
1213  double deltaE = 0.;
1214  double thickness = 0.;
1215  const MaterialEffectsOnTrack* materialEffects =
1216  dynamic_cast<const MaterialEffectsOnTrack*>(
1217  (**s).materialEffectsOnTrack());
1218  if ((**s).materialEffectsOnTrack()) {
1219  if (materialEffects)
1220  deltaE = materialEffects->energyLoss()->deltaE();
1221  thickness = (**s).materialEffectsOnTrack()->thicknessInX0();
1222  }
1223  double p2 = (**s).trackParameters()->momentum().mag();
1225  std::setiosflags(std::ios::fixed)
1226  << " material: RZ" << std::setw(9) << std::setprecision(3)
1227  << (**s).trackParameters()->position().perp() << std::setw(10)
1228  << std::setprecision(3) << (**s).trackParameters()->position().z()
1229  << " distance " << std::setw(10) << std::setprecision(3) << distance
1230  << " pt " << std::setw(8) << std::setprecision(3)
1231  << (**s).trackParameters()->momentum().perp() / Gaudi::Units::GeV
1232  << " X0thickness " << std::setw(8) << std::setprecision(4)
1233  << thickness << " deltaE " << std::setw(8) << std::setprecision(4)
1234  << deltaE << " diffP " << std::setw(8) << std::setprecision(4)
1235  << p2 - p1);
1236  p1 = p2;
1237  }
1238  }
1239 
1240  // firstly: add the material belonging to each measurement layer (and skip
1241  // leading material)
1242  FitMeasurement* leadingDelimiter = nullptr;
1243  Amg::Vector3D nextMomentum(0., 0., 0.);
1244  Amg::Vector3D nextPosition(0., 0., 0.);
1245  m = measurements.begin();
1246  std::vector<const TrackStateOnSurface*>::const_iterator s =
1247  indetMaterial->begin();
1248  for (; m != measurements.end(); ++m) {
1249  if (*m == endIndetMeasurement || s == indetMaterialEnd)
1250  break;
1251  if (!leadingDelimiter && (**m).isOutlier())
1252  continue;
1253 
1254  Amg::Vector3D direction = (**m).intersection(FittedTrajectory).direction();
1255  Amg::Vector3D position = (**m).intersection(FittedTrajectory).position();
1256  double closestDistance = direction.dot(position - startPosition);
1257  const MaterialEffectsOnTrack* materialEffects = nullptr;
1258  const TrackParameters* materialParameters = nullptr;
1259  const Surface* materialSurface = nullptr;
1260 
1261  // find the closest material TSOS (inside radial tolerance)
1262  for (; s != indetMaterialEnd; ++s) {
1263  if (!dynamic_cast<const MaterialEffectsOnTrack*>(
1264  (**s).materialEffectsOnTrack()) ||
1265  !(**s).trackParameters())
1266  continue;
1267  nextMomentum = (**s).trackParameters()->momentum();
1268  nextPosition = (**s).trackParameters()->position();
1269  double distance = direction.dot(nextPosition - position);
1270 
1271  // increasing distance - break when past minimum
1272  if (distance > closestDistance)
1273  break;
1274 
1275  // downstream material - check not significantly closer to following
1276  // measurement
1277  // (material too early is better than too late)
1278  if (distance > 0.) {
1279  ++m;
1280  double nextDistance = direction.dot(
1281  (**s).trackParameters()->position() - (**m).position());
1282  --m;
1283  if (std::abs(nextDistance) < distance && distance > tolerance) {
1284  if (s != indetMaterial->begin())
1285  --s;
1286  materialSurface = nullptr;
1287  break;
1288  }
1289  closestDistance = distance;
1290  } else {
1291  closestDistance = -distance;
1292  }
1293 
1294  // when upstream of leading break any previous surface is going to be
1295  // ignored
1296  if (!leadingDelimiter && materialSurface)
1297  surfaces.push_back(materialSurface);
1298 
1299  materialEffects = dynamic_cast<const MaterialEffectsOnTrack*>(
1300  (**s).materialEffectsOnTrack());
1301  materialParameters = (**s).trackParameters();
1302  materialSurface = &materialParameters->associatedSurface();
1303  }
1304 
1305  // skip if the material has not been allocated to a measurement surface
1306  if (!materialSurface)
1307  continue;
1308 
1309  // or if it's already been allocated upstream
1310  if (!surfaces.empty() && materialSurface == surfaces.back())
1311  continue;
1312 
1313  // skip leading material during the fit (up to and including first
1314  // measurement) insert an materialDelimiter so the leading material can be
1315  // allocated after the fit converges
1316  if (!leadingDelimiter) {
1317  position = 0.5 * (materialParameters->position() + nextPosition);
1318  direction = (materialParameters->momentum() + nextMomentum).unit();
1319  TrackSurfaceIntersection breakIntersection(position, direction, 0.);
1320  leadingDelimiter = new FitMeasurement(breakIntersection, 0.);
1321  while (*m != endIndetMeasurement &&
1322  direction.dot((**m).intersection(FittedTrajectory).position() -
1323  position) < 0.)
1324  ++m;
1325  m = measurements.insert(m, leadingDelimiter);
1326  surfaces.push_back(materialSurface);
1327  continue;
1328  }
1329 
1330  // check inside tolerance
1331  if (closestDistance > tolerance)
1332  continue;
1333 
1334  // insert material at measurement surface
1335  const std::bitset<MaterialEffectsBase::NumberOfMaterialEffectsTypes>
1336  typePattern;
1337  std::unique_ptr<Trk::EnergyLoss> energyLoss = nullptr;
1338  if (materialEffects->energyLoss()) {
1339  energyLoss = std::unique_ptr<Trk::EnergyLoss>(
1340  materialEffects->energyLoss()->clone());
1341  }
1343  materialEffects->thicknessInX0(), std::move(energyLoss),
1344  *(**m).surface(), typePattern);
1345  const TrackSurfaceIntersection& intersection = (**m).intersection(FittedTrajectory);
1346  if (++m == measurements.end())
1347  --m;
1348  m = measurements.insert(
1349  m,
1350  new FitMeasurement(meot, Trk::ParticleMasses::mass[particleHypothesis],
1351  intersection.position()));
1352  (**m).intersection(FittedTrajectory, intersection);
1353  (**m).qOverP(materialParameters->parameters()[Trk::qOverP]);
1354  (**m).setMaterialEffectsOwner();
1355  surfaces.push_back(materialSurface);
1356  }
1357 
1358  // secondly: insert remaining material between measurement layers
1359  m = measurements.begin();
1360  int im = 0;
1361  ATH_MSG_VERBOSE(" measurements.size() "
1362  << measurements.size() << " surfaces.size() "
1363  << surfaces.size() << " indetMaterial->size() "
1364  << indetMaterial->size());
1365  std::vector<const Surface*>::const_iterator r = surfaces.begin();
1366  for (s = indetMaterial->begin(); s != indetMaterialEnd; ++s) {
1367  if (!(**s).trackParameters() || !(**s).materialEffectsOnTrack())
1368  continue;
1369 
1370  if (r != surfaces.end() &&
1371  **r == (**s).trackParameters()->associatedSurface()) {
1372  ++r;
1373  continue;
1374  }
1375 
1376  double distance =
1377  startDirection.dot((**s).trackParameters()->position() - startPosition);
1378 
1379  ATH_MSG_VERBOSE(" startPosition " << startPosition.perp() << " z "
1380  << startPosition.z());
1382  " (**m).intersection(FittedTrajectory).position() measurement "
1383  "position r "
1384  << (**m).intersection(FittedTrajectory).position().perp() << " z "
1385  << (**m).intersection(FittedTrajectory).position().z());
1387  " (**s).trackParameters()->position() material surface position "
1388  "r "
1389  << (**s).trackParameters()->position().perp() << " z "
1390  << (**s).trackParameters()->position().z());
1391  ATH_MSG_VERBOSE(" distance material surface " << distance);
1392 
1393  bool endIndet = false;
1394  while (distance >
1395  startDirection.dot((**m).intersection(FittedTrajectory).position() -
1396  startPosition)) {
1397  if (*m == endIndetMeasurement) {
1398  if (*m != measurements.back()) {
1399  ++m;
1400  ++im;
1401  ATH_MSG_VERBOSE(" measurements.back() im " << im);
1402  }
1403  ATH_MSG_VERBOSE(" break im " << im);
1404  endIndet = true;
1405  break;
1406  }
1407  if (*m != measurements.back()) {
1408  ++m;
1409  ++im;
1411  " loop im "
1412  << im
1413  << " (**m).intersection(FittedTrajectory).position() "
1414  "measurement position r "
1415  << (**m).intersection(FittedTrajectory).position().perp() << " z "
1416  << (**m).intersection(FittedTrajectory).position().z());
1417  } else {
1418  break;
1419  }
1420  }
1422  " im " << im << " distance measurement "
1423  << startDirection.dot(
1424  (**m).intersection(FittedTrajectory).position() -
1425  startPosition));
1427  " (**m).intersection(FittedTrajectory).position() measurement position "
1428  "r "
1429  << (**m).intersection(FittedTrajectory).position().perp() << " z "
1430  << (**m).intersection(FittedTrajectory).position().z());
1431 
1432  m = measurements.insert(
1433  m, new FitMeasurement((**s).materialEffectsOnTrack(),
1434  Trk::ParticleMasses::mass[particleHypothesis],
1435  (**s).trackParameters()->position()));
1437  (**s).trackParameters()->position(),
1438  (**s).trackParameters()->momentum().unit(), 0.);
1439  (**m).intersection(FittedTrajectory, intersection);
1440  (**m).qOverP((**s).trackParameters()->parameters()[Trk::qOverP]);
1441  ATH_MSG_VERBOSE(" successfull insertion ");
1442  if (endIndet)
1443  --m;
1444  }
1445 
1446  m = measurements.begin();
1447  im = 0;
1448  for (; m != measurements.end(); ++m) {
1449  if (!leadingDelimiter && (**m).isOutlier())
1450  continue;
1451 
1452  Amg::Vector3D position = (**m).intersection(FittedTrajectory).position();
1453  ++im;
1454  ATH_MSG_VERBOSE(" im " << im << " position R " << position.perp() << " z "
1455  << position.z());
1456  }
1457 
1458  // memory management
1459  deleteMaterial(indetMaterial, garbage);
1460 
1461  ATH_MSG_VERBOSE(" finished indetMaterial ");
1462 }
1463 
1464 std::pair<FitMeasurement*, FitMeasurement*>
1466  const std::vector<const TrackStateOnSurface*>& material,
1467  std::vector<FitMeasurement*>& /*measurements*/,
1468  double /*particleMass*/) const {
1469  // aggregation possible in indet and MS. Frequent occurrence in MS
1470  ATH_MSG_INFO("segment material aggregation " << material.size());
1471  FitMeasurement* measurement1 = nullptr;
1472  FitMeasurement* measurement2 = nullptr;
1473  if (material.empty())
1474  return std::pair<FitMeasurement*, FitMeasurement*>(measurement1,
1475  measurement2);
1476 
1477 
1478  int adjacentScatterers = 0;
1479  std::vector<FitMeasurement*> aggregateScatterers;
1480  bool hasReferencePosition = false;
1481  Amg::Vector3D referencePosition;
1482  bool haveAggregation = false;
1483  // bool makeAggregation = false;
1484  // double maxDistance = 0.;
1485  for (std::vector<const TrackStateOnSurface*>::const_reverse_iterator tsos =
1486  material.rbegin();
1487  tsos != material.rend(); ++tsos) {
1488  if (!(**tsos).trackParameters() || !(**tsos).materialEffectsOnTrack()){
1489  continue;
1490  }
1491  ++adjacentScatterers;
1492  if (!hasReferencePosition) {
1493  referencePosition = Amg::Vector3D((**tsos).trackParameters()->position());
1494  hasReferencePosition = true;
1495  }
1496  double distance =
1497  ((**tsos).trackParameters()->position() - referencePosition).mag();
1498  double weight = (**tsos).materialEffectsOnTrack()->thicknessInX0();
1499 
1500  ATH_MSG_INFO(" material position " << (**tsos).trackParameters()->position()
1501  << " distance " << distance
1502  << " thickness " << 100. * weight);
1503  }
1504 
1505  // if 2 or less selected TSOS: just set scatterers on TSOS
1506  if (adjacentScatterers < 3) {
1507  }
1508 
1509  // in case of aggregation: insert aggregateScatterers onto track
1510  if (haveAggregation) {
1511  }
1512 
1513  return std::pair<FitMeasurement*, FitMeasurement*>(measurement1,
1514  measurement2);
1515 }
1516 
1518  std::vector<FitMeasurement*>& measurements, double particleMass) const {
1519  // Aggregate when at least 2 scatterers exist between delimiter pair.
1520  //
1521  // First loop over measurements to create aggregateScatterer vector.
1522  // This contains any aggregated scatterers along with sparse existing
1523  // scatterers which haven't been aggregated. The remaining existing scatterers
1524  // (those which have been aggregated) are flagged for discard (via the outlier
1525  // flag).
1526 
1527  // currently aggregation only performed for MS:
1528  Amg::Vector3D referencePosition =
1529  measurements.back()->intersection(FittedTrajectory).position();
1530  if (m_calorimeterVolume->inside(referencePosition))
1531  return;
1532 
1533  Amg::Vector3D referenceDirection =
1534  measurements.back()->intersection(FittedTrajectory).direction();
1535  int adjacentScatterers = 0;
1536  std::vector<FitMeasurement*> aggregateScatterers;
1537  bool haveAggregation = false;
1538  bool makeAggregation = false;
1539  double maxDistance = 0.;
1540  FitMeasurement* measurement1 = nullptr;
1541  FitMeasurement* measurement2 = nullptr;
1542  double totalDistance = 0.;
1543  double totalDistanceSq = 0.;
1544  double totalEnergyDeposit = 0.;
1545  double totalThickness = 0.;
1546  std::vector<FitMeasurement*>::reverse_iterator start;
1547  std::vector<FitMeasurement*>::reverse_iterator previous =
1548  measurements.rbegin();
1549  for (std::vector<FitMeasurement*>::reverse_iterator m = measurements.rbegin();
1550  m != measurements.rend(); ++m) {
1551  if ((**m).isScatterer())
1552  aggregateScatterers.push_back(*m);
1553  if (m_calorimeterVolume->inside((**m).position())) {
1554  if (!adjacentScatterers)
1555  continue;
1556  makeAggregation = true;
1557  }
1558  // if (m_calorimeterVolume->inside((**m).position())
1559  // && ! m_indetVolume->inside((**m).position())) continue;
1560  // look for adjacent scatterers
1561  else if (adjacentScatterers) {
1562  if ((**m).isScatterer()) {
1563  Amg::Vector3D position =
1564  (**m).intersection(FittedTrajectory).position();
1565  double distance =
1566  std::abs(referenceDirection.dot(position - referencePosition));
1567  if (distance < maxDistance) {
1568  ++adjacentScatterers;
1569  double weight = (**m).radiationThickness();
1570  totalDistance += weight * distance;
1571  totalDistanceSq += weight * distance * distance;
1572  totalEnergyDeposit += (**m).energyLoss();
1573  totalThickness += weight;
1574  if (*m == measurements.front())
1575  makeAggregation = true;
1576  // ATH_MSG_INFO(std::setiosflags(std::ios::fixed)
1577  // << " distance "
1578  // << std::setw(8) << std::setprecision(0)
1579  // << distance
1580  // << " adjacentScatterers " << adjacentScatterers );
1581  } else if (adjacentScatterers > 1) {
1582  makeAggregation = true;
1583  } else {
1584  adjacentScatterers = 0;
1585  }
1586  } else if (!(**m).isMaterialDelimiter()) {
1587  previous = m;
1588  continue;
1589  } else if (adjacentScatterers > 1) {
1590  makeAggregation = true;
1591  } else {
1592  adjacentScatterers = 0;
1593  }
1594  }
1595 
1596  if (makeAggregation) {
1597  // double dist =
1598  // ((**m).intersection(FittedTrajectory).position() -
1599  // referencePosition).mag();
1600  // ATH_MSG_INFO(std::setiosflags(std::ios::fixed)
1601  // << " makeAggregation: reference R,Z "
1602  // << std::setw(8) << std::setprecision(0)
1603  // << referencePosition.perp()
1604  // << std::setw(8) << std::setprecision(0)
1605  // << referencePosition.z()
1606  // << " current R,Z "
1607  // << std::setw(8) << std::setprecision(0)
1608  // << (**m).intersection(FittedTrajectory).position().perp()
1609  // << std::setw(8) << std::setprecision(0)
1610  // << (**m).intersection(FittedTrajectory).position().z()
1611  // << " adjacentScatterers " << std::setw(2)
1612  // << adjacentScatterers
1613  // << " distance "
1614  // << std::setw(8) << std::setprecision(0)
1615  // << dist );
1616  double meanDistance = totalDistance / totalThickness;
1617  double rmsDistance = 0.;
1618  double meanSquare =
1619  totalDistanceSq / totalThickness - meanDistance * meanDistance;
1620  if (meanSquare > 0.)
1621  rmsDistance = std::sqrt(meanSquare);
1622  double gap = 2. * rmsDistance;
1623  if (adjacentScatterers > 2 || gap < m_scattererMinGap) {
1624  double distance1 = meanDistance - rmsDistance;
1625  double distance2 = meanDistance + rmsDistance;
1626  if (gap < m_scattererMinGap)
1627  distance2 = meanDistance;
1628  Amg::Vector3D position =
1629  (**m).intersection(FittedTrajectory).position();
1630  double distance =
1631  std::abs(referenceDirection.dot(position - referencePosition));
1632  // ATH_MSG_INFO(std::setiosflags(std::ios::fixed)
1633  // << " distance1 "
1634  // << std::setw(8) << std::setprecision(0)
1635  // << distance1
1636  // << " distance2 "
1637  // << std::setw(8) << std::setprecision(0)
1638  // << distance2
1639  // << " distance "
1640  // << std::setw(8) << std::setprecision(0)
1641  // << distance );
1642  if (distance2 > distance || distance1 < 0.) {
1643  // msg() << " distance out of bounds: range " << distance
1644  // << " to " << 0. << endmsg;
1645  } else {
1646  FitMeasurement* after = nullptr;
1647  FitMeasurement* before = *start;
1648  double previousDistance = 0.;
1649  haveAggregation = true;
1650 
1651  for (std::vector<Trk::FitMeasurement*>::reverse_iterator s = start;
1652  s != measurements.rend(); ++s) {
1653  if (!(**s).isScatterer())
1654  continue;
1655  Amg::Vector3D position =
1656  (**s).intersection(FittedTrajectory).position();
1657  double distance =
1658  std::abs(referenceDirection.dot(position - referencePosition));
1659  if (!measurement1 && distance > distance1 &&
1660  gap > m_scattererMinGap) {
1661  after = *s;
1662  double separation = distance - previousDistance;
1663  double fractionAfter =
1664  (distance1 - previousDistance) / separation;
1665  double fractionBefore = (distance - distance1) / separation;
1666  // ATH_MSG_INFO( std::setiosflags(std::ios::fixed)
1667  // << " distance "
1668  // << std::setw(8) << std::setprecision(0)
1669  // << distance<< " fraction before "
1670  // << std::setw(6) << std::setprecision(2)
1671  // << fractionBefore
1672  // << " fraction after "
1673  // << std::setw(6) << std::setprecision(2)
1674  // << fractionAfter );
1675  position = fractionBefore *
1677  fractionAfter *
1679  Amg::Vector3D direction =
1680  fractionBefore *
1682  fractionAfter *
1684  double qOverP = fractionBefore * before->qOverP() +
1685  fractionAfter * after->qOverP();
1686  measurement1 = new FitMeasurement(
1687  0.5 * totalThickness, -0.5 * totalEnergyDeposit, particleMass,
1688  position, direction, qOverP);
1689  }
1690 
1691  if (distance > distance2) {
1692  after = *s;
1693  double separation = distance - previousDistance;
1694  double fractionAfter =
1695  (distance2 - previousDistance) / separation;
1696  double fractionBefore = (distance - distance2) / separation;
1697  // ATH_MSG_INFO( std::setiosflags(std::ios::fixed)
1698  // << " distance "
1699  // << std::setw(8) << std::setprecision(0)
1700  // << distance<< " fraction before "
1701  // << std::setw(6) << std::setprecision(2)
1702  // << fractionBefore
1703  // << " fraction after "
1704  // << std::setw(6) << std::setprecision(2)
1705  // << fractionAfter << endmsg );
1706  position = fractionBefore *
1708  fractionAfter *
1710  Amg::Vector3D direction =
1711  fractionBefore *
1713  fractionAfter *
1715  double qOverP = fractionBefore * before->qOverP() +
1716  fractionAfter * after->qOverP();
1717  if (measurement1) {
1718  measurement2 = new FitMeasurement(
1719  0.5 * totalThickness, -0.5 * totalEnergyDeposit,
1720  particleMass, position, direction, qOverP);
1721  } else {
1722  measurement2 = new FitMeasurement(
1723  totalThickness, -totalEnergyDeposit, particleMass, position,
1724  direction, qOverP);
1725  }
1726  bool keepCurrentMeas = false;
1727  if ((**m).isScatterer() && *m != measurements.front()) {
1728  keepCurrentMeas = true;
1729  aggregateScatterers.pop_back();
1730  }
1731  while (adjacentScatterers--) {
1732  aggregateScatterers.back()->setOutlier();
1733  aggregateScatterers.pop_back();
1734  }
1735  if (measurement1)
1736  aggregateScatterers.push_back(measurement1);
1737  if (measurement2)
1738  aggregateScatterers.push_back(measurement2);
1739  if (keepCurrentMeas)
1740  aggregateScatterers.push_back(*m);
1741  measurement1 = nullptr;
1742  measurement2 = nullptr;
1743  break;
1744  }
1745  before = *s;
1746  previousDistance = distance;
1747  }
1748  }
1749  }
1750  adjacentScatterers = 0;
1751  makeAggregation = false;
1752  }
1753 
1754  // new candidate for merging
1755  if ((**m).isScatterer() && !adjacentScatterers &&
1756  !m_calorimeterVolume->inside((**m).position())) {
1757  adjacentScatterers = 1;
1758  double weight = (**m).radiationThickness();
1759  referencePosition =
1760  (**previous).intersection(FittedTrajectory).position();
1761  referenceDirection =
1762  (**previous).intersection(FittedTrajectory).direction();
1763  Amg::Vector3D position = (**m).intersection(FittedTrajectory).position();
1764  double distance =
1765  std::abs(referenceDirection.dot(position - referencePosition));
1766  maxDistance = distance + 2. * Gaudi::Units::meter;
1767  start = m;
1768  totalDistance = weight * distance;
1769  totalDistanceSq = weight * distance * distance;
1770  totalEnergyDeposit = (**m).energyLoss();
1771  totalThickness = weight;
1772  // ATH_MSG_INFO(std::setiosflags(std::ios::fixed)
1773  // << " distance "
1774  // << std::setw(8) << std::setprecision(0)
1775  // << distance
1776  // << " adjacentScatterers " << adjacentScatterers );
1777  }
1778  previous = m;
1779  }
1780 
1781  // avoid possible leak
1782  delete measurement1;
1783  // delete measurement2; // redundant!
1784 
1785  // in case of aggregation: insert the aggregateScatterers into the measurement
1786  // list (second loop over measurements)
1787  if (haveAggregation) {
1788  referencePosition =
1789  measurements.back()->intersection(FittedTrajectory).position();
1790  referenceDirection =
1791  (referencePosition -
1792  measurements.front()->intersection(FittedTrajectory).position())
1793  .unit();
1794  std::vector<Trk::FitMeasurement*>::reverse_iterator s =
1795  aggregateScatterers.rbegin();
1796  Amg::Vector3D scattererPosition =
1797  (**s).intersection(FittedTrajectory).position();
1798  double scattererDistance =
1799  std::abs(referenceDirection.dot(scattererPosition - referencePosition));
1800  for (std::vector<Trk::FitMeasurement*>::iterator m = measurements.begin();
1801  m != measurements.end(); ) {
1802  // insert scatterers from aggregrate vector
1803  Amg::Vector3D position = (**m).intersection(FittedTrajectory).position();
1804  double distance =
1805  std::abs(referenceDirection.dot(position - referencePosition));
1806  while (distance <= scattererDistance && s != aggregateScatterers.rend()) {
1807  m = measurements.insert(m, *s);
1808  ++m;
1809  if (++s != aggregateScatterers.rend()) {
1810  scattererPosition = (**s).intersection(FittedTrajectory).position();
1811  scattererDistance = std::abs(
1812  referenceDirection.dot(scattererPosition - referencePosition));
1813  }
1814  }
1815  if ((**m).isScatterer()) {
1816  // delete the scatterer if it has been aggregated
1817  if ((**m).isOutlier())
1818  delete *m;
1819  // in any case it must be removed from the list to avoid double counting
1820  m = measurements.erase(m);
1821  }
1822  else {
1823  ++m;
1824  }
1825  }
1826  }
1827 
1828  // verbose table of fit measurements including material
1829  if (msgLvl(MSG::VERBOSE)) {
1830  ATH_MSG_VERBOSE(" finished material aggregation: ");
1831  int n = 0;
1832  Amg::Vector3D startPosition =
1833  measurements.front()->intersection(FittedTrajectory).position();
1834  Amg::Vector3D startDirection =
1835  measurements.front()->intersection(FittedTrajectory).direction();
1836  for (auto* measurement : measurements) {
1837  Amg::Vector3D position =
1838  (*measurement).intersection(FittedTrajectory).position();
1839  double distance = std::abs(startDirection.dot(position - startPosition));
1840  msg(MSG::VERBOSE) << std::setiosflags(std::ios::fixed) << std::setw(5)
1841  << ++n << std::setw(10) << std::setprecision(3)
1842  << distance << " " << (*measurement).type();
1843  if ((*measurement).isOutlier()) {
1844  msg() << " outlier ";
1845  } else if ((*measurement).materialEffects()) {
1846  msg() << std::setw(8) << std::setprecision(3)
1847  << (*measurement).materialEffects()->thicknessInX0() << " ";
1848  } else {
1849  msg() << " ";
1850  }
1851  if (!(*measurement).isMaterialDelimiter()) {
1852  msg() << std::setw(10) << std::setprecision(1)
1853  << (*measurement).position().perp() << std::setw(9)
1854  << std::setprecision(4) << (*measurement).position().phi()
1855  << std::setw(10) << std::setprecision(1)
1856  << (*measurement).position().z();
1857  }
1858  msg() << endmsg;
1859  }
1860  }
1861 
1862  // loops to erase material delimiters and set energy gain when appropriate
1863  bool energyGain = false;
1864  for (auto& measurement : measurements) {
1865  if ((*measurement).materialEffects() && (*measurement).numberDoF() &&
1866  (*measurement).energyLoss() < 0.)
1867  energyGain = true;
1868  }
1869 
1870  if (energyGain) {
1871  for (auto& measurement : measurements) {
1872  if ((*measurement).materialEffects())
1873  (*measurement).setEnergyGain();
1874  }
1875  }
1876 }
1877 
1879  const TrackStateOnSurface& tsos, double outgoingEnergy,
1880  double particleMass) {
1881  if (!tsos.trackParameters() || !tsos.materialEffectsOnTrack())
1882  return nullptr;
1883 
1884  double deltaE = outgoingEnergy - tsos.trackParameters()->momentum().mag();
1885  double thicknessInX0 = tsos.materialEffectsOnTrack()->thicknessInX0();
1886  Amg::Vector3D position = tsos.trackParameters()->position();
1887  Amg::Vector3D direction = tsos.trackParameters()->momentum().unit();
1888  double qOverP = 1. / outgoingEnergy;
1889  if (tsos.trackParameters()->charge() < 0)
1890  qOverP = -qOverP;
1891 
1892  return new FitMeasurement(thicknessInX0, deltaE, particleMass, position,
1893  direction, qOverP);
1894 }
1895 
1897  std::vector<FitMeasurement*>& measurements) const {
1899  "measurements and material: distance X0 deltaE E "
1900  " pT"
1901  << " R phi Z DoF phi theta");
1902 
1903  if (measurements.empty())
1904  return;
1905 
1906  std::vector<Trk::FitMeasurement*>::iterator m = measurements.begin();
1907  while (m != measurements.end() && !(**m).isPositionMeasurement())
1908  ++m;
1909  if (m == measurements.end())
1910  m = measurements.begin();
1911 
1912  Amg::Vector3D direction = (**m).intersection(FittedTrajectory).direction();
1913  Amg::Vector3D startPosition = (**m).intersection(FittedTrajectory).position();
1914  int scatterers = 0;
1915  int leadingMaterial = 0;
1916  double leadingX0 = 0.;
1917  double sumX0 = 0.;
1918  double leadingELoss = 0.;
1919  double sumELoss = 0.;
1920  int n = 0;
1921  for (auto& measurement : measurements) {
1922  double distance =
1923  direction.dot((*measurement).intersection(FittedTrajectory).position() -
1924  startPosition);
1925  msg(MSG::VERBOSE) << std::setiosflags(std::ios::fixed) << std::setw(5)
1926  << ++n << " " << (*measurement).type() << std::setw(11)
1927  << std::setprecision(3) << distance;
1928  if ((*measurement).isOutlier()) {
1929  msg() << " outlier " << std::setw(44);
1930  } else if ((*measurement).materialEffects()) {
1931  double deltaE = 0.;
1932  const MaterialEffectsOnTrack* materialEffects =
1933  dynamic_cast<const MaterialEffectsOnTrack*>(
1934  (*measurement).materialEffects());
1935  if (materialEffects && materialEffects->energyLoss())
1936  deltaE = materialEffects->energyLoss()->deltaE();
1937  if ((*measurement).isEnergyDeposit())
1938  deltaE = -deltaE;
1939  msg() << std::setw(10) << std::setprecision(3)
1940  << (*measurement).materialEffects()->thicknessInX0() << std::setw(9)
1941  << std::setprecision(1) << deltaE << " ";
1942  if (distance > 0.) {
1943  ++scatterers;
1944  sumX0 += (*measurement).materialEffects()->thicknessInX0();
1945  sumELoss -= deltaE;
1946  } else {
1947  ++leadingMaterial;
1948  leadingX0 += (*measurement).materialEffects()->thicknessInX0();
1949  leadingELoss -= deltaE;
1950  }
1951 
1952  if ((*measurement).qOverP()) {
1953  msg() << std::setw(11) << std::setprecision(4)
1954  << 1. / std::abs((*measurement).qOverP() * Gaudi::Units::GeV)
1955  << std::setw(10) << std::setprecision(3)
1956  << (*measurement)
1957  .intersection(FittedTrajectory)
1958  .direction()
1959  .perp() /
1960  ((*measurement).qOverP() * Gaudi::Units::GeV)
1961  << std::setw(12);
1962  }
1963  } else {
1964  msg() << std::setw(54);
1965  }
1966  if ((*measurement).isMaterialDelimiter()) {
1967  msg() << std::setprecision(1)
1968  << (*measurement).intersection(FittedTrajectory).position().perp()
1969  << std::setw(9) << std::setprecision(4)
1970  << (*measurement).intersection(FittedTrajectory).position().phi()
1971  << std::setw(10) << std::setprecision(1)
1972  << (*measurement).intersection(FittedTrajectory).position().z()
1973  << std::setw(14) << std::setprecision(4)
1974  << (*measurement).intersection(FittedTrajectory).direction().phi()
1975  << std::setw(9) << std::setprecision(4)
1976  << (*measurement).intersection(FittedTrajectory).direction().theta()
1977  << endmsg;
1978  } else {
1979  msg() << std::setprecision(1) << (*measurement).position().perp()
1980  << std::setw(9) << std::setprecision(4)
1981  << (*measurement).position().phi() << std::setw(10)
1982  << std::setprecision(1) << (*measurement).position().z()
1983  << std::setw(5) << (*measurement).numberDoF() << endmsg;
1984  }
1985  }
1986 
1987  // fix counting at allocation stage
1988  if (!scatterers) {
1989  scatterers = leadingMaterial;
1990  leadingMaterial = 0;
1991  }
1992 
1993  ATH_MSG_DEBUG(
1994  " material: "
1995  << scatterers << " (" << leadingMaterial
1996  << ") fitted scattering centres (leading material centres) giving "
1997  << std::setiosflags(std::ios::fixed) << std::setw(8)
1998  << std::setprecision(3) << sumX0 << " (" << std::setw(8)
1999  << std::setprecision(3) << leadingX0 << ")"
2000  << " X0 and " << std::setw(8) << std::setprecision(3)
2001  << sumELoss / Gaudi::Units::GeV << " (" << std::setw(8)
2002  << std::setprecision(3) << leadingELoss / Gaudi::Units::GeV << ")"
2003  << " GeV Eloss");
2004 }
2005 
2007  std::vector<FitMeasurement*>& measurements,
2008  ParticleHypothesis particleHypothesis, FitParameters& fitParameters,
2009  const TrackParameters& startParameters, Garbage_t& garbage) const {
2010  const EventContext& ctx = Gaudi::Hive::currentContext();
2011  // return if no MS measurement
2012  if (m_calorimeterVolume->inside(measurements.back()->position()))
2013  return;
2014 
2015  // check that the spectrometer measurements are ordered and that material
2016  // allocation is required
2017  Amg::Vector3D startDirection = startParameters.momentum().unit();
2018  Amg::Vector3D startPosition = startParameters.position();
2019  bool haveMaterial = false;
2020  bool haveLeadingMaterial = false;
2021  bool reorderMS = false;
2022  bool reorderID = false;
2023  bool firstMSHit = false;
2024  double previousDistance = 0.;
2025  double previousDistanceR = 0.;
2026  double previousDistanceZ = 0.;
2027  double minDistanceID = 0.;
2028  double minDistanceMS = 0.;
2029  double minRDistanceMS = 0.;
2030  double minZDistanceMS = 0.;
2031  std::vector<Trk::FitMeasurement*>::iterator m = measurements.begin();
2032  for (; m != measurements.end(); ++m) {
2033  Amg::Vector3D position = (**m).intersection(FittedTrajectory).position();
2034  Amg::Vector3D positionSurf = (**m).surface()->center();
2035  Amg::Vector3D positionMst = startPosition;
2036  if ((**m).measurementBase())
2037  positionMst = (**m).measurementBase()->globalPosition();
2038  double distance = startDirection.dot(position - startPosition);
2039  double distanceR = std::hypot(positionMst.x() - startPosition.x(),
2040  positionMst.y() - startPosition.y());
2041  double distanceZ = (positionMst.z() - startPosition.z());
2042  if (startDirection.z() < 0)
2043  distanceZ = -distanceZ;
2044  if (!m_calorimeterVolume->inside(position) ||
2045  !m_calorimeterVolume->inside(positionSurf)) {
2046  if (distance - previousDistance < -m_orderingTolerance) {
2047  reorderMS = true;
2048  if (distance - previousDistance < minDistanceMS) {
2049  minDistanceMS = distance - previousDistance;
2050  minRDistanceMS = distanceR - previousDistanceR;
2051  minZDistanceMS = distanceZ - previousDistanceZ;
2052  }
2053  }
2054  if ((**m).isScatterer())
2055  haveMaterial = true;
2056  if ((**m).measurementBase() && !firstMSHit) {
2057  firstMSHit = true;
2058  }
2059  if ((**m).isScatterer() && !firstMSHit)
2060  haveLeadingMaterial = true;
2061  } else {
2062  if (distance - previousDistance < -m_orderingTolerance) {
2063  reorderID = true;
2064  if (distance - previousDistance < minDistanceID)
2065  minDistanceID = distance - previousDistance;
2066  }
2067  }
2068  previousDistance = distance;
2069  previousDistanceZ = distanceZ;
2070  previousDistanceR = distanceR;
2071  }
2072 
2073  if (reorderMS && (minRDistanceMS > -m_orderingTolerance ||
2074  minZDistanceMS > -m_orderingTolerance)) {
2075  // 3D distance of the intersection is problematic but the R or Z distance
2076  // of the measurementBase is fine we should not reorder
2077 
2078  reorderMS = false;
2079  }
2080 
2081  // if(!m_allowReordering) {
2082  if (reorderMS && fabs(minDistanceMS) > -2.)
2083  ATH_MSG_DEBUG(" reorder MS part of track with minimum distance "
2084  << minDistanceMS << " minRDistanceMS " << minRDistanceMS
2085  << " minZDistanceMS " << minZDistanceMS);
2086  if (reorderID && fabs(minDistanceID) > -2.)
2087  ATH_MSG_DEBUG(" reorder ID part of track with minimum distance "
2088  << minDistanceID);
2089  // }
2090 
2091  if (reorderMS || reorderID) {
2092  if (msgLvl(MSG::DEBUG))
2093  printMeasurements(measurements);
2094  }
2095 
2096  if (!haveLeadingMaterial && haveMaterial) {
2098  " MS part of track has no leading material in front of first MS hit ");
2099  }
2100 
2101  if (reorderMS)
2102  orderMeasurements(measurements, startDirection, startPosition);
2103 
2104  // nothing to do if spectrometer material already exists
2105  if (haveMaterial)
2106  return;
2107 
2108  ATH_MSG_DEBUG(
2109  " spectrometerMaterial: ALARM no material found on track can happen for "
2110  "MuGirl");
2111 
2112  // material has to be added: need inner and outer TrackParameters
2113  FitMeasurement* innerMeasurement = nullptr;
2114  FitMeasurement* outerMeasurement = nullptr;
2115  for (m = measurements.begin(); m != measurements.end(); ++m) {
2116  if (!(**m).isPositionMeasurement() || (**m).isOutlier())
2117  continue;
2119  if (m_calorimeterVolume->inside(position))
2120  continue;
2121  if (innerMeasurement) {
2122  outerMeasurement = *m;
2123  } else {
2124  innerMeasurement = *m;
2125  }
2126  }
2127  if (!outerMeasurement)
2128  return;
2129 
2130  // insert delimiters
2131  addSpectrometerDelimiters(measurements);
2132 
2133  const Trk::TrackingVolume* spectrometerEntrance = getSpectrometerEntrance();
2134  if (!spectrometerEntrance)
2135  return;
2136 
2137  // entranceParameters are at the MS entrance surface (0 if perigee downstream)
2138  TrackSurfaceIntersection* entranceIntersection = nullptr;
2139  std::unique_ptr<const TrackParameters> entranceParameters;
2140  MsgStream log(msgSvc(), name());
2141  if (m_calorimeterVolume->inside(startParameters.position())) {
2142  std::unique_ptr<const TrackParameters> innerParameters(
2143  fitParameters.trackParameters(log, *innerMeasurement, false));
2144  if (!innerParameters)
2145  innerParameters.reset(startParameters.clone());
2146  entranceParameters = m_extrapolator->extrapolateToVolume(
2147  ctx, *innerParameters, *spectrometerEntrance, anyDirection,
2149  if (entranceParameters) {
2150  startDirection = entranceParameters->momentum().unit();
2151  startPosition = entranceParameters->position();
2152  entranceIntersection = new TrackSurfaceIntersection(
2153  entranceParameters->position(), entranceParameters->momentum().unit(),
2154  0.);
2155  std::vector<Trk::FitMeasurement*>::iterator e = measurements.begin();
2156  FitMeasurement* entranceDelimiter =
2157  new FitMeasurement(*entranceIntersection, 0.);
2158  for (m = measurements.begin(); m != measurements.end(); ++m) {
2159  if (!m_calorimeterVolume->inside((**m).position()))
2160  break;
2161  e = m;
2162  }
2163 
2164  // insert a material delimiter at the start of the spectrometer (or at
2165  // perigee if in MS)
2166  e = measurements.insert(++e, entranceDelimiter);
2167  delete entranceIntersection;
2168  } else {
2169  // did not find MS entrance surface - no MS material taken into account
2170  // m_messageHelper->printWarning(3); ATLASRECTS-7528
2171  return;
2172  }
2173  }
2174 
2175  // insert a material delimiter after the last measurement (endParameters)
2176  std::unique_ptr<const TrackParameters> outerParameters(
2177  fitParameters.trackParameters(log, *outerMeasurement, false));
2178  if (!outerParameters)
2179  outerParameters.reset(startParameters.clone());
2180  const Surface& endSurface = *measurements.back()->surface();
2181  std::unique_ptr<const TrackParameters> endParameters(
2182  m_extrapolator->extrapolate(ctx, *outerParameters, endSurface,
2183  anyDirection, false, particleHypothesis));
2184 
2185  if (!endParameters) {
2186  endParameters =
2187  m_extrapolator->extrapolate(ctx, *outerParameters, endSurface,
2189 
2190  if (!endParameters) {
2191  // failed extrapolation
2192  m_messageHelper->printWarning(4);
2193  endParameters = std::move(outerParameters);
2194  }
2195  }
2196  // insert delimiter
2197  const TrackSurfaceIntersection endIntersection(
2198  endParameters->position(), endParameters->momentum().unit(), 0.);
2199  FitMeasurement* endBreak =
2200  new FitMeasurement(endIntersection, 20. * Gaudi::Units::mm);
2201  measurements.push_back(endBreak);
2202 
2203  double endSpectrometerDistance = startDirection.dot(
2204  measurements.back()->intersection(FittedTrajectory).position() -
2205  startPosition);
2206  const std::vector<const TrackStateOnSurface*>* spectrometerMaterial = nullptr;
2207 
2208  // protect the momentum to avoid excessive Eloss
2209 
2210  Amg::VectorX parameterVector = endParameters->parameters();
2211  double Emax = 50000.;
2212  if (parameterVector[Trk::qOverP] == 0.) {
2213  parameterVector[Trk::qOverP] = 1. / Emax;
2214  } else {
2215  if (std::abs(parameterVector[Trk::qOverP]) * Emax < 1)
2216  parameterVector[Trk::qOverP] = endParameters->charge() / Emax;
2217  }
2218 
2219  // correct track parameters for high momentum track (otherwise Eloss is too
2220  // large)
2221  endParameters =
2222  endParameters->associatedSurface().createUniqueTrackParameters(
2223  parameterVector[Trk::loc1], parameterVector[Trk::loc2],
2224  parameterVector[Trk::phi], parameterVector[Trk::theta],
2225  parameterVector[Trk::qOverP], std::nullopt);
2226 
2227  if (entranceParameters) {
2228  const Surface& entranceSurface = entranceParameters->associatedSurface();
2230  extrapolatedMaterial(m_extrapolator, *endParameters, entranceSurface,
2231  anyDirection, false, Trk::muon, garbage);
2232  } else {
2233  const Surface& entranceSurface = startParameters.associatedSurface();
2235  extrapolatedMaterial(m_extrapolator, *endParameters, entranceSurface,
2236  anyDirection, false, Trk::muon, garbage);
2237  }
2238 
2239  // debug
2241  !spectrometerMaterial->empty()) {
2242  ATH_MSG_VERBOSE(" spectrometerMaterial: "
2243  << "using extrapolateM inwards from outermost measurement");
2244  double p1 = 0.;
2245  if (spectrometerMaterial->front()->trackParameters())
2246  p1 = spectrometerMaterial->front()->trackParameters()->momentum().mag();
2247  for (const auto* ss : *spectrometerMaterial) {
2248  if (!(*ss).trackParameters() || !(*ss).materialEffectsOnTrack())
2249  continue;
2250  double distance = startDirection.dot((*ss).trackParameters()->position() -
2251  startPosition);
2252  double deltaE = 0.;
2253  double thickness = (*ss).materialEffectsOnTrack()->thicknessInX0();
2254  const MaterialEffectsOnTrack* materialEffects =
2255  dynamic_cast<const MaterialEffectsOnTrack*>(
2256  (*ss).materialEffectsOnTrack());
2257  if (materialEffects && materialEffects->energyLoss())
2258  deltaE = materialEffects->energyLoss()->deltaE();
2259  double p2 = (*ss).trackParameters()->momentum().mag();
2261  std::setiosflags(std::ios::fixed)
2262  << " material: RZ" << std::setw(9) << std::setprecision(3)
2263  << (*ss).trackParameters()->position().perp() << std::setw(10)
2264  << std::setprecision(3) << (*ss).trackParameters()->position().z()
2265  << " distance " << std::setw(10) << std::setprecision(3) << distance
2266  << " pt " << std::setw(8) << std::setprecision(3)
2267  << (*ss).trackParameters()->momentum().perp() / Gaudi::Units::GeV
2268  << " X0thickness " << std::setw(8) << std::setprecision(4)
2269  << thickness << " deltaE " << std::setw(8) << std::setprecision(4)
2270  << deltaE << " diffP " << std::setw(8) << std::setprecision(4)
2271  << p2 - p1);
2272  p1 = p2;
2273  }
2274  }
2275 
2276  // insert the material into the measurement list
2277  if (!spectrometerMaterial || spectrometerMaterial->empty()) {
2278  // m_messageHelper->printWarning(5);
2279  // Suppressing, as discussed in ATLASRECTS-7515, but keeping this here to remind us
2280  // to investigate it properly.
2281  delete spectrometerMaterial;
2282  spectrometerMaterial = nullptr;
2283  } else {
2284  std::vector<const TrackStateOnSurface*>::const_reverse_iterator s =
2285  spectrometerMaterial->rbegin();
2286  std::vector<FitMeasurement*> material;
2287  double particleMass = Trk::ParticleMasses::mass[particleHypothesis];
2288  material.reserve(spectrometerMaterial->size());
2289  std::vector<FitMeasurement*>::iterator m = measurements.begin();
2290  for (; s != spectrometerMaterial->rend();) {
2291  const TrackStateOnSurface& tsos = **s;
2292  while (++s != spectrometerMaterial->rend() && !(**s).trackParameters())
2293  ;
2294 
2295  double outgoingEnergy = 0.;
2296  if (s != spectrometerMaterial->rend()) {
2297  outgoingEnergy = (**s).trackParameters()->momentum().mag();
2298  } else {
2299  outgoingEnergy = endParameters->momentum().mag();
2300  }
2301 
2302  FitMeasurement* measurement =
2303  measurementFromTSOS(tsos, outgoingEnergy, particleMass);
2304  if (!measurement)
2305  continue;
2306 
2307  // insert next to adjacent measurement
2308  material.push_back(measurement);
2309  double distance = startDirection.dot(tsos.trackParameters()->position() -
2310  startPosition);
2311  if (distance > endSpectrometerDistance) {
2312  delete measurement;
2313  break;
2314  }
2315  while (m != measurements.end() &&
2316  distance > startDirection.dot(
2317  (**m).intersection(FittedTrajectory).position() -
2318  startPosition)) {
2319  ++m;
2320  }
2321  if (m == measurements.end()) {
2322  delete measurement;
2323  break;
2324  }
2325 
2326  m = measurements.insert(m, material.back());
2327  }
2328  }
2329 
2330  // // check sign and order here
2331  // printMeasurements(measurements);
2332 
2333  // memory management
2334  ATH_MSG_VERBOSE(" spectrometer: mem management");
2336 
2337  materialAggregation(measurements,
2338  Trk::ParticleMasses::mass[particleHypothesis]);
2339 }
2340 } // namespace Trk
Trk::MaterialAllocator::printMeasurements
void printMeasurements(std::vector< FitMeasurement * > &measurements) const
Definition: MaterialAllocator.cxx:1899
xAOD::iterator
JetConstituentVector::iterator iterator
Definition: JetConstituentVector.cxx:68
Trk::MaterialAllocator::m_scattererMinGap
double m_scattererMinGap
Definition: MaterialAllocator.h:182
Trk::anyDirection
@ anyDirection
Definition: PropDirection.h:22
AllowedVariables::e
e
Definition: AsgElectronSelectorTool.cxx:37
beamspotman.r
def r
Definition: beamspotman.py:676
Trk::TrackStateOnSurface::trackParameters
const TrackParameters * trackParameters() const
return ptr to trackparameters const overload
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:213
fillPileUpNoiseLumi.current
current
Definition: fillPileUpNoiseLumi.py:52
Trk::FitMeasurement::intersection
const TrackSurfaceIntersection & intersection(ExtrapolationType type) const
Definition: FitMeasurement.h:359
TrkDetElementBase.h
EnergyLoss.h
GeV
#define GeV
Definition: PhysicsAnalysis/TauID/TauAnalysisTools/Root/HelperFunctions.cxx:17
python.SystemOfUnits.s
int s
Definition: SystemOfUnits.py:131
Amg::VectorX
Eigen::Matrix< double, Eigen::Dynamic, 1 > VectorX
Dynamic Vector - dynamic allocation.
Definition: EventPrimitives.h:30
tolerance
constexpr double tolerance
Definition: runMdtGeoComparison.cxx:104
python.SystemOfUnits.m
int m
Definition: SystemOfUnits.py:91
StraightLineSurface.h
TrackParameters.h
PowhegControl_ttHplus_NLO.ss
ss
Definition: PowhegControl_ttHplus_NLO.py:83
MeasurementBase.h
Trk::MagneticFieldProperties
Definition: MagneticFieldProperties.h:31
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
Trk::MaterialAllocator::m_allowReordering
bool m_allowReordering
Definition: MaterialAllocator.h:175
Trk::ParametersBase::charge
double charge() const
Returns the charge.
Trk::FitMeasurement::hasIntersection
bool hasIntersection(ExtrapolationType type) const
Definition: FitMeasurement.h:355
Surface.h
Base_Fragment.mass
mass
Definition: Sherpa_i/share/common/Base_Fragment.py:59
Trk::FitParameters::direction
Amg::Vector3D direction(void) const
Definition: FitParameters.h:200
perp
Scalar perp() const
perp method - perpenticular length
Definition: AmgMatrixBasePlugin.h:44
Trk::Volume::inside
bool inside(const Amg::Vector3D &gp, double tol=0.) const
Inside() method for checks.
Definition: Volume.cxx:90
Trk::next
@ next
Definition: BinningData.h:33
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
Trk::oppositeMomentum
@ oppositeMomentum
Definition: PropDirection.h:21
index
Definition: index.py:1
Trk::ParametersBase::associatedSurface
virtual const Surface & associatedSurface() const override=0
Access to the Surface associated to the Parameters.
Trk::ParametersT
Dummy class used to allow special convertors to be called for surfaces owned by a detector element.
Definition: EMErrorDetail.h:25
Trk::MaterialAllocator::m_maxWarnings
unsigned m_maxWarnings
Definition: MaterialAllocator.h:177
Trk::FitMeasurement::surface
const Surface * surface(void) const
Definition: FitMeasurement.h:585
mergePhysValFiles.start
start
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:14
Trk::MaterialAllocator::m_scatteringLogCoeff
double m_scatteringLogCoeff
Definition: MaterialAllocator.h:184
python.SystemOfUnits.MeV
int MeV
Definition: SystemOfUnits.py:154
Trk::MaterialAllocator::m_messageHelper
std::unique_ptr< MessageHelper > m_messageHelper
Definition: MaterialAllocator.h:195
Trk::MaterialAllocator::m_stepPropagator
ToolHandle< IPropagator > m_stepPropagator
Definition: MaterialAllocator.h:151
Trk::MaterialAllocator::m_stepField
Trk::MagneticFieldProperties m_stepField
Definition: MaterialAllocator.h:192
TRTCalib_cfilter.p1
p1
Definition: TRTCalib_cfilter.py:130
Trk::MaterialAllocator::m_trackingGeometryReadKey
SG::ReadCondHandleKey< TrackingGeometry > m_trackingGeometryReadKey
Definition: MaterialAllocator.h:154
Trk::MaterialAllocator::allocateMaterial
virtual void allocateMaterial(std::vector< FitMeasurement * > &measurements, ParticleHypothesis particleHypothesis, FitParameters &fitParameters, const TrackParameters &startParameters, Garbage_t &garbage) const override
IMaterialAllocator interface: allocate material.
Definition: MaterialAllocator.cxx:520
Trk::MaterialAllocator::spectrometerMaterial
void spectrometerMaterial(std::vector< FitMeasurement * > &measurements, ParticleHypothesis particleHypothesis, FitParameters &fitParameters, const TrackParameters &startParameters, Garbage_t &garbage) const
Definition: MaterialAllocator.cxx:2009
Trk::ITrackingVolumesSvc::MuonSpectrometerEntryLayer
@ MuonSpectrometerEntryLayer
Tracking Volume which defines the entrance surfaces of the MS.
Definition: ITrackingVolumesSvc.h:41
Surface
Definition: Trigger/TrigAccel/TrigCudaFitter/src/Surface.h:8
Trk::MaterialAllocator::m_calorimeterVolume
const Trk::Volume * m_calorimeterVolume
Definition: MaterialAllocator.h:189
python.atlas_oh.im
im
Definition: atlas_oh.py:167
AthCommonMsg< AlgTool >::msgLvl
bool msgLvl(const MSG::Level lvl) const
Definition: AthCommonMsg.h:30
Trk::MaterialAllocator::initialize
virtual StatusCode initialize() override
Definition: MaterialAllocator.cxx:74
Trk::MaterialAllocator::addLeadingMaterial
virtual void addLeadingMaterial(std::vector< FitMeasurement * > &measurements, ParticleHypothesis particleHypothesis, FitParameters &fitParameters, Garbage_t &garbage) const override
IMaterialAllocator interface: add leading material effects to fit measurements and parameters.
Definition: MaterialAllocator.cxx:133
Trk::loc2
@ loc2
generic first and second local coordinate
Definition: ParamDefs.h:35
Trk::FitParameters::vertex
const Amg::Vector3D & vertex(void) const
Definition: FitParameters.h:285
Trk::MaterialEffectsBase::thicknessInX0
double thicknessInX0() const
returns the actually traversed material .
UploadAMITag.l
list l
Definition: UploadAMITag.larcaf.py:158
Trk::TrackSurfaceIntersection
Definition: TrackSurfaceIntersection.h:32
Trk::alongMomentum
@ alongMomentum
Definition: PropDirection.h:20
Trk::FitMeasurement::position
const Amg::Vector3D & position(void) const
Definition: FitMeasurement.h:482
Trk::MaterialAllocator::m_scatteringConstant
double m_scatteringConstant
Definition: MaterialAllocator.h:183
Trk::locR
@ locR
Definition: ParamDefs.h:44
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
intersection
std::vector< std::string > intersection(std::vector< std::string > &v1, std::vector< std::string > &v2)
Definition: compareFlatTrees.cxx:25
CaloSwCorrections.gap
def gap(flags, cells_name, *args, **kw)
Definition: CaloSwCorrections.py:212
Trk::MaterialAllocator::MaterialAllocator
MaterialAllocator(const std::string &type, const std::string &name, const IInterface *parent)
Definition: MaterialAllocator.cxx:38
FitParameters.h
Trk::MaterialAllocator::deleteMaterial
static void deleteMaterial(const std::vector< const TrackStateOnSurface * > *material, Garbage_t &garbage)
Definition: MaterialAllocator.cxx:990
Trk::MaterialAllocator::m_useStepPropagator
int m_useStepPropagator
Definition: MaterialAllocator.h:176
MessageHelper.h
dqt_zlumi_pandas.weight
int weight
Definition: dqt_zlumi_pandas.py:189
Track.h
ExtrapolationType.h
Trk::MaterialAllocator::finalize
virtual StatusCode finalize() override
Definition: MaterialAllocator.cxx:127
MaterialEffectsOnTrack.h
Trk::FastField
@ FastField
call the fast field access method of the FieldSvc
Definition: MagneticFieldMode.h:20
Trk::AmgSymMatrix
AmgSymMatrix(5) &GXFTrackState
Definition: GXFTrackState.h:156
PixelModuleFeMask_create_db.remove
string remove
Definition: PixelModuleFeMask_create_db.py:83
Trk::ParticleHypothesis
ParticleHypothesis
Definition: ParticleHypothesis.h:25
Trk::ParametersT::associatedSurface
virtual const S & associatedSurface() const override final
Access to the Surface method.
Trk::MaterialEffectsOnTrack
represents the full description of deflection and e-loss of a track in material.
Definition: MaterialEffectsOnTrack.h:40
TRTCalib_cfilter.p2
p2
Definition: TRTCalib_cfilter.py:131
Trk::MaterialAllocator::orderMeasurements
virtual void orderMeasurements(std::vector< FitMeasurement * > &measurements, Amg::Vector3D startDirection, Amg::Vector3D startPosition) const override
IMaterialAllocator interface: clear temporary TSOS.
Definition: MaterialAllocator.cxx:696
Trk::PropDirection
PropDirection
Definition: PropDirection.h:19
python.AthDsoLogger.delimiter
delimiter
Definition: AthDsoLogger.py:71
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:210
Trk::FitMeasurement::isOutlier
bool isOutlier(void) const
Definition: FitMeasurement.h:389
Trk::MaterialAllocator::m_indetVolume
const Trk::Volume * m_indetVolume
Definition: MaterialAllocator.h:190
python.SystemOfUnits.meter
int meter
Definition: SystemOfUnits.py:61
Trk::locZ
@ locZ
local cylindrical
Definition: ParamDefs.h:42
StdJOSetup.msgSvc
msgSvc
Provide convenience handles for various services.
Definition: StdJOSetup.py:36
Trk::TrackSurfaceIntersection::position
const Amg::Vector3D & position() const
Method to retrieve the position of the Intersection.
Definition: TrackSurfaceIntersection.h:80
beamspotman.n
n
Definition: beamspotman.py:731
Trk::theta
@ theta
Definition: ParamDefs.h:66
Trk::FitMeasurement
Definition: FitMeasurement.h:40
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
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
angle
double angle(const GeoTrf::Vector2D &a, const GeoTrf::Vector2D &b)
Definition: TRTDetectorFactory_Full.cxx:73
mc.order
order
Configure Herwig7.
Definition: mc.Herwig7_Dijet.py:12
Trk::MaterialAllocator::m_orderingTolerance
double m_orderingTolerance
Definition: MaterialAllocator.h:181
Trk::EnergyLoss::deltaE
double deltaE() const
returns the
test_pyathena.parent
parent
Definition: test_pyathena.py:15
Trk::IMaterialAllocator::Garbage_t
std::vector< std::unique_ptr< const TrackStateOnSurface > > Garbage_t
Definition: IMaterialAllocator.h:40
Trk::MaterialAllocator::measurementFromTSOS
static FitMeasurement * measurementFromTSOS(const TrackStateOnSurface &tsos, double outwardsEnergy, double particleMass)
Definition: MaterialAllocator.cxx:1881
Trk::FitParameters::update
void update(const Amg::VectorX &differences)
Definition: FitParameters.cxx:603
Trk::FitParameters::position
const Amg::Vector3D & position(void) const
Definition: FitParameters.h:253
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
Trk::MaterialAllocator::addSpectrometerDelimiters
void addSpectrometerDelimiters(std::vector< FitMeasurement * > &measurements) const
Definition: MaterialAllocator.cxx:877
Trk::FitParameters::qOverP
double qOverP(void) const
Definition: FitParameters.h:257
Trk::ParametersBase
Definition: ParametersBase.h:55
Trk::MaterialAllocator::m_sectorMaxPhi
double m_sectorMaxPhi
Definition: MaterialAllocator.h:185
Trk::muon
@ muon
Definition: ParticleHypothesis.h:28
Trk::MaterialAllocator::m_intersector
ToolHandle< IIntersector > m_intersector
Definition: MaterialAllocator.h:143
Trk::FullField
@ FullField
Field is set to be realistic, but within a given Volume.
Definition: MagneticFieldMode.h:21
MaterialAllocator.h
Trk::MaterialAllocator::getSpectrometerEntrance
const Trk::TrackingVolume * getSpectrometerEntrance() const
Definition: MaterialAllocator.h:158
beamspotman.dir
string dir
Definition: beamspotman.py:623
Trk::ITrackingVolumesSvc::CalorimeterEntryLayer
@ CalorimeterEntryLayer
Tracking Volume which defines the entrance srufaces of the calorimeter.
Definition: ITrackingVolumesSvc.h:40
tolerance
Definition: suep_shower.h:17
Athena::Units
Definition: Units.h:45
Trk::ParticleMasses::mass
constexpr double mass[PARTICLEHYPOTHESES]
the array of masses
Definition: ParticleHypothesis.h:53
Trk
Ensure that the ATLAS eigen extensions are properly loaded.
Definition: FakeTrackBuilder.h:9
Trk::TrackStateOnSurface
represents the track state (measurement, material, fit parameters and quality) at a surface.
Definition: TrackStateOnSurface.h:71
Trk::MaterialAllocator::m_trackingGeometrySvc
ServiceHandle< ITrackingGeometrySvc > m_trackingGeometrySvc
Definition: MaterialAllocator.h:146
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:221
Trk::MaterialAllocator::indetMaterial
void indetMaterial(std::vector< FitMeasurement * > &measurements, ParticleHypothesis particleHypothesis, const TrackParameters &startParameters, Garbage_t &garbage) const
Definition: MaterialAllocator.cxx:1053
Trk::nonInteracting
@ nonInteracting
Definition: ParticleHypothesis.h:25
Trk::TrackParameters
ParametersBase< TrackParametersDim, Charged > TrackParameters
Definition: Tracking/TrkEvent/TrkParameters/TrkParameters/TrackParameters.h:27
Trk::FittedTrajectory
@ FittedTrajectory
Definition: ExtrapolationType.h:19
charge
double charge(const T &p)
Definition: AtlasPID.h:538
Trk::MaterialAllocator::m_trackingVolumesSvc
ServiceHandle< ITrackingVolumesSvc > m_trackingVolumesSvc
Definition: MaterialAllocator.h:148
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
ParticleGun_SamplingFraction.radius
radius
Definition: ParticleGun_SamplingFraction.py:96
Trk::TrackSurfaceIntersection::direction
const Amg::Vector3D & direction() const
Method to retrieve the direction at the Intersection.
Definition: TrackSurfaceIntersection.h:88
FitMeasurement.h
python.SystemOfUnits.mm
int mm
Definition: SystemOfUnits.py:83
Trk::ParametersBase::momentum
const Amg::Vector3D & momentum() const
Access method for the momentum.
Trk::MaterialAllocator::reallocateMaterial
virtual bool reallocateMaterial(std::vector< FitMeasurement * > &measurements, FitParameters &fitParameters, Garbage_t &garbage) const override
IMaterialAllocator interface: has material been reallocated?
Definition: MaterialAllocator.cxx:752
TrackingVolume.h
Trk::MaterialEffectsOnTrack::energyLoss
const EnergyLoss * energyLoss() const
returns the energy loss object.
Trk::CurvilinearUVT
Definition: CurvilinearUVT.h:45
GlobalVariables.Emax
Emax
Definition: GlobalVariables.py:185
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
Trk::MaterialAllocator::materialAggregation
std::pair< FitMeasurement *, FitMeasurement * > materialAggregation(const std::vector< const TrackStateOnSurface * > &material, std::vector< FitMeasurement * > &measurements, double particleMass) const
Definition: MaterialAllocator.cxx:1468
Trk::PlaneSurface
Definition: PlaneSurface.h:64
Trk::BoundaryCheck
Definition: BoundaryCheck.h:51
Trk::MaterialAllocator::m_extrapolator
ToolHandle< IExtrapolator > m_extrapolator
Definition: MaterialAllocator.h:141
PlaneSurface.h
unit
const PlainObject unit() const
This is a plugin that makes Eigen look like CLHEP & defines some convenience methods.
Definition: AmgMatrixBasePlugin.h:21
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
DEBUG
#define DEBUG
Definition: page_access.h:11
AthCommonMsg< AlgTool >::msg
MsgStream & msg() const
Definition: AthCommonMsg.h:24
generate::integrate
TH1D * integrate(TH1D *hin)
generate an integrated distribution
Definition: generate.cxx:68
Trk::qOverP
@ qOverP
perigee
Definition: ParamDefs.h:67
Trk::SurfaceType::Disc
@ Disc
python.CaloCondTools.log
log
Definition: CaloCondTools.py:20
Trk::MaterialAllocator::initializeScattering
virtual void initializeScattering(std::vector< FitMeasurement * > &measurements) const override
IMaterialAllocator interface: initialize scattering (needs to know X0 integral)
Definition: MaterialAllocator.cxx:537
convertTimingResiduals.offset
offset
Definition: convertTimingResiduals.py:71
Trk::MaterialAllocator::m_stationMaxGap
double m_stationMaxGap
Definition: MaterialAllocator.h:186
Gaudi
=============================================================================
Definition: CaloGPUClusterAndCellDataMonitorOptions.h:273
physics_parameters.parameters
parameters
Definition: physics_parameters.py:144
TrackingGeometry.h
Trk::SurfaceType::Plane
@ Plane
Trk::phi
@ phi
Definition: ParamDefs.h:75
Trk::FitParameters
Definition: FitParameters.h:29
python.Constants.VERBOSE
int VERBOSE
Definition: Control/AthenaCommon/python/Constants.py:14
Amg::distance2
float distance2(const Amg::Vector3D &p1, const Amg::Vector3D &p2)
calculates the squared distance between two point in 3D space
Definition: GeoPrimitivesHelpers.h:48
AthAlgTool
Definition: AthAlgTool.h:26
TrackSurfaceIntersection.h
Trk::loc1
@ loc1
Definition: ParamDefs.h:34
Trk::FitMeasurement::qOverP
double qOverP(void) const
Definition: FitMeasurement.h:486
Trk::Surface
Definition: Tracking/TrkDetDescr/TrkSurfaces/TrkSurfaces/Surface.h:75
Trk::TrackingVolume
Definition: TrackingVolume.h:121
Trk::EnergyLoss::clone
virtual EnergyLoss * clone() const
Virtual constructor.
Amg::distance
float distance(const Amg::Vector3D &p1, const Amg::Vector3D &p2)
calculates the distance between two point in 3D space
Definition: GeoPrimitivesHelpers.h:54
makeComparison.deltaR
float deltaR
Definition: makeComparison.py:36
mag
Scalar mag() const
mag method
Definition: AmgMatrixBasePlugin.h:26
generateReferenceFile.duplicates
duplicates
Definition: generateReferenceFile.py:24
Trk::MaterialAllocator::extrapolatedMaterial
const std::vector< const TrackStateOnSurface * > * extrapolatedMaterial(const ToolHandle< IExtrapolator > &extrapolator, const TrackParameters &parameters, const Surface &surface, PropDirection dir, const BoundaryCheck &boundsCheck, ParticleHypothesis particleHypothesis, Garbage_t &garbage) const
Definition: MaterialAllocator.cxx:1002
TrackStateOnSurface.h
Trk::MaterialAllocator::leadingSpectrometerTSOS
virtual std::vector< const TrackStateOnSurface * > * leadingSpectrometerTSOS(const TrackParameters &spectrometerParameters, Garbage_t &garbage) const override
IMaterialAllocator interface: material TSOS between spectrometer entrance surface and parameters give...
Definition: MaterialAllocator.cxx:608
Trk::ParametersBase::clone
virtual ParametersBase< DIM, T > * clone() const override=0
clone method for polymorphic deep copy
Trk::previous
@ previous
Definition: BinningData.h:32