ATLAS Offline Software
Loading...
Searching...
No Matches
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
34namespace Trk {
36 const std::string& name,
37 const IInterface* parent)
38 : AthAlgTool(type, name, parent),
40 m_allowReordering(false),
42 m_maxWarnings(10),
44 m_scattererMinGap(100. * Gaudi::Units::mm),
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);
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()) {
102 } else
104 // need to create the IndetExit and MuonEntrance TrackingVolumes
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 const 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
266 indetMaterial = nullptr;
267
268 std::vector<const TrackStateOnSurface*>* indetMaterialF = nullptr;
269 const std::vector<const TrackStateOnSurface*>* indetMaterialR = nullptr;
270 const CurvilinearUVT uvt(intersection->direction());
271 Amg::Vector2D localPos;
272 const PlaneSurface plane(intersection->position(), uvt);
273 if (plane.globalToLocal(intersection->position(),
274 intersection->direction(), localPos)) {
275 const AtaPlane parameters(localPos[locR], localPos[locZ],
276 intersection->direction().phi(),
277 intersection->direction().theta(), qOverP, plane);
278
279 indetMaterialR = extrapolatedMaterial(
280 m_extrapolator, parameters, perigee.associatedSurface(),
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> const newIntersectionSTEP =
336 m_stepPropagator->intersectSurface(
337 ctx, (**r).trackParameters()->associatedSurface(),
340 intersection = m_intersector->intersectSurface(
341 (**r).trackParameters()->associatedSurface(), *intersection,
342 qOverP);
343 } else {
346 ? m_stepPropagator->intersectSurface(
347 ctx, (**r).trackParameters()->associatedSurface(),
349 : m_intersector->intersectSurface(
350 (**r).trackParameters()->associatedSurface(),
352 }
353
354 // quit if tracking problem
355 if (!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 const 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> const newIntersectionSTEP =
423 m_stepPropagator->intersectSurface(
424 ctx, perigee.associatedSurface(), *intersection, qOverP,
426 intersection = m_intersector->intersectSurface(
428 } else {
431 ? m_stepPropagator->intersectSurface(
432 ctx, perigee.associatedSurface(), *intersection, qOverP,
434 : m_intersector->intersectSurface(perigee.associatedSurface(),
436 }
437 } else {
438 intersection = std::nullopt;
439 }
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 const double logTerm = 1.0 + m_scatteringLogCoeff * std::log(leadingX0Integral);
467 leadingScattering = leadingX0Integral * logTerm * logTerm;
468 const 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 const double deltaR = ((**m).intersection(FittedTrajectory).position() -
477 fitParameters.vertex())
478 .perp();
479 const 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
558 std::vector<Trk::FitMeasurement*>::iterator next = m;
559 if (++next != measurements.end() && !(**next).hitOnTrack() &&
560 (**next).isPositionMeasurement() && !(**next).isOutlier()) {
561 const 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 const double scattering = X0Integral * logTerm * logTerm;
595 const 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
604std::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> const 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 const 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)
711 distance += m_orderingTolerance;
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(),
718 std::vector<std::pair<double, FitMeasurement*>>::const_iterator orig =
719 originalOrder.begin();
720 bool shouldReorder = false;
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 const double distance =
760 ((*measurement).intersection(FittedTrajectory).position() -
761 (*measurement).position())
762 .mag();
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
796 const double mass = Trk::ParticleMasses::mass[Trk::muon];
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 const 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
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*> const fms =
843 materialAggregation(*spectrometerMaterial, measurements, mass);
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 " );
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;
866 std::vector<Trk::FitMeasurement*>::iterator const n = 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 const 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()) ||
925 distance > m_stationMaxGap ||
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;
958 FitMeasurement* current = *m;
959 while (*m != previous)
960 --m;
961 FitMeasurement* delimiter = new FitMeasurement(
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
972 FitMeasurement* delimiter =
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
998const 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 const 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 const 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 const Amg::Vector3D offset = intersection->direction() * tolerance;
1092 const CurvilinearUVT uvt(intersection->direction());
1093 const PlaneSurface plane(intersection->position() - offset, uvt);
1094
1095 if (m_useStepPropagator == 99) {
1096 std::optional<TrackSurfaceIntersection> const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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
1464std::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 const 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 const double distance =
1497 ((**tsos).trackParameters()->position() - referencePosition).mag();
1498 const 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 const Amg::Vector3D position =
1564 (**m).intersection(FittedTrajectory).position();
1565 const double distance =
1566 std::abs(referenceDirection.dot(position - referencePosition));
1567 if (distance < maxDistance) {
1568 ++adjacentScatterers;
1569 const 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 const double meanDistance = totalDistance / totalThickness;
1617 double rmsDistance = 0.;
1618 const double meanSquare =
1619 totalDistanceSq / totalThickness - meanDistance * meanDistance;
1620 if (meanSquare > 0.)
1621 rmsDistance = std::sqrt(meanSquare);
1622 const double gap = 2. * rmsDistance;
1623 if (adjacentScatterers > 2 || gap < m_scattererMinGap) {
1624 const double distance1 = meanDistance - rmsDistance;
1625 double distance2 = meanDistance + rmsDistance;
1626 if (gap < m_scattererMinGap)
1627 distance2 = meanDistance;
1628 const Amg::Vector3D position =
1629 (**m).intersection(FittedTrajectory).position();
1630 const 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 const double distance =
1658 std::abs(referenceDirection.dot(position - referencePosition));
1659 if (!measurement1 && distance > distance1 &&
1660 gap > m_scattererMinGap) {
1661 after = *s;
1662 const double separation = distance - previousDistance;
1663 const double fractionAfter =
1664 (distance1 - previousDistance) / separation;
1665 const 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 const Amg::Vector3D direction =
1680 fractionBefore *
1682 fractionAfter *
1684 const 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 const double separation = distance - previousDistance;
1694 const double fractionAfter =
1695 (distance2 - previousDistance) / separation;
1696 const 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 const Amg::Vector3D direction =
1711 fractionBefore *
1713 fractionAfter *
1715 const 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 const double weight = (**m).radiationThickness();
1759 referencePosition =
1760 (**previous).intersection(FittedTrajectory).position();
1761 referenceDirection =
1762 (**previous).intersection(FittedTrajectory).direction();
1763 const Amg::Vector3D position = (**m).intersection(FittedTrajectory).position();
1764 const 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 const Amg::Vector3D position = (**m).intersection(FittedTrajectory).position();
1804 const 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 const Amg::Vector3D startPosition =
1833 measurements.front()->intersection(FittedTrajectory).position();
1834 const Amg::Vector3D startDirection =
1835 measurements.front()->intersection(FittedTrajectory).direction();
1836 for (auto* measurement : measurements) {
1837 const Amg::Vector3D position =
1838 (*measurement).intersection(FittedTrajectory).position();
1839 const 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 const double deltaE = outgoingEnergy - tsos.trackParameters()->momentum().mag();
1885 const double thicknessInX0 = tsos.materialEffectsOnTrack()->thicknessInX0();
1886 const Amg::Vector3D position = tsos.trackParameters()->position();
1887 const 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 const Amg::Vector3D direction = (**m).intersection(FittedTrajectory).direction();
1913 const 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 const 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
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 const Amg::Vector3D position = (**m).intersection(FittedTrajectory).position();
2034 const Amg::Vector3D positionSurf = (**m).surface()->center();
2035 Amg::Vector3D positionMst = startPosition;
2036 if ((**m).measurementBase())
2037 positionMst = (**m).measurementBase()->globalPosition();
2038 const double distance = startDirection.dot(position - startPosition);
2039 const 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
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;
2118 const Amg::Vector3D position = (**m).intersection(FittedTrajectory).position();
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 const 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 const 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
2240 if (msgLvl(MSG::VERBOSE) && spectrometerMaterial &&
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 const double distance = startDirection.dot((*ss).trackParameters()->position() -
2251 startPosition);
2252 double deltaE = 0.;
2253 const 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 const 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 const 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 const 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
Scalar deltaR(const MatrixBase< Derived > &vec) const
const PlainObject unit() const
This is a plugin that makes Eigen look like CLHEP & defines some convenience methods.
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
double charge(const T &p)
Definition AtlasPID.h:997
#define AmgSymMatrix(dim)
static Double_t ss
double angle(const GeoTrf::Vector2D &a, const GeoTrf::Vector2D &b)
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
bool msgLvl(const MSG::Level lvl) const
MsgStream & msg() const
The BoundaryCheck class allows to steer the way surface boundaries are used for inside/outside checks...
simple class that constructs the curvilinear vectors curvU and curvV from a given momentum direction ...
virtual EnergyLoss * clone() const
Virtual constructor.
double deltaE() const
returns the
bool hasIntersection(ExtrapolationType type) const
bool isOutlier(void) const
const TrackSurfaceIntersection & intersection(ExtrapolationType type) const
double qOverP(void) const
const Surface * surface(void) const
Amg::Vector3D direction(void) const
TrackParameters * trackParameters(MsgStream &log, const FitMeasurement &measurement, bool withCovariance=false)
double qOverP(void) const
const Amg::Vector3D & vertex(void) const
const Amg::Vector3D & position(void) const
void update(const Amg::VectorX &differences)
std::vector< std::unique_ptr< const TrackStateOnSurface > > Garbage_t
@ CalorimeterEntryLayer
Tracking Volume which defines the entrance srufaces of the calorimeter.
@ MuonSpectrometerEntryLayer
Tracking Volume which defines the entrance surfaces of the MS.
magnetic field properties to steer the behavior of the extrapolation
void addSpectrometerDelimiters(std::vector< FitMeasurement * > &measurements) const
MaterialAllocator(const std::string &type, const std::string &name, const IInterface *parent)
const Trk::Volume * m_calorimeterVolume
ToolHandle< IPropagator > m_stepPropagator
ToolHandle< IIntersector > m_intersector
virtual void orderMeasurements(std::vector< FitMeasurement * > &measurements, Amg::Vector3D startDirection, Amg::Vector3D startPosition) const override
IMaterialAllocator interface: clear temporary TSOS.
virtual StatusCode initialize() override
const Trk::TrackingVolume * getSpectrometerEntrance() const
void spectrometerMaterial(std::vector< FitMeasurement * > &measurements, ParticleHypothesis particleHypothesis, FitParameters &fitParameters, const TrackParameters &startParameters, Garbage_t &garbage) const
Trk::MagneticFieldProperties m_stepField
virtual bool reallocateMaterial(std::vector< FitMeasurement * > &measurements, FitParameters &fitParameters, Garbage_t &garbage) const override
IMaterialAllocator interface: has material been reallocated?
void printMeasurements(std::vector< FitMeasurement * > &measurements) const
ServiceHandle< ITrackingVolumesSvc > m_trackingVolumesSvc
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
std::pair< FitMeasurement *, FitMeasurement * > materialAggregation(const std::vector< const TrackStateOnSurface * > &material, std::vector< FitMeasurement * > &measurements, double particleMass) const
void indetMaterial(std::vector< FitMeasurement * > &measurements, ParticleHypothesis particleHypothesis, const TrackParameters &startParameters, Garbage_t &garbage) const
virtual StatusCode finalize() override
const Trk::Volume * m_indetVolume
static void deleteMaterial(const std::vector< const TrackStateOnSurface * > *material, Garbage_t &garbage)
static FitMeasurement * measurementFromTSOS(const TrackStateOnSurface &tsos, double outwardsEnergy, double particleMass)
virtual void initializeScattering(std::vector< FitMeasurement * > &measurements) const override
IMaterialAllocator interface: initialize scattering (needs to know X0 integral)
SG::ReadCondHandleKey< TrackingGeometry > m_trackingGeometryReadKey
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.
ToolHandle< IExtrapolator > m_extrapolator
virtual void allocateMaterial(std::vector< FitMeasurement * > &measurements, ParticleHypothesis particleHypothesis, FitParameters &fitParameters, const TrackParameters &startParameters, Garbage_t &garbage) const override
IMaterialAllocator interface: allocate material.
ServiceHandle< ITrackingGeometrySvc > m_trackingGeometrySvc
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...
std::unique_ptr< MessageHelper > m_messageHelper
double thicknessInX0() const
returns the actually traversed material .
represents the full description of deflection and e-loss of a track in material.
const EnergyLoss * energyLoss() const
returns the energy loss object.
const Amg::Vector3D & momentum() const
Access method for the momentum.
virtual ParametersBase< DIM, T > * clone() const override=0
clone method for polymorphic deep copy
const Amg::Vector3D & position() const
Access method for the position.
double charge() const
Returns the charge.
virtual const Surface & associatedSurface() const override=0
Access to the Surface associated to the Parameters.
virtual const S & associatedSurface() const override final
Access to the Surface method.
Class for a planaer rectangular or trapezoidal surface in the ATLAS detector.
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...
Abstract Base Class for tracking surfaces.
represents the track state (measurement, material, fit parameters and quality) at a surface.
const TrackParameters * trackParameters() const
return ptr to trackparameters const overload
const MaterialEffectsBase * materialEffectsOnTrack() const
return material effects const overload
An intersection with a Surface is given by.
const Amg::Vector3D & direction() const
Method to retrieve the direction at the Intersection.
const Amg::Vector3D & position() const
Method to retrieve the position of the Intersection.
Full Volume description used in Tracking, it inherits from Volume to get the geometrical structure,...
std::vector< std::string > intersection(std::vector< std::string > &v1, std::vector< std::string > &v2)
int r
Definition globals.cxx:22
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
Eigen::Matrix< double, Eigen::Dynamic, 1 > VectorX
Dynamic Vector - dynamic allocation.
=============================================================================
constexpr double mass[PARTICLEHYPOTHESES]
the array of masses
Ensure that the ATLAS eigen extensions are properly loaded.
PropDirection
PropDirection, enum for direction of the propagation.
@ oppositeMomentum
@ alongMomentum
@ anyDirection
@ next
Definition BinningData.h:33
@ previous
Definition BinningData.h:32
ParametersT< TrackParametersDim, Charged, PerigeeSurface > Perigee
@ FastField
call the fast field access method of the FieldSvc
@ FullField
Field is set to be realistic, but within a given Volume.
@ locR
Definition ParamDefs.h:44
@ theta
Definition ParamDefs.h:66
@ qOverP
perigee
Definition ParamDefs.h:67
@ loc2
generic first and second local coordinate
Definition ParamDefs.h:35
@ phi
Definition ParamDefs.h:75
@ loc1
Definition ParamDefs.h:34
@ locZ
local cylindrical
Definition ParamDefs.h:42
ParticleHypothesis
Enumeration for Particle hypothesis respecting the interaction with material.
ParametersBase< TrackParametersDim, Charged > TrackParameters
ParametersT< TrackParametersDim, Charged, PlaneSurface > AtaPlane
@ FittedTrajectory
Definition index.py:1
DataModel_detail::iterator< DVL > remove(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end, const T &value)
Specialization of remove for DataVector/List.
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.