ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DenseEnvironmentExtension.hpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file DenseEnvironmentExtension.hpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2018-2019 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 
9 #pragma once
10 
11 #include <functional>
12 
18 
19 namespace Acts {
20 
28  double currentMomentum = 0.;
30  double initialMomentum = 0.;
35  std::array<double, 4> dLdl;
37  std::array<double, 4> qop;
39  std::array<double, 4> dPds;
41  double dgdqopValue = 0.;
43  double g = 0.;
45  std::array<double, 4> tKi;
47  std::array<double, 4> Lambdappi;
49  std::array<double, 4> energy;
50 
52  DenseEnvironmentExtension() = default;
53 
60  template <typename propagator_state_t, typename stepper_t>
61  int bid(const propagator_state_t& state, const stepper_t& stepper) const {
62  // Check for valid particle properties
63  if (stepper.charge(state.stepping) == 0. || state.options.mass == 0. ||
64  stepper.momentum(state.stepping) < state.options.momentumCutOff) {
65  return 0;
66  }
67 
68  // Check existence of a volume with material
69  if (!state.navigation.currentVolume ||
70  !state.navigation.currentVolume->volumeMaterial()) {
71  return 0;
72  }
73  return 2;
74  }
75 
89  template <typename propagator_state_t, typename stepper_t>
90  bool k(const propagator_state_t& state, const stepper_t& stepper,
91  Vector3D& knew, const Vector3D& bField, std::array<double, 4>& kQoP,
92  const int i = 0, const double h = 0.,
93  const Vector3D& kprev = Vector3D()) {
94  // i = 0 is used for setup and evaluation of k
95  if (i == 0) {
96  // Set up container for energy loss
97  auto volumeMaterial = state.navigation.currentVolume->volumeMaterial();
98  Vector3D position = stepper.position(state.stepping);
99  material = (volumeMaterial->material(position));
100  initialMomentum = stepper.momentum(state.stepping);
102  qop[0] = stepper.charge(state.stepping) / initialMomentum;
103  initializeEnergyLoss(state);
104  // Evaluate k
105  knew = qop[0] * stepper.direction(state.stepping).cross(bField);
106  // Evaluate k for the time propagation
107  Lambdappi[0] =
108  -qop[0] * qop[0] * qop[0] * g * energy[0] /
109  (stepper.charge(state.stepping) * stepper.charge(state.stepping));
110  //~ tKi[0] = std::hypot(1, state.options.mass / initialMomentum);
111  tKi[0] = std::hypot(1, state.options.mass * qop[0]);
112  kQoP[0] = Lambdappi[0];
113  } else {
114  // Update parameters and check for momentum condition
115  updateEnergyLoss(state.options.mass, h, state.stepping, stepper, i);
116  if (currentMomentum < state.options.momentumCutOff) {
117  return false;
118  }
119  // Evaluate k
120  knew = qop[i] *
121  (stepper.direction(state.stepping) + h * kprev).cross(bField);
122  // Evaluate k_i for the time propagation
123  double qopNew = qop[0] + h * Lambdappi[i - 1];
124  Lambdappi[i] =
125  -qopNew * qopNew * qopNew * g * energy[i] /
126  (stepper.charge(state.stepping) * stepper.charge(state.stepping) *
128  tKi[i] = std::hypot(1, state.options.mass * qopNew);
129  kQoP[i] = Lambdappi[i];
130  }
131  return true;
132  }
133 
144  template <typename propagator_state_t, typename stepper_t>
145  bool finalize(propagator_state_t& state, const stepper_t& stepper,
146  const double h) const {
147  // Evaluate the new momentum
148  double newMomentum =
149  stepper.momentum(state.stepping) +
150  (h / 6.) * (dPds[0] + 2. * (dPds[1] + dPds[2]) + dPds[3]);
151 
152  // Break propagation if momentum becomes below cut-off
153  if (newMomentum < state.options.momentumCutOff) {
154  return false;
155  }
156 
157  // Add derivative dlambda/ds = Lambda''
158  state.stepping.derivative(7) =
159  -std::sqrt(state.options.mass * state.options.mass +
160  newMomentum * newMomentum) *
161  g / (newMomentum * newMomentum * newMomentum);
162 
163  // Update momentum
164  state.stepping.p = newMomentum;
165  // Add derivative dt/ds = 1/(beta * c) = sqrt(m^2 * p^{-2} + c^{-2})
166  state.stepping.derivative(3) =
167  std::hypot(1, state.options.mass / newMomentum);
168  // Update time
169  state.stepping.t += (h / 6.) * (tKi[0] + 2. * (tKi[1] + tKi[2]) + tKi[3]);
170 
171  return true;
172  }
173 
187  template <typename propagator_state_t, typename stepper_t>
188  bool finalize(propagator_state_t& state, const stepper_t& stepper,
189  const double h, FreeMatrix& D) const {
190  return finalize(state, stepper, h) && transportMatrix(state, stepper, h, D);
191  }
192 
193  private:
202  template <typename propagator_state_t, typename stepper_t>
203  bool transportMatrix(propagator_state_t& state, const stepper_t& stepper,
204  const double h, FreeMatrix& D) const {
224 
225  auto& sd = state.stepping.stepData;
226  auto dir = stepper.direction(state.stepping);
227 
228  D = FreeMatrix::Identity();
229  const double half_h = h * 0.5;
230 
231  // This sets the reference to the sub matrices
232  // dFdx is already initialised as (3x3) zero
233  auto dFdT = D.block<3, 3>(0, 4);
234  auto dFdL = D.block<3, 1>(0, 7);
235  // dGdx is already initialised as (3x3) identity
236  auto dGdT = D.block<3, 3>(4, 4);
237  auto dGdL = D.block<3, 1>(4, 7);
238 
243 
248 
250  std::array<double, 4> jdL;
251 
252  // Evaluation of the rightmost column without the last term.
253  jdL[0] = dLdl[0];
254  dk1dL = dir.cross(sd.B_first);
255 
256  jdL[1] = dLdl[1] * (1. + half_h * jdL[0]);
257  dk2dL = (1. + half_h * jdL[0]) * (dir + half_h * sd.k1).cross(sd.B_middle) +
258  qop[1] * half_h * dk1dL.cross(sd.B_middle);
259 
260  jdL[2] = dLdl[2] * (1. + half_h * jdL[1]);
261  dk3dL = (1. + half_h * jdL[1]) * (dir + half_h * sd.k2).cross(sd.B_middle) +
262  qop[2] * half_h * dk2dL.cross(sd.B_middle);
263 
264  jdL[3] = dLdl[3] * (1. + h * jdL[2]);
265  dk4dL = (1. + h * jdL[2]) * (dir + h * sd.k3).cross(sd.B_last) +
266  qop[3] * h * dk3dL.cross(sd.B_last);
267 
268  dk1dT(0, 1) = sd.B_first.z();
269  dk1dT(0, 2) = -sd.B_first.y();
270  dk1dT(1, 0) = -sd.B_first.z();
271  dk1dT(1, 2) = sd.B_first.x();
272  dk1dT(2, 0) = sd.B_first.y();
273  dk1dT(2, 1) = -sd.B_first.x();
274  dk1dT *= qop[0];
275 
276  dk2dT += half_h * dk1dT;
277  dk2dT = qop[1] * VectorHelpers::cross(dk2dT, sd.B_middle);
278 
279  dk3dT += half_h * dk2dT;
280  dk3dT = qop[2] * VectorHelpers::cross(dk3dT, sd.B_middle);
281 
282  dk4dT += h * dk3dT;
283  dk4dT = qop[3] * VectorHelpers::cross(dk4dT, sd.B_last);
284 
285  dFdT.setIdentity();
286  dFdT += h / 6. * (dk1dT + dk2dT + dk3dT);
287  dFdT *= h;
288 
289  dFdL = h * h / 6. * (dk1dL + dk2dL + dk3dL);
290 
291  dGdT += h / 6. * (dk1dT + 2. * (dk2dT + dk3dT) + dk4dT);
292 
293  dGdL = h / 6. * (dk1dL + 2. * (dk2dL + dk3dL) + dk4dL);
294 
295  // Evaluation of the dLambda''/dlambda term
296  D(7, 7) += (h / 6.) * (jdL[0] + 2. * (jdL[1] + jdL[2]) + jdL[3]);
297 
298  // The following comment lines refer to the application of the time being
299  // treated as a position. Since t and qop are treated independently for now,
300  // this just serves as entry point for building their relation
301  //~ double dtpp1dl = -state.options.mass * state.options.mass * qop[0] *
302  //~ qop[0] *
303  //~ (3. * g + qop[0] * dgdqop(energy[0], state.options.mass,
304  //~ state.options.absPdgCode,
305  //~ state.options.meanEnergyLoss));
306 
307  double dtp1dl = qop[0] * state.options.mass * state.options.mass /
308  std::hypot(1, qop[0] * state.options.mass);
309  double qopNew = qop[0] + half_h * Lambdappi[0];
310 
311  //~ double dtpp2dl = -state.options.mass * state.options.mass * qopNew *
312  //~ qopNew *
313  //~ (3. * g * (1. + half_h * jdL[0]) +
314  //~ qopNew * dgdqop(energy[1], state.options.mass,
315  //~ state.options.absPdgCode,
316  //~ state.options.meanEnergyLoss));
317 
318  double dtp2dl = qopNew * state.options.mass * state.options.mass /
319  std::hypot(1, qopNew * state.options.mass);
320  qopNew = qop[0] + half_h * Lambdappi[1];
321 
322  //~ double dtpp3dl = -state.options.mass * state.options.mass * qopNew *
323  //~ qopNew *
324  //~ (3. * g * (1. + half_h * jdL[1]) +
325  //~ qopNew * dgdqop(energy[2], state.options.mass,
326  //~ state.options.absPdgCode,
327  //~ state.options.meanEnergyLoss));
328 
329  double dtp3dl = qopNew * state.options.mass * state.options.mass /
330  std::hypot(1, qopNew * state.options.mass);
331  qopNew = qop[0] + half_h * Lambdappi[2];
332  double dtp4dl = qopNew * state.options.mass * state.options.mass /
333  std::hypot(1, qopNew * state.options.mass);
334 
335  //~ D(3, 7) = h * state.options.mass * state.options.mass * qop[0] /
336  //~ std::hypot(1., state.options.mass * qop[0])
337  //~ + h * h / 6. * (dtpp1dl + dtpp2dl + dtpp3dl);
338 
339  D(3, 7) = (h / 6.) * (dtp1dl + 2. * (dtp2dl + dtp3dl) + dtp4dl);
340  return true;
341  }
342 
348  template <typename propagator_state_t>
349  void initializeEnergyLoss(const propagator_state_t& state) {
350  energy[0] = std::hypot(initialMomentum, state.options.mass);
351  // use unit length as thickness to compute the energy loss per unit length
353  // Use the same energy loss throughout the step.
354  if (state.options.meanEnergyLoss) {
355  g = -computeEnergyLossMean(slab, state.options.absPdgCode,
356  state.options.mass, qop[0]);
357  } else {
358  // TODO using the unit path length is not quite right since the most
359  // probably energy loss is not independent from the path length.
360  g = -computeEnergyLossMode(slab, state.options.absPdgCode,
361  state.options.mass, qop[0]);
362  }
363  // Change of the momentum per path length
364  // dPds = dPdE * dEds
365  dPds[0] = g * energy[0] / initialMomentum;
366  if (state.stepping.covTransport) {
367  // Calculate the change of the energy loss per path length and
368  // inverse momentum
369  if (state.options.includeGgradient) {
370  if (state.options.meanEnergyLoss) {
372  slab, state.options.absPdgCode, state.options.mass, qop[0]);
373  } else {
374  // TODO path length dependence; see above
376  slab, state.options.absPdgCode, state.options.mass, qop[0]);
377  }
378  }
379  // Calculate term for later error propagation
380  dLdl[0] = (-qop[0] * qop[0] * g * energy[0] *
381  (3. - (initialMomentum * initialMomentum) /
382  (energy[0] * energy[0])) -
383  qop[0] * qop[0] * qop[0] * energy[0] * dgdqopValue);
384  }
385  }
386 
395  template <typename stepper_state_t, typename stepper_t>
396  void updateEnergyLoss(const double mass, const double h,
397  const stepper_state_t& state, const stepper_t& stepper,
398  const int i) {
399  // Update parameters related to a changed momentum
400  currentMomentum = initialMomentum + h * dPds[i - 1];
401  energy[i] = std::sqrt(currentMomentum * currentMomentum + mass * mass);
402  dPds[i] = g * energy[i] / currentMomentum;
403  qop[i] = stepper.charge(state) / currentMomentum;
404  // Calculate term for later error propagation
405  if (state.covTransport) {
406  dLdl[i] = (-qop[i] * qop[i] * g * energy[i] *
407  (3. - (currentMomentum * currentMomentum) /
408  (energy[i] * energy[i])) -
409  qop[i] * qop[i] * qop[i] * energy[i] * dgdqopValue);
410  }
411  }
412 };
413 
414 template <typename action_list_t = ActionList<>,
415  typename aborter_list_t = AbortList<>>
417  : public PropagatorOptions<action_list_t, aborter_list_t> {
421  dspo) = default;
422 
428  std::reference_wrapper<const GeometryContext> gctx,
429  std::reference_wrapper<const MagneticFieldContext> mctx)
430  : PropagatorOptions<action_list_t, aborter_list_t>(gctx, mctx) {}
431 
433  bool meanEnergyLoss = true;
434 
436  bool includeGgradient = true;
437 
439  double momentumCutOff = 0.;
440 
446  template <typename extended_aborter_list_t>
448  extended_aborter_list_t aborters) const {
450  eoptions(this->geoContext, this->magFieldContext);
451  // Copy the options over
452  eoptions.direction = this->direction;
453  eoptions.absPdgCode = this->absPdgCode;
454  eoptions.mass = this->mass;
455  eoptions.maxSteps = this->maxSteps;
456  eoptions.maxStepSize = this->maxStepSize;
457  eoptions.targetTolerance = this->targetTolerance;
458  eoptions.pathLimit = this->pathLimit;
459  eoptions.loopProtection = this->loopProtection;
460  eoptions.loopFraction = this->loopFraction;
461  // Output option
462  eoptions.debug = this->debug;
463  eoptions.debugString = this->debugString;
464  eoptions.debugPfxWidth = this->debugPfxWidth;
465  eoptions.debugMsgWidth = this->debugMsgWidth;
466  // Stepper options
467  eoptions.tolerance = this->tolerance;
468  eoptions.stepSizeCutOff = this->stepSizeCutOff;
469  // Action / abort list
470  eoptions.actionList = this->actionList;
471  eoptions.abortList = std::move(aborters);
472  // Copy dense environment specific parameters
473  eoptions.meanEnergyLoss = meanEnergyLoss;
475  eoptions.momentumCutOff = momentumCutOff;
476  // And return the options
477  return eoptions;
478  }
479 };
480 
481 } // namespace Acts