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 for (std::vector<FitMeasurement*>::iterator m = measurements.begin();
893 m != measurements.end(); ++m) {
894 // skip 'non'-measurements
895 if (!(**m).isPositionMeasurement() || (**m).isPseudo())
896 continue;
897
898 // material delimiters in MS follow the entrance break which should be
899 // already present
900 const Amg::Vector3D position = (**m).position();
901 if (m_calorimeterVolume->inside(position))
902 continue;
903
904 // break can be before measurement or after previous measurement
905 bool preBreak = false;
906 bool postBreak = false;
907 double distance = 0.;
908 if (!previous) {
909 // preBreak at first measurement in MS
910 preBreak = true;
911 referenceDirection = (**m).intersection(FittedTrajectory).direction();
912 referencePosition = (**m).intersection(FittedTrajectory).position();
913 referencePhi = position.phi();
914 startDirection = referenceDirection;
915 startPosition = referencePosition;
916 } else {
917 // post and pre breaks for cluster/drift transition,
918 // large gap between measurements,
919 // sector overlap
920 distance = referenceDirection.dot(
921 (**m).intersection(FittedTrajectory).position() - referencePosition);
922 if (((**m).isDrift() && !previous->isDrift()) ||
923 (!(**m).isDrift() && previous->isDrift()) ||
924 distance > m_stationMaxGap ||
925 ((**m).isDrift() &&
926 std::abs(position.phi() - referencePhi) > m_sectorMaxPhi)) {
927 preBreak = true;
928 if (distance > previousDistance + m_scattererMinGap)
929 postBreak = true;
930 }
931 }
932
933 if (!(preBreak || postBreak)) {
934 previous = *m;
935 previousDistance = distance;
936 continue;
937 }
938
939 if (postBreak && previous) {
940 // if (distance < offset) offset = 0.5*distance;
941 FitMeasurement* current = *m;
942 while (*m != previous)
943 --m;
944 FitMeasurement* delimiter = new FitMeasurement(
945 (**m).intersection(FittedTrajectory), 0.5 * m_scattererMinGap);
946 m = measurements.insert(++m, delimiter);
947 while (*m != current)
948 ++m;
949 }
950 if (preBreak) {
951 double offset = -0.5 * m_scattererMinGap;
952 if (distance - previousDistance < m_scattererMinGap)
953 offset = 0.5 * (previousDistance - distance);
954
955 FitMeasurement* delimiter =
956 new FitMeasurement((**m).intersection(FittedTrajectory), offset);
957 m = measurements.insert(m, delimiter);
958 ++m;
959 }
960 previous = *m;
961 previousDistance = 0.;
962 referenceDirection = (**m).intersection(FittedTrajectory).direction();
963 referencePosition = (**m).intersection(FittedTrajectory).position();
964 referencePhi = position.phi();
965 }
966 // orderMeasurements(measurements,startDirection,startPosition);
967 // printMeasurements(measurements);
968}
969
971 const std::vector<const TrackStateOnSurface*>* material,
972 Garbage_t& garbage) {
973 if (material) {
974 for (const TrackStateOnSurface* m : *material) {
975 garbage.push_back(std::unique_ptr<const TrackStateOnSurface>(m));
976 }
977 delete material;
978 }
979}
980
981const std::vector<const TrackStateOnSurface*>*
983 const ToolHandle<IExtrapolator>& extrapolator,
984 const TrackParameters& parameters, const Surface& surface,
985 PropDirection dir, const BoundaryCheck& boundsCheck,
986 ParticleHypothesis particleHypothesis, Garbage_t& garbage) const {
987 const EventContext& ctx = Gaudi::Hive::currentContext();
988 // fix up material duplication appearing after recent TrackingGeometry
989 // speed-up
990 const std::vector<const TrackStateOnSurface*>* TGMaterial =
991 extrapolator->extrapolateM(ctx, parameters, surface, dir, boundsCheck,
992 particleHypothesis);
993
994 if (!TGMaterial || TGMaterial->empty())
995 return TGMaterial;
996
997 std::vector<const TrackStateOnSurface*>* duplicates = nullptr;
998 std::vector<const TrackStateOnSurface*>* material =
999 new std::vector<const TrackStateOnSurface*>;
1000 material->reserve(TGMaterial->size());
1001 std::vector<const TrackStateOnSurface*>::const_iterator tg =
1002 TGMaterial->begin();
1003 material->push_back(*tg);
1004 ++tg;
1005 for (; tg != TGMaterial->end(); ++tg) {
1006 const TrackStateOnSurface* TSOS = material->back();
1007 double separation = 0.;
1008 if (TSOS->trackParameters())
1009 separation = (TSOS->trackParameters()->position() -
1010 (**tg).trackParameters()->position())
1011 .mag();
1012
1013 if (separation > 0.001 * Gaudi::Units::mm) {
1014 material->push_back(*tg);
1015 } else {
1017 std::setiosflags(std::ios::fixed)
1018 << " duplicate: RZ" << std::setw(9) << std::setprecision(3)
1019 << (**tg).trackParameters()->position().perp() << std::setw(10)
1020 << std::setprecision(3) << (**tg).trackParameters()->position().z());
1021 if (!duplicates)
1022 duplicates = new std::vector<const TrackStateOnSurface*>;
1023 duplicates->push_back(*tg);
1024 }
1025 }
1026
1027 delete TGMaterial;
1028 if (duplicates)
1029 deleteMaterial(duplicates, garbage);
1030 return material;
1031}
1032
1034 std::vector<FitMeasurement*>& measurements,
1035 ParticleHypothesis particleHypothesis,
1036 const TrackParameters& startParameters, Garbage_t& garbage) const {
1037 const EventContext& ctx = Gaudi::Hive::currentContext();
1038 // gather material between first and last measurements inside indet volume
1039 // allow a few mm radial tolerance around first&last measurements for their
1040 // associated material
1041 const double tolerance =
1042 10. * Gaudi::Units::mm / startParameters.momentum().unit().perp();
1043
1044 // loop over measurements to define portions of track needing indet material
1045 double endIndetDistance = 0.;
1046 FitMeasurement* endIndetMeasurement = nullptr;
1047 const double qOverP = startParameters.charge() / startParameters.momentum().mag();
1048
1049 Amg::Vector3D startDirection = startParameters.momentum().unit();
1050 Amg::Vector3D startPosition = startParameters.position();
1051 const TrackParameters* parameters = &startParameters;
1052 std::unique_ptr<AtaPlane> newParameters;
1053
1054 std::vector<Trk::FitMeasurement*>::iterator m = measurements.begin();
1055 if ((**m).isVertex())
1056 ++m;
1057 for (; m != measurements.end(); ++m) {
1058 if ((**m).isOutlier())
1059 continue;
1060 if (m_indetVolume->inside((**m).position())) {
1061 // quit if pre-existing indet material
1062 if ((**m).isScatterer()) {
1063 return;
1064 }
1065
1066 // use first measurement at a plane surface to create starting parameters
1067 if (!(**m).isPositionMeasurement())
1068 continue;
1069 if (!endIndetMeasurement && (**m).hasIntersection(FittedTrajectory) &&
1070 ((**m).surface()->type() == Trk::SurfaceType::Plane ||
1071 (**m).surface()->type() == Trk::SurfaceType::Disc)) {
1072 std::optional<TrackSurfaceIntersection> intersection =
1073 (**m).intersection(FittedTrajectory);
1074 const Amg::Vector3D offset = intersection->direction() * tolerance;
1075 const CurvilinearUVT uvt(intersection->direction());
1076 const PlaneSurface plane(intersection->position() - offset, uvt);
1077
1078 if (m_useStepPropagator == 99) {
1079 std::optional<TrackSurfaceIntersection> const newIntersectionSTEP =
1080 m_stepPropagator->intersectSurface(
1081 ctx, plane, *intersection, qOverP,
1083 intersection =
1084 m_intersector->intersectSurface(plane, *intersection, qOverP);
1085 if (newIntersectionSTEP && intersection) {
1086 // double dist =
1087 // 1000.*(newIntersectionSTEP->position()-intersection->position()).mag();
1088 // std::cout << " iMat 3 distance STEP and
1089 // Intersector " << dist << std::endl;
1090 // if(dist>10.) std::cout << " iMat 3 ALARM
1091 // distance STEP and Intersector " << dist <<
1092 // std::endl;
1093 } else {
1094 // if(intersection) std::cout << " iMat 3 ALARM
1095 // STEP did not intersect! " << std::endl;
1096 }
1097 } else {
1099 ? m_stepPropagator->intersectSurface(
1100 ctx, plane, *intersection, qOverP,
1102 : m_intersector->intersectSurface(
1103 plane, *intersection, qOverP);
1104 }
1105 Amg::Vector2D localPos;
1106 if (intersection &&
1107 plane.globalToLocal(intersection->position(),
1108 intersection->direction(), localPos)) {
1109 newParameters = std::make_unique<AtaPlane>(
1110 localPos[locR], localPos[locZ], intersection->direction().phi(),
1111 intersection->direction().theta(), qOverP, plane);
1112 parameters = newParameters.get();
1113 startDirection = intersection->direction();
1114 startPosition = intersection->position();
1115 }
1116 }
1117
1118 // save the last indet measurement, signal any out-of-order meas
1119 const double distance = startDirection.dot(
1120 (**m).intersection(FittedTrajectory).position() - startPosition);
1121 if (!endIndetMeasurement || distance > endIndetDistance) {
1122 endIndetDistance = distance;
1123 endIndetMeasurement = *m;
1124 }
1125 } else { // outside indet
1126 break;
1127 }
1128 }
1129 if (!endIndetMeasurement) {
1130 return;
1131 }
1132
1133 ATH_MSG_DEBUG(" indetMaterial: ALARM no material found on track");
1134
1135 // allocate indet material from TrackingGeometry
1136 const Amg::Vector3D endPosition =
1137 endIndetMeasurement->intersection(FittedTrajectory).position();
1138 startDirection = (endPosition - startPosition).unit();
1139 endIndetDistance =
1140 startDirection.dot(endPosition - startPosition) + tolerance;
1141 ATH_MSG_VERBOSE(" indetMaterial: using extrapolateM out to distance "
1142 << endIndetDistance);
1143 const std::vector<const TrackStateOnSurface*>* indetMaterial =
1145 *endIndetMeasurement->surface(), alongMomentum,
1146 false, particleHypothesis, garbage);
1147
1148 if (!indetMaterial || indetMaterial->empty()) {
1149 deleteMaterial(indetMaterial, garbage);
1150 return;
1151 }
1152
1153 // insert the material into the measurement list
1154 // ignore trailing material - with a few mm radial tolerance
1155 std::vector<const Surface*> surfaces;
1156 surfaces.reserve(indetMaterial->size());
1157 std::vector<const TrackStateOnSurface*>::const_iterator indetMaterialEnd =
1158 indetMaterial->begin();
1159 int trailing = indetMaterial->size();
1160 for (std::vector<const TrackStateOnSurface*>::const_iterator s =
1161 indetMaterial->begin();
1162 s != indetMaterial->end(); ++s, --trailing) {
1163 if ((**s).trackParameters()) {
1164 if (startDirection.dot((**s).trackParameters()->position() -
1165 startPosition) < endIndetDistance) {
1166 indetMaterialEnd = s;
1167 ++indetMaterialEnd;
1168 } else {
1169 ATH_MSG_VERBOSE(" indetMaterial: "
1170 << trailing
1171 << " trailing TSOS (after last measurement)");
1172 break;
1173 }
1174 }
1175 }
1176
1177 // return in case of extrapolateM problem
1178 if (indetMaterialEnd == indetMaterial->begin()) {
1179 // extrapolateM finds no material on track !!
1180 m_messageHelper->printWarning(1);
1181 deleteMaterial(indetMaterial, garbage);
1182 return;
1183 }
1184
1185 // debug
1186 if (msgLvl(MSG::VERBOSE)) {
1187 double p1 = indetMaterial->front()->trackParameters()->momentum().mag();
1188
1189 for (std::vector<const TrackStateOnSurface*>::const_iterator s =
1190 indetMaterial->begin();
1191 s != indetMaterialEnd; ++s) {
1192 if (!(**s).trackParameters())
1193 continue;
1194 const double distance = startDirection.dot((**s).trackParameters()->position() -
1195 startPosition);
1196 double deltaE = 0.;
1197 double thickness = 0.;
1198 const MaterialEffectsOnTrack* materialEffects =
1199 dynamic_cast<const MaterialEffectsOnTrack*>(
1200 (**s).materialEffectsOnTrack());
1201 if ((**s).materialEffectsOnTrack()) {
1202 if (materialEffects)
1203 deltaE = materialEffects->energyLoss()->deltaE();
1204 thickness = (**s).materialEffectsOnTrack()->thicknessInX0();
1205 }
1206 const double p2 = (**s).trackParameters()->momentum().mag();
1208 std::setiosflags(std::ios::fixed)
1209 << " material: RZ" << std::setw(9) << std::setprecision(3)
1210 << (**s).trackParameters()->position().perp() << std::setw(10)
1211 << std::setprecision(3) << (**s).trackParameters()->position().z()
1212 << " distance " << std::setw(10) << std::setprecision(3) << distance
1213 << " pt " << std::setw(8) << std::setprecision(3)
1214 << (**s).trackParameters()->momentum().perp() / Gaudi::Units::GeV
1215 << " X0thickness " << std::setw(8) << std::setprecision(4)
1216 << thickness << " deltaE " << std::setw(8) << std::setprecision(4)
1217 << deltaE << " diffP " << std::setw(8) << std::setprecision(4)
1218 << p2 - p1);
1219 p1 = p2;
1220 }
1221 }
1222
1223 // firstly: add the material belonging to each measurement layer (and skip
1224 // leading material)
1225 FitMeasurement* leadingDelimiter = nullptr;
1226 Amg::Vector3D nextMomentum(0., 0., 0.);
1227 Amg::Vector3D nextPosition(0., 0., 0.);
1228 m = measurements.begin();
1229 std::vector<const TrackStateOnSurface*>::const_iterator s =
1230 indetMaterial->begin();
1231 for (; m != measurements.end(); ++m) {
1232 if (*m == endIndetMeasurement || s == indetMaterialEnd)
1233 break;
1234 if (!leadingDelimiter && (**m).isOutlier())
1235 continue;
1236
1237 Amg::Vector3D direction = (**m).intersection(FittedTrajectory).direction();
1238 Amg::Vector3D position = (**m).intersection(FittedTrajectory).position();
1239 double closestDistance = direction.dot(position - startPosition);
1240 const MaterialEffectsOnTrack* materialEffects = nullptr;
1241 const TrackParameters* materialParameters = nullptr;
1242 const Surface* materialSurface = nullptr;
1243
1244 // find the closest material TSOS (inside radial tolerance)
1245 for (; s != indetMaterialEnd; ++s) {
1246 if (!dynamic_cast<const MaterialEffectsOnTrack*>(
1247 (**s).materialEffectsOnTrack()) ||
1248 !(**s).trackParameters())
1249 continue;
1250 nextMomentum = (**s).trackParameters()->momentum();
1251 nextPosition = (**s).trackParameters()->position();
1252 const double distance = direction.dot(nextPosition - position);
1253
1254 // increasing distance - break when past minimum
1255 if (distance > closestDistance)
1256 break;
1257
1258 // downstream material - check not significantly closer to following
1259 // measurement
1260 // (material too early is better than too late)
1261 if (distance > 0.) {
1262 ++m;
1263 const double nextDistance = direction.dot(
1264 (**s).trackParameters()->position() - (**m).position());
1265 --m;
1266 if (std::abs(nextDistance) < distance && distance > tolerance) {
1267 if (s != indetMaterial->begin())
1268 --s;
1269 materialSurface = nullptr;
1270 break;
1271 }
1272 closestDistance = distance;
1273 } else {
1274 closestDistance = -distance;
1275 }
1276
1277 // when upstream of leading break any previous surface is going to be
1278 // ignored
1279 if (!leadingDelimiter && materialSurface)
1280 surfaces.push_back(materialSurface);
1281
1282 materialEffects = dynamic_cast<const MaterialEffectsOnTrack*>(
1283 (**s).materialEffectsOnTrack());
1284 materialParameters = (**s).trackParameters();
1285 materialSurface = &materialParameters->associatedSurface();
1286 }
1287
1288 // skip if the material has not been allocated to a measurement surface
1289 if (!materialSurface)
1290 continue;
1291
1292 // or if it's already been allocated upstream
1293 if (!surfaces.empty() && materialSurface == surfaces.back())
1294 continue;
1295
1296 // skip leading material during the fit (up to and including first
1297 // measurement) insert an materialDelimiter so the leading material can be
1298 // allocated after the fit converges
1299 if (!leadingDelimiter) {
1300 position = 0.5 * (materialParameters->position() + nextPosition);
1301 direction = (materialParameters->momentum() + nextMomentum).unit();
1302 TrackSurfaceIntersection const breakIntersection(position, direction, 0.);
1303 leadingDelimiter = new FitMeasurement(breakIntersection, 0.);
1304 while (*m != endIndetMeasurement &&
1305 direction.dot((**m).intersection(FittedTrajectory).position() -
1306 position) < 0.)
1307 ++m;
1308 m = measurements.insert(m, leadingDelimiter);
1309 surfaces.push_back(materialSurface);
1310 continue;
1311 }
1312
1313 // check inside tolerance
1314 if (closestDistance > tolerance)
1315 continue;
1316
1317 // insert material at measurement surface
1318 const std::bitset<MaterialEffectsBase::NumberOfMaterialEffectsTypes>
1319 typePattern;
1320 std::unique_ptr<Trk::EnergyLoss> energyLoss = nullptr;
1321 if (materialEffects->energyLoss()) {
1322 energyLoss = std::unique_ptr<Trk::EnergyLoss>(
1323 materialEffects->energyLoss()->clone());
1324 }
1326 materialEffects->thicknessInX0(), std::move(energyLoss),
1327 *(**m).surface(), typePattern);
1328 const TrackSurfaceIntersection& intersection = (**m).intersection(FittedTrajectory);
1329 if (++m == measurements.end())
1330 --m;
1331 m = measurements.insert(
1332 m,
1333 new FitMeasurement(meot, Trk::ParticleMasses::mass[particleHypothesis],
1334 intersection.position()));
1335 (**m).intersection(FittedTrajectory, intersection);
1336 (**m).qOverP(materialParameters->parameters()[Trk::qOverP]);
1337 (**m).setMaterialEffectsOwner();
1338 surfaces.push_back(materialSurface);
1339 }
1340
1341 // secondly: insert remaining material between measurement layers
1342 m = measurements.begin();
1343 int im = 0;
1344 ATH_MSG_VERBOSE(" measurements.size() "
1345 << measurements.size() << " surfaces.size() "
1346 << surfaces.size() << " indetMaterial->size() "
1347 << indetMaterial->size());
1348 std::vector<const Surface*>::const_iterator r = surfaces.begin();
1349 for (s = indetMaterial->begin(); s != indetMaterialEnd; ++s) {
1350 if (!(**s).trackParameters() || !(**s).materialEffectsOnTrack())
1351 continue;
1352
1353 if (r != surfaces.end() &&
1354 **r == (**s).trackParameters()->associatedSurface()) {
1355 ++r;
1356 continue;
1357 }
1358
1359 const double distance =
1360 startDirection.dot((**s).trackParameters()->position() - startPosition);
1361
1362 ATH_MSG_VERBOSE(" startPosition " << startPosition.perp() << " z "
1363 << startPosition.z());
1365 " (**m).intersection(FittedTrajectory).position() measurement "
1366 "position r "
1367 << (**m).intersection(FittedTrajectory).position().perp() << " z "
1368 << (**m).intersection(FittedTrajectory).position().z());
1370 " (**s).trackParameters()->position() material surface position "
1371 "r "
1372 << (**s).trackParameters()->position().perp() << " z "
1373 << (**s).trackParameters()->position().z());
1374 ATH_MSG_VERBOSE(" distance material surface " << distance);
1375
1376 bool endIndet = false;
1377 while (distance >
1378 startDirection.dot((**m).intersection(FittedTrajectory).position() -
1379 startPosition)) {
1380 if (*m == endIndetMeasurement) {
1381 if (*m != measurements.back()) {
1382 ++m;
1383 ++im;
1384 ATH_MSG_VERBOSE(" measurements.back() im " << im);
1385 }
1386 ATH_MSG_VERBOSE(" break im " << im);
1387 endIndet = true;
1388 break;
1389 }
1390 if (*m != measurements.back()) {
1391 ++m;
1392 ++im;
1394 " loop im "
1395 << im
1396 << " (**m).intersection(FittedTrajectory).position() "
1397 "measurement position r "
1398 << (**m).intersection(FittedTrajectory).position().perp() << " z "
1399 << (**m).intersection(FittedTrajectory).position().z());
1400 } else {
1401 break;
1402 }
1403 }
1405 " im " << im << " distance measurement "
1406 << startDirection.dot(
1407 (**m).intersection(FittedTrajectory).position() -
1408 startPosition));
1410 " (**m).intersection(FittedTrajectory).position() measurement position "
1411 "r "
1412 << (**m).intersection(FittedTrajectory).position().perp() << " z "
1413 << (**m).intersection(FittedTrajectory).position().z());
1414
1415 m = measurements.insert(
1416 m, new FitMeasurement((**s).materialEffectsOnTrack(),
1417 Trk::ParticleMasses::mass[particleHypothesis],
1418 (**s).trackParameters()->position()));
1420 (**s).trackParameters()->position(),
1421 (**s).trackParameters()->momentum().unit(), 0.);
1422 (**m).intersection(FittedTrajectory, intersection);
1423 (**m).qOverP((**s).trackParameters()->parameters()[Trk::qOverP]);
1424 ATH_MSG_VERBOSE(" successfull insertion ");
1425 if (endIndet)
1426 --m;
1427 }
1428
1429 m = measurements.begin();
1430 im = 0;
1431 for (; m != measurements.end(); ++m) {
1432 if (!leadingDelimiter && (**m).isOutlier())
1433 continue;
1434
1435 Amg::Vector3D position = (**m).intersection(FittedTrajectory).position();
1436 ++im;
1437 ATH_MSG_VERBOSE(" im " << im << " position R " << position.perp() << " z "
1438 << position.z());
1439 }
1440
1441 // memory management
1442 deleteMaterial(indetMaterial, garbage);
1443
1444 ATH_MSG_VERBOSE(" finished indetMaterial ");
1445}
1446
1447std::pair<FitMeasurement*, FitMeasurement*>
1449 const std::vector<const TrackStateOnSurface*>& material,
1450 std::vector<FitMeasurement*>& /*measurements*/,
1451 double /*particleMass*/) const {
1452 // aggregation possible in indet and MS. Frequent occurrence in MS
1453 ATH_MSG_INFO("segment material aggregation " << material.size());
1454 FitMeasurement* measurement1 = nullptr;
1455 FitMeasurement* measurement2 = nullptr;
1456 if (material.empty())
1457 return std::pair<FitMeasurement*, FitMeasurement*>(measurement1,
1458 measurement2);
1459
1460
1461 int adjacentScatterers = 0;
1462 std::vector<FitMeasurement*> aggregateScatterers;
1463 bool hasReferencePosition = false;
1464 Amg::Vector3D referencePosition;
1465 bool const haveAggregation = false;
1466 // bool makeAggregation = false;
1467 // double maxDistance = 0.;
1468 for (std::vector<const TrackStateOnSurface*>::const_reverse_iterator tsos =
1469 material.rbegin();
1470 tsos != material.rend(); ++tsos) {
1471 if (!(**tsos).trackParameters() || !(**tsos).materialEffectsOnTrack()){
1472 continue;
1473 }
1474 ++adjacentScatterers;
1475 if (!hasReferencePosition) {
1476 referencePosition = Amg::Vector3D((**tsos).trackParameters()->position());
1477 hasReferencePosition = true;
1478 }
1479 const double distance =
1480 ((**tsos).trackParameters()->position() - referencePosition).mag();
1481 const double weight = (**tsos).materialEffectsOnTrack()->thicknessInX0();
1482
1483 ATH_MSG_INFO(" material position " << (**tsos).trackParameters()->position()
1484 << " distance " << distance
1485 << " thickness " << 100. * weight);
1486 }
1487
1488 // if 2 or less selected TSOS: just set scatterers on TSOS
1489 if (adjacentScatterers < 3) {
1490 }
1491
1492 // in case of aggregation: insert aggregateScatterers onto track
1493 if (haveAggregation) {
1494 }
1495
1496 return std::pair<FitMeasurement*, FitMeasurement*>(measurement1,
1497 measurement2);
1498}
1499
1501 std::vector<FitMeasurement*>& measurements, double particleMass) const {
1502 // Aggregate when at least 2 scatterers exist between delimiter pair.
1503 //
1504 // First loop over measurements to create aggregateScatterer vector.
1505 // This contains any aggregated scatterers along with sparse existing
1506 // scatterers which haven't been aggregated. The remaining existing scatterers
1507 // (those which have been aggregated) are flagged for discard (via the outlier
1508 // flag).
1509
1510 // currently aggregation only performed for MS:
1511 Amg::Vector3D referencePosition =
1512 measurements.back()->intersection(FittedTrajectory).position();
1513 if (m_calorimeterVolume->inside(referencePosition))
1514 return;
1515
1516 Amg::Vector3D referenceDirection =
1517 measurements.back()->intersection(FittedTrajectory).direction();
1518 int adjacentScatterers = 0;
1519 std::vector<FitMeasurement*> aggregateScatterers;
1520 bool haveAggregation = false;
1521 bool makeAggregation = false;
1522 double maxDistance = 0.;
1523 FitMeasurement* measurement1 = nullptr;
1524 FitMeasurement* measurement2 = nullptr;
1525 double totalDistance = 0.;
1526 double totalDistanceSq = 0.;
1527 double totalEnergyDeposit = 0.;
1528 double totalThickness = 0.;
1529 std::vector<FitMeasurement*>::reverse_iterator start;
1530 std::vector<FitMeasurement*>::reverse_iterator previous =
1531 measurements.rbegin();
1532 for (std::vector<FitMeasurement*>::reverse_iterator m = measurements.rbegin();
1533 m != measurements.rend(); ++m) {
1534 if ((**m).isScatterer())
1535 aggregateScatterers.push_back(*m);
1536 if (m_calorimeterVolume->inside((**m).position())) {
1537 if (!adjacentScatterers)
1538 continue;
1539 makeAggregation = true;
1540 }
1541 // if (m_calorimeterVolume->inside((**m).position())
1542 // && ! m_indetVolume->inside((**m).position())) continue;
1543 // look for adjacent scatterers
1544 else if (adjacentScatterers) {
1545 if ((**m).isScatterer()) {
1546 const Amg::Vector3D position =
1547 (**m).intersection(FittedTrajectory).position();
1548 const double distance =
1549 std::abs(referenceDirection.dot(position - referencePosition));
1550 if (distance < maxDistance) {
1551 ++adjacentScatterers;
1552 const double weight = (**m).radiationThickness();
1553 totalDistance += weight * distance;
1554 totalDistanceSq += weight * distance * distance;
1555 totalEnergyDeposit += (**m).energyLoss();
1556 totalThickness += weight;
1557 if (*m == measurements.front())
1558 makeAggregation = true;
1559 // ATH_MSG_INFO(std::setiosflags(std::ios::fixed)
1560 // << " distance "
1561 // << std::setw(8) << std::setprecision(0)
1562 // << distance
1563 // << " adjacentScatterers " << adjacentScatterers );
1564 } else if (adjacentScatterers > 1) {
1565 makeAggregation = true;
1566 } else {
1567 adjacentScatterers = 0;
1568 }
1569 } else if (!(**m).isMaterialDelimiter()) {
1570 previous = m;
1571 continue;
1572 } else if (adjacentScatterers > 1) {
1573 makeAggregation = true;
1574 } else {
1575 adjacentScatterers = 0;
1576 }
1577 }
1578
1579 if (makeAggregation) {
1580 // double dist =
1581 // ((**m).intersection(FittedTrajectory).position() -
1582 // referencePosition).mag();
1583 // ATH_MSG_INFO(std::setiosflags(std::ios::fixed)
1584 // << " makeAggregation: reference R,Z "
1585 // << std::setw(8) << std::setprecision(0)
1586 // << referencePosition.perp()
1587 // << std::setw(8) << std::setprecision(0)
1588 // << referencePosition.z()
1589 // << " current R,Z "
1590 // << std::setw(8) << std::setprecision(0)
1591 // << (**m).intersection(FittedTrajectory).position().perp()
1592 // << std::setw(8) << std::setprecision(0)
1593 // << (**m).intersection(FittedTrajectory).position().z()
1594 // << " adjacentScatterers " << std::setw(2)
1595 // << adjacentScatterers
1596 // << " distance "
1597 // << std::setw(8) << std::setprecision(0)
1598 // << dist );
1599 const double meanDistance = totalDistance / totalThickness;
1600 double rmsDistance = 0.;
1601 const double meanSquare =
1602 totalDistanceSq / totalThickness - meanDistance * meanDistance;
1603 if (meanSquare > 0.)
1604 rmsDistance = std::sqrt(meanSquare);
1605 const double gap = 2. * rmsDistance;
1606 if (adjacentScatterers > 2 || gap < m_scattererMinGap) {
1607 const double distance1 = meanDistance - rmsDistance;
1608 double distance2 = meanDistance + rmsDistance;
1609 if (gap < m_scattererMinGap)
1610 distance2 = meanDistance;
1611 const Amg::Vector3D position =
1612 (**m).intersection(FittedTrajectory).position();
1613 const double distance =
1614 std::abs(referenceDirection.dot(position - referencePosition));
1615 // ATH_MSG_INFO(std::setiosflags(std::ios::fixed)
1616 // << " distance1 "
1617 // << std::setw(8) << std::setprecision(0)
1618 // << distance1
1619 // << " distance2 "
1620 // << std::setw(8) << std::setprecision(0)
1621 // << distance2
1622 // << " distance "
1623 // << std::setw(8) << std::setprecision(0)
1624 // << distance );
1625 if (distance2 > distance || distance1 < 0.) {
1626 // msg() << " distance out of bounds: range " << distance
1627 // << " to " << 0. << endmsg;
1628 } else {
1629 FitMeasurement* after = nullptr;
1630 FitMeasurement* before = *start;
1631 double previousDistance = 0.;
1632 haveAggregation = true;
1633
1634 for (std::vector<Trk::FitMeasurement*>::reverse_iterator s = start;
1635 s != measurements.rend(); ++s) {
1636 if (!(**s).isScatterer())
1637 continue;
1638 Amg::Vector3D position =
1639 (**s).intersection(FittedTrajectory).position();
1640 const double distance =
1641 std::abs(referenceDirection.dot(position - referencePosition));
1642 if (!measurement1 && distance > distance1 &&
1643 gap > m_scattererMinGap) {
1644 after = *s;
1645 const double separation = distance - previousDistance;
1646 const double fractionAfter =
1647 (distance1 - previousDistance) / separation;
1648 const double fractionBefore = (distance - distance1) / separation;
1649 // ATH_MSG_INFO( std::setiosflags(std::ios::fixed)
1650 // << " distance "
1651 // << std::setw(8) << std::setprecision(0)
1652 // << distance<< " fraction before "
1653 // << std::setw(6) << std::setprecision(2)
1654 // << fractionBefore
1655 // << " fraction after "
1656 // << std::setw(6) << std::setprecision(2)
1657 // << fractionAfter );
1658 position = fractionBefore *
1660 fractionAfter *
1662 const Amg::Vector3D direction =
1663 fractionBefore *
1665 fractionAfter *
1667 const double qOverP = fractionBefore * before->qOverP() +
1668 fractionAfter * after->qOverP();
1669 measurement1 = new FitMeasurement(
1670 0.5 * totalThickness, -0.5 * totalEnergyDeposit, particleMass,
1671 position, direction, qOverP);
1672 }
1673
1674 if (distance > distance2) {
1675 after = *s;
1676 const double separation = distance - previousDistance;
1677 const double fractionAfter =
1678 (distance2 - previousDistance) / separation;
1679 const double fractionBefore = (distance - distance2) / separation;
1680 // ATH_MSG_INFO( std::setiosflags(std::ios::fixed)
1681 // << " distance "
1682 // << std::setw(8) << std::setprecision(0)
1683 // << distance<< " fraction before "
1684 // << std::setw(6) << std::setprecision(2)
1685 // << fractionBefore
1686 // << " fraction after "
1687 // << std::setw(6) << std::setprecision(2)
1688 // << fractionAfter << endmsg );
1689 position = fractionBefore *
1691 fractionAfter *
1693 const Amg::Vector3D direction =
1694 fractionBefore *
1696 fractionAfter *
1698 const double qOverP = fractionBefore * before->qOverP() +
1699 fractionAfter * after->qOverP();
1700 if (measurement1) {
1701 measurement2 = new FitMeasurement(
1702 0.5 * totalThickness, -0.5 * totalEnergyDeposit,
1703 particleMass, position, direction, qOverP);
1704 } else {
1705 measurement2 = new FitMeasurement(
1706 totalThickness, -totalEnergyDeposit, particleMass, position,
1707 direction, qOverP);
1708 }
1709 bool keepCurrentMeas = false;
1710 if ((**m).isScatterer() && *m != measurements.front()) {
1711 keepCurrentMeas = true;
1712 aggregateScatterers.pop_back();
1713 }
1714 while (adjacentScatterers--) {
1715 aggregateScatterers.back()->setOutlier();
1716 aggregateScatterers.pop_back();
1717 }
1718 if (measurement1)
1719 aggregateScatterers.push_back(measurement1);
1720 if (measurement2)
1721 aggregateScatterers.push_back(measurement2);
1722 if (keepCurrentMeas)
1723 aggregateScatterers.push_back(*m);
1724 measurement1 = nullptr;
1725 measurement2 = nullptr;
1726 break;
1727 }
1728 before = *s;
1729 previousDistance = distance;
1730 }
1731 }
1732 }
1733 adjacentScatterers = 0;
1734 makeAggregation = false;
1735 }
1736
1737 // new candidate for merging
1738 if ((**m).isScatterer() && !adjacentScatterers &&
1739 !m_calorimeterVolume->inside((**m).position())) {
1740 adjacentScatterers = 1;
1741 const double weight = (**m).radiationThickness();
1742 referencePosition =
1743 (**previous).intersection(FittedTrajectory).position();
1744 referenceDirection =
1745 (**previous).intersection(FittedTrajectory).direction();
1746 const Amg::Vector3D position = (**m).intersection(FittedTrajectory).position();
1747 const double distance =
1748 std::abs(referenceDirection.dot(position - referencePosition));
1749 maxDistance = distance + 2. * Gaudi::Units::meter;
1750 start = m;
1751 totalDistance = weight * distance;
1752 totalDistanceSq = weight * distance * distance;
1753 totalEnergyDeposit = (**m).energyLoss();
1754 totalThickness = weight;
1755 // ATH_MSG_INFO(std::setiosflags(std::ios::fixed)
1756 // << " distance "
1757 // << std::setw(8) << std::setprecision(0)
1758 // << distance
1759 // << " adjacentScatterers " << adjacentScatterers );
1760 }
1761 previous = m;
1762 }
1763
1764 // avoid possible leak
1765 delete measurement1;
1766 // delete measurement2; // redundant!
1767
1768 // in case of aggregation: insert the aggregateScatterers into the measurement
1769 // list (second loop over measurements)
1770 if (haveAggregation) {
1771 referencePosition =
1772 measurements.back()->intersection(FittedTrajectory).position();
1773 referenceDirection =
1774 (referencePosition -
1775 measurements.front()->intersection(FittedTrajectory).position())
1776 .unit();
1777 std::vector<Trk::FitMeasurement*>::reverse_iterator s =
1778 aggregateScatterers.rbegin();
1779 Amg::Vector3D scattererPosition =
1780 (**s).intersection(FittedTrajectory).position();
1781 double scattererDistance =
1782 std::abs(referenceDirection.dot(scattererPosition - referencePosition));
1783 for (std::vector<Trk::FitMeasurement*>::iterator m = measurements.begin();
1784 m != measurements.end(); ) {
1785 // insert scatterers from aggregrate vector
1786 const Amg::Vector3D position = (**m).intersection(FittedTrajectory).position();
1787 const double distance =
1788 std::abs(referenceDirection.dot(position - referencePosition));
1789 while (distance <= scattererDistance && s != aggregateScatterers.rend()) {
1790 m = measurements.insert(m, *s);
1791 ++m;
1792 if (++s != aggregateScatterers.rend()) {
1793 scattererPosition = (**s).intersection(FittedTrajectory).position();
1794 scattererDistance = std::abs(
1795 referenceDirection.dot(scattererPosition - referencePosition));
1796 }
1797 }
1798 if ((**m).isScatterer()) {
1799 // delete the scatterer if it has been aggregated
1800 if ((**m).isOutlier())
1801 delete *m;
1802 // in any case it must be removed from the list to avoid double counting
1803 m = measurements.erase(m);
1804 }
1805 else {
1806 ++m;
1807 }
1808 }
1809 }
1810
1811 // verbose table of fit measurements including material
1812 if (msgLvl(MSG::VERBOSE)) {
1813 ATH_MSG_VERBOSE(" finished material aggregation: ");
1814 int n = 0;
1815 const Amg::Vector3D startPosition =
1816 measurements.front()->intersection(FittedTrajectory).position();
1817 const Amg::Vector3D startDirection =
1818 measurements.front()->intersection(FittedTrajectory).direction();
1819 for (auto* measurement : measurements) {
1820 const Amg::Vector3D position =
1821 (*measurement).intersection(FittedTrajectory).position();
1822 const double distance = std::abs(startDirection.dot(position - startPosition));
1823 msg(MSG::VERBOSE) << std::setiosflags(std::ios::fixed) << std::setw(5)
1824 << ++n << std::setw(10) << std::setprecision(3)
1825 << distance << " " << (*measurement).type();
1826 if ((*measurement).isOutlier()) {
1827 msg() << " outlier ";
1828 } else if ((*measurement).materialEffects()) {
1829 msg() << std::setw(8) << std::setprecision(3)
1830 << (*measurement).materialEffects()->thicknessInX0() << " ";
1831 } else {
1832 msg() << " ";
1833 }
1834 if (!(*measurement).isMaterialDelimiter()) {
1835 msg() << std::setw(10) << std::setprecision(1)
1836 << (*measurement).position().perp() << std::setw(9)
1837 << std::setprecision(4) << (*measurement).position().phi()
1838 << std::setw(10) << std::setprecision(1)
1839 << (*measurement).position().z();
1840 }
1841 msg() << endmsg;
1842 }
1843 }
1844
1845 // loops to erase material delimiters and set energy gain when appropriate
1846 bool energyGain = false;
1847 for (auto& measurement : measurements) {
1848 if ((*measurement).materialEffects() && (*measurement).numberDoF() &&
1849 (*measurement).energyLoss() < 0.)
1850 energyGain = true;
1851 }
1852
1853 if (energyGain) {
1854 for (auto& measurement : measurements) {
1855 if ((*measurement).materialEffects())
1856 (*measurement).setEnergyGain();
1857 }
1858 }
1859}
1860
1862 const TrackStateOnSurface& tsos, double outgoingEnergy,
1863 double particleMass) {
1864 if (!tsos.trackParameters() || !tsos.materialEffectsOnTrack())
1865 return nullptr;
1866
1867 const double deltaE = outgoingEnergy - tsos.trackParameters()->momentum().mag();
1868 const double thicknessInX0 = tsos.materialEffectsOnTrack()->thicknessInX0();
1869 const Amg::Vector3D position = tsos.trackParameters()->position();
1870 const Amg::Vector3D direction = tsos.trackParameters()->momentum().unit();
1871 double qOverP = 1. / outgoingEnergy;
1872 if (tsos.trackParameters()->charge() < 0)
1873 qOverP = -qOverP;
1874
1875 return new FitMeasurement(thicknessInX0, deltaE, particleMass, position,
1876 direction, qOverP);
1877}
1878
1880 std::vector<FitMeasurement*>& measurements) const {
1882 "measurements and material: distance X0 deltaE E "
1883 " pT"
1884 << " R phi Z DoF phi theta");
1885
1886 if (measurements.empty())
1887 return;
1888
1889 std::vector<Trk::FitMeasurement*>::iterator m = measurements.begin();
1890 while (m != measurements.end() && !(**m).isPositionMeasurement())
1891 ++m;
1892 if (m == measurements.end())
1893 m = measurements.begin();
1894
1895 const Amg::Vector3D direction = (**m).intersection(FittedTrajectory).direction();
1896 const Amg::Vector3D startPosition = (**m).intersection(FittedTrajectory).position();
1897 int scatterers = 0;
1898 int leadingMaterial = 0;
1899 double leadingX0 = 0.;
1900 double sumX0 = 0.;
1901 double leadingELoss = 0.;
1902 double sumELoss = 0.;
1903 int n = 0;
1904 for (auto& measurement : measurements) {
1905 const double distance =
1906 direction.dot((*measurement).intersection(FittedTrajectory).position() -
1907 startPosition);
1908 msg(MSG::VERBOSE) << std::setiosflags(std::ios::fixed) << std::setw(5)
1909 << ++n << " " << (*measurement).type() << std::setw(11)
1910 << std::setprecision(3) << distance;
1911 if ((*measurement).isOutlier()) {
1912 msg() << " outlier " << std::setw(44);
1913 } else if ((*measurement).materialEffects()) {
1914 double deltaE = 0.;
1915 const MaterialEffectsOnTrack* materialEffects =
1916 dynamic_cast<const MaterialEffectsOnTrack*>(
1917 (*measurement).materialEffects());
1918 if (materialEffects && materialEffects->energyLoss())
1919 deltaE = materialEffects->energyLoss()->deltaE();
1920 if ((*measurement).isEnergyDeposit())
1921 deltaE = -deltaE;
1922 msg() << std::setw(10) << std::setprecision(3)
1923 << (*measurement).materialEffects()->thicknessInX0() << std::setw(9)
1924 << std::setprecision(1) << deltaE << " ";
1925 if (distance > 0.) {
1926 ++scatterers;
1927 sumX0 += (*measurement).materialEffects()->thicknessInX0();
1928 sumELoss -= deltaE;
1929 } else {
1930 ++leadingMaterial;
1931 leadingX0 += (*measurement).materialEffects()->thicknessInX0();
1932 leadingELoss -= deltaE;
1933 }
1934
1935 if ((*measurement).qOverP()) {
1936 msg() << std::setw(11) << std::setprecision(4)
1937 << 1. / std::abs((*measurement).qOverP() * Gaudi::Units::GeV)
1938 << std::setw(10) << std::setprecision(3)
1939 << (*measurement)
1940 .intersection(FittedTrajectory)
1941 .direction()
1942 .perp() /
1943 ((*measurement).qOverP() * Gaudi::Units::GeV)
1944 << std::setw(12);
1945 }
1946 } else {
1947 msg() << std::setw(54);
1948 }
1949 if ((*measurement).isMaterialDelimiter()) {
1950 msg() << std::setprecision(1)
1951 << (*measurement).intersection(FittedTrajectory).position().perp()
1952 << std::setw(9) << std::setprecision(4)
1953 << (*measurement).intersection(FittedTrajectory).position().phi()
1954 << std::setw(10) << std::setprecision(1)
1955 << (*measurement).intersection(FittedTrajectory).position().z()
1956 << std::setw(14) << std::setprecision(4)
1957 << (*measurement).intersection(FittedTrajectory).direction().phi()
1958 << std::setw(9) << std::setprecision(4)
1959 << (*measurement).intersection(FittedTrajectory).direction().theta()
1960 << endmsg;
1961 } else {
1962 msg() << std::setprecision(1) << (*measurement).position().perp()
1963 << std::setw(9) << std::setprecision(4)
1964 << (*measurement).position().phi() << std::setw(10)
1965 << std::setprecision(1) << (*measurement).position().z()
1966 << std::setw(5) << (*measurement).numberDoF() << endmsg;
1967 }
1968 }
1969
1970 // fix counting at allocation stage
1971 if (!scatterers) {
1972 scatterers = leadingMaterial;
1973 leadingMaterial = 0;
1974 }
1975
1977 " material: "
1978 << scatterers << " (" << leadingMaterial
1979 << ") fitted scattering centres (leading material centres) giving "
1980 << std::setiosflags(std::ios::fixed) << std::setw(8)
1981 << std::setprecision(3) << sumX0 << " (" << std::setw(8)
1982 << std::setprecision(3) << leadingX0 << ")"
1983 << " X0 and " << std::setw(8) << std::setprecision(3)
1984 << sumELoss / Gaudi::Units::GeV << " (" << std::setw(8)
1985 << std::setprecision(3) << leadingELoss / Gaudi::Units::GeV << ")"
1986 << " GeV Eloss");
1987}
1988
1990 std::vector<FitMeasurement*>& measurements,
1991 ParticleHypothesis particleHypothesis, FitParameters& fitParameters,
1992 const TrackParameters& startParameters, Garbage_t& garbage) const {
1993 const EventContext& ctx = Gaudi::Hive::currentContext();
1994 // return if no MS measurement
1995 if (m_calorimeterVolume->inside(measurements.back()->position()))
1996 return;
1997
1998 // check that the spectrometer measurements are ordered and that material
1999 // allocation is required
2000 Amg::Vector3D startDirection = startParameters.momentum().unit();
2001 Amg::Vector3D startPosition = startParameters.position();
2002 bool haveMaterial = false;
2003 bool haveLeadingMaterial = false;
2004 bool reorderMS = false;
2005 bool reorderID = false;
2006 bool firstMSHit = false;
2007 double previousDistance = 0.;
2008 double previousDistanceR = 0.;
2009 double previousDistanceZ = 0.;
2010 double minDistanceID = 0.;
2011 double minDistanceMS = 0.;
2012 double minRDistanceMS = 0.;
2013 double minZDistanceMS = 0.;
2014 std::vector<Trk::FitMeasurement*>::iterator m = measurements.begin();
2015 for (; m != measurements.end(); ++m) {
2016 const Amg::Vector3D position = (**m).intersection(FittedTrajectory).position();
2017 const Amg::Vector3D positionSurf = (**m).surface()->center();
2018 Amg::Vector3D positionMst = startPosition;
2019 if ((**m).measurementBase())
2020 positionMst = (**m).measurementBase()->globalPosition();
2021 const double distance = startDirection.dot(position - startPosition);
2022 const double distanceR = std::hypot(positionMst.x() - startPosition.x(),
2023 positionMst.y() - startPosition.y());
2024 double distanceZ = (positionMst.z() - startPosition.z());
2025 if (startDirection.z() < 0)
2026 distanceZ = -distanceZ;
2027 if (!m_calorimeterVolume->inside(position) ||
2028 !m_calorimeterVolume->inside(positionSurf)) {
2029 if (distance - previousDistance < -m_orderingTolerance) {
2030 reorderMS = true;
2031 if (distance - previousDistance < minDistanceMS) {
2032 minDistanceMS = distance - previousDistance;
2033 minRDistanceMS = distanceR - previousDistanceR;
2034 minZDistanceMS = distanceZ - previousDistanceZ;
2035 }
2036 }
2037 if ((**m).isScatterer())
2038 haveMaterial = true;
2039 if ((**m).measurementBase() && !firstMSHit) {
2040 firstMSHit = true;
2041 }
2042 if ((**m).isScatterer() && !firstMSHit)
2043 haveLeadingMaterial = true;
2044 } else {
2045 if (distance - previousDistance < -m_orderingTolerance) {
2046 reorderID = true;
2047 if (distance - previousDistance < minDistanceID)
2048 minDistanceID = distance - previousDistance;
2049 }
2050 }
2051 previousDistance = distance;
2052 previousDistanceZ = distanceZ;
2053 previousDistanceR = distanceR;
2054 }
2055
2056 if (reorderMS && (minRDistanceMS > -m_orderingTolerance ||
2057 minZDistanceMS > -m_orderingTolerance)) {
2058 // 3D distance of the intersection is problematic but the R or Z distance
2059 // of the measurementBase is fine we should not reorder
2060
2061 reorderMS = false;
2062 }
2063
2064 // if(!m_allowReordering) {
2065 if (reorderMS && fabs(minDistanceMS) > -2.)
2066 ATH_MSG_DEBUG(" reorder MS part of track with minimum distance "
2067 << minDistanceMS << " minRDistanceMS " << minRDistanceMS
2068 << " minZDistanceMS " << minZDistanceMS);
2069 if (reorderID && fabs(minDistanceID) > -2.)
2070 ATH_MSG_DEBUG(" reorder ID part of track with minimum distance "
2071 << minDistanceID);
2072 // }
2073
2074 if (reorderMS || reorderID) {
2075 if (msgLvl(MSG::DEBUG))
2076 printMeasurements(measurements);
2077 }
2078
2079 if (!haveLeadingMaterial && haveMaterial) {
2081 " MS part of track has no leading material in front of first MS hit ");
2082 }
2083
2084 if (reorderMS)
2085 orderMeasurements(measurements, startDirection, startPosition);
2086
2087 // nothing to do if spectrometer material already exists
2088 if (haveMaterial)
2089 return;
2090
2092 " spectrometerMaterial: ALARM no material found on track can happen for "
2093 "MuGirl");
2094
2095 // material has to be added: need inner and outer TrackParameters
2096 FitMeasurement* innerMeasurement = nullptr;
2097 FitMeasurement* outerMeasurement = nullptr;
2098 for (m = measurements.begin(); m != measurements.end(); ++m) {
2099 if (!(**m).isPositionMeasurement() || (**m).isOutlier())
2100 continue;
2101 const Amg::Vector3D position = (**m).intersection(FittedTrajectory).position();
2102 if (m_calorimeterVolume->inside(position))
2103 continue;
2104 if (innerMeasurement) {
2105 outerMeasurement = *m;
2106 } else {
2107 innerMeasurement = *m;
2108 }
2109 }
2110 if (!outerMeasurement)
2111 return;
2112
2113 // insert delimiters
2114 addSpectrometerDelimiters(measurements);
2115
2116 const Trk::TrackingVolume* spectrometerEntrance = getSpectrometerEntrance();
2117 if (!spectrometerEntrance)
2118 return;
2119
2120 // entranceParameters are at the MS entrance surface (0 if perigee downstream)
2121 TrackSurfaceIntersection* entranceIntersection = nullptr;
2122 std::unique_ptr<const TrackParameters> entranceParameters;
2123 MsgStream log(msgSvc(), name());
2124 if (m_calorimeterVolume->inside(startParameters.position())) {
2125 std::unique_ptr<const TrackParameters> innerParameters(
2126 fitParameters.trackParameters(log, *innerMeasurement, false));
2127 if (!innerParameters)
2128 innerParameters.reset(startParameters.clone());
2129 entranceParameters = m_extrapolator->extrapolateToVolume(
2130 ctx, *innerParameters, *spectrometerEntrance, anyDirection,
2132 if (entranceParameters) {
2133 startDirection = entranceParameters->momentum().unit();
2134 startPosition = entranceParameters->position();
2135 entranceIntersection = new TrackSurfaceIntersection(
2136 entranceParameters->position(), entranceParameters->momentum().unit(),
2137 0.);
2138 std::vector<Trk::FitMeasurement*>::iterator e = measurements.begin();
2139 FitMeasurement* entranceDelimiter =
2140 new FitMeasurement(*entranceIntersection, 0.);
2141 for (m = measurements.begin(); m != measurements.end(); ++m) {
2142 if (!m_calorimeterVolume->inside((**m).position()))
2143 break;
2144 e = m;
2145 }
2146
2147 // insert a material delimiter at the start of the spectrometer (or at
2148 // perigee if in MS)
2149 e = measurements.insert(++e, entranceDelimiter);
2150 delete entranceIntersection;
2151 } else {
2152 // did not find MS entrance surface - no MS material taken into account
2153 // m_messageHelper->printWarning(3); ATLASRECTS-7528
2154 return;
2155 }
2156 }
2157
2158 // insert a material delimiter after the last measurement (endParameters)
2159 std::unique_ptr<const TrackParameters> outerParameters(
2160 fitParameters.trackParameters(log, *outerMeasurement, false));
2161 if (!outerParameters)
2162 outerParameters.reset(startParameters.clone());
2163 const Surface& endSurface = *measurements.back()->surface();
2164 std::unique_ptr<const TrackParameters> endParameters(
2165 m_extrapolator->extrapolate(ctx, *outerParameters, endSurface,
2166 anyDirection, false, particleHypothesis));
2167
2168 if (!endParameters) {
2169 endParameters =
2170 m_extrapolator->extrapolate(ctx, *outerParameters, endSurface,
2172
2173 if (!endParameters) {
2174 // failed extrapolation
2175 m_messageHelper->printWarning(4);
2176 endParameters = std::move(outerParameters);
2177 }
2178 }
2179 // insert delimiter
2180 const TrackSurfaceIntersection endIntersection(
2181 endParameters->position(), endParameters->momentum().unit(), 0.);
2182 FitMeasurement* endBreak =
2183 new FitMeasurement(endIntersection, 20. * Gaudi::Units::mm);
2184 measurements.push_back(endBreak);
2185
2186 const double endSpectrometerDistance = startDirection.dot(
2187 measurements.back()->intersection(FittedTrajectory).position() -
2188 startPosition);
2189 const std::vector<const TrackStateOnSurface*>* spectrometerMaterial = nullptr;
2190
2191 // protect the momentum to avoid excessive Eloss
2192
2193 Amg::VectorX parameterVector = endParameters->parameters();
2194 const double Emax = 50000.;
2195 if (parameterVector[Trk::qOverP] == 0.) {
2196 parameterVector[Trk::qOverP] = 1. / Emax;
2197 } else {
2198 if (std::abs(parameterVector[Trk::qOverP]) * Emax < 1)
2199 parameterVector[Trk::qOverP] = endParameters->charge() / Emax;
2200 }
2201
2202 // correct track parameters for high momentum track (otherwise Eloss is too
2203 // large)
2204 endParameters =
2205 endParameters->associatedSurface().createUniqueTrackParameters(
2206 parameterVector[Trk::loc1], parameterVector[Trk::loc2],
2207 parameterVector[Trk::phi], parameterVector[Trk::theta],
2208 parameterVector[Trk::qOverP], std::nullopt);
2209
2210 if (entranceParameters) {
2211 const Surface& entranceSurface = entranceParameters->associatedSurface();
2213 extrapolatedMaterial(m_extrapolator, *endParameters, entranceSurface,
2214 anyDirection, false, Trk::muon, garbage);
2215 } else {
2216 const Surface& entranceSurface = startParameters.associatedSurface();
2218 extrapolatedMaterial(m_extrapolator, *endParameters, entranceSurface,
2219 anyDirection, false, Trk::muon, garbage);
2220 }
2221
2222 // debug
2223 if (msgLvl(MSG::VERBOSE) && spectrometerMaterial &&
2224 !spectrometerMaterial->empty()) {
2225 ATH_MSG_VERBOSE(" spectrometerMaterial: "
2226 << "using extrapolateM inwards from outermost measurement");
2227 double p1 = 0.;
2228 if (spectrometerMaterial->front()->trackParameters())
2229 p1 = spectrometerMaterial->front()->trackParameters()->momentum().mag();
2230 for (const auto* ss : *spectrometerMaterial) {
2231 if (!(*ss).trackParameters() || !(*ss).materialEffectsOnTrack())
2232 continue;
2233 const double distance = startDirection.dot((*ss).trackParameters()->position() -
2234 startPosition);
2235 double deltaE = 0.;
2236 const double thickness = (*ss).materialEffectsOnTrack()->thicknessInX0();
2237 const MaterialEffectsOnTrack* materialEffects =
2238 dynamic_cast<const MaterialEffectsOnTrack*>(
2239 (*ss).materialEffectsOnTrack());
2240 if (materialEffects && materialEffects->energyLoss())
2241 deltaE = materialEffects->energyLoss()->deltaE();
2242 const double p2 = (*ss).trackParameters()->momentum().mag();
2244 std::setiosflags(std::ios::fixed)
2245 << " material: RZ" << std::setw(9) << std::setprecision(3)
2246 << (*ss).trackParameters()->position().perp() << std::setw(10)
2247 << std::setprecision(3) << (*ss).trackParameters()->position().z()
2248 << " distance " << std::setw(10) << std::setprecision(3) << distance
2249 << " pt " << std::setw(8) << std::setprecision(3)
2250 << (*ss).trackParameters()->momentum().perp() / Gaudi::Units::GeV
2251 << " X0thickness " << std::setw(8) << std::setprecision(4)
2252 << thickness << " deltaE " << std::setw(8) << std::setprecision(4)
2253 << deltaE << " diffP " << std::setw(8) << std::setprecision(4)
2254 << p2 - p1);
2255 p1 = p2;
2256 }
2257 }
2258
2259 // insert the material into the measurement list
2260 if (!spectrometerMaterial || spectrometerMaterial->empty()) {
2261 // m_messageHelper->printWarning(5);
2262 // Suppressing, as discussed in ATLASRECTS-7515, but keeping this here to remind us
2263 // to investigate it properly.
2264 delete spectrometerMaterial;
2265 spectrometerMaterial = nullptr;
2266 } else {
2267 std::vector<const TrackStateOnSurface*>::const_reverse_iterator s =
2268 spectrometerMaterial->rbegin();
2269 std::vector<FitMeasurement*> material;
2270 const double particleMass = Trk::ParticleMasses::mass[particleHypothesis];
2271 material.reserve(spectrometerMaterial->size());
2272 std::vector<FitMeasurement*>::iterator m = measurements.begin();
2273 for (; s != spectrometerMaterial->rend();) {
2274 const TrackStateOnSurface& tsos = **s;
2275 while (++s != spectrometerMaterial->rend() && !(**s).trackParameters())
2276 ;
2277
2278 double outgoingEnergy = 0.;
2279 if (s != spectrometerMaterial->rend()) {
2280 outgoingEnergy = (**s).trackParameters()->momentum().mag();
2281 } else {
2282 outgoingEnergy = endParameters->momentum().mag();
2283 }
2284
2285 FitMeasurement* measurement =
2286 measurementFromTSOS(tsos, outgoingEnergy, particleMass);
2287 if (!measurement)
2288 continue;
2289
2290 // insert next to adjacent measurement
2291 material.push_back(measurement);
2292 const double distance = startDirection.dot(tsos.trackParameters()->position() -
2293 startPosition);
2294 if (distance > endSpectrometerDistance) {
2295 delete measurement;
2296 break;
2297 }
2298 while (m != measurements.end() &&
2299 distance > startDirection.dot(
2300 (**m).intersection(FittedTrajectory).position() -
2301 startPosition)) {
2302 ++m;
2303 }
2304 if (m == measurements.end()) {
2305 delete measurement;
2306 break;
2307 }
2308
2309 m = measurements.insert(m, material.back());
2310 }
2311 }
2312
2313 // // check sign and order here
2314 // printMeasurements(measurements);
2315
2316 // memory management
2317 ATH_MSG_VERBOSE(" spectrometer: mem management");
2319
2320 materialAggregation(measurements,
2321 Trk::ParticleMasses::mass[particleHypothesis]);
2322}
2323} // 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
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.