Propagator.cxx
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////
2 ///
3 /// \file Propagator.cxx
4 ///
5 /// \brief Base class for Kalman filter propagator.
6 ///
7 /// \author H. Greenlee
8 ///
9 ////////////////////////////////////////////////////////////////////////
10 
12 #include "cetlib_except/exception.h"
16 
17 namespace trkf {
18 
19  /// Constructor.
20  ///
21  /// Arguments:
22  ///
23  /// tcut - Maximum delta ray energy.
24  /// doDedx - dE/dx enable flag.
25  ///
27  double tcut,
28  bool doDedx,
29  const std::shared_ptr<const Interactor>& interactor)
30  : fDetProp{detProp}, fTcut(tcut), fDoDedx(doDedx), fInteractor(interactor)
31  {}
32 
33  /// Destructor.
34  Propagator::~Propagator() = default;
35 
36  /// Propagate without error (long distance).
37  ///
38  /// Arguments:
39  ///
40  /// trk - Track to propagate.
41  /// psurf - Destination surface.
42  /// dir - Propagation direction (FORWARD, BACKWARD, or UNKNOWN).
43  /// doDedx - dE/dx enable/disable flag.
44  /// prop_matrix - Return propagation matrix if not null.
45  /// noise_matrix - Return noise matrix if not null.
46  ///
47  /// Returned value: Propagation distance & success flag.
48  ///
49  /// This method calls virtual method short_vec_prop in steps of some
50  /// maximum size.
51  ///
52  std::optional<double>
54  const std::shared_ptr<const Surface>& psurf,
56  bool doDedx,
57  TrackMatrix* prop_matrix,
58  TrackError* noise_matrix) const
59  {
60  std::optional<double> result{std::nullopt};
61 
62  // Get the inverse momentum (assumed to be track parameter four).
63 
64  double pinv = trk.getVector()(4);
65 
66  // If dE/dx is not requested, or if inverse momentum is zero, then
67  // it is safe to propagate in one step. In this case, just pass
68  // the call to short_vec_prop with unlimited distance.
69 
70  bool dedx = getDoDedx() && doDedx;
71  if (!dedx || pinv == 0.)
72  result = short_vec_prop(trk, psurf, dir, dedx, prop_matrix, noise_matrix);
73 
74  else {
75 
76  // dE/dx is requested. In this case we limit the maximum
77  // propagation distance such that the kinetic energy of the
78  // particle should not change by more thatn 10%.
79 
80  // Initialize propagation matrix to unit matrix (if specified).
81 
82  int nvec = trk.getVector().size();
83  if (prop_matrix) *prop_matrix = ublas::identity_matrix<TrackVector::value_type>(nvec);
84 
85  // Initialize noise matrix to zero matrix (if specified).
86 
87  if (noise_matrix) {
88  noise_matrix->resize(nvec, nvec, false);
89  noise_matrix->clear();
90  }
91 
92  // Remember the starting track.
93 
94  KTrack trk0(trk);
95 
96  // Make pointer variables pointing to local versions of the
97  // propagation and noise matrices, or null if not specified.
98 
99  TrackMatrix local_prop_matrix;
100  TrackMatrix* plocal_prop_matrix = (prop_matrix == 0 ? 0 : &local_prop_matrix);
101  TrackError local_noise_matrix;
102  TrackError* plocal_noise_matrix = (noise_matrix == 0 ? 0 : &local_noise_matrix);
103 
104  // Cumulative propagation distance.
105 
106  double s = 0.;
107 
108  // Begin stepping loop.
109  // We put a maximum iteration count to prevent infinite loops caused by
110  // floating point pathologies. The iteration count is large enough to reach
111  // any point in the tpc using the minimum step size (for a reasonable tpc).
112 
113  bool done = false;
114  int nitmax = 10000; // Maximum number of iterations.
115  int nit = 0; // Iteration count.
116  while (!done) {
117 
118  // If the iteration count exceeds the maximum, return failure.
119 
120  ++nit;
121  if (nit > nitmax) {
122  trk = trk0;
123  result = std::nullopt;
124  return result;
125  }
126 
127  // Estimate maximum step distance according to the above
128  // stated principle.
129 
130  pinv = trk.getVector()(4);
131  double mass = trk.Mass();
132  double p = 1. / std::abs(pinv);
133  double e = std::hypot(p, mass);
134  double t = p * p / (e + mass);
135  double dedx = 0.001 * fDetProp.Eloss(p, mass, fTcut);
136  double smax = 0.1 * t / dedx;
137  if (smax <= 0.)
138  throw cet::exception("Propagator") << __func__ << ": maximum step " << smax << "\n";
139 
140  // Always allow a step of at least 0.3 cm (about one wire spacing).
141 
142  if (smax < 0.3) smax = 0.3;
143 
144  // First do a test propagation (without dE/dx and errors) to
145  // find the distance to the destination surface.
146 
147  KTrack trktest(trk);
148  std::optional<double> dist = short_vec_prop(trktest, psurf, dir, false, 0, 0);
149 
150  // If the test propagation failed, return failure.
151 
152  if (!dist) {
153  trk = trk0;
154  return dist;
155  }
156 
157  // Generate destionation surface for this step (either final
158  // destination, or some intermediate surface).
159 
160  std::shared_ptr<const Surface> pstep;
161  if (std::abs(*dist) <= smax) {
162  done = true;
163  pstep = psurf;
164  }
165  else {
166 
167  // Generate intermediate surface.
168  // First get point where track will intersect intermediate surface.
169 
170  double xyz0[3]; // Starting point.
171  trk.getPosition(xyz0);
172  double xyz1[3]; // Destination point.
173  trktest.getPosition(xyz1);
174  double frac = smax / std::abs(*dist);
175  double xyz[3]; // Intermediate point.
176  xyz[0] = xyz0[0] + frac * (xyz1[0] - xyz0[0]);
177  xyz[1] = xyz0[1] + frac * (xyz1[1] - xyz0[1]);
178  xyz[2] = xyz0[2] + frac * (xyz1[2] - xyz0[2]);
179 
180  // Choose orientation of intermediate surface perpendicular
181  // to track.
182 
183  double mom[3];
184  trk.getMomentum(mom);
185 
186  // Make intermediate surface object.
187 
188  pstep = std::shared_ptr<const Surface>(
189  new SurfXYZPlane(xyz[0], xyz[1], xyz[2], mom[0], mom[1], mom[2]));
190  }
191 
192  // Do the actual step propagation.
193 
194  dist = short_vec_prop(trk, pstep, dir, doDedx, plocal_prop_matrix, plocal_noise_matrix);
195 
196  // If the step propagation failed, return failure.
197 
198  if (!dist) {
199  trk = trk0;
200  return dist;
201  }
202 
203  // Update cumulative propagation distance.
204 
205  s += *dist;
206 
207  // Update cumulative propagation matrix (left-multiply).
208 
209  if (prop_matrix != 0) {
210  TrackMatrix temp = prod(*plocal_prop_matrix, *prop_matrix);
211  *prop_matrix = temp;
212  }
213 
214  // Update cumulative noise matrix.
215 
216  if (noise_matrix != 0) {
217  TrackMatrix temp = prod(*noise_matrix, trans(*plocal_prop_matrix));
218  TrackMatrix temp2 = prod(*plocal_prop_matrix, temp);
219  *noise_matrix = ublas::symmetric_adaptor<TrackMatrix>(temp2);
220  *noise_matrix += *plocal_noise_matrix;
221  }
222  }
223 
224  // Set the final result (distance + success).
225 
226  result = std::make_optional(s);
227  }
228 
229  // Done.
230 
231  return result;
232  }
233 
234  /// Linearized propagate without error.
235  ///
236  /// Arguments:
237  ///
238  /// trk - Track to propagate.
239  /// psurf - Destination surface.
240  /// dir - Propagation direction (FORWARD, BACKWARD, or UNKNOWN).
241  /// doDedx - dE/dx enable/disable flag.
242  /// ref - Reference track (for linearized propagation). Can be null.
243  /// prop_matrix - Return propagation matrix if not null.
244  /// noise_matrix - Return noise matrix if not null.
245  ///
246  /// Returned value: Propagation distance & success flag.
247  ///
248  /// If the reference track is null, this method simply calls vec_prop.
249  ///
250  std::optional<double>
252  const std::shared_ptr<const Surface>& psurf,
254  bool doDedx,
255  KTrack* ref,
256  TrackMatrix* prop_matrix,
257  TrackError* noise_matrix) const
258  {
259  // Default result.
260 
261  std::optional<double> result;
262 
263  if (ref == 0)
264  result = vec_prop(trk, psurf, dir, doDedx, prop_matrix, noise_matrix);
265  else {
266 
267  // A reference track has been provided.
268 
269  // It is an error (throw exception) if the reference track and
270  // the track to be propagted are not on the same surface.
271 
272  if (!trk.getSurface()->isEqual(*(ref->getSurface())))
273  throw cet::exception("Propagator")
274  << "Input track and reference track not on same surface.\n";
275 
276  // Remember the starting track and reference track.
277 
278  KTrack trk0(trk);
279  KTrack ref0(*ref);
280 
281  // Propagate the reference track. Make sure we calculate the
282  // propagation matrix.
283 
284  TrackMatrix prop_temp;
285  if (prop_matrix == 0) prop_matrix = &prop_temp;
286 
287  // Do the propgation. The returned result will be the result of
288  // this propagatrion.
289 
290  result = vec_prop(*ref, psurf, dir, doDedx, prop_matrix, noise_matrix);
291  if (!!result) {
292 
293  // Propagation of reference track succeeded. Update the track
294  // state vector and surface of the track to be propagated.
295 
296  TrackVector diff = trk.getSurface()->getDiff(trk.getVector(), ref0.getVector());
297  TrackVector newvec = ref->getVector() + prod(*prop_matrix, diff);
298 
299  // Store updated state vector and surface.
300 
301  trk.setVector(newvec);
302  trk.setSurface(psurf);
303  trk.setDirection(ref->getDirection());
304  if (!trk.getSurface()->isEqual(*(ref->getSurface())))
305  throw cet::exception("Propagator") << __func__ << ": surface mismatch";
306 
307  // Final validity check. In case of failure, restore the track
308  // and reference track to their starting values.
309 
310  if (!trk.isValid()) {
311  result = std::nullopt;
312  trk = trk0;
313  *ref = ref0;
314  }
315  }
316  else {
317 
318  // Propagation failed.
319  // Restore the reference track to its starting value, so that we ensure
320  // the reference track and the actual track remain on the same surface.
321 
322  trk = trk0;
323  *ref = ref0;
324  }
325  }
326 
327  // Done.
328 
329  return result;
330  }
331 
332  /// Propagate with error, but without noise (i.e. reversibly).
333  ///
334  /// Arguments:
335  ///
336  /// tre - Track to propagate.
337  /// psurf - Destination surface.
338  /// dir - Propagation direction (FORWARD, BACKWARD, or UNKNOWN).
339  /// doDedx - dE/dx enable/disable flag.
340  /// ref - Reference track (for linearized propagation). Can be null.
341  /// prop_matrix - Return propagation matrix if not null.
342  ///
343  /// Returned value: propagation distance + success flag.
344  ///
345  std::optional<double>
347  const std::shared_ptr<const Surface>& psurf,
349  bool doDedx,
350  KTrack* ref,
351  TrackMatrix* prop_matrix) const
352  {
353  // Propagate without error, get propagation matrix.
354 
355  TrackMatrix prop_temp;
356  if (prop_matrix == 0) prop_matrix = &prop_temp;
357  std::optional<double> result = lin_prop(tre, psurf, dir, doDedx, ref, prop_matrix, 0);
358 
359  // If propagation succeeded, update track error matrix.
360 
361  if (!!result) {
362  TrackMatrix temp = prod(tre.getError(), trans(*prop_matrix));
363  TrackMatrix temp2 = prod(*prop_matrix, temp);
364  TrackError newerr = ublas::symmetric_adaptor<TrackMatrix>(temp2);
365  tre.setError(newerr);
366  }
367 
368  // Done.
369 
370  return result;
371  }
372 
373  /// Propagate with error and noise.
374  ///
375  /// Arguments:
376  ///
377  /// tre - Track to propagate.
378  /// psurf - Destination surface.
379  /// dir - Propagation direction (FORWARD, BACKWARD, or UNKNOWN).
380  /// doDedx - dE/dx enable/disable flag.
381  /// ref - Reference track (for linearized propagation). Can be null.
382  ///
383  /// Returned value: propagation distance + success flag.
384  ///
385  std::optional<double>
387  const std::shared_ptr<const Surface>& psurf,
389  bool doDedx,
390  KTrack* ref) const
391  {
392  // Propagate without error, get propagation matrix and noise matrix.
393 
394  TrackMatrix prop_matrix;
395  TrackError noise_matrix;
396  std::optional<double> result =
397  lin_prop(tre, psurf, dir, doDedx, ref, &prop_matrix, &noise_matrix);
398 
399  // If propagation succeeded, update track error matrix.
400 
401  if (!!result) {
402  TrackMatrix temp = prod(tre.getError(), trans(prop_matrix));
403  TrackMatrix temp2 = prod(prop_matrix, temp);
404  TrackError newerr = ublas::symmetric_adaptor<TrackMatrix>(temp2);
405  newerr += noise_matrix;
406  tre.setError(newerr);
407  }
408 
409  // Done.
410 
411  return result;
412  }
413 
414  /// Method to calculate updated momentum due to dE/dx.
415  ///
416  /// Arguments:
417  ///
418  /// pinv - Initial inverse momentum (units c/GeV).
419  /// mass - Particle mass (GeV/c^2).
420  /// s - Path distance.
421  /// deriv - Pointer to store derivative d(pinv2)/d(pinv1) if nonzero.
422  ///
423  /// Returns: Final inverse momentum (pinv2) + success flag.
424  ///
425  /// Failure is returned in case of range out.
426  ///
427  /// Inverse momentum can be signed (q/p). Returned inverse momentum
428  /// has the same sign as the input.
429  ///
430  /// In this method, we are solving the differential equation in
431  /// terms of energy.
432  ///
433  /// dE/dx = -f(E)
434  ///
435  /// where f(E) is the stopping power returned by method
436  /// LArProperties::Eloss.
437  ///
438  /// We expect that this method will be called exclusively for short
439  /// distance propagation. The differential equation is solved using
440  /// the midpoint method using a single step, which requires two
441  /// evaluations of f(E).
442  ///
443  /// dE = -s*f(E1)
444  /// E2 = E1 - s*f(E1 + 0.5*dE)
445  ///
446  /// The derivative is calculated assuming E2 = E1 + constant, giving
447  ///
448  /// d(pinv2)/d(pinv1) = pinv2^3 E2 / (pinv1^3 E1).
449  ///
450  ///
451  std::optional<double>
452  Propagator::dedx_prop(double pinv, double mass, double s, double* deriv) const
453  {
454  // For infinite initial momentum, return with success status,
455  // still infinite momentum.
456 
457  if (pinv == 0.) return std::make_optional(0.);
458 
459  // Set the default return value to be uninitialized with value 0.
460 
461  std::optional<double> result{std::nullopt};
462 
463  // Calculate final energy.
464 
465  double p1 = 1. / std::abs(pinv);
466  double e1 = std::hypot(p1, mass);
467  double de = -0.001 * s * fDetProp.Eloss(p1, mass, fTcut);
468  double emid = e1 + 0.5 * de;
469  if (emid > mass) {
470  double pmid = std::sqrt(emid * emid - mass * mass);
471  double e2 = e1 - 0.001 * s * fDetProp.Eloss(pmid, mass, fTcut);
472  if (e2 > mass) {
473  double p2 = std::sqrt(e2 * e2 - mass * mass);
474  double pinv2 = 1. / p2;
475  if (pinv < 0.) pinv2 = -pinv2;
476 
477  // Calculation was successful, update result.
478 
479  result = std::make_optional(pinv2);
480 
481  // Also calculate derivative, if requested.
482 
483  if (deriv != 0) *deriv = pinv2 * pinv2 * pinv2 * e2 / (pinv * pinv * pinv * e1);
484  }
485  }
486 
487  // Done.
488 
489  return result;
490  }
491 } // end namespace trkf
const TrackError & getError() const
Track error matrix.
Definition: KETrack.h:53
double Mass() const
Based on pdg code.
Definition: KTrack.cxx:129
const std::shared_ptr< const Surface > & getSurface() const
Surface.
Definition: KTrack.h:55
static QCString result
General planar surface.
KSymMatrix< 5 >::type TrackError
Track error matrix, dimension 5x5.
void setVector(const TrackVector &vec)
Set state vector.
Definition: KTrack.h:67
void setDirection(Surface::TrackDirection dir)
Set direction.
Definition: KTrack.h:68
double fTcut
Maximum delta ray energy for dE/dx.
Definition: Propagator.h:177
string dir
virtual std::optional< double > short_vec_prop(KTrack &trk, const std::shared_ptr< const Surface > &psurf, PropDirection dir, bool doDedx, TrackMatrix *prop_matrix=0, TrackError *noise_matrix=0) const =0
Propagate without error (short distance).
virtual ~Propagator()
Destructor.
void setError(const TrackError &err)
Set error matrix.
Definition: KETrack.h:67
std::enable_if_t< std::is_arithmetic_v< T >, T > hypot(T x, T y)
Definition: hypot.h:60
std::optional< double > vec_prop(KTrack &trk, const std::shared_ptr< const Surface > &psurf, PropDirection dir, bool doDedx, TrackMatrix *prop_matrix=0, TrackError *noise_matrix=0) const
Propagate without error (long distance).
Definition: Propagator.cxx:53
std::optional< double > noise_prop(KETrack &tre, const std::shared_ptr< const Surface > &psurf, PropDirection dir, bool doDedx, KTrack *ref=0) const
Propagate with error and noise.
Definition: Propagator.cxx:386
void setSurface(const std::shared_ptr< const Surface > &psurf)
Set surface.
Definition: KTrack.h:66
detinfo::DetectorPropertiesData const & fDetProp
Definition: Propagator.h:176
T abs(T value)
std::optional< double > lin_prop(KTrack &trk, const std::shared_ptr< const Surface > &psurf, PropDirection dir, bool doDedx, KTrack *ref=0, TrackMatrix *prop_matrix=0, TrackError *noise_matrix=0) const
Linearized propagate without error.
Definition: Propagator.cxx:251
const double e
void getPosition(double xyz[3]) const
Get position of track.
Definition: KTrack.cxx:171
std::optional< double > err_prop(KETrack &tre, const std::shared_ptr< const Surface > &psurf, PropDirection dir, bool doDedx, KTrack *ref=0, TrackMatrix *prop_matrix=0) const
Propagate with error, but without noise.
Definition: Propagator.cxx:346
p
Definition: test.py:223
Base class for Kalman filter track propagator.
KVector< 5 >::type TrackVector
Track state vector, dimension 5.
double Eloss(double mom, double mass, double tcut) const
Restricted mean energy loss (dE/dx)
bool getDoDedx() const
Definition: Propagator.h:113
const TrackVector & getVector() const
Track state vector.
Definition: KTrack.h:56
constexpr double dist(const TReal *x, const TReal *y, const unsigned int dimension)
KMatrix< 5, 5 >::type TrackMatrix
General 5x5 matrix.
std::optional< double > dedx_prop(double pinv, double mass, double s, double *deriv=0) const
Method to calculate updated momentum due to dE/dx.
Definition: Propagator.cxx:452
void getMomentum(double mom[3]) const
Get momentum vector of track.
Definition: KTrack.cxx:218
Surface::TrackDirection getDirection() const
Track direction.
Definition: KTrack.cxx:73
std::shared_ptr< const Interactor > fInteractor
Interactor (for calculating noise).
Definition: Propagator.h:179
bool fDoDedx
Energy loss enable flag.
Definition: Propagator.h:178
Propagator(detinfo::DetectorPropertiesData const &detProp, double tcut, bool doDedx, const std::shared_ptr< const Interactor > &interactor)
Constructor.
Definition: Propagator.cxx:26
static QCString * s
Definition: config.cpp:1042
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
bool isValid() const
Test if track is valid.
Definition: KTrack.cxx:91
PropDirection
Propagation direction enum.
Definition: Propagator.h:94