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> 
const 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> 
const 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       const double scatteringAngle =
 
  470           std::sqrt(leadingScattering - previousScattering);
 
  471       previousScattering = leadingScattering;
 
  472       (**m).scatteringAngle(scatteringAngle, leadingX0Integral);
 
  475       double angleSquared = 1. / (**m).weight();
 
  479       const 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       const 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> 
const 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   const 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*> 
const 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> 
const newIntersectionSTEP =
 
 1126           newParameters = std::make_unique<AtaPlane>(
 
 1136       const 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       const 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       const double p2 = (**s).trackParameters()->momentum().mag();
 
 1225           std::setiosflags(std::ios::fixed)
 
 1226           << 
"         material: RZ" << std::setw(9) << std::setprecision(3)
 
 1227           << (**s).trackParameters()->position().perp() << std::setw(10)
 
 1228           << std::setprecision(3) << (**s).trackParameters()->position().z()
 
 1229           << 
"   distance " << std::setw(10) << std::setprecision(3) << 
distance 
 1230           << 
"   pt " << std::setw(8) << std::setprecision(3)
 
 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       const double distance = direction.dot(nextPosition - position);
 
 1280         const 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 const 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     const 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           const 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       const double meanDistance = totalDistance / totalThickness;
 
 1617       double rmsDistance = 0.;
 
 1618       const double meanSquare =
 
 1619           totalDistanceSq / totalThickness - meanDistance * meanDistance;
 
 1620       if (meanSquare > 0.)
 
 1621         rmsDistance = std::sqrt(meanSquare);
 
 1622       const double gap = 2. * rmsDistance;
 
 1624         const 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               const double separation = 
distance - previousDistance;
 
 1663               const double fractionAfter =
 
 1664                   (distance1 - previousDistance) / separation;
 
 1665               const double fractionBefore = (
distance - distance1) / separation;
 
 1675               position = fractionBefore *
 
 1684               const double qOverP = fractionBefore * before->
qOverP() +
 
 1685                               fractionAfter * after->
qOverP();
 
 1687                   0.5 * totalThickness, -0.5 * totalEnergyDeposit, particleMass,
 
 1688                   position, direction, 
qOverP);
 
 1693               const double separation = 
distance - previousDistance;
 
 1694               const double fractionAfter =
 
 1695                   (
distance2 - previousDistance) / separation;
 
 1706               position = fractionBefore *
 
 1715               const double qOverP = fractionBefore * before->
qOverP() +
 
 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       const 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       const double distance = std::abs(startDirection.dot(position - startPosition));
 
 1840       msg(
MSG::VERBOSE) << std::setiosflags(std::ios::fixed) << std::setw(5)
 
 1841                         << ++
n << std::setw(10) << std::setprecision(3)
 
 1842                         << 
distance << 
"  " << (*measurement).type();
 
 1843       if ((*measurement).isOutlier()) {
 
 1844         msg() << 
"  outlier ";
 
 1845       } 
else if ((*measurement).materialEffects()) {
 
 1846         msg() << std::setw(8) << std::setprecision(3)
 
 1847               << (*measurement).materialEffects()->thicknessInX0() << 
"  ";
 
 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   const double deltaE = outgoingEnergy - tsos.trackParameters()->momentum().mag();
 
 1885   const double thicknessInX0 = tsos.materialEffectsOnTrack()->thicknessInX0();
 
 1887   const 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) {
 
 2034     const Amg::Vector3D positionSurf = (**m).surface()->center();
 
 2036     if ((**m).measurementBase())
 
 2037       positionMst = (**m).measurementBase()->globalPosition();
 
 2038     const double distance = startDirection.dot(position - startPosition);
 
 2039     const double distanceR = std::hypot(positionMst.x() - startPosition.x(),
 
 2040                                   positionMst.y() - startPosition.y());
 
 2041     double distanceZ = (positionMst.z() - startPosition.z());
 
 2042     if (startDirection.z() < 0)
 
 2043       distanceZ = -distanceZ;
 
 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   const double endSpectrometerDistance = startDirection.dot(
 
 2210   Amg::VectorX parameterVector = endParameters->parameters();
 
 2211   const 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       const double distance = startDirection.dot((*ss).trackParameters()->position() -
 
 2253       const double thickness = (*ss).materialEffectsOnTrack()->thicknessInX0();
 
 2256               (*ss).materialEffectsOnTrack());
 
 2257       if (materialEffects && materialEffects->
energyLoss())
 
 2259       const double p2 = (*ss).trackParameters()->momentum().mag();
 
 2261           std::setiosflags(std::ios::fixed)
 
 2262           << 
"         material: RZ" << std::setw(9) << std::setprecision(3)
 
 2263           << (*ss).trackParameters()->position().perp() << std::setw(10)
 
 2264           << std::setprecision(3) << (*ss).trackParameters()->position().z()
 
 2265           << 
"   distance " << std::setw(10) << std::setprecision(3) << 
distance 
 2266           << 
"   pt " << std::setw(8) << std::setprecision(3)
 
 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());