Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-11 07:49:52

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #pragma once
0010 
0011 #include "Acts/Propagator/MultiEigenStepperLoop.hpp"
0012 
0013 #include "Acts/Propagator/MultiStepperError.hpp"
0014 #include "Acts/Utilities/Logger.hpp"
0015 
0016 namespace Acts {
0017 
0018 template <typename E, typename R>
0019 auto MultiEigenStepperLoop<E, R>::boundState(
0020     State& state, const Surface& surface, bool transportCov,
0021     const FreeToBoundCorrection& freeToBoundCorrection) const
0022     -> Result<BoundState> {
0023   assert(!state.components.empty());
0024 
0025   std::vector<std::tuple<double, BoundVector, Covariance>> cmps;
0026   cmps.reserve(numberComponents(state));
0027   double accumulatedPathLength = 0.0;
0028 
0029   for (auto i = 0ul; i < numberComponents(state); ++i) {
0030     auto& cmpState = state.components[i].state;
0031 
0032     // Force the component to be on the surface
0033     // This needs to be done because of the `averageOnSurface`-option of the
0034     // `MultiStepperSurfaceReached`-Aborter, which can be configured to end the
0035     // propagation when the mean of all components reached the destination
0036     // surface. Thus, it is not garantueed that all states are actually
0037     // onSurface.
0038     cmpState.pars.template segment<3>(eFreePos0) =
0039         surface
0040             .intersect(state.options.geoContext,
0041                        cmpState.pars.template segment<3>(eFreePos0),
0042                        cmpState.pars.template segment<3>(eFreeDir0),
0043                        BoundaryTolerance::Infinite())
0044             .closest()
0045             .position();
0046 
0047     auto bs = SingleStepper::boundState(cmpState, surface, transportCov,
0048                                         freeToBoundCorrection);
0049 
0050     if (bs.ok()) {
0051       const auto& btp = std::get<BoundTrackParameters>(*bs);
0052       cmps.emplace_back(
0053           state.components[i].weight, btp.parameters(),
0054           btp.covariance().value_or(Acts::BoundSquareMatrix::Zero()));
0055       accumulatedPathLength +=
0056           std::get<double>(*bs) * state.components[i].weight;
0057     }
0058   }
0059 
0060   if (cmps.empty()) {
0061     return MultiStepperError::AllComponentsConversionToBoundFailed;
0062   }
0063 
0064   return BoundState{MultiComponentBoundTrackParameters(
0065                         surface.getSharedPtr(), cmps, state.particleHypothesis),
0066                     Jacobian::Zero(), accumulatedPathLength};
0067 }
0068 
0069 template <typename E, typename R>
0070 auto MultiEigenStepperLoop<E, R>::curvilinearState(
0071     State& state, bool transportCov) const -> BoundState {
0072   assert(!state.components.empty());
0073 
0074   std::vector<std::tuple<double, Vector4, Vector3, double, BoundSquareMatrix>>
0075       cmps;
0076   cmps.reserve(numberComponents(state));
0077   double accumulatedPathLength = 0.0;
0078 
0079   for (auto i = 0ul; i < numberComponents(state); ++i) {
0080     const auto [cp, jac, pl] = SingleStepper::curvilinearState(
0081         state.components[i].state, transportCov);
0082 
0083     cmps.emplace_back(state.components[i].weight,
0084                       cp.fourPosition(state.options.geoContext), cp.direction(),
0085                       cp.qOverP(),
0086                       cp.covariance().value_or(BoundSquareMatrix::Zero()));
0087     accumulatedPathLength += state.components[i].weight * pl;
0088   }
0089 
0090   return BoundState{
0091       MultiComponentBoundTrackParameters::createCurvilinear(
0092           state.options.geoContext, cmps, state.particleHypothesis),
0093       Jacobian::Zero(), accumulatedPathLength};
0094 }
0095 
0096 template <typename E, typename R>
0097 Result<double> MultiEigenStepperLoop<E, R>::step(
0098     State& state, Direction propDir, const IVolumeMaterial* material) const {
0099   using Status = Acts::IntersectionStatus;
0100 
0101   auto& components = state.components;
0102   const Logger& logger = *m_logger;
0103 
0104   // Update step count
0105   state.steps++;
0106 
0107   // Check if we abort because of m_stepLimitAfterFirstComponentOnSurface
0108   if (state.stepCounterAfterFirstComponentOnSurface) {
0109     (*state.stepCounterAfterFirstComponentOnSurface)++;
0110 
0111     // If the limit is reached, remove all components which are not on a
0112     // surface, reweight the components, perform no step and return 0
0113     if (*state.stepCounterAfterFirstComponentOnSurface >=
0114         m_stepLimitAfterFirstComponentOnSurface) {
0115       for (auto& cmp : components) {
0116         if (cmp.status != Status::onSurface) {
0117           cmp.status = Status::unreachable;
0118         }
0119       }
0120 
0121       ACTS_VERBOSE("Stepper performed "
0122                    << m_stepLimitAfterFirstComponentOnSurface
0123                    << " steps after the first component hit a surface.");
0124       ACTS_VERBOSE(
0125           "-> remove all components not on a surface, perform no step");
0126 
0127       removeMissedComponents(state);
0128       reweightComponents(state);
0129 
0130       ACTS_VERBOSE(components.size()
0131                    << " components left after removing missed components");
0132 
0133       state.stepCounterAfterFirstComponentOnSurface.reset();
0134 
0135       return 0.0;
0136     }
0137   }
0138 
0139   // Flag indicating if we need to reweight in the end
0140   bool reweightNecessary = false;
0141 
0142   // If at least one component is on a surface, we can remove all missed
0143   // components before the step. If not, we must keep them for the case that all
0144   // components miss and we need to retarget
0145   const auto cmpsOnSurface = std::count_if(
0146       components.cbegin(), components.cend(),
0147       [&](auto& cmp) { return cmp.status == IntersectionStatus::onSurface; });
0148 
0149   if (cmpsOnSurface > 0) {
0150     removeMissedComponents(state);
0151     reweightNecessary = true;
0152   }
0153 
0154   // Loop over all components and collect results in vector, write some
0155   // summary information to a stringstream
0156   SmallVector<std::optional<Result<double>>> results;
0157   double accumulatedPathLength = 0.0;
0158   std::size_t errorSteps = 0;
0159 
0160   // Lambda that performs the step for a component and returns false if the step
0161   // went ok and true if there was an error
0162   auto errorInStep = [this, &results, propDir, material, &accumulatedPathLength,
0163                       &errorSteps, &reweightNecessary](auto& component) {
0164     if (component.status == Status::onSurface) {
0165       // We need to add these, so the propagation does not fail if we have only
0166       // components on surfaces and failing states
0167       results.emplace_back(std::nullopt);
0168       return false;
0169     }
0170 
0171     results.emplace_back(
0172         SingleStepper::step(component.state, propDir, material));
0173 
0174     if (results.back()->ok()) {
0175       accumulatedPathLength += component.weight * results.back()->value();
0176       return false;
0177     } else {
0178       ++errorSteps;
0179       reweightNecessary = true;
0180       return true;
0181     }
0182   };
0183 
0184   // Loop over components and remove errorous components
0185   components.erase(
0186       std::remove_if(components.begin(), components.end(), errorInStep),
0187       components.end());
0188 
0189   // Reweight if necessary
0190   if (reweightNecessary) {
0191     reweightComponents(state);
0192   }
0193 
0194   // Print the result vector to a string so we can log it
0195   auto summary = [](auto& result_vec) {
0196     std::stringstream ss;
0197     for (auto& optRes : result_vec) {
0198       if (!optRes) {
0199         ss << "on surface | ";
0200       } else if (optRes->ok()) {
0201         ss << optRes->value() << " | ";
0202       } else {
0203         ss << optRes->error() << " | ";
0204       }
0205     }
0206     auto str = ss.str();
0207     str.resize(str.size() - 3);
0208     return str;
0209   };
0210 
0211   // Print the summary
0212   if (errorSteps == 0) {
0213     ACTS_VERBOSE("Performed steps: " << summary(results));
0214   } else {
0215     ACTS_WARNING("Performed steps with errors: " << summary(results));
0216   }
0217 
0218   // Return error if there is no ok result
0219   if (components.empty()) {
0220     return MultiStepperError::AllComponentsSteppingError;
0221   }
0222 
0223   // Invalidate the component status after each step
0224   for (auto& cmp : components) {
0225     cmp.status = Status::unreachable;
0226   }
0227 
0228   // Return the weighted accumulated path length of all successful steps
0229   state.pathAccumulated += accumulatedPathLength;
0230   return accumulatedPathLength;
0231 }
0232 
0233 }  // namespace Acts