15 #include "GaudiKernel/SystemOfUnits.h"
36 const std::string&
name,
39 m_aggregateMaterial(true),
40 m_allowReordering(false),
41 m_useStepPropagator(1),
45 m_scatteringConstant(13.6 *
47 m_scatteringLogCoeff(0.038),
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);
56 declareProperty(
"AggregateMaterial", m_aggregateMaterial);
57 declareProperty(
"AllowReordering", m_allowReordering);
64 declareProperty(
"UseStepPropagator", m_useStepPropagator);
65 declareProperty(
"OrderingTolerance", m_orderingTolerance);
67 "MaxNumberOfWarnings", m_maxWarnings,
68 "Maximum number of permitted WARNING messages per message type.");
76 "leadingSpectrometerTSOS: missing TrackingGeometrySvc - no leading "
77 "material will be added");
79 1,
"indetMaterial: extrapolateM finds no material on track");
82 "spectrometerMaterial: missing TrackingGeometrySvc - no spectrometer "
85 "spectrometerMaterial: did not find MS entrance "
86 "surface - no MS material taken into account");
87 m_messageHelper->setMessage(4,
"spectrometerMaterial: failed extrapolation");
89 5,
"spectrometerMaterial: extrapolateM finds no material on track");
121 return StatusCode::SUCCESS;
127 return StatusCode::SUCCESS;
131 std::vector<FitMeasurement*>& measurements,
134 const EventContext& ctx = Gaudi::Hive::currentContext();
136 if (measurements.front()->isVertex()) {
156 bool energyGain =
false;
157 bool haveDelimiter =
false;
158 std::optional<TrackSurfaceIntersection>
intersection = std::nullopt;
159 int leadingScatterers = 0;
161 for (
auto* measurement : measurements) {
162 if ((*measurement).isMaterialDelimiter()) {
163 haveDelimiter =
true;
164 }
else if ((*measurement).isScatterer()) {
166 if (!(*measurement).numberDoF()) {
168 leadingScatterer = measurement;
170 if (std::abs(1. / (*measurement).qOverP()) >
p)
178 if (haveDelimiter && !leadingScatterers) {
180 haveDelimiter =
false;
182 const Surface* firstMeasurementSurface =
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);
197 firstMeasurementSurface = (*measurement).surface();
205 }
else if ((*measurement).isScatterer()) {
209 if (std::abs(1. / (*measurement).qOverP()) >
p)
221 bool haveMaterial =
false;
222 const std::vector<const TrackStateOnSurface*>*
indetMaterial =
nullptr;
230 " addLeadingMaterial: using extrapolateM from distance "
231 << direction.dot(fitParameters.
position() - startPosition));
237 particleHypothesis, garbage);
241 std::vector<const TrackStateOnSurface*>::const_reverse_iterator
r =
245 if (!(**r).trackParameters() || !(**r).materialEffectsOnTrack() ||
247 (**r).trackParameters()->position() - endPosition) > 0.)
254 haveDelimiter =
false;
258 if (haveDelimiter && !haveMaterial) {
261 " no leading material found with forward extrapolation"
262 <<
", try again with back extrapolation ");
268 std::vector<const TrackStateOnSurface*>* indetMaterialF =
nullptr;
269 const std::vector<const TrackStateOnSurface*>* indetMaterialR =
nullptr;
283 if (indetMaterialR && !indetMaterialR->empty()) {
284 indetMaterialF =
new std::vector<const TrackStateOnSurface*>;
285 indetMaterialF->reserve(indetMaterialR->size());
287 std::vector<const TrackStateOnSurface*>::const_reverse_iterator
r =
288 indetMaterialR->rbegin();
289 for (;
r != indetMaterialR->rend(); ++
r) {
290 indetMaterialF->push_back(*
r);
293 for (
r = indetMaterialF->rbegin();
r != indetMaterialF->rend(); ++
r) {
295 if (!(**r).trackParameters() || !(**r).materialEffectsOnTrack() ||
297 (**r).trackParameters()->position() - endPosition) > 0.)
303 indetMaterialF =
nullptr;
306 delete indetMaterialR;
313 std::vector<const TrackStateOnSurface*>::const_reverse_iterator
r =
317 if (!(**r).trackParameters() || !(**r).materialEffectsOnTrack() ||
318 intersection->direction().dot((**r).trackParameters()->position() -
326 (**r).materialEffectsOnTrack());
327 if (materialEffects) {
333 if (leadingScatterers++ || !firstMeasurementSurface) {
335 std::optional<TrackSurfaceIntersection> newIntersectionSTEP =
337 ctx, (**r).trackParameters()->associatedSurface(),
341 (**r).trackParameters()->associatedSurface(), *
intersection,
347 ctx, (**r).trackParameters()->associatedSurface(),
350 (**r).trackParameters()->associatedSurface(),
367 for (std::vector<Trk::FitMeasurement*>::const_iterator
l =
368 leadingOutliers.begin();
369 l != leadingOutliers.end(); ++
l) {
370 leadingOutlier = leadingOutliers.back();
372 std::remove(measurements.begin(), measurements.end(), *
l),
376 (**r).materialEffectsOnTrack()->thicknessInX0(), -eLoss,
379 firstMeasurementSurface);
380 leadingScatterer = leadingMeas;
387 if (leadingOutlier) {
394 leadingOutliers.pop_back();
395 measurements.insert(measurements.begin(), leadingOutlier);
396 if (!leadingOutliers.empty()) {
397 leadingOutlier = leadingOutliers.back();
399 leadingOutlier =
nullptr;
406 measurements.insert(measurements.begin(), leadingMeas);
409 if (materialEffects) {
422 std::optional<TrackSurfaceIntersection> newIntersectionSTEP =
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)
456 for (;
m != measurements.rend(); ++
m) {
457 if (!(**m).isScatterer())
461 if (!materialEffects)
465 leadingX0Integral += (**m).materialEffects()->
thicknessInX0();
467 leadingScattering = leadingX0Integral * logTerm * logTerm;
468 double scatteringAngle =
470 std::sqrt(leadingScattering - previousScattering);
471 previousScattering = leadingScattering;
472 (**m).scatteringAngle(scatteringAngle, leadingX0Integral);
475 double angleSquared = 1. / (**m).weight();
479 double sinThetaSquared =
481 angleSquared *= angleSquared / sinThetaSquared;
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;
490 leadingCovariance(1, 1) +=
492 leadingCovariance(1, 3) +=
deltaR * angleSquared;
493 leadingCovariance(3, 1) = leadingCovariance(1, 3);
494 leadingCovariance(3, 3) += angleSquared * sinThetaSquared;
501 qOverP, leadingCovariance);
506 qOverP, leadingCovariance);
518 std::vector<FitMeasurement*>& measurements,
522 indetMaterial(measurements, particleHypothesis, startParameters, garbage);
525 startParameters, garbage);
535 std::vector<FitMeasurement*>& measurements)
const {
539 double previousScattering = 0.;
540 double X0Integral = 0.;
545 while (!(**m).isPositionMeasurement() || (**m).isOutlier())
548 for (;
m != measurements.end(); ++
m) {
549 if (
integrate && (**m).isPositionMeasurement() && !(**m).isOutlier()) {
552 previousScattering = 0.;
555 if ((**m).isScatterer()) {
559 if (++
next != measurements.end() && !(**next).hitOnTrack() &&
560 (**next).isPositionMeasurement() && !(**next).isOutlier()) {
570 previousScattering = 0.;
576 double thicknessInX0 = (**m).materialEffects()->thicknessInX0();
577 if ((**m).materialEffects()->thicknessInX0() < 0.) {
579 << (**m).materialEffects()->thicknessInX0() <<
" "
580 << *(**m).materialEffects());
581 thicknessInX0 = 1
e-6;
583 X0Integral += thicknessInX0;
585 if (X0Integral > 0.) {
589 << X0Integral <<
" thicknessInX0 "
590 << (**m).materialEffects()->thicknessInX0() <<
" "
591 << *(**m).materialEffects());
594 double scattering = X0Integral * logTerm * logTerm;
597 previousScattering = scattering;
599 (**m).scatteringAngle(
angle, X0Integral);
604 std::vector<const TrackStateOnSurface*>*
606 const TrackParameters& spectrometerParameters, Garbage_t& garbage)
const {
607 const EventContext& ctx = Gaudi::Hive::currentContext();
609 if (!spectrometerEntrance)
615 std::unique_ptr<const TrackParameters> entranceParameters(
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)
631 const Surface& entranceSurface = entranceParameters->associatedSurface();
632 std::unique_ptr<const std::vector<const TrackStateOnSurface*>>
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)
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();
656 for (
const auto*
s : *extrapolatedTSOS) {
657 if (!(*s).trackParameters())
659 std::unique_ptr<FitMeasurement> measurement(
661 outgoingEnergy = (*s).trackParameters()->momentum().mag();
664 leadingMeasurements.emplace(leadingMeasurements.begin(),
665 std::move(measurement));
667 leadingTSOS->push_back((*s).clone());
672 for (
const auto&
m : leadingMeasurements)
673 leadingTSOS->emplace_back(
new TrackStateOnSurface(
674 nullptr,
nullptr,
m->materialEffects()->uniqueClone()));
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)
690 return leadingTSOS.release();
694 std::vector<FitMeasurement*>& measurements,
Amg::Vector3D startDirection,
698 << startDirection.phi() <<
" theta "
699 << startDirection.theta());
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(
713 measurementOrder.emplace_back(
distance, measurement);
714 originalOrder.emplace_back(
distance, measurement);
716 std::sort(measurementOrder.begin(), measurementOrder.end(),
717 compareByDistance());
718 std::vector<std::pair<double, FitMeasurement*>>::const_iterator orig =
719 originalOrder.begin();
720 bool shouldReorder =
false;
722 measurements.erase(measurements.begin(), measurements.end());
724 for (std::vector<std::pair<double, FitMeasurement*>>::const_iterator
order =
725 measurementOrder.begin();
726 order != measurementOrder.end(); ++
order, ++orig) {
728 measurements.push_back((*order).second);
733 if ((*order).second == (*orig).second ||
736 shouldReorder =
true;
744 ATH_MSG_DEBUG(
" measurement reordering would improve the track fit ");
750 std::vector<FitMeasurement*>& measurements, FitParameters&
parameters,
751 Garbage_t& garbage)
const {
755 for (
auto& measurement : measurements) {
756 if (!(*measurement).isMaterialDelimiter())
761 (*measurement).position())
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)
769 << std::setw(9) << std::setprecision(4)
771 << std::setw(10) << std::setprecision(1)
780 for (;
m != measurements.end(); ++
m) {
783 if ((**m).materialEffects())
785 if ((**m).isMaterialDelimiter())
789 if ((**m).isMaterialDelimiter())
802 Amg::VectorX parameterVector = trackParameters->parameters();
803 double Emax = 50000.;
814 (trackParameters->associatedSurface())
815 .createUniqueTrackParameters(
821 for (std::vector<Trk::FitMeasurement*>::reverse_iterator
r =
822 measurements.rbegin();
823 r != measurements.rend(); ++
r) {
824 if (!(**r).isMaterialDelimiter())
842 std::pair<FitMeasurement*, FitMeasurement*> fms =
853 delete trackParameters;
859 delete trackParameters;
862 for (
m = measurements.begin();
m != measurements.end(); ++
m) {
863 if (!(**m).isMaterialDelimiter())
868 measurements.erase(
n);
875 std::vector<FitMeasurement*>& measurements)
const {
885 double previousDistance = 0.;
891 double referencePhi = 0.;
894 m != measurements.end(); ++
m, ++
index) {
896 if (!(**m).isPositionMeasurement() || (**m).isPseudo())
906 bool preBreak =
false;
907 bool postBreak =
false;
914 referencePhi = position.phi();
915 startDirection = referenceDirection;
916 startPosition = referencePosition;
923 if (((**m).isDrift() && !
previous->isDrift()) ||
924 (!(**m).isDrift() &&
previous->isDrift()) ||
934 if (!(preBreak || postBreak)) {
978 previousDistance = 0.;
981 referencePhi = position.phi();
988 const std::vector<const TrackStateOnSurface*>* material,
989 Garbage_t& garbage) {
992 garbage.push_back(std::unique_ptr<const TrackStateOnSurface>(
m));
998 const std::vector<const TrackStateOnSurface*>*
1000 const ToolHandle<IExtrapolator>& extrapolator,
1004 const EventContext& ctx = Gaudi::Hive::currentContext();
1007 const std::vector<const TrackStateOnSurface*>* TGMaterial =
1008 extrapolator->extrapolateM(ctx,
parameters, surface,
dir, boundsCheck,
1009 particleHypothesis);
1011 if (!TGMaterial || TGMaterial->empty())
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);
1022 for (; tg != TGMaterial->end(); ++tg) {
1024 double separation = 0.;
1027 (**tg).trackParameters()->position())
1031 material->push_back(*tg);
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());
1039 duplicates =
new std::vector<const TrackStateOnSurface*>;
1051 std::vector<FitMeasurement*>& measurements,
1054 const EventContext& ctx = Gaudi::Hive::currentContext();
1062 double endIndetDistance = 0.;
1069 std::unique_ptr<AtaPlane> newParameters;
1072 if ((**m).isVertex())
1074 for (;
m != measurements.end(); ++
m) {
1075 if ((**m).isOutlier())
1079 if ((**m).isScatterer()) {
1084 if (!(**m).isPositionMeasurement())
1096 std::optional<TrackSurfaceIntersection> newIntersectionSTEP =
1126 newParameters = std::make_unique<AtaPlane>(
1136 double distance = startDirection.dot(
1138 if (!endIndetMeasurement ||
distance > endIndetDistance) {
1140 endIndetMeasurement = *
m;
1146 if (!endIndetMeasurement) {
1150 ATH_MSG_DEBUG(
" indetMaterial: ALARM no material found on track");
1155 startDirection = (endPosition - startPosition).
unit();
1157 startDirection.dot(endPosition - startPosition) +
tolerance;
1159 << endIndetDistance);
1160 const std::vector<const TrackStateOnSurface*>*
indetMaterial =
1163 false, particleHypothesis, garbage);
1172 std::vector<const Surface*> surfaces;
1174 std::vector<const TrackStateOnSurface*>::const_iterator indetMaterialEnd =
1177 for (std::vector<const TrackStateOnSurface*>::const_iterator
s =
1180 if ((**s).trackParameters()) {
1181 if (startDirection.dot((**s).trackParameters()->position() -
1182 startPosition) < endIndetDistance) {
1183 indetMaterialEnd =
s;
1188 <<
" trailing TSOS (after last measurement)");
1204 double p1 =
indetMaterial->front()->trackParameters()->momentum().mag();
1206 for (std::vector<const TrackStateOnSurface*>::const_iterator
s =
1208 s != indetMaterialEnd; ++
s) {
1209 if (!(**s).trackParameters())
1211 double distance = startDirection.dot((**s).trackParameters()->position() -
1214 double thickness = 0.;
1217 (**s).materialEffectsOnTrack());
1218 if ((**s).materialEffectsOnTrack()) {
1219 if (materialEffects)
1221 thickness = (**s).materialEffectsOnTrack()->thicknessInX0();
1223 double p2 = (**s).trackParameters()->momentum().mag();
1225 std::setiosflags(std::ios::fixed)
1226 <<
" material: RZ" << std::setw(9) << std::setprecision(3)
1227 << (**s).trackParameters()->position().perp() << std::setw(10)
1228 << std::setprecision(3) << (**s).trackParameters()->position().z()
1229 <<
" distance " << std::setw(10) << std::setprecision(3) <<
distance
1230 <<
" pt " << std::setw(8) << std::setprecision(3)
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)
1245 m = measurements.begin();
1246 std::vector<const TrackStateOnSurface*>::const_iterator
s =
1248 for (;
m != measurements.end(); ++
m) {
1249 if (*
m == endIndetMeasurement ||
s == indetMaterialEnd)
1251 if (!leadingDelimiter && (**m).
isOutlier())
1256 double closestDistance = direction.dot(position - startPosition);
1259 const Surface* materialSurface =
nullptr;
1262 for (;
s != indetMaterialEnd; ++
s) {
1264 (**s).materialEffectsOnTrack()) ||
1265 !(**s).trackParameters())
1267 nextMomentum = (**s).trackParameters()->momentum();
1268 nextPosition = (**s).trackParameters()->position();
1269 double distance = direction.dot(nextPosition - position);
1280 double nextDistance = direction.dot(
1281 (**s).trackParameters()->position() - (**m).position());
1286 materialSurface =
nullptr;
1296 if (!leadingDelimiter && materialSurface)
1297 surfaces.push_back(materialSurface);
1300 (**s).materialEffectsOnTrack());
1301 materialParameters = (**s).trackParameters();
1306 if (!materialSurface)
1310 if (!surfaces.empty() && materialSurface == surfaces.back())
1316 if (!leadingDelimiter) {
1317 position = 0.5 * (materialParameters->
position() + nextPosition);
1318 direction = (materialParameters->
momentum() + nextMomentum).
unit();
1321 while (*
m != endIndetMeasurement &&
1325 m = measurements.insert(
m, leadingDelimiter);
1326 surfaces.push_back(materialSurface);
1335 const std::bitset<MaterialEffectsBase::NumberOfMaterialEffectsTypes>
1337 std::unique_ptr<Trk::EnergyLoss> energyLoss =
nullptr;
1339 energyLoss = std::unique_ptr<Trk::EnergyLoss>(
1344 *(**m).surface(), typePattern);
1346 if (++
m == measurements.end())
1348 m = measurements.insert(
1353 (**m).qOverP(materialParameters->parameters()[
Trk::qOverP]);
1354 (**m).setMaterialEffectsOwner();
1355 surfaces.push_back(materialSurface);
1359 m = measurements.begin();
1362 << measurements.size() <<
" surfaces.size() "
1363 << surfaces.size() <<
" indetMaterial->size() "
1365 std::vector<const Surface*>::const_iterator
r = surfaces.begin();
1367 if (!(**s).trackParameters() || !(**s).materialEffectsOnTrack())
1370 if (
r != surfaces.end() &&
1371 **
r == (**s).trackParameters()->associatedSurface()) {
1377 startDirection.dot((**s).trackParameters()->position() - startPosition);
1380 << startPosition.z());
1382 " (**m).intersection(FittedTrajectory).position() measurement "
1387 " (**s).trackParameters()->position() material surface position "
1389 << (**s).trackParameters()->position().perp() <<
" z "
1390 << (**s).trackParameters()->position().z());
1393 bool endIndet =
false;
1397 if (*
m == endIndetMeasurement) {
1398 if (*
m != measurements.back()) {
1407 if (*
m != measurements.back()) {
1413 <<
" (**m).intersection(FittedTrajectory).position() "
1414 "measurement position r "
1422 " im " <<
im <<
" distance measurement "
1423 << startDirection.dot(
1427 " (**m).intersection(FittedTrajectory).position() measurement position "
1432 m = measurements.insert(
1435 (**s).trackParameters()->position()));
1437 (**s).trackParameters()->position(),
1438 (**s).trackParameters()->momentum().unit(), 0.);
1440 (**m).qOverP((**s).trackParameters()->parameters()[
Trk::qOverP]);
1446 m = measurements.begin();
1448 for (;
m != measurements.end(); ++
m) {
1449 if (!leadingDelimiter && (**m).
isOutlier())
1464 std::pair<FitMeasurement*, FitMeasurement*>
1466 const std::vector<const TrackStateOnSurface*>& material,
1467 std::vector<FitMeasurement*>& ,
1470 ATH_MSG_INFO(
"segment material aggregation " << material.size());
1473 if (material.empty())
1474 return std::pair<FitMeasurement*, FitMeasurement*>(measurement1,
1478 int adjacentScatterers = 0;
1479 std::vector<FitMeasurement*> aggregateScatterers;
1480 bool hasReferencePosition =
false;
1482 bool haveAggregation =
false;
1485 for (std::vector<const TrackStateOnSurface*>::const_reverse_iterator tsos =
1487 tsos != material.rend(); ++tsos) {
1488 if (!(**tsos).trackParameters() || !(**tsos).materialEffectsOnTrack()){
1491 ++adjacentScatterers;
1492 if (!hasReferencePosition) {
1493 referencePosition =
Amg::Vector3D((**tsos).trackParameters()->position());
1494 hasReferencePosition =
true;
1497 ((**tsos).trackParameters()->position() - referencePosition).
mag();
1498 double weight = (**tsos).materialEffectsOnTrack()->thicknessInX0();
1500 ATH_MSG_INFO(
" material position " << (**tsos).trackParameters()->position()
1502 <<
" thickness " << 100. *
weight);
1506 if (adjacentScatterers < 3) {
1510 if (haveAggregation) {
1513 return std::pair<FitMeasurement*, FitMeasurement*>(measurement1,
1518 std::vector<FitMeasurement*>& measurements,
double particleMass)
const {
1535 int adjacentScatterers = 0;
1536 std::vector<FitMeasurement*> aggregateScatterers;
1537 bool haveAggregation =
false;
1538 bool makeAggregation =
false;
1539 double maxDistance = 0.;
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);
1554 if (!adjacentScatterers)
1556 makeAggregation =
true;
1561 else if (adjacentScatterers) {
1562 if ((**m).isScatterer()) {
1566 std::abs(referenceDirection.dot(position - referencePosition));
1568 ++adjacentScatterers;
1569 double weight = (**m).radiationThickness();
1572 totalEnergyDeposit += (**m).energyLoss();
1573 totalThickness +=
weight;
1574 if (*
m == measurements.front())
1575 makeAggregation =
true;
1581 }
else if (adjacentScatterers > 1) {
1582 makeAggregation =
true;
1584 adjacentScatterers = 0;
1586 }
else if (!(**m).isMaterialDelimiter()) {
1589 }
else if (adjacentScatterers > 1) {
1590 makeAggregation =
true;
1592 adjacentScatterers = 0;
1596 if (makeAggregation) {
1616 double meanDistance = totalDistance / totalThickness;
1617 double rmsDistance = 0.;
1619 totalDistanceSq / totalThickness - meanDistance * meanDistance;
1620 if (meanSquare > 0.)
1621 rmsDistance = std::sqrt(meanSquare);
1622 double gap = 2. * rmsDistance;
1624 double distance1 = meanDistance - rmsDistance;
1625 double distance2 = meanDistance + rmsDistance;
1631 std::abs(referenceDirection.dot(position - referencePosition));
1648 double previousDistance = 0.;
1649 haveAggregation =
true;
1651 for (std::vector<Trk::FitMeasurement*>::reverse_iterator
s =
start;
1652 s != measurements.rend(); ++
s) {
1653 if (!(**s).isScatterer())
1658 std::abs(referenceDirection.dot(position - referencePosition));
1659 if (!measurement1 &&
distance > distance1 &&
1662 double separation =
distance - previousDistance;
1663 double fractionAfter =
1664 (distance1 - previousDistance) / separation;
1665 double fractionBefore = (
distance - distance1) / separation;
1675 position = fractionBefore *
1685 fractionAfter * after->
qOverP();
1687 0.5 * totalThickness, -0.5 * totalEnergyDeposit, particleMass,
1688 position, direction,
qOverP);
1693 double separation =
distance - previousDistance;
1694 double fractionAfter =
1695 (
distance2 - previousDistance) / separation;
1706 position = fractionBefore *
1716 fractionAfter * after->
qOverP();
1719 0.5 * totalThickness, -0.5 * totalEnergyDeposit,
1720 particleMass, position, direction,
qOverP);
1723 totalThickness, -totalEnergyDeposit, particleMass, position,
1726 bool keepCurrentMeas =
false;
1727 if ((**m).isScatterer() && *
m != measurements.front()) {
1728 keepCurrentMeas =
true;
1729 aggregateScatterers.pop_back();
1731 while (adjacentScatterers--) {
1732 aggregateScatterers.back()->setOutlier();
1733 aggregateScatterers.pop_back();
1736 aggregateScatterers.push_back(measurement1);
1738 aggregateScatterers.push_back(measurement2);
1739 if (keepCurrentMeas)
1740 aggregateScatterers.push_back(*
m);
1741 measurement1 =
nullptr;
1742 measurement2 =
nullptr;
1750 adjacentScatterers = 0;
1751 makeAggregation =
false;
1755 if ((**m).isScatterer() && !adjacentScatterers &&
1757 adjacentScatterers = 1;
1758 double weight = (**m).radiationThickness();
1761 referenceDirection =
1765 std::abs(referenceDirection.dot(position - referencePosition));
1770 totalEnergyDeposit = (**m).energyLoss();
1782 delete measurement1;
1787 if (haveAggregation) {
1790 referenceDirection =
1791 (referencePosition -
1794 std::vector<Trk::FitMeasurement*>::reverse_iterator
s =
1795 aggregateScatterers.rbegin();
1798 double scattererDistance =
1799 std::abs(referenceDirection.dot(scattererPosition - referencePosition));
1801 m != measurements.end(); ) {
1805 std::abs(referenceDirection.dot(position - referencePosition));
1806 while (
distance <= scattererDistance &&
s != aggregateScatterers.rend()) {
1807 m = measurements.insert(
m, *
s);
1809 if (++
s != aggregateScatterers.rend()) {
1811 scattererDistance = std::abs(
1812 referenceDirection.dot(scattererPosition - referencePosition));
1815 if ((**m).isScatterer()) {
1817 if ((**m).isOutlier())
1820 m = measurements.erase(
m);
1836 for (
auto* measurement : measurements) {
1839 double distance = std::abs(startDirection.dot(position - startPosition));
1840 msg(
MSG::VERBOSE) << std::setiosflags(std::ios::fixed) << std::setw(5)
1841 << ++
n << std::setw(10) << std::setprecision(3)
1842 <<
distance <<
" " << (*measurement).type();
1843 if ((*measurement).isOutlier()) {
1844 msg() <<
" outlier ";
1845 }
else if ((*measurement).materialEffects()) {
1846 msg() << std::setw(8) << std::setprecision(3)
1847 << (*measurement).materialEffects()->thicknessInX0() <<
" ";
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();
1863 bool energyGain =
false;
1864 for (
auto& measurement : measurements) {
1865 if ((*measurement).materialEffects() && (*measurement).numberDoF() &&
1866 (*measurement).energyLoss() < 0.)
1871 for (
auto& measurement : measurements) {
1872 if ((*measurement).materialEffects())
1873 (*measurement).setEnergyGain();
1879 const TrackStateOnSurface& tsos,
double outgoingEnergy,
1880 double particleMass) {
1881 if (!tsos.trackParameters() || !tsos.materialEffectsOnTrack())
1884 double deltaE = outgoingEnergy - tsos.trackParameters()->momentum().mag();
1885 double thicknessInX0 = tsos.materialEffectsOnTrack()->thicknessInX0();
1887 Amg::Vector3D direction = tsos.trackParameters()->momentum().unit();
1888 double qOverP = 1. / outgoingEnergy;
1889 if (tsos.trackParameters()->charge() < 0)
1892 return new FitMeasurement(thicknessInX0, deltaE, particleMass, position,
1897 std::vector<FitMeasurement*>& measurements)
const {
1899 "measurements and material: distance X0 deltaE E "
1901 <<
" R phi Z DoF phi theta");
1903 if (measurements.empty())
1907 while (
m != measurements.end() && !(**m).isPositionMeasurement())
1909 if (
m == measurements.end())
1910 m = measurements.begin();
1915 int leadingMaterial = 0;
1916 double leadingX0 = 0.;
1918 double leadingELoss = 0.;
1919 double sumELoss = 0.;
1921 for (
auto& measurement : measurements) {
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()) {
1934 (*measurement).materialEffects());
1935 if (materialEffects && materialEffects->
energyLoss())
1937 if ((*measurement).isEnergyDeposit())
1939 msg() << std::setw(10) << std::setprecision(3)
1940 << (*measurement).materialEffects()->thicknessInX0() << std::setw(9)
1941 << std::setprecision(1) << deltaE <<
" ";
1944 sumX0 += (*measurement).materialEffects()->thicknessInX0();
1948 leadingX0 += (*measurement).materialEffects()->thicknessInX0();
1949 leadingELoss -= deltaE;
1952 if ((*measurement).qOverP()) {
1953 msg() << std::setw(11) << std::setprecision(4)
1955 << std::setw(10) << std::setprecision(3)
1964 msg() << std::setw(54);
1966 if ((*measurement).isMaterialDelimiter()) {
1967 msg() << std::setprecision(1)
1969 << std::setw(9) << std::setprecision(4)
1971 << std::setw(10) << std::setprecision(1)
1973 << std::setw(14) << std::setprecision(4)
1975 << std::setw(9) << std::setprecision(4)
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;
1989 scatterers = leadingMaterial;
1990 leadingMaterial = 0;
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)
2007 std::vector<FitMeasurement*>& measurements,
2010 const EventContext& ctx = Gaudi::Hive::currentContext();
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.;
2032 for (;
m != measurements.end(); ++
m) {
2036 if ((**m).measurementBase())
2037 positionMst = (**m).measurementBase()->globalPosition();
2038 double distance = startDirection.dot(position - startPosition);
2039 double distanceR = std::hypot(positionMst.x() - startPosition.x(),
2040 positionMst.y() - startPosition.y());
2041 double distanceZ = (positionMst.z() - startPosition.z());
2042 if (startDirection.z() < 0)
2043 distanceZ = -distanceZ;
2048 if (
distance - previousDistance < minDistanceMS) {
2049 minDistanceMS =
distance - previousDistance;
2050 minRDistanceMS = distanceR - previousDistanceR;
2051 minZDistanceMS = distanceZ - previousDistanceZ;
2054 if ((**m).isScatterer())
2055 haveMaterial =
true;
2056 if ((**m).measurementBase() && !firstMSHit) {
2059 if ((**m).isScatterer() && !firstMSHit)
2060 haveLeadingMaterial =
true;
2064 if (
distance - previousDistance < minDistanceID)
2065 minDistanceID =
distance - previousDistance;
2069 previousDistanceZ = distanceZ;
2070 previousDistanceR = distanceR;
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 "
2091 if (reorderMS || reorderID) {
2096 if (!haveLeadingMaterial && haveMaterial) {
2098 " MS part of track has no leading material in front of first MS hit ");
2109 " spectrometerMaterial: ALARM no material found on track can happen for "
2115 for (
m = measurements.begin();
m != measurements.end(); ++
m) {
2116 if (!(**m).isPositionMeasurement() || (**m).isOutlier())
2121 if (innerMeasurement) {
2122 outerMeasurement = *
m;
2124 innerMeasurement = *
m;
2127 if (!outerMeasurement)
2134 if (!spectrometerEntrance)
2139 std::unique_ptr<const TrackParameters> entranceParameters;
2142 std::unique_ptr<const TrackParameters> innerParameters(
2143 fitParameters.trackParameters(
log, *innerMeasurement,
false));
2144 if (!innerParameters)
2145 innerParameters.reset(startParameters.
clone());
2147 ctx, *innerParameters, *spectrometerEntrance,
anyDirection,
2149 if (entranceParameters) {
2150 startDirection = entranceParameters->momentum().unit();
2151 startPosition = entranceParameters->position();
2153 entranceParameters->position(), entranceParameters->momentum().unit(),
2158 for (
m = measurements.begin();
m != measurements.end(); ++
m) {
2166 e = measurements.insert(++
e, entranceDelimiter);
2167 delete entranceIntersection;
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(
2185 if (!endParameters) {
2190 if (!endParameters) {
2193 endParameters = std::move(outerParameters);
2198 endParameters->position(), endParameters->momentum().unit(), 0.);
2201 measurements.push_back(endBreak);
2203 double endSpectrometerDistance = startDirection.dot(
2210 Amg::VectorX parameterVector = endParameters->parameters();
2211 double Emax = 50000.;
2222 endParameters->associatedSurface().createUniqueTrackParameters(
2227 if (entranceParameters) {
2228 const Surface& entranceSurface = entranceParameters->associatedSurface();
2243 <<
"using extrapolateM inwards from outermost measurement");
2248 if (!(*ss).trackParameters() || !(*ss).materialEffectsOnTrack())
2250 double distance = startDirection.dot((*ss).trackParameters()->position() -
2253 double thickness = (*ss).materialEffectsOnTrack()->thicknessInX0();
2256 (*ss).materialEffectsOnTrack());
2257 if (materialEffects && materialEffects->
energyLoss())
2259 double p2 = (*ss).trackParameters()->momentum().mag();
2261 std::setiosflags(std::ios::fixed)
2262 <<
" material: RZ" << std::setw(9) << std::setprecision(3)
2263 << (*ss).trackParameters()->position().perp() << std::setw(10)
2264 << std::setprecision(3) << (*ss).trackParameters()->position().z()
2265 <<
" distance " << std::setw(10) << std::setprecision(3) <<
distance
2266 <<
" pt " << std::setw(8) << std::setprecision(3)
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)
2284 std::vector<const TrackStateOnSurface*>::const_reverse_iterator
s =
2286 std::vector<FitMeasurement*> material;
2295 double outgoingEnergy = 0.;
2297 outgoingEnergy = (**s).trackParameters()->momentum().mag();
2299 outgoingEnergy = endParameters->momentum().mag();
2308 material.push_back(measurement);
2311 if (
distance > endSpectrometerDistance) {
2315 while (
m != measurements.end() &&
2321 if (
m == measurements.end()) {
2326 m = measurements.insert(
m, material.back());