Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MultiEigenStepperLoop.ipp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file MultiEigenStepperLoop.ipp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2021 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
10 
11 namespace Acts {
12 
13 template <typename E, typename R, typename A>
15  State& state, const Surface& surface, bool transportCov,
16  const FreeToBoundCorrection& freeToBoundCorrection) const
18  assert(!state.components.empty());
19 
20  std::vector<std::tuple<double, BoundVector, Covariance>> cmps;
21  cmps.reserve(numberComponents(state));
22  double accumulatedPathLength = 0.0;
23 
24  for (auto i = 0ul; i < numberComponents(state); ++i) {
25  auto& cmpState = state.components[i].state;
26 
27  // Force the component to be on the surface
28  // This needs to be done because of the `averageOnSurface`-option of the
29  // `MultiStepperSurfaceReached`-Aborter, which can be configured to end the
30  // propagation when the mean of all components reached the destination
31  // surface. Thus, it is not garantueed that all states are actually
32  // onSurface.
33  cmpState.pars.template segment<3>(eFreePos0) =
34  surface
35  .intersect(state.geoContext,
36  cmpState.pars.template segment<3>(eFreePos0),
37  cmpState.pars.template segment<3>(eFreeDir0), false)
38  .closest()
39  .position();
40 
41  auto bs = SingleStepper::boundState(cmpState, surface, transportCov,
42  freeToBoundCorrection);
43 
44  if (bs.ok()) {
45  const auto& btp = std::get<BoundTrackParameters>(*bs);
46  cmps.emplace_back(
47  state.components[i].weight, btp.parameters(),
48  btp.covariance().value_or(Acts::BoundSquareMatrix::Zero()));
49  accumulatedPathLength +=
50  std::get<double>(*bs) * state.components[i].weight;
51  }
52  }
53 
54  if (cmps.empty()) {
55  return MultiStepperError::AllComponentsConversionToBoundFailed;
56  }
57 
59  surface.getSharedPtr(), cmps, state.particleHypothesis),
60  Jacobian::Zero(), accumulatedPathLength};
61 }
62 
63 template <typename E, typename R, typename A>
65  bool transportCov) const
66  -> CurvilinearState {
67  assert(!state.components.empty());
68 
69  std::vector<
70  std::tuple<double, Vector4, Vector3, ActsScalar, BoundSquareMatrix>>
71  cmps;
72  cmps.reserve(numberComponents(state));
73  double accumulatedPathLength = 0.0;
74 
75  for (auto i = 0ul; i < numberComponents(state); ++i) {
76  const auto [cp, jac, pl] = SingleStepper::curvilinearState(
77  state.components[i].state, transportCov);
78 
79  cmps.emplace_back(state.components[i].weight,
80  cp.fourPosition(state.geoContext), cp.direction(),
81  (cp.charge() / cp.absoluteMomentum()),
82  cp.covariance().value_or(BoundSquareMatrix::Zero()));
83  accumulatedPathLength += state.components[i].weight * pl;
84  }
85 
86  return CurvilinearState{
87  MultiComponentCurvilinearTrackParameters(cmps, state.particleHypothesis),
88  Jacobian::Zero(), accumulatedPathLength};
89 }
90 
91 template <typename E, typename R, typename A>
92 template <typename propagator_state_t, typename navigator_t>
94  propagator_state_t& state, const navigator_t& navigator) const {
95  using Status = Acts::Intersection3D::Status;
96 
97  State& stepping = state.stepping;
98  auto& components = stepping.components;
99  const Logger& logger = *m_logger;
100 
101  // Update step count
102  stepping.steps++;
103 
104  // Check if we abort because of m_stepLimitAfterFirstComponentOnSurface
105  if (stepping.stepCounterAfterFirstComponentOnSurface) {
106  (*stepping.stepCounterAfterFirstComponentOnSurface)++;
107 
108  // If the limit is reached, remove all components which are not on a
109  // surface, reweight the components, perform no step and return 0
110  if (*stepping.stepCounterAfterFirstComponentOnSurface >=
111  m_stepLimitAfterFirstComponentOnSurface) {
112  for (auto& cmp : components) {
113  if (cmp.status != Status::onSurface) {
114  cmp.status = Status::missed;
115  }
116  }
117 
118  removeMissedComponents(stepping);
119  reweightComponents(stepping);
120 
121  ACTS_VERBOSE("Stepper performed "
122  << m_stepLimitAfterFirstComponentOnSurface
123  << " after the first component hit a surface.");
124  ACTS_VERBOSE(
125  "-> remove all components not on a surface, perform no step");
126 
127  stepping.stepCounterAfterFirstComponentOnSurface.reset();
128 
129  return 0.0;
130  }
131  }
132 
133  // Flag indicating if we need to reweight in the end
134  bool reweightNecessary = false;
135 
136  // If at least one component is on a surface, we can remove all missed
137  // components before the step. If not, we must keep them for the case that all
138  // components miss and we need to retarget
139  const auto cmpsOnSurface =
140  std::count_if(components.cbegin(), components.cend(), [&](auto& cmp) {
141  return cmp.status == Intersection3D::Status::onSurface;
142  });
143 
144  if (cmpsOnSurface > 0) {
145  removeMissedComponents(stepping);
146  reweightNecessary = true;
147  }
148 
149  // Loop over all components and collect results in vector, write some
150  // summary information to a stringstream
152  double accumulatedPathLength = 0.0;
153  std::size_t errorSteps = 0;
154 
155  // Type of the proxy single propagation2 state
156  using ThisSinglePropState =
157  SinglePropState<SingleState, decltype(state.navigation),
158  decltype(state.options), decltype(state.geoContext)>;
159 
160  // Lambda that performs the step for a component and returns false if the step
161  // went ok and true if there was an error
162  auto errorInStep = [&](auto& component) {
163  if (component.status == Status::onSurface) {
164  // We need to add these, so the propagation does not fail if we have only
165  // components on surfaces and failing states
166  results.emplace_back(std::nullopt);
167  return false;
168  }
169 
170  ThisSinglePropState single_state(component.state, state.navigation,
171  state.options, state.geoContext);
172 
173  results.emplace_back(SingleStepper::step(single_state, navigator));
174 
175  if (results.back()->ok()) {
176  accumulatedPathLength += component.weight * results.back()->value();
177  return false;
178  } else {
179  ++errorSteps;
180  reweightNecessary = true;
181  return true;
182  }
183  };
184 
185  // Loop over components and remove errorous components
186  stepping.components.erase(
187  std::remove_if(components.begin(), components.end(), errorInStep),
188  components.end());
189 
190  // Reweight if necessary
191  if (reweightNecessary) {
192  reweightComponents(stepping);
193  }
194 
195  // Print the result vector to a string so we can log it
196  auto summary = [](auto& result_vec) {
197  std::stringstream ss;
198  for (auto& optRes : result_vec) {
199  if (not optRes) {
200  ss << "on surface | ";
201  } else if (optRes->ok()) {
202  ss << optRes->value() << " | ";
203  } else {
204  ss << optRes->error() << " | ";
205  }
206  }
207  auto str = ss.str();
208  str.resize(str.size() - 3);
209  return str;
210  };
211 
212  // Print the summary
213  if (errorSteps == 0) {
214  ACTS_VERBOSE("Performed steps: " << summary(results));
215  } else {
216  ACTS_WARNING("Performed steps with errors: " << summary(results));
217  }
218 
219  // Return error if there is no ok result
220  if (stepping.components.empty()) {
221  return MultiStepperError::AllComponentsSteppingError;
222  }
223 
224  // Return the weighted accumulated path length of all successful steps
225  stepping.pathAccumulated += accumulatedPathLength;
226  return accumulatedPathLength;
227 }
228 
229 } // namespace Acts