Belle II Software  release-05-02-19
RKTrackRep.cc
1 /* Copyright 2008-2013, Technische Universitaet Muenchen, Ludwig-Maximilians-Universität München
2  Authors: Christian Hoeppner & Sebastian Neubert & Johannes Rauch & Tobias Schlüter
3 
4  This file is part of GENFIT.
5 
6  GENFIT is free software: you can redistribute it and/or modify
7  it under the terms of the GNU Lesser General Public License as published
8  by the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  GENFIT is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public License
17  along with GENFIT. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "RKTrackRep.h"
21 #include "IO.h"
22 
23 #include <Exception.h>
24 #include <FieldManager.h>
25 #include <MaterialEffects.h>
26 #include <MeasuredStateOnPlane.h>
27 #include <MeasurementOnPlane.h>
28 
29 #include <TBuffer.h>
30 #include <TDecompLU.h>
31 #include <TMath.h>
32 
33 #include <algorithm>
34 
35 #define MINSTEP 0.001 // minimum step [cm] for Runge Kutta and iteration to POCA
36 
37 namespace {
38  // Use fast inversion instead of LU decomposition?
39  const bool useInvertFast = false;
40 }
41 
42 namespace genfit {
43 
44 
45 RKTrackRep::RKTrackRep() :
46  AbsTrackRep(),
47  lastStartState_(this),
48  lastEndState_(this),
49  RKStepsFXStart_(0),
50  RKStepsFXStop_(0),
51  fJacobian_(5,5),
52  fNoise_(5),
53  useCache_(false),
54  cachePos_(0)
55 {
56  initArrays();
57 }
58 
59 
60 RKTrackRep::RKTrackRep(int pdgCode, char propDir) :
61  AbsTrackRep(pdgCode, propDir),
62  lastStartState_(this),
63  lastEndState_(this),
64  RKStepsFXStart_(0),
65  RKStepsFXStop_(0),
66  fJacobian_(5,5),
67  fNoise_(5),
68  useCache_(false),
69  cachePos_(0)
70 {
71  initArrays();
72 }
73 
74 
75 RKTrackRep::~RKTrackRep() {
76  ;
77 }
78 
79 
81  const SharedPlanePtr& plane,
82  bool stopAtBoundary,
83  bool calcJacobianNoise) const {
84 
85  if (debugLvl_ > 0) {
86  debugOut << "RKTrackRep::extrapolateToPlane()\n";
87  }
88 
89 
90  if (state.getPlane() == plane) {
91  if (debugLvl_ > 0) {
92  debugOut << "state is already defined at plane. Do nothing! \n";
93  }
94  return 0;
95  }
96 
97  checkCache(state, &plane);
98 
99  // to 7D
100  M1x7 state7 = {{0, 0, 0, 0, 0, 0, 0}};
101  getState7(state, state7);
102 
103  TMatrixDSym* covPtr(nullptr);
104  bool fillExtrapSteps(false);
105  if (dynamic_cast<MeasuredStateOnPlane*>(&state) != nullptr) {
106  covPtr = &(static_cast<MeasuredStateOnPlane*>(&state)->getCov());
107  fillExtrapSteps = true;
108  }
109  else if (calcJacobianNoise)
110  fillExtrapSteps = true;
111 
112  // actual extrapolation
113  bool isAtBoundary(false);
114  double flightTime( 0. );
115  double coveredDistance( Extrap(*(state.getPlane()), *plane, getCharge(state), getMass(state), isAtBoundary, state7, flightTime, fillExtrapSteps, covPtr, false, stopAtBoundary) );
116 
117  if (stopAtBoundary && isAtBoundary) {
118  state.setPlane(SharedPlanePtr(new DetPlane(TVector3(state7[0], state7[1], state7[2]),
119  TVector3(state7[3], state7[4], state7[5]))));
120  }
121  else {
122  state.setPlane(plane);
123  }
124 
125  // back to 5D
126  getState5(state, state7);
127  setTime(state, getTime(state) + flightTime);
128 
129  lastEndState_ = state;
130 
131  return coveredDistance;
132 }
133 
134 
136  const TVector3& linePoint,
137  const TVector3& lineDirection,
138  bool stopAtBoundary,
139  bool calcJacobianNoise) const {
140 
141  if (debugLvl_ > 0) {
142  debugOut << "RKTrackRep::extrapolateToLine()\n";
143  }
144 
145  checkCache(state, nullptr);
146 
147  static const unsigned int maxIt(1000);
148 
149  // to 7D
150  M1x7 state7;
151  getState7(state, state7);
152 
153  bool fillExtrapSteps(false);
154  if (dynamic_cast<MeasuredStateOnPlane*>(&state) != nullptr) {
155  fillExtrapSteps = true;
156  }
157  else if (calcJacobianNoise)
158  fillExtrapSteps = true;
159 
160  double step(0.), lastStep(0.), maxStep(1.E99), angle(0), distToPoca(0), tracklength(0);
161  double charge = getCharge(state);
162  double mass = getMass(state);
163  double flightTime = 0;
164  TVector3 dir(state7[3], state7[4], state7[5]);
165  TVector3 lastDir(0,0,0);
166  TVector3 poca, poca_onwire;
167  bool isAtBoundary(false);
168 
169  DetPlane startPlane(*(state.getPlane()));
170  SharedPlanePtr plane(new DetPlane(linePoint, dir.Cross(lineDirection), lineDirection));
171  unsigned int iterations(0);
172 
173  while(true){
174  if(++iterations == maxIt) {
175  Exception exc("RKTrackRep::extrapolateToLine ==> extrapolation to line failed, maximum number of iterations reached",__LINE__,__FILE__);
176  exc.setFatal();
177  throw exc;
178  }
179 
180  lastStep = step;
181  lastDir = dir;
182 
183  step = this->Extrap(startPlane, *plane, charge, mass, isAtBoundary, state7, flightTime, false, nullptr, true, stopAtBoundary, maxStep);
184  tracklength += step;
185 
186  dir.SetXYZ(state7[3], state7[4], state7[5]);
187  poca.SetXYZ(state7[0], state7[1], state7[2]);
188  poca_onwire = pocaOnLine(linePoint, lineDirection, poca);
189 
190  // check break conditions
191  if (stopAtBoundary && isAtBoundary) {
192  plane->setON(dir, poca);
193  break;
194  }
195 
196  angle = fabs(dir.Angle((poca_onwire-poca))-TMath::PiOver2()); // angle between direction and connection to point - 90 deg
197  distToPoca = (poca_onwire-poca).Mag();
198  if (angle*distToPoca < 0.1*MINSTEP) break;
199 
200  // if lastStep and step have opposite sign, the real normal vector lies somewhere between the last two normal vectors (i.e. the directions)
201  // -> try mean value of the two (normalization not needed)
202  if (lastStep*step < 0){
203  dir += lastDir;
204  maxStep = 0.5*fabs(lastStep); // make it converge!
205  }
206 
207  startPlane = *plane;
208  plane->setU(dir.Cross(lineDirection));
209  }
210 
211  if (fillExtrapSteps) { // now do the full extrapolation with covariance matrix
212  // make use of the cache
213  lastEndState_.setPlane(plane);
214  getState5(lastEndState_, state7);
215 
216  tracklength = extrapolateToPlane(state, plane, false, true);
217  lastEndState_.getAuxInfo()(1) = state.getAuxInfo()(1); // Flight time
218  }
219  else {
220  state.setPlane(plane);
221  getState5(state, state7);
222  state.getAuxInfo()(1) += flightTime;
223  }
224 
225  if (debugLvl_ > 0) {
226  debugOut << "RKTrackRep::extrapolateToLine(): Reached POCA after " << iterations+1 << " iterations. Distance: " << (poca_onwire-poca).Mag() << " cm. Angle deviation: " << dir.Angle((poca_onwire-poca))-TMath::PiOver2() << " rad \n";
227  }
228 
229  lastEndState_ = state;
230 
231  return tracklength;
232 }
233 
234 
235 double RKTrackRep::extrapToPoint(StateOnPlane& state,
236  const TVector3& point,
237  const TMatrixDSym* G,
238  bool stopAtBoundary,
239  bool calcJacobianNoise) const {
240 
241  if (debugLvl_ > 0) {
242  debugOut << "RKTrackRep::extrapolateToPoint()\n";
243  }
244 
245  checkCache(state, nullptr);
246 
247  static const unsigned int maxIt(1000);
248 
249  // to 7D
250  M1x7 state7;
251  getState7(state, state7);
252 
253  bool fillExtrapSteps(false);
254  if (dynamic_cast<MeasuredStateOnPlane*>(&state) != nullptr) {
255  fillExtrapSteps = true;
256  }
257  else if (calcJacobianNoise)
258  fillExtrapSteps = true;
259 
260  double step(0.), lastStep(0.), maxStep(1.E99), angle(0), distToPoca(0), tracklength(0);
261  TVector3 dir(state7[3], state7[4], state7[5]);
262  if (G != nullptr) {
263  if(G->GetNrows() != 3) {
264  Exception exc("RKTrackRep::extrapolateToLine ==> G is not 3x3",__LINE__,__FILE__);
265  exc.setFatal();
266  throw exc;
267  }
268  dir = TMatrix(*G) * dir;
269  }
270  TVector3 lastDir(0,0,0);
271 
272  TVector3 poca;
273  bool isAtBoundary(false);
274 
275  DetPlane startPlane(*(state.getPlane()));
276  SharedPlanePtr plane(new DetPlane(point, dir));
277  unsigned int iterations(0);
278  double charge = getCharge(state);
279  double mass = getMass(state);
280  double flightTime = 0;
281 
282  while(true){
283  if(++iterations == maxIt) {
284  Exception exc("RKTrackRep::extrapolateToPoint ==> extrapolation to point failed, maximum number of iterations reached",__LINE__,__FILE__);
285  exc.setFatal();
286  throw exc;
287  }
288 
289  lastStep = step;
290  lastDir = dir;
291 
292  step = this->Extrap(startPlane, *plane, charge, mass, isAtBoundary, state7, flightTime, false, nullptr, true, stopAtBoundary, maxStep);
293  tracklength += step;
294 
295  dir.SetXYZ(state7[3], state7[4], state7[5]);
296  if (G != nullptr) {
297  dir = TMatrix(*G) * dir;
298  }
299  poca.SetXYZ(state7[0], state7[1], state7[2]);
300 
301  // check break conditions
302  if (stopAtBoundary && isAtBoundary) {
303  plane->setON(dir, poca);
304  break;
305  }
306 
307  angle = fabs(dir.Angle((point-poca))-TMath::PiOver2()); // angle between direction and connection to point - 90 deg
308  distToPoca = (point-poca).Mag();
309  if (angle*distToPoca < 0.1*MINSTEP) break;
310 
311  // if lastStep and step have opposite sign, the real normal vector lies somewhere between the last two normal vectors (i.e. the directions)
312  // -> try mean value of the two
313  if (lastStep*step < 0){
314  if (G != nullptr) { // after multiplication with G, dir has not length 1 anymore in general
315  dir.SetMag(1.);
316  lastDir.SetMag(1.);
317  }
318  dir += lastDir;
319  maxStep = 0.5*fabs(lastStep); // make it converge!
320  }
321 
322  startPlane = *plane;
323  plane->setNormal(dir);
324  }
325 
326  if (fillExtrapSteps) { // now do the full extrapolation with covariance matrix
327  // make use of the cache
328  lastEndState_.setPlane(plane);
329  getState5(lastEndState_, state7);
330 
331  tracklength = extrapolateToPlane(state, plane, false, true);
332  lastEndState_.getAuxInfo()(1) = state.getAuxInfo()(1); // Flight time
333  }
334  else {
335  state.setPlane(plane);
336  getState5(state, state7);
337  state.getAuxInfo()(1) += flightTime;
338  }
339 
340 
341  if (debugLvl_ > 0) {
342  debugOut << "RKTrackRep::extrapolateToPoint(): Reached POCA after " << iterations+1 << " iterations. Distance: " << (point-poca).Mag() << " cm. Angle deviation: " << dir.Angle((point-poca))-TMath::PiOver2() << " rad \n";
343  }
344 
345  lastEndState_ = state;
346 
347  return tracklength;
348 }
349 
350 
352  double radius,
353  const TVector3& linePoint,
354  const TVector3& lineDirection,
355  bool stopAtBoundary,
356  bool calcJacobianNoise) const {
357 
358  if (debugLvl_ > 0) {
359  debugOut << "RKTrackRep::extrapolateToCylinder()\n";
360  }
361 
362  checkCache(state, nullptr);
363 
364  static const unsigned int maxIt(1000);
365 
366  // to 7D
367  M1x7 state7;
368  getState7(state, state7);
369 
370  bool fillExtrapSteps(false);
371  if (dynamic_cast<MeasuredStateOnPlane*>(&state) != nullptr) {
372  fillExtrapSteps = true;
373  }
374  else if (calcJacobianNoise)
375  fillExtrapSteps = true;
376 
377  double tracklength(0.), maxStep(1.E99);
378 
379  TVector3 dest, pos, dir;
380 
381  bool isAtBoundary(false);
382 
383  DetPlane startPlane(*(state.getPlane()));
384  SharedPlanePtr plane(new DetPlane());
385  unsigned int iterations(0);
386  double charge = getCharge(state);
387  double mass = getMass(state);
388  double flightTime = 0;
389 
390  while(true){
391  if(++iterations == maxIt) {
392  Exception exc("RKTrackRep::extrapolateToCylinder ==> maximum number of iterations reached",__LINE__,__FILE__);
393  exc.setFatal();
394  throw exc;
395  }
396 
397  pos.SetXYZ(state7[0], state7[1], state7[2]);
398  dir.SetXYZ(state7[3], state7[4], state7[5]);
399 
400  // solve quadratic equation
401  TVector3 AO = (pos - linePoint);
402  TVector3 AOxAB = (AO.Cross(lineDirection));
403  TVector3 VxAB = (dir.Cross(lineDirection));
404  float ab2 = (lineDirection * lineDirection);
405  float a = (VxAB * VxAB);
406  float b = 2 * (VxAB * AOxAB);
407  float c = (AOxAB * AOxAB) - (radius*radius * ab2);
408  double arg = b*b - 4.*a*c;
409  if(arg < 0) {
410  Exception exc("RKTrackRep::extrapolateToCylinder ==> cannot solve",__LINE__,__FILE__);
411  exc.setFatal();
412  throw exc;
413  }
414  double term = sqrt(arg);
415  double k1, k2;
416  if (b<0) {
417  k1 = (-b + term)/(2.*a);
418  k2 = 2.*c/(-b + term);
419  }
420  else {
421  k1 = 2.*c/(-b - term);
422  k2 = (-b - term)/(2.*a);
423  }
424 
425  // select smallest absolute solution -> closest cylinder surface
426  double k = k1;
427  if (fabs(k2)<fabs(k))
428  k = k2;
429 
430  if (debugLvl_ > 0) {
431  debugOut << "RKTrackRep::extrapolateToCylinder(); k = " << k << "\n";
432  }
433 
434  dest = pos + k * dir;
435 
436  plane->setO(dest);
437  plane->setUV((dest-linePoint).Cross(lineDirection), lineDirection);
438 
439  tracklength += this->Extrap(startPlane, *plane, charge, mass, isAtBoundary, state7, flightTime, false, nullptr, true, stopAtBoundary, maxStep);
440 
441  // check break conditions
442  if (stopAtBoundary && isAtBoundary) {
443  pos.SetXYZ(state7[0], state7[1], state7[2]);
444  dir.SetXYZ(state7[3], state7[4], state7[5]);
445  plane->setO(pos);
446  plane->setUV((pos-linePoint).Cross(lineDirection), lineDirection);
447  break;
448  }
449 
450  if(fabs(k)<MINSTEP) break;
451 
452  startPlane = *plane;
453 
454  }
455 
456  if (fillExtrapSteps) { // now do the full extrapolation with covariance matrix
457  // make use of the cache
458  lastEndState_.setPlane(plane);
459  getState5(lastEndState_, state7);
460 
461  tracklength = extrapolateToPlane(state, plane, false, true);
462  lastEndState_.getAuxInfo()(1) = state.getAuxInfo()(1); // Flight time
463  }
464  else {
465  state.setPlane(plane);
466  getState5(state, state7);
467  state.getAuxInfo()(1) += flightTime;
468  }
469 
470  lastEndState_ = state;
471 
472  return tracklength;
473 }
474 
475 
477  double openingAngle,
478  const TVector3& conePoint,
479  const TVector3& coneDirection,
480  bool stopAtBoundary,
481  bool calcJacobianNoise) const {
482 
483  if (debugLvl_ > 0) {
484  debugOut << "RKTrackRep::extrapolateToCone()\n";
485  }
486 
487  checkCache(state, nullptr);
488 
489  static const unsigned int maxIt(1000);
490 
491  // to 7D
492  M1x7 state7;
493  getState7(state, state7);
494 
495  bool fillExtrapSteps(false);
496  if (dynamic_cast<MeasuredStateOnPlane*>(&state) != nullptr) {
497  fillExtrapSteps = true;
498  }
499  else if (calcJacobianNoise)
500  fillExtrapSteps = true;
501 
502  double tracklength(0.), maxStep(1.E99);
503 
504  TVector3 dest, pos, dir;
505 
506  bool isAtBoundary(false);
507 
508  DetPlane startPlane(*(state.getPlane()));
509  SharedPlanePtr plane(new DetPlane());
510  unsigned int iterations(0);
511  double charge = getCharge(state);
512  double mass = getMass(state);
513  double flightTime = 0;
514 
515  while(true){
516  if(++iterations == maxIt) {
517  Exception exc("RKTrackRep::extrapolateToCone ==> maximum number of iterations reached",__LINE__,__FILE__);
518  exc.setFatal();
519  throw exc;
520  }
521 
522  pos.SetXYZ(state7[0], state7[1], state7[2]);
523  dir.SetXYZ(state7[3], state7[4], state7[5]);
524 
525  // solve quadratic equation a k^2 + 2 b k + c = 0
526  // a = (U . D)^2 - cos^2 alpha * U^2
527  // b = (Delta . D) * (U . D) - cos^2 alpha * (U . Delta)
528  // c = (Delta . D)^2 - cos^2 alpha * Delta^2
529  // Delta = P - V, P track point, U track direction, V cone point, D cone direction, alpha opening angle of cone
530  TVector3 cDirection = coneDirection.Unit();
531  TVector3 Delta = (pos - conePoint);
532  double DirDelta = cDirection * Delta;
533  double Delta2 = Delta*Delta;
534  double UDir = dir * cDirection;
535  double UDelta = dir * Delta;
536  double U2 = dir * dir;
537  double cosAngle2 = cos(openingAngle)*cos(openingAngle);
538  double a = UDir*UDir - cosAngle2*U2;
539  double b = UDir*DirDelta - cosAngle2*UDelta;
540  double c = DirDelta*DirDelta - cosAngle2*Delta2;
541 
542  double arg = b*b - a*c;
543  if(arg < -1e-9) {
544  Exception exc("RKTrackRep::extrapolateToCone ==> cannot solve",__LINE__,__FILE__);
545  exc.setFatal();
546  throw exc;
547  } else if(arg < 0) {
548  arg = 0;
549  }
550 
551  double term = sqrt(arg);
552  double k1, k2;
553  k1 = (-b + term) / a;
554  k2 = (-b - term) / a;
555 
556  // select smallest absolute solution -> closest cone surface
557  double k = k1;
558  if(fabs(k2) < fabs(k)) {
559  k = k2;
560  }
561 
562  if (debugLvl_ > 0) {
563  debugOut << "RKTrackRep::extrapolateToCone(); k = " << k << "\n";
564  }
565 
566  dest = pos + k * dir;
567  // debugOut << "In cone extrapolation ";
568  // dest.Print();
569 
570  plane->setO(dest);
571  plane->setUV((dest-conePoint).Cross(coneDirection), dest-conePoint);
572 
573  tracklength += this->Extrap(startPlane, *plane, charge, mass, isAtBoundary, state7, flightTime, false, nullptr, true, stopAtBoundary, maxStep);
574 
575  // check break conditions
576  if (stopAtBoundary && isAtBoundary) {
577  pos.SetXYZ(state7[0], state7[1], state7[2]);
578  dir.SetXYZ(state7[3], state7[4], state7[5]);
579  plane->setO(pos);
580  plane->setUV((pos-conePoint).Cross(coneDirection), pos-conePoint);
581  break;
582  }
583 
584  if(fabs(k)<MINSTEP) break;
585 
586  startPlane = *plane;
587 
588  }
589 
590  if (fillExtrapSteps) { // now do the full extrapolation with covariance matrix
591  // make use of the cache
592  lastEndState_.setPlane(plane);
593  getState5(lastEndState_, state7);
594 
595  tracklength = extrapolateToPlane(state, plane, false, true);
596  lastEndState_.getAuxInfo()(1) = state.getAuxInfo()(1); // Flight time
597  }
598  else {
599  state.setPlane(plane);
600  getState5(state, state7);
601  state.getAuxInfo()(1) += flightTime;
602  }
603 
604  lastEndState_ = state;
605 
606  return tracklength;
607 }
608 
609 
611  double radius,
612  const TVector3& point, // center
613  bool stopAtBoundary,
614  bool calcJacobianNoise) const {
615 
616  if (debugLvl_ > 0) {
617  debugOut << "RKTrackRep::extrapolateToSphere()\n";
618  }
619 
620  checkCache(state, nullptr);
621 
622  static const unsigned int maxIt(1000);
623 
624  // to 7D
625  M1x7 state7;
626  getState7(state, state7);
627 
628  bool fillExtrapSteps(false);
629  if (dynamic_cast<MeasuredStateOnPlane*>(&state) != nullptr) {
630  fillExtrapSteps = true;
631  }
632  else if (calcJacobianNoise)
633  fillExtrapSteps = true;
634 
635  double tracklength(0.), maxStep(1.E99);
636 
637  TVector3 dest, pos, dir;
638 
639  bool isAtBoundary(false);
640 
641  DetPlane startPlane(*(state.getPlane()));
642  SharedPlanePtr plane(new DetPlane());
643  unsigned int iterations(0);
644  double charge = getCharge(state);
645  double mass = getMass(state);
646  double flightTime = 0;
647 
648  while(true){
649  if(++iterations == maxIt) {
650  Exception exc("RKTrackRep::extrapolateToSphere ==> maximum number of iterations reached",__LINE__,__FILE__);
651  exc.setFatal();
652  throw exc;
653  }
654 
655  pos.SetXYZ(state7[0], state7[1], state7[2]);
656  dir.SetXYZ(state7[3], state7[4], state7[5]);
657 
658  // solve quadratic equation
659  TVector3 AO = (pos - point);
660  double dirAO = dir * AO;
661  double arg = dirAO*dirAO - AO*AO + radius*radius;
662  if(arg < 0) {
663  Exception exc("RKTrackRep::extrapolateToSphere ==> cannot solve",__LINE__,__FILE__);
664  exc.setFatal();
665  throw exc;
666  }
667  double term = sqrt(arg);
668  double k1, k2;
669  k1 = -dirAO + term;
670  k2 = -dirAO - term;
671 
672  // select smallest absolute solution -> closest cylinder surface
673  double k = k1;
674  if (fabs(k2)<fabs(k))
675  k = k2;
676 
677  if (debugLvl_ > 0) {
678  debugOut << "RKTrackRep::extrapolateToSphere(); k = " << k << "\n";
679  }
680 
681  dest = pos + k * dir;
682 
683  plane->setON(dest, dest-point);
684 
685  tracklength += this->Extrap(startPlane, *plane, charge, mass, isAtBoundary, state7, flightTime, false, nullptr, true, stopAtBoundary, maxStep);
686 
687  // check break conditions
688  if (stopAtBoundary && isAtBoundary) {
689  pos.SetXYZ(state7[0], state7[1], state7[2]);
690  dir.SetXYZ(state7[3], state7[4], state7[5]);
691  plane->setON(pos, pos-point);
692  break;
693  }
694 
695  if(fabs(k)<MINSTEP) break;
696 
697  startPlane = *plane;
698 
699  }
700 
701  if (fillExtrapSteps) { // now do the full extrapolation with covariance matrix
702  // make use of the cache
703  lastEndState_.setPlane(plane);
704  getState5(lastEndState_, state7);
705 
706  tracklength = extrapolateToPlane(state, plane, false, true);
707  lastEndState_.getAuxInfo()(1) = state.getAuxInfo()(1); // Flight time
708  }
709  else {
710  state.setPlane(plane);
711  getState5(state, state7);
712  state.getAuxInfo()(1) += flightTime;
713  }
714 
715  lastEndState_ = state;
716 
717  return tracklength;
718 }
719 
720 
722  double step,
723  bool stopAtBoundary,
724  bool calcJacobianNoise) const {
725 
726  if (debugLvl_ > 0) {
727  debugOut << "RKTrackRep::extrapolateBy()\n";
728  }
729 
730  checkCache(state, nullptr);
731 
732  static const unsigned int maxIt(1000);
733 
734  // to 7D
735  M1x7 state7;
736  getState7(state, state7);
737 
738  bool fillExtrapSteps(false);
739  if (dynamic_cast<MeasuredStateOnPlane*>(&state) != nullptr) {
740  fillExtrapSteps = true;
741  }
742  else if (calcJacobianNoise)
743  fillExtrapSteps = true;
744 
745  double tracklength(0.);
746 
747  TVector3 dest, pos, dir;
748 
749  bool isAtBoundary(false);
750 
751  DetPlane startPlane(*(state.getPlane()));
752  SharedPlanePtr plane(new DetPlane());
753  unsigned int iterations(0);
754  double charge = getCharge(state);
755  double mass = getMass(state);
756  double flightTime = 0;
757 
758  while(true){
759  if(++iterations == maxIt) {
760  Exception exc("RKTrackRep::extrapolateBy ==> maximum number of iterations reached",__LINE__,__FILE__);
761  exc.setFatal();
762  throw exc;
763  }
764 
765  pos.SetXYZ(state7[0], state7[1], state7[2]);
766  dir.SetXYZ(state7[3], state7[4], state7[5]);
767 
768  dest = pos + 1.5*(step-tracklength) * dir;
769 
770  plane->setON(dest, dir);
771 
772  tracklength += this->Extrap(startPlane, *plane, charge, mass, isAtBoundary, state7, flightTime, false, nullptr, true, stopAtBoundary, (step-tracklength));
773 
774  // check break conditions
775  if (stopAtBoundary && isAtBoundary) {
776  pos.SetXYZ(state7[0], state7[1], state7[2]);
777  dir.SetXYZ(state7[3], state7[4], state7[5]);
778  plane->setON(pos, dir);
779  break;
780  }
781 
782  if (fabs(tracklength-step) < MINSTEP) {
783  if (debugLvl_ > 0) {
784  debugOut << "RKTrackRep::extrapolateBy(): reached after " << iterations << " iterations. \n";
785  }
786  pos.SetXYZ(state7[0], state7[1], state7[2]);
787  dir.SetXYZ(state7[3], state7[4], state7[5]);
788  plane->setON(pos, dir);
789  break;
790  }
791 
792  startPlane = *plane;
793 
794  }
795 
796  if (fillExtrapSteps) { // now do the full extrapolation with covariance matrix
797  // make use of the cache
798  lastEndState_.setPlane(plane);
799  getState5(lastEndState_, state7);
800 
801  tracklength = extrapolateToPlane(state, plane, false, true);
802  lastEndState_.getAuxInfo()(1) = state.getAuxInfo()(1); // Flight time
803  }
804  else {
805  state.setPlane(plane);
806  getState5(state, state7);
807  state.getAuxInfo()(1) += flightTime;
808  }
809 
810  lastEndState_ = state;
811 
812  return tracklength;
813 }
814 
815 
816 TVector3 RKTrackRep::getPos(const StateOnPlane& state) const {
817  M1x7 state7;
818  getState7(state, state7);
819 
820  return TVector3(state7[0], state7[1], state7[2]);
821 }
822 
823 
824 TVector3 RKTrackRep::getMom(const StateOnPlane& state) const {
825  M1x7 state7 = {{0, 0, 0, 0, 0, 0, 0}};
826  getState7(state, state7);
827 
828  TVector3 mom(state7[3], state7[4], state7[5]);
829  mom.SetMag(getCharge(state)/state7[6]);
830  return mom;
831 }
832 
833 
834 void RKTrackRep::getPosMom(const StateOnPlane& state, TVector3& pos, TVector3& mom) const {
835  M1x7 state7 = {{0, 0, 0, 0, 0, 0, 0}};
836  getState7(state, state7);
837 
838  pos.SetXYZ(state7[0], state7[1], state7[2]);
839  mom.SetXYZ(state7[3], state7[4], state7[5]);
840  mom.SetMag(getCharge(state)/state7[6]);
841 }
842 
843 
844 void RKTrackRep::getPosMomCov(const MeasuredStateOnPlane& state, TVector3& pos, TVector3& mom, TMatrixDSym& cov) const {
845  getPosMom(state, pos, mom);
846  cov.ResizeTo(6,6);
847  transformPM6(state, *((M6x6*) cov.GetMatrixArray()));
848 }
849 
850 
851 TMatrixDSym RKTrackRep::get6DCov(const MeasuredStateOnPlane& state) const {
852  TMatrixDSym cov(6);
853  transformPM6(state, *((M6x6*) cov.GetMatrixArray()));
854 
855  return cov;
856 }
857 
858 
859 double RKTrackRep::getCharge(const StateOnPlane& state) const {
860 
861  if (dynamic_cast<const MeasurementOnPlane*>(&state) != nullptr) {
862  Exception exc("RKTrackRep::getCharge - cannot get charge from MeasurementOnPlane",__LINE__,__FILE__);
863  exc.setFatal();
864  throw exc;
865  }
866 
867  double pdgCharge( this->getPDGCharge() );
868 
869  // return pdgCharge with sign of q/p
870  if (state.getState()(0) * pdgCharge < 0)
871  return -pdgCharge;
872  else
873  return pdgCharge;
874 }
875 
876 
877 double RKTrackRep::getMomMag(const StateOnPlane& state) const {
878  // p = q / qop
879  double p = getCharge(state)/state.getState()(0);
880  assert (p>=0);
881  return p;
882 }
883 
884 
885 double RKTrackRep::getMomVar(const MeasuredStateOnPlane& state) const {
886 
887  if (dynamic_cast<const MeasurementOnPlane*>(&state) != nullptr) {
888  Exception exc("RKTrackRep::getMomVar - cannot get momVar from MeasurementOnPlane",__LINE__,__FILE__);
889  exc.setFatal();
890  throw exc;
891  }
892 
893  // p(qop) = q/qop
894  // dp/d(qop) = - q / (qop^2)
895  // (delta p) = (delta qop) * |dp/d(qop)| = delta qop * |q / (qop^2)|
896  // (var p) = (var qop) * q^2 / (qop^4)
897 
898  // delta means sigma
899  // cov(0,0) is sigma^2
900 
901  return state.getCov()(0,0) * pow(getCharge(state), 2) / pow(state.getState()(0), 4);
902 }
903 
904 
905 double RKTrackRep::getSpu(const StateOnPlane& state) const {
906 
907  if (dynamic_cast<const MeasurementOnPlane*>(&state) != nullptr) {
908  Exception exc("RKTrackRep::getSpu - cannot get spu from MeasurementOnPlane",__LINE__,__FILE__);
909  exc.setFatal();
910  throw exc;
911  }
912 
913  const TVectorD& auxInfo = state.getAuxInfo();
914  if (auxInfo.GetNrows() == 2
915  || auxInfo.GetNrows() == 1) // backwards compatibility with old RKTrackRep
916  return state.getAuxInfo()(0);
917  else
918  return 1.;
919 }
920 
921 double RKTrackRep::getTime(const StateOnPlane& state) const {
922 
923  const TVectorD& auxInfo = state.getAuxInfo();
924  if (auxInfo.GetNrows() == 2)
925  return state.getAuxInfo()(1);
926  else
927  return 0.;
928 }
929 
930 
931 void RKTrackRep::calcForwardJacobianAndNoise(const M1x7& startState7, const DetPlane& startPlane,
932  const M1x7& destState7, const DetPlane& destPlane) const {
933 
934  if (debugLvl_ > 0) {
935  debugOut << "RKTrackRep::calcForwardJacobianAndNoise " << std::endl;
936  }
937 
938  if (ExtrapSteps_.size() == 0) {
939  Exception exc("RKTrackRep::calcForwardJacobianAndNoise ==> cache is empty. Extrapolation must run with a MeasuredStateOnPlane.",__LINE__,__FILE__);
940  throw exc;
941  }
942 
943  // The Jacobians returned from RKutta are transposed.
944  TMatrixD jac(TMatrixD::kTransposed, TMatrixD(7, 7, ExtrapSteps_.back().jac7_.begin()));
945  TMatrixDSym noise(7, ExtrapSteps_.back().noise7_.begin());
946  for (int i = ExtrapSteps_.size() - 2; i >= 0; --i) {
947  noise += TMatrixDSym(7, ExtrapSteps_[i].noise7_.begin()).Similarity(jac);
948  jac *= TMatrixD(TMatrixD::kTransposed, TMatrixD(7, 7, ExtrapSteps_[i].jac7_.begin()));
949  }
950 
951  // Project into 5x5 space.
952  M1x3 pTilde = {{startState7[3], startState7[4], startState7[5]}};
953  const TVector3& normal = startPlane.getNormal();
954  double pTildeW = pTilde[0] * normal.X() + pTilde[1] * normal.Y() + pTilde[2] * normal.Z();
955  double spu = pTildeW > 0 ? 1 : -1;
956  for (unsigned int i=0; i<3; ++i) {
957  pTilde[i] *= spu/pTildeW; // | pTilde * W | has to be 1 (definition of pTilde)
958  }
959  M5x7 J_pM;
960  calcJ_pM_5x7(J_pM, startPlane.getU(), startPlane.getV(), pTilde, spu);
961  M7x5 J_Mp;
962  calcJ_Mp_7x5(J_Mp, destPlane.getU(), destPlane.getV(), destPlane.getNormal(), *((M1x3*) &destState7[3]));
963  jac.Transpose(jac); // Because the helper function wants transposed input.
964  RKTools::J_pMTTxJ_MMTTxJ_MpTT(J_Mp, *(M7x7 *)jac.GetMatrixArray(),
965  J_pM, *(M5x5 *)fJacobian_.GetMatrixArray());
966  RKTools::J_MpTxcov7xJ_Mp(J_Mp, *(M7x7 *)noise.GetMatrixArray(),
967  *(M5x5 *)fNoise_.GetMatrixArray());
968 
969  if (debugLvl_ > 0) {
970  debugOut << "total jacobian : "; fJacobian_.Print();
971  debugOut << "total noise : "; fNoise_.Print();
972  }
973 
974 }
975 
976 
977 void RKTrackRep::getForwardJacobianAndNoise(TMatrixD& jacobian, TMatrixDSym& noise, TVectorD& deltaState) const {
978 
979  jacobian.ResizeTo(5,5);
980  jacobian = fJacobian_;
981 
982  noise.ResizeTo(5,5);
983  noise = fNoise_;
984 
985  // lastEndState_ = jacobian * lastStartState_ + deltaState
986  deltaState.ResizeTo(5);
987  // Calculate this without temporaries:
988  //deltaState = lastEndState_.getState() - jacobian * lastStartState_.getState()
989  deltaState = lastStartState_.getState();
990  deltaState *= jacobian;
991  deltaState -= lastEndState_.getState();
992  deltaState *= -1;
993 
994 
995  if (debugLvl_ > 0) {
996  debugOut << "delta state : "; deltaState.Print();
997  }
998 }
999 
1000 
1001 void RKTrackRep::getBackwardJacobianAndNoise(TMatrixD& jacobian, TMatrixDSym& noise, TVectorD& deltaState) const {
1002 
1003  if (debugLvl_ > 0) {
1004  debugOut << "RKTrackRep::getBackwardJacobianAndNoise " << std::endl;
1005  }
1006 
1007  if (ExtrapSteps_.size() == 0) {
1008  Exception exc("RKTrackRep::getBackwardJacobianAndNoise ==> cache is empty. Extrapolation must run with a MeasuredStateOnPlane.",__LINE__,__FILE__);
1009  throw exc;
1010  }
1011 
1012  jacobian.ResizeTo(5,5);
1013  jacobian = fJacobian_;
1014  if (!useInvertFast) {
1015  bool status = TDecompLU::InvertLU(jacobian, 0.0);
1016  if(status == 0){
1017  Exception e("cannot invert matrix, status = 0", __LINE__,__FILE__);
1018  e.setFatal();
1019  throw e;
1020  }
1021  } else {
1022  double det;
1023  jacobian.InvertFast(&det);
1024  if(det < 1e-80){
1025  Exception e("cannot invert matrix, status = 0", __LINE__,__FILE__);
1026  e.setFatal();
1027  throw e;
1028  }
1029  }
1030 
1031  noise.ResizeTo(5,5);
1032  noise = fNoise_;
1033  noise.Similarity(jacobian);
1034 
1035  // lastStartState_ = jacobian * lastEndState_ + deltaState
1036  deltaState.ResizeTo(5);
1037  deltaState = lastStartState_.getState() - jacobian * lastEndState_.getState();
1038 }
1039 
1040 
1041 std::vector<genfit::MatStep> RKTrackRep::getSteps() const {
1042 
1043  // Todo: test
1044 
1045  if (RKSteps_.size() == 0) {
1046  Exception exc("RKTrackRep::getSteps ==> cache is empty.",__LINE__,__FILE__);
1047  throw exc;
1048  }
1049 
1050  std::vector<MatStep> retVal;
1051  retVal.reserve(RKSteps_.size());
1052 
1053  for (unsigned int i = 0; i<RKSteps_.size(); ++i) {
1054  retVal.push_back(RKSteps_[i].matStep_);
1055  }
1056 
1057  return retVal;
1058 }
1059 
1060 
1062 
1063  // Todo: test
1064 
1065  if (RKSteps_.size() == 0) {
1066  Exception exc("RKTrackRep::getRadiationLenght ==> cache is empty.",__LINE__,__FILE__);
1067  throw exc;
1068  }
1069 
1070  double radLen(0);
1071 
1072  for (unsigned int i = 0; i<RKSteps_.size(); ++i) {
1073  radLen += RKSteps_.at(i).matStep_.stepSize_ / RKSteps_.at(i).matStep_.material_.radiationLength;
1074  }
1075 
1076  return radLen;
1077 }
1078 
1079 
1080 
1081 void RKTrackRep::setPosMom(StateOnPlane& state, const TVector3& pos, const TVector3& mom) const {
1082 
1083  if (state.getRep() != this){
1084  Exception exc("RKTrackRep::setPosMom ==> state is defined wrt. another TrackRep",__LINE__,__FILE__);
1085  throw exc;
1086  }
1087 
1088  if (dynamic_cast<MeasurementOnPlane*>(&state) != nullptr) {
1089  Exception exc("RKTrackRep::setPosMom - cannot set pos/mom of a MeasurementOnPlane",__LINE__,__FILE__);
1090  exc.setFatal();
1091  throw exc;
1092  }
1093 
1094  if (mom.Mag2() == 0) {
1095  Exception exc("RKTrackRep::setPosMom - momentum is 0",__LINE__,__FILE__);
1096  exc.setFatal();
1097  throw exc;
1098  }
1099 
1100  // init auxInfo if that has not yet happened
1101  TVectorD& auxInfo = state.getAuxInfo();
1102  if (auxInfo.GetNrows() != 2) {
1103  bool alreadySet = auxInfo.GetNrows() == 1; // backwards compatibility: don't overwrite old setting
1104  auxInfo.ResizeTo(2);
1105  if (!alreadySet)
1106  setSpu(state, 1.);
1107  }
1108 
1109  if (state.getPlane() != nullptr && state.getPlane()->distance(pos) < MINSTEP) { // pos is on plane -> do not change plane!
1110 
1111  M1x7 state7;
1112 
1113  state7[0] = pos.X();
1114  state7[1] = pos.Y();
1115  state7[2] = pos.Z();
1116 
1117  state7[3] = mom.X();
1118  state7[4] = mom.Y();
1119  state7[5] = mom.Z();
1120 
1121  // normalize dir
1122  double norm = 1. / sqrt(state7[3]*state7[3] + state7[4]*state7[4] + state7[5]*state7[5]);
1123  for (unsigned int i=3; i<6; ++i)
1124  state7[i] *= norm;
1125 
1126  state7[6] = getCharge(state) * norm;
1127 
1128  getState5(state, state7);
1129 
1130  }
1131  else { // pos is not on plane -> create new plane!
1132 
1133  // TODO: Raise Warning that a new plane has been created!
1134  SharedPlanePtr plane(new DetPlane(pos, mom));
1135  state.setPlane(plane);
1136 
1137  TVectorD& state5(state.getState());
1138 
1139  state5(0) = getCharge(state)/mom.Mag(); // q/p
1140  state5(1) = 0.; // u'
1141  state5(2) = 0.; // v'
1142  state5(3) = 0.; // u
1143  state5(4) = 0.; // v
1144 
1145  setSpu(state, 1.);
1146  }
1147 
1148 }
1149 
1150 
1151 void RKTrackRep::setPosMom(StateOnPlane& state, const TVectorD& state6) const {
1152  if (state6.GetNrows()!=6){
1153  Exception exc("RKTrackRep::setPosMom ==> state has to be 6d (x, y, z, px, py, pz)",__LINE__,__FILE__);
1154  throw exc;
1155  }
1156  setPosMom(state, TVector3(state6(0), state6(1), state6(2)), TVector3(state6(3), state6(4), state6(5)));
1157 }
1158 
1159 
1160 void RKTrackRep::setPosMomErr(MeasuredStateOnPlane& state, const TVector3& pos, const TVector3& mom, const TVector3& posErr, const TVector3& momErr) const {
1161 
1162  // TODO: test!
1163 
1164  setPosMom(state, pos, mom);
1165 
1166  const TVector3& U(state.getPlane()->getU());
1167  const TVector3& V(state.getPlane()->getV());
1168  TVector3 W(state.getPlane()->getNormal());
1169 
1170  double pw = mom * W;
1171  double pu = mom * U;
1172  double pv = mom * V;
1173 
1174  TMatrixDSym& cov(state.getCov());
1175 
1176  cov(0,0) = pow(getCharge(state), 2) / pow(mom.Mag(), 6) *
1177  (mom.X()*mom.X() * momErr.X()*momErr.X()+
1178  mom.Y()*mom.Y() * momErr.Y()*momErr.Y()+
1179  mom.Z()*mom.Z() * momErr.Z()*momErr.Z());
1180 
1181  cov(1,1) = pow((U.X()/pw - W.X()*pu/(pw*pw)),2.) * momErr.X()*momErr.X() +
1182  pow((U.Y()/pw - W.Y()*pu/(pw*pw)),2.) * momErr.Y()*momErr.Y() +
1183  pow((U.Z()/pw - W.Z()*pu/(pw*pw)),2.) * momErr.Z()*momErr.Z();
1184 
1185  cov(2,2) = pow((V.X()/pw - W.X()*pv/(pw*pw)),2.) * momErr.X()*momErr.X() +
1186  pow((V.Y()/pw - W.Y()*pv/(pw*pw)),2.) * momErr.Y()*momErr.Y() +
1187  pow((V.Z()/pw - W.Z()*pv/(pw*pw)),2.) * momErr.Z()*momErr.Z();
1188 
1189  cov(3,3) = posErr.X()*posErr.X() * U.X()*U.X() +
1190  posErr.Y()*posErr.Y() * U.Y()*U.Y() +
1191  posErr.Z()*posErr.Z() * U.Z()*U.Z();
1192 
1193  cov(4,4) = posErr.X()*posErr.X() * V.X()*V.X() +
1194  posErr.Y()*posErr.Y() * V.Y()*V.Y() +
1195  posErr.Z()*posErr.Z() * V.Z()*V.Z();
1196 
1197 }
1198 
1199 
1200 
1201 
1202 void RKTrackRep::setPosMomCov(MeasuredStateOnPlane& state, const TVector3& pos, const TVector3& mom, const TMatrixDSym& cov6x6) const {
1203 
1204  if (cov6x6.GetNcols()!=6 || cov6x6.GetNrows()!=6){
1205  Exception exc("RKTrackRep::setPosMomCov ==> cov has to be 6x6 (x, y, z, px, py, pz)",__LINE__,__FILE__);
1206  throw exc;
1207  }
1208 
1209  setPosMom(state, pos, mom); // charge does not change!
1210 
1211  M1x7 state7;
1212  getState7(state, state7);
1213 
1214  const M6x6& cov6x6_( *((M6x6*) cov6x6.GetMatrixArray()) );
1215 
1216  transformM6P(cov6x6_, state7, state);
1217 
1218 }
1219 
1220 void RKTrackRep::setPosMomCov(MeasuredStateOnPlane& state, const TVectorD& state6, const TMatrixDSym& cov6x6) const {
1221 
1222  if (state6.GetNrows()!=6){
1223  Exception exc("RKTrackRep::setPosMomCov ==> state has to be 6d (x, y, z, px, py, pz)",__LINE__,__FILE__);
1224  throw exc;
1225  }
1226 
1227  if (cov6x6.GetNcols()!=6 || cov6x6.GetNrows()!=6){
1228  Exception exc("RKTrackRep::setPosMomCov ==> cov has to be 6x6 (x, y, z, px, py, pz)",__LINE__,__FILE__);
1229  throw exc;
1230  }
1231 
1232  TVector3 pos(state6(0), state6(1), state6(2));
1233  TVector3 mom(state6(3), state6(4), state6(5));
1234  setPosMom(state, pos, mom); // charge does not change!
1235 
1236  M1x7 state7;
1237  getState7(state, state7);
1238 
1239  const M6x6& cov6x6_( *((M6x6*) cov6x6.GetMatrixArray()) );
1240 
1241  transformM6P(cov6x6_, state7, state);
1242 
1243 }
1244 
1245 
1246 void RKTrackRep::setChargeSign(StateOnPlane& state, double charge) const {
1247 
1248  if (dynamic_cast<MeasurementOnPlane*>(&state) != nullptr) {
1249  Exception exc("RKTrackRep::setChargeSign - cannot set charge of a MeasurementOnPlane",__LINE__,__FILE__);
1250  exc.setFatal();
1251  throw exc;
1252  }
1253 
1254  if (state.getState()(0) * charge < 0) {
1255  state.getState()(0) *= -1.;
1256  }
1257 }
1258 
1259 
1260 void RKTrackRep::setSpu(StateOnPlane& state, double spu) const {
1261  state.getAuxInfo().ResizeTo(2);
1262  (state.getAuxInfo())(0) = spu;
1263 }
1264 
1265 void RKTrackRep::setTime(StateOnPlane& state, double time) const {
1266  state.getAuxInfo().ResizeTo(2);
1267  (state.getAuxInfo())(1) = time;
1268 }
1269 
1270 
1271 
1273  M7x7* jacobianT,
1274  M1x3& SA,
1275  double S,
1276  bool varField,
1277  bool calcOnlyLastRowOfJ) const {
1278  // The algorithm is
1279  // E Lund et al 2009 JINST 4 P04001 doi:10.1088/1748-0221/4/04/P04001
1280  // "Track parameter propagation through the application of a new adaptive Runge-Kutta-Nyström method in the ATLAS experiment"
1281  // http://inspirehep.net/search?ln=en&ln=en&p=10.1088/1748-0221/4/04/P04001&of=hb&action_search=Search&sf=earliestdate&so=d&rm=&rg=25&sc=0
1282  // where the transport of the Jacobian is described in
1283  // L. Bugge, J. Myrheim Nucl.Instrum.Meth. 160 (1979) 43-48
1284  // "A Fast Runge-kutta Method For Fitting Tracks In A Magnetic Field"
1285  // http://inspirehep.net/record/145692
1286  // and
1287  // L. Bugge, J. Myrheim Nucl.Instrum.Meth. 179 (1981) 365-381
1288  // "Tracking And Track Fitting"
1289  // http://inspirehep.net/record/160548
1290 
1291  // important fixed numbers
1292  static const double EC ( 0.000149896229 ); // c/(2*10^12) resp. c/2Tera
1293  static const double P3 ( 1./3. ); // 1/3
1294  static const double DLT ( .0002 ); // max. deviation for approximation-quality test
1295  // Aux parameters
1296  M1x3& R = *((M1x3*) &state7[0]); // Start coordinates [cm] (x, y, z)
1297  M1x3& A = *((M1x3*) &state7[3]); // Start directions (ax, ay, az); ax^2+ay^2+az^2=1
1298  double S3(0), S4(0), PS2(0);
1299  M1x3 H0 = {{0.,0.,0.}}, H1 = {{0.,0.,0.}}, H2 = {{0.,0.,0.}};
1300  M1x3 r = {{0.,0.,0.}};
1301  // Variables for Runge Kutta solver
1302  double A0(0), A1(0), A2(0), A3(0), A4(0), A5(0), A6(0);
1303  double B0(0), B1(0), B2(0), B3(0), B4(0), B5(0), B6(0);
1304  double C0(0), C1(0), C2(0), C3(0), C4(0), C5(0), C6(0);
1305 
1306  //
1307  // Runge Kutta Extrapolation
1308  //
1309  S3 = P3*S;
1310  S4 = 0.25*S;
1311  PS2 = state7[6]*EC * S;
1312 
1313  // First point
1314  r[0] = R[0]; r[1] = R[1]; r[2]=R[2];
1315  FieldManager::getInstance()->getFieldVal(r[0], r[1], r[2], H0[0], H0[1], H0[2]); // magnetic field in 10^-1 T = kGauss
1316  H0[0] *= PS2; H0[1] *= PS2; H0[2] *= PS2; // H0 is PS2*(Hx, Hy, Hz) @ R0
1317  A0 = A[1]*H0[2]-A[2]*H0[1]; B0 = A[2]*H0[0]-A[0]*H0[2]; C0 = A[0]*H0[1]-A[1]*H0[0]; // (ax, ay, az) x H0
1318  A2 = A[0]+A0 ; B2 = A[1]+B0 ; C2 = A[2]+C0 ; // (A0, B0, C0) + (ax, ay, az)
1319  A1 = A2+A[0] ; B1 = B2+A[1] ; C1 = C2+A[2] ; // (A0, B0, C0) + 2*(ax, ay, az)
1320 
1321  // Second point
1322  if (varField) {
1323  r[0] += A1*S4; r[1] += B1*S4; r[2] += C1*S4;
1324  FieldManager::getInstance()->getFieldVal(r[0], r[1], r[2], H1[0], H1[1], H1[2]);
1325  H1[0] *= PS2; H1[1] *= PS2; H1[2] *= PS2; // H1 is PS2*(Hx, Hy, Hz) @ (x, y, z) + 0.25*S * [(A0, B0, C0) + 2*(ax, ay, az)]
1326  }
1327  else { H1 = H0; };
1328  A3 = B2*H1[2]-C2*H1[1]+A[0]; B3 = C2*H1[0]-A2*H1[2]+A[1]; C3 = A2*H1[1]-B2*H1[0]+A[2]; // (A2, B2, C2) x H1 + (ax, ay, az)
1329  A4 = B3*H1[2]-C3*H1[1]+A[0]; B4 = C3*H1[0]-A3*H1[2]+A[1]; C4 = A3*H1[1]-B3*H1[0]+A[2]; // (A3, B3, C3) x H1 + (ax, ay, az)
1330  A5 = A4-A[0]+A4 ; B5 = B4-A[1]+B4 ; C5 = C4-A[2]+C4 ; // 2*(A4, B4, C4) - (ax, ay, az)
1331 
1332  // Last point
1333  if (varField) {
1334  r[0]=R[0]+S*A4; r[1]=R[1]+S*B4; r[2]=R[2]+S*C4; //setup.Field(r,H2);
1335  FieldManager::getInstance()->getFieldVal(r[0], r[1], r[2], H2[0], H2[1], H2[2]);
1336  H2[0] *= PS2; H2[1] *= PS2; H2[2] *= PS2; // H2 is PS2*(Hx, Hy, Hz) @ (x, y, z) + 0.25*S * (A4, B4, C4)
1337  }
1338  else { H2 = H0; };
1339  A6 = B5*H2[2]-C5*H2[1]; B6 = C5*H2[0]-A5*H2[2]; C6 = A5*H2[1]-B5*H2[0]; // (A5, B5, C5) x H2
1340 
1341 
1342  //
1343  // Derivatives of track parameters
1344  //
1345  if(jacobianT != nullptr){
1346 
1347  // jacobianT
1348  // 1 0 0 0 0 0 0 x
1349  // 0 1 0 0 0 0 0 y
1350  // 0 0 1 0 0 0 0 z
1351  // x x x x x x 0 a_x
1352  // x x x x x x 0 a_y
1353  // x x x x x x 0 a_z
1354  // x x x x x x 1 q/p
1355  M7x7& J = *jacobianT;
1356 
1357  double dA0(0), dA2(0), dA3(0), dA4(0), dA5(0), dA6(0);
1358  double dB0(0), dB2(0), dB3(0), dB4(0), dB5(0), dB6(0);
1359  double dC0(0), dC2(0), dC3(0), dC4(0), dC5(0), dC6(0);
1360 
1361  int start(0);
1362 
1363  if (!calcOnlyLastRowOfJ) {
1364 
1365  if (!varField) {
1366  // d(x, y, z)/d(x, y, z) submatrix is unit matrix
1367  J(0, 0) = 1; J(1, 1) = 1; J(2, 2) = 1;
1368  // d(ax, ay, az)/d(ax, ay, az) submatrix is 0
1369  // start with d(x, y, z)/d(ax, ay, az)
1370  start = 3;
1371  }
1372 
1373  for(int i=start; i<6; ++i) {
1374 
1375  //first point
1376  dA0 = H0[2]*J(i, 4)-H0[1]*J(i, 5); // dA0/dp }
1377  dB0 = H0[0]*J(i, 5)-H0[2]*J(i, 3); // dB0/dp } = dA x H0
1378  dC0 = H0[1]*J(i, 3)-H0[0]*J(i, 4); // dC0/dp }
1379 
1380  dA2 = dA0+J(i, 3); // }
1381  dB2 = dB0+J(i, 4); // } = (dA0, dB0, dC0) + dA
1382  dC2 = dC0+J(i, 5); // }
1383 
1384  //second point
1385  dA3 = J(i, 3)+dB2*H1[2]-dC2*H1[1]; // dA3/dp }
1386  dB3 = J(i, 4)+dC2*H1[0]-dA2*H1[2]; // dB3/dp } = dA + (dA2, dB2, dC2) x H1
1387  dC3 = J(i, 5)+dA2*H1[1]-dB2*H1[0]; // dC3/dp }
1388 
1389  dA4 = J(i, 3)+dB3*H1[2]-dC3*H1[1]; // dA4/dp }
1390  dB4 = J(i, 4)+dC3*H1[0]-dA3*H1[2]; // dB4/dp } = dA + (dA3, dB3, dC3) x H1
1391  dC4 = J(i, 5)+dA3*H1[1]-dB3*H1[0]; // dC4/dp }
1392 
1393  //last point
1394  dA5 = dA4+dA4-J(i, 3); // }
1395  dB5 = dB4+dB4-J(i, 4); // } = 2*(dA4, dB4, dC4) - dA
1396  dC5 = dC4+dC4-J(i, 5); // }
1397 
1398  dA6 = dB5*H2[2]-dC5*H2[1]; // dA6/dp }
1399  dB6 = dC5*H2[0]-dA5*H2[2]; // dB6/dp } = (dA5, dB5, dC5) x H2
1400  dC6 = dA5*H2[1]-dB5*H2[0]; // dC6/dp }
1401 
1402  // this gives the same results as multiplying the old with the new Jacobian
1403  J(i, 0) += (dA2+dA3+dA4)*S3; J(i, 3) = ((dA0+2.*dA3)+(dA5+dA6))*P3; // dR := dR + S3*[(dA2, dB2, dC2) + (dA3, dB3, dC3) + (dA4, dB4, dC4)]
1404  J(i, 1) += (dB2+dB3+dB4)*S3; J(i, 4) = ((dB0+2.*dB3)+(dB5+dB6))*P3; // dA := 1/3*[(dA0, dB0, dC0) + 2*(dA3, dB3, dC3) + (dA5, dB5, dC5) + (dA6, dB6, dC6)]
1405  J(i, 2) += (dC2+dC3+dC4)*S3; J(i, 5) = ((dC0+2.*dC3)+(dC5+dC6))*P3;
1406  }
1407 
1408  } // end if (!calcOnlyLastRowOfJ)
1409 
1410  J(6, 3) *= state7[6]; J(6, 4) *= state7[6]; J(6, 5) *= state7[6];
1411 
1412  //first point
1413  dA0 = H0[2]*J(6, 4)-H0[1]*J(6, 5) + A0; // dA0/dp }
1414  dB0 = H0[0]*J(6, 5)-H0[2]*J(6, 3) + B0; // dB0/dp } = dA x H0 + (A0, B0, C0)
1415  dC0 = H0[1]*J(6, 3)-H0[0]*J(6, 4) + C0; // dC0/dp }
1416 
1417  dA2 = dA0+J(6, 3); // }
1418  dB2 = dB0+J(6, 4); // } = (dA0, dB0, dC0) + dA
1419  dC2 = dC0+J(6, 5); // }
1420 
1421  //second point
1422  dA3 = J(6, 3)+dB2*H1[2]-dC2*H1[1] + (A3-A[0]); // dA3/dp }
1423  dB3 = J(6, 4)+dC2*H1[0]-dA2*H1[2] + (B3-A[1]); // dB3/dp } = dA + (dA2, dB2, dC2) x H1
1424  dC3 = J(6, 5)+dA2*H1[1]-dB2*H1[0] + (C3-A[2]); // dC3/dp }
1425 
1426  dA4 = J(6, 3)+dB3*H1[2]-dC3*H1[1] + (A4-A[0]); // dA4/dp }
1427  dB4 = J(6, 4)+dC3*H1[0]-dA3*H1[2] + (B4-A[1]); // dB4/dp } = dA + (dA3, dB3, dC3) x H1
1428  dC4 = J(6, 5)+dA3*H1[1]-dB3*H1[0] + (C4-A[2]); // dC4/dp }
1429 
1430  //last point
1431  dA5 = dA4+dA4-J(6, 3); // }
1432  dB5 = dB4+dB4-J(6, 4); // } = 2*(dA4, dB4, dC4) - dA
1433  dC5 = dC4+dC4-J(6, 5); // }
1434 
1435  dA6 = dB5*H2[2]-dC5*H2[1] + A6; // dA6/dp }
1436  dB6 = dC5*H2[0]-dA5*H2[2] + B6; // dB6/dp } = (dA5, dB5, dC5) x H2 + (A6, B6, C6)
1437  dC6 = dA5*H2[1]-dB5*H2[0] + C6; // dC6/dp }
1438 
1439  // this gives the same results as multiplying the old with the new Jacobian
1440  J(6, 0) += (dA2+dA3+dA4)*S3/state7[6]; J(6, 3) = ((dA0+2.*dA3)+(dA5+dA6))*P3/state7[6]; // dR := dR + S3*[(dA2, dB2, dC2) + (dA3, dB3, dC3) + (dA4, dB4, dC4)]
1441  J(6, 1) += (dB2+dB3+dB4)*S3/state7[6]; J(6, 4) = ((dB0+2.*dB3)+(dB5+dB6))*P3/state7[6]; // dA := 1/3*[(dA0, dB0, dC0) + 2*(dA3, dB3, dC3) + (dA5, dB5, dC5) + (dA6, dB6, dC6)]
1442  J(6, 2) += (dC2+dC3+dC4)*S3/state7[6]; J(6, 5) = ((dC0+2.*dC3)+(dC5+dC6))*P3/state7[6];
1443 
1444  }
1445 
1446  //
1447  // Track parameters in last point
1448  //
1449  R[0] += (A2+A3+A4)*S3; A[0] += (SA[0]=((A0+2.*A3)+(A5+A6))*P3-A[0]); // R = R0 + S3*[(A2, B2, C2) + (A3, B3, C3) + (A4, B4, C4)]
1450  R[1] += (B2+B3+B4)*S3; A[1] += (SA[1]=((B0+2.*B3)+(B5+B6))*P3-A[1]); // A = 1/3*[(A0, B0, C0) + 2*(A3, B3, C3) + (A5, B5, C5) + (A6, B6, C6)]
1451  R[2] += (C2+C3+C4)*S3; A[2] += (SA[2]=((C0+2.*C3)+(C5+C6))*P3-A[2]); // SA = A_new - A_old
1452 
1453  // normalize A
1454  double CBA ( 1./sqrt(A[0]*A[0]+A[1]*A[1]+A[2]*A[2]) ); // 1/|A|
1455  A[0] *= CBA; A[1] *= CBA; A[2] *= CBA;
1456 
1457 
1458  // Test approximation quality on given step
1459  double EST ( fabs((A1+A6)-(A3+A4)) +
1460  fabs((B1+B6)-(B3+B4)) +
1461  fabs((C1+C6)-(C3+C4)) ); // EST = ||(ABC1+ABC6)-(ABC3+ABC4)||_1 = ||(axzy x H0 + ABC5 x H2) - (ABC2 x H1 + ABC3 x H1)||_1
1462  if (debugLvl_ > 0) {
1463  debugOut << " RKTrackRep::RKPropagate. Step = "<< S << "; quality EST = " << EST << " \n";
1464  }
1465 
1466  // Prevent the step length increase from getting too large, this is
1467  // just the point where it becomes 10.
1468  if (EST < DLT*1e-5)
1469  return 10;
1470 
1471  // Step length increase for a fifth order Runge-Kutta, see e.g. 17.2
1472  // in Numerical Recipes. FIXME: move to caller.
1473  return pow(DLT/EST, 1./5.);
1474 }
1475 
1476 
1477 
1478 void RKTrackRep::initArrays() const {
1479  std::fill(noiseArray_.begin(), noiseArray_.end(), 0);
1480  std::fill(noiseProjection_.begin(), noiseProjection_.end(), 0);
1481  for (unsigned int i=0; i<7; ++i) // initialize as diagonal matrix
1482  noiseProjection_[i*8] = 1;
1483  std::fill(J_MMT_.begin(), J_MMT_.end(), 0);
1484 
1485  fJacobian_.UnitMatrix();
1486  fNoise_.Zero();
1487  limits_.reset();
1488 
1489  RKSteps_.reserve(100);
1490  ExtrapSteps_.reserve(100);
1491 
1492  lastStartState_.getAuxInfo().ResizeTo(2);
1493  lastEndState_.getAuxInfo().ResizeTo(2);
1494 }
1495 
1496 
1497 void RKTrackRep::getState7(const StateOnPlane& state, M1x7& state7) const {
1498 
1499  if (dynamic_cast<const MeasurementOnPlane*>(&state) != nullptr) {
1500  Exception exc("RKTrackRep::getState7 - cannot get pos or mom from a MeasurementOnPlane",__LINE__,__FILE__);
1501  exc.setFatal();
1502  throw exc;
1503  }
1504 
1505  const TVector3& U(state.getPlane()->getU());
1506  const TVector3& V(state.getPlane()->getV());
1507  const TVector3& O(state.getPlane()->getO());
1508  const TVector3& W(state.getPlane()->getNormal());
1509 
1510  assert(state.getState().GetNrows() == 5);
1511  const double* state5 = state.getState().GetMatrixArray();
1512 
1513  double spu = getSpu(state);
1514 
1515  state7[0] = O.X() + state5[3]*U.X() + state5[4]*V.X(); // x
1516  state7[1] = O.Y() + state5[3]*U.Y() + state5[4]*V.Y(); // y
1517  state7[2] = O.Z() + state5[3]*U.Z() + state5[4]*V.Z(); // z
1518 
1519  state7[3] = spu * (W.X() + state5[1]*U.X() + state5[2]*V.X()); // a_x
1520  state7[4] = spu * (W.Y() + state5[1]*U.Y() + state5[2]*V.Y()); // a_y
1521  state7[5] = spu * (W.Z() + state5[1]*U.Z() + state5[2]*V.Z()); // a_z
1522 
1523  // normalize dir
1524  double norm = 1. / sqrt(state7[3]*state7[3] + state7[4]*state7[4] + state7[5]*state7[5]);
1525  for (unsigned int i=3; i<6; ++i) state7[i] *= norm;
1526 
1527  state7[6] = state5[0]; // q/p
1528 }
1529 
1530 
1531 void RKTrackRep::getState5(StateOnPlane& state, const M1x7& state7) const {
1532 
1533  // state5: (q/p, u', v'. u, v)
1534 
1535  double spu(1.);
1536 
1537  const TVector3& O(state.getPlane()->getO());
1538  const TVector3& U(state.getPlane()->getU());
1539  const TVector3& V(state.getPlane()->getV());
1540  const TVector3& W(state.getPlane()->getNormal());
1541 
1542  // force A to be in normal direction and set spu accordingly
1543  double AtW( state7[3]*W.X() + state7[4]*W.Y() + state7[5]*W.Z() );
1544  if (AtW < 0.) {
1545  //fDir *= -1.;
1546  //AtW *= -1.;
1547  spu = -1.;
1548  }
1549 
1550  double* state5 = state.getState().GetMatrixArray();
1551 
1552  state5[0] = state7[6]; // q/p
1553  state5[1] = (state7[3]*U.X() + state7[4]*U.Y() + state7[5]*U.Z()) / AtW; // u' = (A * U) / (A * W)
1554  state5[2] = (state7[3]*V.X() + state7[4]*V.Y() + state7[5]*V.Z()) / AtW; // v' = (A * V) / (A * W)
1555  state5[3] = ((state7[0]-O.X())*U.X() +
1556  (state7[1]-O.Y())*U.Y() +
1557  (state7[2]-O.Z())*U.Z()); // u = (pos - O) * U
1558  state5[4] = ((state7[0]-O.X())*V.X() +
1559  (state7[1]-O.Y())*V.Y() +
1560  (state7[2]-O.Z())*V.Z()); // v = (pos - O) * V
1561 
1562  setSpu(state, spu);
1563 
1564 }
1565 
1566 void RKTrackRep::calcJ_pM_5x7(M5x7& J_pM, const TVector3& U, const TVector3& V, const M1x3& pTilde, double spu) const {
1567  /*if (debugLvl_ > 1) {
1568  debugOut << "RKTrackRep::calcJ_pM_5x7 \n";
1569  debugOut << " U = "; U.Print();
1570  debugOut << " V = "; V.Print();
1571  debugOut << " pTilde = "; RKTools::printDim(pTilde, 3,1);
1572  debugOut << " spu = " << spu << "\n";
1573  }*/
1574 
1575  std::fill(J_pM.begin(), J_pM.end(), 0);
1576 
1577  const double pTildeMag = sqrt(pTilde[0]*pTilde[0] + pTilde[1]*pTilde[1] + pTilde[2]*pTilde[2]);
1578  const double pTildeMag2 = pTildeMag*pTildeMag;
1579 
1580  const double utpTildeOverpTildeMag2 = (U.X()*pTilde[0] + U.Y()*pTilde[1] + U.Z()*pTilde[2]) / pTildeMag2;
1581  const double vtpTildeOverpTildeMag2 = (V.X()*pTilde[0] + V.Y()*pTilde[1] + V.Z()*pTilde[2]) / pTildeMag2;
1582 
1583  //J_pM matrix is d(x,y,z,ax,ay,az,q/p) / d(q/p,u',v',u,v) (out is 7x7)
1584 
1585  // d(x,y,z)/d(u)
1586  J_pM[21] = U.X(); // [3][0]
1587  J_pM[22] = U.Y(); // [3][1]
1588  J_pM[23] = U.Z(); // [3][2]
1589  // d(x,y,z)/d(v)
1590  J_pM[28] = V.X(); // [4][0]
1591  J_pM[29] = V.Y(); // [4][1]
1592  J_pM[30] = V.Z(); // [4][2]
1593  // d(q/p)/d(q/p)
1594  J_pM[6] = 1.; // not needed for array matrix multiplication
1595  // d(ax,ay,az)/d(u')
1596  double fact = spu / pTildeMag;
1597  J_pM[10] = fact * ( U.X() - pTilde[0]*utpTildeOverpTildeMag2 ); // [1][3]
1598  J_pM[11] = fact * ( U.Y() - pTilde[1]*utpTildeOverpTildeMag2 ); // [1][4]
1599  J_pM[12] = fact * ( U.Z() - pTilde[2]*utpTildeOverpTildeMag2 ); // [1][5]
1600  // d(ax,ay,az)/d(v')
1601  J_pM[17] = fact * ( V.X() - pTilde[0]*vtpTildeOverpTildeMag2 ); // [2][3]
1602  J_pM[18] = fact * ( V.Y() - pTilde[1]*vtpTildeOverpTildeMag2 ); // [2][4]
1603  J_pM[19] = fact * ( V.Z() - pTilde[2]*vtpTildeOverpTildeMag2 ); // [2][5]
1604 
1605  /*if (debugLvl_ > 1) {
1606  debugOut << " J_pM_5x7_ = "; RKTools::printDim(J_pM_5x7_, 5,7);
1607  }*/
1608 }
1609 
1610 
1611 void RKTrackRep::transformPM6(const MeasuredStateOnPlane& state,
1612  M6x6& out6x6) const {
1613 
1614  // get vectors and aux variables
1615  const TVector3& U(state.getPlane()->getU());
1616  const TVector3& V(state.getPlane()->getV());
1617  const TVector3& W(state.getPlane()->getNormal());
1618 
1619  const TVectorD& state5(state.getState());
1620  double spu(getSpu(state));
1621 
1622  M1x3 pTilde;
1623  pTilde[0] = spu * (W.X() + state5(1)*U.X() + state5(2)*V.X()); // a_x
1624  pTilde[1] = spu * (W.Y() + state5(1)*U.Y() + state5(2)*V.Y()); // a_y
1625  pTilde[2] = spu * (W.Z() + state5(1)*U.Z() + state5(2)*V.Z()); // a_z
1626 
1627  const double pTildeMag = sqrt(pTilde[0]*pTilde[0] + pTilde[1]*pTilde[1] + pTilde[2]*pTilde[2]);
1628  const double pTildeMag2 = pTildeMag*pTildeMag;
1629 
1630  const double utpTildeOverpTildeMag2 = (U.X()*pTilde[0] + U.Y()*pTilde[1] + U.Z()*pTilde[2]) / pTildeMag2;
1631  const double vtpTildeOverpTildeMag2 = (V.X()*pTilde[0] + V.Y()*pTilde[1] + V.Z()*pTilde[2]) / pTildeMag2;
1632 
1633  //J_pM matrix is d(x,y,z,px,py,pz) / d(q/p,u',v',u,v) (out is 6x6)
1634 
1635  const double qop = state5(0);
1636  const double p = getCharge(state)/qop; // momentum
1637 
1638  M5x6 J_pM_5x6;
1639  std::fill(J_pM_5x6.begin(), J_pM_5x6.end(), 0);
1640 
1641  // d(px,py,pz)/d(q/p)
1642  double fact = -1. * p / (pTildeMag * qop);
1643  J_pM_5x6[3] = fact * pTilde[0]; // [0][3]
1644  J_pM_5x6[4] = fact * pTilde[1]; // [0][4]
1645  J_pM_5x6[5] = fact * pTilde[2]; // [0][5]
1646  // d(px,py,pz)/d(u')
1647  fact = p * spu / pTildeMag;
1648  J_pM_5x6[9] = fact * ( U.X() - pTilde[0]*utpTildeOverpTildeMag2 ); // [1][3]
1649  J_pM_5x6[10] = fact * ( U.Y() - pTilde[1]*utpTildeOverpTildeMag2 ); // [1][4]
1650  J_pM_5x6[11] = fact * ( U.Z() - pTilde[2]*utpTildeOverpTildeMag2 ); // [1][5]
1651  // d(px,py,pz)/d(v')
1652  J_pM_5x6[15] = fact * ( V.X() - pTilde[0]*vtpTildeOverpTildeMag2 ); // [2][3]
1653  J_pM_5x6[16] = fact * ( V.Y() - pTilde[1]*vtpTildeOverpTildeMag2 ); // [2][4]
1654  J_pM_5x6[17] = fact * ( V.Z() - pTilde[2]*vtpTildeOverpTildeMag2 ); // [2][5]
1655  // d(x,y,z)/d(u)
1656  J_pM_5x6[18] = U.X(); // [3][0]
1657  J_pM_5x6[19] = U.Y(); // [3][1]
1658  J_pM_5x6[20] = U.Z(); // [3][2]
1659  // d(x,y,z)/d(v)
1660  J_pM_5x6[24] = V.X(); // [4][0]
1661  J_pM_5x6[25] = V.Y(); // [4][1]
1662  J_pM_5x6[26] = V.Z(); // [4][2]
1663 
1664 
1665  // do the transformation
1666  // out = J_pM^T * in5x5 * J_pM
1667  const M5x5& in5x5_ = *((M5x5*) state.getCov().GetMatrixArray());
1668  RKTools::J_pMTxcov5xJ_pM(J_pM_5x6, in5x5_, out6x6);
1669 
1670 }
1671 
1672 void RKTrackRep::calcJ_Mp_7x5(M7x5& J_Mp, const TVector3& U, const TVector3& V, const TVector3& W, const M1x3& A) const {
1673 
1674  /*if (debugLvl_ > 1) {
1675  debugOut << "RKTrackRep::calcJ_Mp_7x5 \n";
1676  debugOut << " U = "; U.Print();
1677  debugOut << " V = "; V.Print();
1678  debugOut << " W = "; W.Print();
1679  debugOut << " A = "; RKTools::printDim(A, 3,1);
1680  }*/
1681 
1682  std::fill(J_Mp.begin(), J_Mp.end(), 0);
1683 
1684  const double AtU = A[0]*U.X() + A[1]*U.Y() + A[2]*U.Z();
1685  const double AtV = A[0]*V.X() + A[1]*V.Y() + A[2]*V.Z();
1686  const double AtW = A[0]*W.X() + A[1]*W.Y() + A[2]*W.Z();
1687 
1688  // J_Mp matrix is d(q/p,u',v',u,v) / d(x,y,z,ax,ay,az,q/p) (in is 7x7)
1689 
1690  // d(u')/d(ax,ay,az)
1691  double fact = 1./(AtW*AtW);
1692  J_Mp[16] = fact * (U.X()*AtW - W.X()*AtU); // [3][1]
1693  J_Mp[21] = fact * (U.Y()*AtW - W.Y()*AtU); // [4][1]
1694  J_Mp[26] = fact * (U.Z()*AtW - W.Z()*AtU); // [5][1]
1695  // d(v')/d(ax,ay,az)
1696  J_Mp[17] = fact * (V.X()*AtW - W.X()*AtV); // [3][2]
1697  J_Mp[22] = fact * (V.Y()*AtW - W.Y()*AtV); // [4][2]
1698  J_Mp[27] = fact * (V.Z()*AtW - W.Z()*AtV); // [5][2]
1699  // d(q/p)/d(q/p)
1700  J_Mp[30] = 1.; // [6][0] - not needed for array matrix multiplication
1701  //d(u)/d(x,y,z)
1702  J_Mp[3] = U.X(); // [0][3]
1703  J_Mp[8] = U.Y(); // [1][3]
1704  J_Mp[13] = U.Z(); // [2][3]
1705  //d(v)/d(x,y,z)
1706  J_Mp[4] = V.X(); // [0][4]
1707  J_Mp[9] = V.Y(); // [1][4]
1708  J_Mp[14] = V.Z(); // [2][4]
1709 
1710  /*if (debugLvl_ > 1) {
1711  debugOut << " J_Mp_7x5_ = "; RKTools::printDim(J_Mp, 7,5);
1712  }*/
1713 
1714 }
1715 
1716 
1717 void RKTrackRep::transformM6P(const M6x6& in6x6,
1718  const M1x7& state7,
1719  MeasuredStateOnPlane& state) const { // plane and charge must already be set!
1720 
1721  // get vectors and aux variables
1722  const TVector3& U(state.getPlane()->getU());
1723  const TVector3& V(state.getPlane()->getV());
1724  const TVector3& W(state.getPlane()->getNormal());
1725 
1726  const double AtU = state7[3]*U.X() + state7[4]*U.Y() + state7[5]*U.Z();
1727  const double AtV = state7[3]*V.X() + state7[4]*V.Y() + state7[5]*V.Z();
1728  const double AtW = state7[3]*W.X() + state7[4]*W.Y() + state7[5]*W.Z();
1729 
1730  // J_Mp matrix is d(q/p,u',v',u,v) / d(x,y,z,px,py,pz) (in is 6x6)
1731 
1732  const double qop = state7[6];
1733  const double p = getCharge(state)/qop; // momentum
1734 
1735  M6x5 J_Mp_6x5;
1736  std::fill(J_Mp_6x5.begin(), J_Mp_6x5.end(), 0);
1737 
1738  //d(u)/d(x,y,z)
1739  J_Mp_6x5[3] = U.X(); // [0][3]
1740  J_Mp_6x5[8] = U.Y(); // [1][3]
1741  J_Mp_6x5[13] = U.Z(); // [2][3]
1742  //d(v)/d(x,y,z)
1743  J_Mp_6x5[4] = V.X(); // [0][4]
1744  J_Mp_6x5[9] = V.Y(); // [1][4]
1745  J_Mp_6x5[14] = V.Z(); // [2][4]
1746  // d(q/p)/d(px,py,pz)
1747  double fact = (-1.) * qop / p;
1748  J_Mp_6x5[15] = fact * state7[3]; // [3][0]
1749  J_Mp_6x5[20] = fact * state7[4]; // [4][0]
1750  J_Mp_6x5[25] = fact * state7[5]; // [5][0]
1751  // d(u')/d(px,py,pz)
1752  fact = 1./(p*AtW*AtW);
1753  J_Mp_6x5[16] = fact * (U.X()*AtW - W.X()*AtU); // [3][1]
1754  J_Mp_6x5[21] = fact * (U.Y()*AtW - W.Y()*AtU); // [4][1]
1755  J_Mp_6x5[26] = fact * (U.Z()*AtW - W.Z()*AtU); // [5][1]
1756  // d(v')/d(px,py,pz)
1757  J_Mp_6x5[17] = fact * (V.X()*AtW - W.X()*AtV); // [3][2]
1758  J_Mp_6x5[22] = fact * (V.Y()*AtW - W.Y()*AtV); // [4][2]
1759  J_Mp_6x5[27] = fact * (V.Z()*AtW - W.Z()*AtV); // [5][2]
1760 
1761  // do the transformation
1762  // out5x5 = J_Mp^T * in * J_Mp
1763  M5x5& out5x5_ = *((M5x5*) state.getCov().GetMatrixArray());
1764  RKTools::J_MpTxcov6xJ_Mp(J_Mp_6x5, in6x6, out5x5_);
1765 
1766 }
1767 
1768 
1769 //
1770 // Runge-Kutta method for tracking a particles through a magnetic field.
1771 // Uses Nystroem algorithm (See Handbook Nat. Bur. of Standards, procedure 25.5.20)
1772 // in the way described in
1773 // E Lund et al 2009 JINST 4 P04001 doi:10.1088/1748-0221/4/04/P04001
1774 // "Track parameter propagation through the application of a new adaptive Runge-Kutta-Nyström method in the ATLAS experiment"
1775 // http://inspirehep.net/search?ln=en&ln=en&p=10.1088/1748-0221/4/04/P04001&of=hb&action_search=Search&sf=earliestdate&so=d&rm=&rg=25&sc=0
1776 //
1777 // Input parameters:
1778 // SU - plane parameters
1779 // SU[0] - direction cosines normal to surface Ex
1780 // SU[1] - ------- Ey
1781 // SU[2] - ------- Ez; Ex*Ex+Ey*Ey+Ez*Ez=1
1782 // SU[3] - distance to surface from (0,0,0) > 0 cm
1783 //
1784 // state7 - initial parameters (coordinates(cm), direction,
1785 // charge/momentum (Gev-1)
1786 // cov and derivatives this parameters (7x7)
1787 //
1788 // X Y Z Ax Ay Az q/P
1789 // state7[0] state7[1] state7[2] state7[3] state7[4] state7[5] state7[6]
1790 //
1791 // dX/dp dY/dp dZ/dp dAx/dp dAy/dp dAz/dp d(q/P)/dp
1792 // cov[ 0] cov[ 1] cov[ 2] cov[ 3] cov[ 4] cov[ 5] cov[ 6] d()/dp1
1793 //
1794 // cov[ 7] cov[ 8] cov[ 9] cov[10] cov[11] cov[12] cov[13] d()/dp2
1795 // ............................................................................ d()/dpND
1796 //
1797 // Authors: R.Brun, M.Hansroul, V.Perevoztchikov (Geant3)
1798 //
1799 bool RKTrackRep::RKutta(const M1x4& SU,
1800  const DetPlane& plane,
1801  double charge,
1802  double mass,
1803  M1x7& state7,
1804  M7x7* jacobianT,
1805  M1x7* J_MMT_unprojected_lastRow,
1806  double& coveredDistance,
1807  double& flightTime,
1808  bool& checkJacProj,
1809  M7x7& noiseProjection,
1810  StepLimits& limits,
1811  bool onlyOneStep,
1812  bool calcOnlyLastRowOfJ) const {
1813 
1814  // limits, check-values, etc. Can be tuned!
1815  static const double Wmax ( 3000. ); // max. way allowed [cm]
1816  static const double AngleMax ( 6.3 ); // max. total angle change of momentum. Prevents extrapolating a curler round and round if no active plane is found.
1817  static const double Pmin ( 4.E-3 ); // minimum momentum for propagation [GeV]
1818  static const unsigned int maxNumIt ( 1000 ); // maximum number of iterations in main loop
1819  // Aux parameters
1820  M1x3& R ( *((M1x3*) &state7[0]) ); // Start coordinates [cm] (x, y, z)
1821  M1x3& A ( *((M1x3*) &state7[3]) ); // Start directions (ax, ay, az); ax^2+ay^2+az^2=1
1822  M1x3 SA = {{0.,0.,0.}}; // Start directions derivatives dA/S
1823  double Way ( 0. ); // Sum of absolute values of all extrapolation steps [cm]
1824  double momentum ( fabs(charge/state7[6]) ); // momentum [GeV]
1825  double relMomLoss ( 0 ); // relative momentum loss in RKutta
1826  double deltaAngle ( 0. ); // total angle by which the momentum has changed during extrapolation
1827  double An(0), S(0), Sl(0), CBA(0);
1828 
1829 
1830  if (debugLvl_ > 0) {
1831  debugOut << "RKTrackRep::RKutta \n";
1832  debugOut << "position: "; TVector3(R[0], R[1], R[2]).Print();
1833  debugOut << "direction: "; TVector3(A[0], A[1], A[2]).Print();
1834  debugOut << "momentum: " << momentum << " GeV\n";
1835  debugOut << "destination: "; plane.Print();
1836  }
1837 
1838  checkJacProj = false;
1839 
1840  // check momentum
1841  if(momentum < Pmin){
1842  std::ostringstream sstream;
1843  sstream << "RKTrackRep::RKutta ==> momentum too low: " << momentum*1000. << " MeV";
1844  Exception exc(sstream.str(),__LINE__,__FILE__);
1845  exc.setFatal();
1846  throw exc;
1847  }
1848 
1849  unsigned int counter(0);
1850 
1851  // Step estimation (signed)
1852  S = estimateStep(state7, SU, plane, charge, relMomLoss, limits);
1853 
1854  //
1855  // Main loop of Runge-Kutta method
1856  //
1857  while (fabs(S) >= MINSTEP || counter == 0) {
1858 
1859  if(++counter > maxNumIt){
1860  Exception exc("RKTrackRep::RKutta ==> maximum number of iterations exceeded",__LINE__,__FILE__);
1861  exc.setFatal();
1862  throw exc;
1863  }
1864 
1865  if (debugLvl_ > 0) {
1866  debugOut << "------ RKutta main loop nr. " << counter-1 << " ------\n";
1867  }
1868 
1869  M1x3 ABefore = {{ A[0], A[1], A[2] }};
1870  RKPropagate(state7, jacobianT, SA, S, true, calcOnlyLastRowOfJ); // the actual Runge Kutta propagation
1871 
1872  // update paths
1873  coveredDistance += S; // add stepsize to way (signed)
1874  Way += fabs(S);
1875 
1876  double beta = 1/hypot(1, mass*state7[6]/charge);
1877  flightTime += S / beta / 29.9792458; // in ns
1878 
1879  // check way limit
1880  if(Way > Wmax){
1881  std::ostringstream sstream;
1882  sstream << "RKTrackRep::RKutta ==> Total extrapolation length is longer than length limit : " << Way << " cm !";
1883  Exception exc(sstream.str(),__LINE__,__FILE__);
1884  exc.setFatal();
1885  throw exc;
1886  }
1887 
1888  if (onlyOneStep) return(true);
1889 
1890  // if stepsize has been limited by material, break the loop and return. No linear extrapolation!
1891  if (limits.getLowestLimit().first == stp_momLoss) {
1892  if (debugLvl_ > 0) {
1893  debugOut<<" momLossExceeded -> return(true); \n";
1894  }
1895  return(true);
1896  }
1897 
1898  // if stepsize has been limited by material boundary, break the loop and return. No linear extrapolation!
1899  if (limits.getLowestLimit().first == stp_boundary) {
1900  if (debugLvl_ > 0) {
1901  debugOut<<" at boundary -> return(true); \n";
1902  }
1903  return(true);
1904  }
1905 
1906 
1907  // estimate Step for next loop or linear extrapolation
1908  Sl = S; // last S used
1909  limits.removeLimit(stp_fieldCurv);
1910  limits.removeLimit(stp_momLoss);
1911  limits.removeLimit(stp_boundary);
1912  limits.removeLimit(stp_plane);
1913  S = estimateStep(state7, SU, plane, charge, relMomLoss, limits);
1914 
1915  if (limits.getLowestLimit().first == stp_plane &&
1916  fabs(S) < MINSTEP) {
1917  if (debugLvl_ > 0) {
1918  debugOut<<" (at Plane && fabs(S) < MINSTEP) -> break and do linear extrapolation \n";
1919  }
1920  break;
1921  }
1922  if (limits.getLowestLimit().first == stp_momLoss &&
1923  fabs(S) < MINSTEP) {
1924  if (debugLvl_ > 0) {
1925  debugOut<<" (momLossExceeded && fabs(S) < MINSTEP) -> return(true), no linear extrapolation; \n";
1926  }
1927  RKSteps_.erase(RKSteps_.end()-1);
1928  --RKStepsFXStop_;
1929  return(true); // no linear extrapolation!
1930  }
1931 
1932  // check if total angle is bigger than AngleMax. Can happen if a curler should be fitted and it does not hit the active area of the next plane.
1933  double arg = ABefore[0]*A[0] + ABefore[1]*A[1] + ABefore[2]*A[2];
1934  arg = arg > 1 ? 1 : arg;
1935  arg = arg < -1 ? -1 : arg;
1936  deltaAngle += acos(arg);
1937  if (fabs(deltaAngle) > AngleMax){
1938  std::ostringstream sstream;
1939  sstream << "RKTrackRep::RKutta ==> Do not get to an active plane! Already extrapolated " << deltaAngle * 180 / TMath::Pi() << "°.";
1940  Exception exc(sstream.str(),__LINE__,__FILE__);
1941  exc.setFatal();
1942  throw exc;
1943  }
1944 
1945  // check if we went back and forth multiple times -> we don't come closer to the plane!
1946  if (counter > 3){
1947  if (S *RKSteps_.at(counter-1).matStep_.stepSize_ < 0 &&
1948  RKSteps_.at(counter-1).matStep_.stepSize_*RKSteps_.at(counter-2).matStep_.stepSize_ < 0 &&
1949  RKSteps_.at(counter-2).matStep_.stepSize_*RKSteps_.at(counter-3).matStep_.stepSize_ < 0){
1950  Exception exc("RKTrackRep::RKutta ==> Do not get closer to plane!",__LINE__,__FILE__);
1951  exc.setFatal();
1952  throw exc;
1953  }
1954  }
1955 
1956  } //end of main loop
1957 
1958 
1959  //
1960  // linear extrapolation to plane
1961  //
1962  if (limits.getLowestLimit().first == stp_plane) {
1963 
1964  if (fabs(Sl) > 0.001*MINSTEP){
1965  if (debugLvl_ > 0) {
1966  debugOut << " RKutta - linear extrapolation to surface\n";
1967  }
1968  Sl = 1./Sl; // Sl = inverted last Stepsize Sl
1969 
1970  // normalize SA
1971  SA[0]*=Sl; SA[1]*=Sl; SA[2]*=Sl; // SA/Sl = delta A / delta way; local derivative of A with respect to the length of the way
1972 
1973  // calculate A
1974  A[0] += SA[0]*S; // S = distance to surface
1975  A[1] += SA[1]*S; // A = A + S * SA*Sl
1976  A[2] += SA[2]*S;
1977 
1978  // normalize A
1979  CBA = 1./sqrt(A[0]*A[0]+A[1]*A[1]+A[2]*A[2]); // 1/|A|
1980  A[0] *= CBA; A[1] *= CBA; A[2] *= CBA;
1981 
1982  R[0] += S*(A[0]-0.5*S*SA[0]); // R = R + S*(A - 0.5*S*SA); approximation for final point on surface
1983  R[1] += S*(A[1]-0.5*S*SA[1]);
1984  R[2] += S*(A[2]-0.5*S*SA[2]);
1985 
1986 
1987  coveredDistance += S;
1988  Way += fabs(S);
1989 
1990  double beta = 1/hypot(1, mass*state7[6]/charge);
1991  flightTime += S / beta / 29.9792458; // in ns;
1992  }
1993  else if (debugLvl_ > 0) {
1994  debugOut << " RKutta - last stepsize too small -> can't do linear extrapolation! \n";
1995  }
1996 
1997  //
1998  // Project Jacobian of extrapolation onto destination plane
1999  //
2000  if (jacobianT != nullptr) {
2001 
2002  // projected jacobianT
2003  // x x x x x x 0
2004  // x x x x x x 0
2005  // x x x x x x 0
2006  // x x x x x x 0
2007  // x x x x x x 0
2008  // x x x x x x 0
2009  // x x x x x x 1
2010 
2011  if (checkJacProj && RKSteps_.size()>0){
2012  Exception exc("RKTrackRep::Extrap ==> covariance is projected onto destination plane again",__LINE__,__FILE__);
2013  throw exc;
2014  }
2015 
2016  if (debugLvl_ > 0) {
2017  //debugOut << " Jacobian^T of extrapolation before Projection:\n";
2018  //RKTools::printDim(*jacobianT, 7,7);
2019  debugOut << " Project Jacobian of extrapolation onto destination plane\n";
2020  }
2021  An = A[0]*SU[0] + A[1]*SU[1] + A[2]*SU[2];
2022  An = (fabs(An) > 1.E-7 ? 1./An : 0); // 1/A_normal
2023  double norm;
2024  int i=0;
2025  if (calcOnlyLastRowOfJ)
2026  i = 42;
2027 
2028  double* jacPtr = jacobianT->begin();
2029 
2030  for(unsigned int j=42; j<49; j+=7) {
2031  (*J_MMT_unprojected_lastRow)[j-42] = jacPtr[j];
2032  }
2033 
2034  for(; i<49; i+=7) {
2035  norm = (jacPtr[i]*SU[0] + jacPtr[i+1]*SU[1] + jacPtr[i+2]*SU[2]) * An; // dR_normal / A_normal
2036  jacPtr[i] -= norm*A [0]; jacPtr[i+1] -= norm*A [1]; jacPtr[i+2] -= norm*A [2];
2037  jacPtr[i+3] -= norm*SA[0]; jacPtr[i+4] -= norm*SA[1]; jacPtr[i+5] -= norm*SA[2];
2038  }
2039  checkJacProj = true;
2040 
2041 
2042  if (debugLvl_ > 0) {
2043  //debugOut << " Jacobian^T of extrapolation after Projection:\n";
2044  //RKTools::printDim(*jacobianT, 7,7);
2045  }
2046 
2047  if (!calcOnlyLastRowOfJ) {
2048  for (int iRow = 0; iRow < 3; ++iRow) {
2049  for (int iCol = 0; iCol < 3; ++iCol) {
2050  noiseProjection[iRow*7 + iCol] = (iRow == iCol) - An * SU[iCol] * A[iRow];
2051  noiseProjection[(iRow + 3)*7 + iCol] = - An * SU[iCol] * SA[iRow];
2052  }
2053  }
2054 
2055  // noiseProjection will look like this:
2056  // x x x 0 0 0 0
2057  // x x x 0 0 0 0
2058  // x x x 0 0 0 0
2059  // x x x 1 0 0 0
2060  // x x x 0 1 0 0
2061  // x x x 0 0 1 0
2062  // 0 0 0 0 0 0 1
2063  }
2064 
2065  }
2066  } // end of linear extrapolation to surface
2067 
2068  return(true);
2069 
2070 }
2071 
2072 
2073 double RKTrackRep::estimateStep(const M1x7& state7,
2074  const M1x4& SU,
2075  const DetPlane& plane,
2076  const double& charge,
2077  double& relMomLoss,
2078  StepLimits& limits) const {
2079 
2080  if (useCache_) {
2081  if (cachePos_ >= RKSteps_.size()) {
2082  useCache_ = false;
2083  }
2084  else {
2085  if (RKSteps_.at(cachePos_).limits_.getLowestLimit().first == stp_plane) {
2086  // we need to step exactly to the plane, so don't use the cache!
2087  useCache_ = false;
2088  RKSteps_.erase(RKSteps_.begin() + cachePos_, RKSteps_.end());
2089  }
2090  else {
2091  if (debugLvl_ > 0) {
2092  debugOut << " RKTrackRep::estimateStep: use stepSize " << cachePos_ << " from cache: " << RKSteps_.at(cachePos_).matStep_.stepSize_ << "\n";
2093  }
2094  //for(int n = 0; n < 1*7; ++n) RKSteps_[cachePos_].state7_[n] = state7[n];
2095  ++RKStepsFXStop_;
2096  limits = RKSteps_.at(cachePos_).limits_;
2097  return RKSteps_.at(cachePos_++).matStep_.stepSize_;
2098  }
2099  }
2100  }
2101 
2102  limits.setLimit(stp_sMax, 25.); // max. step allowed [cm]
2103 
2104  if (debugLvl_ > 0) {
2105  debugOut << " RKTrackRep::estimateStep \n";
2106  debugOut << " position: "; TVector3(state7[0], state7[1], state7[2]).Print();
2107  debugOut << " direction: "; TVector3(state7[3], state7[4], state7[5]).Print();
2108  }
2109 
2110  // calculate SL distance to surface
2111  double Dist ( SU[3] - (state7[0]*SU[0] +
2112  state7[1]*SU[1] +
2113  state7[2]*SU[2]) ); // Distance between start coordinates and surface
2114  double An ( state7[3]*SU[0] +
2115  state7[4]*SU[1] +
2116  state7[5]*SU[2] ); // An = dir * N; component of dir normal to surface
2117 
2118  double SLDist; // signed
2119  if (fabs(An) > 1.E-10)
2120  SLDist = Dist/An;
2121  else {
2122  SLDist = Dist*1.E10;
2123  if (An<0) SLDist *= -1.;
2124  }
2125 
2126  limits.setLimit(stp_plane, SLDist);
2127  limits.setStepSign(SLDist);
2128 
2129  if (debugLvl_ > 0) {
2130  debugOut << " Distance to plane: " << Dist << "\n";
2131  debugOut << " SL distance to plane: " << SLDist << "\n";
2132  if (limits.getStepSign()>0)
2133  debugOut << " Direction is pointing towards surface.\n";
2134  else
2135  debugOut << " Direction is pointing away from surface.\n";
2136  }
2137  // DONE calculate SL distance to surface
2138 
2139  //
2140  // Limit according to curvature and magnetic field inhomogenities
2141  // and improve stepsize estimation to reach plane
2142  //
2143  double fieldCurvLimit( limits.getLowestLimitSignedVal() ); // signed
2144  std::pair<double, double> distVsStep (9.E99, 9.E99); // first: smallest straight line distances to plane; second: RK steps
2145 
2146  static const unsigned int maxNumIt = 10;
2147  unsigned int counter(0);
2148 
2149  while (fabs(fieldCurvLimit) > MINSTEP) {
2150 
2151  if(++counter > maxNumIt){
2152  // if max iterations are reached, take a safe value
2153  // (in previous iteration, fieldCurvLimit has been not more than doubled)
2154  // and break.
2155  fieldCurvLimit *= 0.5;
2156  break;
2157  }
2158 
2159  M1x7 state7_temp = state7;
2160  M1x3 SA = {{0, 0, 0}};
2161 
2162  double q ( RKPropagate(state7_temp, nullptr, SA, fieldCurvLimit, true) );
2163  if (debugLvl_ > 0) {
2164  debugOut << " maxStepArg = " << fieldCurvLimit << "; q = " << q << " \n";
2165  }
2166 
2167  // remember steps and resulting SL distances to plane for stepsize improvement
2168  // calculate distance to surface
2169  Dist = SU[3] - (state7_temp[0] * SU[0] +
2170  state7_temp[1] * SU[1] +
2171  state7_temp[2] * SU[2]); // Distance between position and surface
2172 
2173  An = state7_temp[3] * SU[0] +
2174  state7_temp[4] * SU[1] +
2175  state7_temp[5] * SU[2]; // An = dir * N; component of dir normal to surface
2176 
2177  if (fabs(Dist/An) < fabs(distVsStep.first)) {
2178  distVsStep.first = Dist/An;
2179  distVsStep.second = fieldCurvLimit;
2180  }
2181 
2182  // resize limit according to q never grow step size more than
2183  // two-fold to avoid infinite grow-shrink loops with strongly
2184  // inhomogeneous fields.
2185  if (q>2) {
2186  fieldCurvLimit *= 2;
2187  break;
2188  }
2189 
2190  fieldCurvLimit *= q * 0.95;
2191 
2192  if (fabs(q-1) < 0.25 || // good enough!
2193  fabs(fieldCurvLimit) > limits.getLowestLimitVal()) // other limits are lower!
2194  break;
2195  }
2196  if (fabs(fieldCurvLimit) < MINSTEP)
2197  limits.setLimit(stp_fieldCurv, MINSTEP);
2198  else
2199  limits.setLimit(stp_fieldCurv, fieldCurvLimit);
2200 
2201  double stepToPlane(limits.getLimitSigned(stp_plane));
2202  if (fabs(distVsStep.first) < 8.E99) {
2203  stepToPlane = distVsStep.first + distVsStep.second;
2204  }
2205  limits.setLimit(stp_plane, stepToPlane);
2206 
2207 
2208  //
2209  // Select direction
2210  //
2211  // auto select
2212  if (propDir_ == 0 || !plane.isFinite()){
2213  if (debugLvl_ > 0) {
2214  debugOut << " auto select direction";
2215  if (!plane.isFinite()) debugOut << ", plane is not finite";
2216  debugOut << ".\n";
2217  }
2218  }
2219  // see if straight line approximation is ok
2220  else if ( limits.getLimit(stp_plane) < 0.2*limits.getLimit(stp_fieldCurv) ){
2221  if (debugLvl_ > 0) {
2222  debugOut << " straight line approximation is fine.\n";
2223  }
2224 
2225  // if direction is pointing to active part of surface
2226  if( plane.isInActive(state7[0], state7[1], state7[2], state7[3], state7[4], state7[5]) ) {
2227  if (debugLvl_ > 0) {
2228  debugOut << " direction is pointing to active part of surface. \n";
2229  }
2230  }
2231  // if we are near the plane, but not pointing to the active area, make a big step!
2232  else {
2233  limits.removeLimit(stp_plane);
2234  limits.setStepSign(propDir_);
2235  if (debugLvl_ > 0) {
2236  debugOut << " we are near the plane, but not pointing to the active area. make a big step! \n";
2237  }
2238  }
2239  }
2240  // propDir_ is set and we are not pointing to an active part of a plane -> propDir_ decides!
2241  else {
2242  if (limits.getStepSign() * propDir_ < 0){
2243  limits.removeLimit(stp_plane);
2244  limits.setStepSign(propDir_);
2245  if (debugLvl_ > 0) {
2246  debugOut << " invert Step according to propDir_ and make a big step. \n";
2247  }
2248  }
2249  }
2250 
2251 
2252  // call stepper and reduce stepsize if step not too small
2253  static const RKStep defaultRKStep;
2254  RKSteps_.push_back( defaultRKStep );
2255  std::vector<RKStep>::iterator lastStep = RKSteps_.end() - 1;
2256  lastStep->state7_ = state7;
2257  ++RKStepsFXStop_;
2258 
2259  if(limits.getLowestLimitVal() > MINSTEP){ // only call stepper if step estimation big enough
2260  M1x7 state7_temp = {{ state7[0], state7[1], state7[2], state7[3], state7[4], state7[5], state7[6] }};
2261 
2262  MaterialEffects::getInstance()->stepper(this,
2263  state7_temp,
2264  charge/state7[6], // |p|
2265  relMomLoss,
2266  pdgCode_,
2267  lastStep->matStep_.material_,
2268  limits,
2269  true);
2270  } else { //assume material has not changed
2271  if (RKSteps_.size()>1) {
2272  lastStep->matStep_.material_ = (lastStep - 1)->matStep_.material_;
2273  }
2274  }
2275 
2276  if (debugLvl_ > 0) {
2277  debugOut << " final limits:\n";
2278  limits.Print();
2279  }
2280 
2281  double finalStep = limits.getLowestLimitSignedVal();
2282 
2283  lastStep->matStep_.stepSize_ = finalStep;
2284  lastStep->limits_ = limits;
2285 
2286  if (debugLvl_ > 0) {
2287  debugOut << " --> Step to be used: " << finalStep << "\n";
2288  }
2289 
2290  return finalStep;
2291 
2292 }
2293 
2294 
2295 TVector3 RKTrackRep::pocaOnLine(const TVector3& linePoint, const TVector3& lineDirection, const TVector3& point) const {
2296 
2297  TVector3 retVal(lineDirection);
2298 
2299  double t = 1./(retVal.Mag2()) * ((point*retVal) - (linePoint*retVal));
2300  retVal *= t;
2301  retVal += linePoint;
2302  return retVal; // = linePoint + t*lineDirection
2303 
2304 }
2305 
2306 
2307 double RKTrackRep::Extrap(const DetPlane& startPlane,
2308  const DetPlane& destPlane,
2309  double charge,
2310  double mass,
2311  bool& isAtBoundary,
2312  M1x7& state7,
2313  double& flightTime,
2314  bool fillExtrapSteps,
2315  TMatrixDSym* cov, // 5D
2316  bool onlyOneStep,
2317  bool stopAtBoundary,
2318  double maxStep) const
2319 {
2320 
2321  static const unsigned int maxNumIt(500);
2322  unsigned int numIt(0);
2323 
2324  double coveredDistance(0.);
2325  double dqop(0.);
2326 
2327  const TVector3 W(destPlane.getNormal());
2328  M1x4 SU = {{W.X(), W.Y(), W.Z(), destPlane.distance(0., 0., 0.)}};
2329 
2330  // make SU vector point away from origin
2331  if (W*destPlane.getO() < 0) {
2332  SU[0] *= -1;
2333  SU[1] *= -1;
2334  SU[2] *= -1;
2335  }
2336 
2337 
2338  M1x7 startState7 = state7;
2339 
2340  while(true){
2341 
2342  if (debugLvl_ > 0) {
2343  debugOut << "\n============ RKTrackRep::Extrap loop nr. " << numIt << " ============\n";
2344  debugOut << "Start plane: "; startPlane.Print();
2345  debugOut << "fillExtrapSteps " << fillExtrapSteps << "\n";
2346  }
2347 
2348  if(++numIt > maxNumIt){
2349  Exception exc("RKTrackRep::Extrap ==> maximum number of iterations exceeded",__LINE__,__FILE__);
2350  exc.setFatal();
2351  throw exc;
2352  }
2353 
2354  // initialize jacobianT with unit matrix
2355  for(int i = 0; i < 7*7; ++i) J_MMT_[i] = 0;
2356  for(int i=0; i<7; ++i) J_MMT_[8*i] = 1.;
2357 
2358  M7x7* noise = nullptr;
2359  isAtBoundary = false;
2360 
2361  // propagation
2362  bool checkJacProj = false;
2363  limits_.reset();
2364  limits_.setLimit(stp_sMaxArg, maxStep-fabs(coveredDistance));
2365 
2366  M1x7 J_MMT_unprojected_lastRow = {{0, 0, 0, 0, 0, 0, 1}};
2367 
2368  if( ! RKutta(SU, destPlane, charge, mass, state7, &J_MMT_, &J_MMT_unprojected_lastRow,
2369  coveredDistance, flightTime, checkJacProj, noiseProjection_,
2370  limits_, onlyOneStep, !fillExtrapSteps) ) {
2371  Exception exc("RKTrackRep::Extrap ==> Runge Kutta propagation failed",__LINE__,__FILE__);
2372  exc.setFatal();
2373  throw exc;
2374  }
2375 
2376  bool atPlane(limits_.getLowestLimit().first == stp_plane);
2377  if (limits_.getLowestLimit().first == stp_boundary)
2378  isAtBoundary = true;
2379 
2380 
2381  if (debugLvl_ > 0) {
2382  debugOut<<"RKSteps \n";
2383  for (std::vector<RKStep>::iterator it = RKSteps_.begin(); it != RKSteps_.end(); ++it){
2384  debugOut << "stepSize = " << it->matStep_.stepSize_ << "\t";
2385  it->matStep_.material_.Print();
2386  }
2387  debugOut<<"\n";
2388  }
2389 
2390 
2391 
2392  // call MatFX
2393  if(fillExtrapSteps) {
2394  noise = &noiseArray_;
2395  for(int i = 0; i < 7*7; ++i) noiseArray_[i] = 0; // set noiseArray_ to 0
2396  }
2397 
2398  unsigned int nPoints(RKStepsFXStop_ - RKStepsFXStart_);
2399  if ( nPoints>0){
2400  // momLoss has a sign - negative loss means momentum gain
2401  double momLoss = MaterialEffects::getInstance()->effects(RKSteps_,
2403  RKStepsFXStop_,
2404  fabs(charge/state7[6]), // momentum
2405  pdgCode_,
2406  noise);
2407 
2408  RKStepsFXStart_ = RKStepsFXStop_;
2409 
2410  if (debugLvl_ > 0) {
2411  debugOut << "momLoss: " << momLoss << " GeV; relative: " << momLoss/fabs(charge/state7[6])
2412  << "; coveredDistance = " << coveredDistance << "\n";
2413  if (debugLvl_ > 1 && noise != nullptr) {
2414  debugOut << "7D noise: \n";
2415  RKTools::printDim(noise->begin(), 7, 7);
2416  }
2417  }
2418 
2419  // do momLoss only for defined 1/momentum .ne.0
2420  if(fabs(state7[6])>1.E-10) {
2421 
2422  if (debugLvl_ > 0) {
2423  debugOut << "correct state7 with dx/dqop, dy/dqop ...\n";
2424  }
2425 
2426  dqop = charge/(fabs(charge/state7[6])-momLoss) - state7[6];
2427 
2428  // Correct coveredDistance and flightTime and momLoss if checkJacProj == true
2429  // The idea is to calculate the state correction (based on the mometum loss) twice:
2430  // Once with the unprojected Jacobian (which preserves coveredDistance),
2431  // and once with the projected Jacobian (which is constrained to the plane and does NOT preserve coveredDistance).
2432  // The difference of these two corrections can then be used to calculate a correction factor.
2433  if (checkJacProj && fabs(coveredDistance) > MINSTEP) {
2434  M1x3 state7_correction_unprojected = {{0, 0, 0}};
2435  for (unsigned int i=0; i<3; ++i) {
2436  state7_correction_unprojected[i] = 0.5 * dqop * J_MMT_unprojected_lastRow[i];
2437  //debugOut << "J_MMT_unprojected_lastRow[i] " << J_MMT_unprojected_lastRow[i] << "\n";
2438  //debugOut << "state7_correction_unprojected[i] " << state7_correction_unprojected[i] << "\n";
2439  }
2440 
2441  M1x3 state7_correction_projected = {{0, 0, 0}};
2442  for (unsigned int i=0; i<3; ++i) {
2443  state7_correction_projected[i] = 0.5 * dqop * J_MMT_[6*7 + i];
2444  //debugOut << "J_MMT_[6*7 + i] " << J_MMT_[6*7 + i] << "\n";
2445  //debugOut << "state7_correction_projected[i] " << state7_correction_projected[i] << "\n";
2446  }
2447 
2448  // delta distance
2449  M1x3 delta_state = {{0, 0, 0}};
2450  for (unsigned int i=0; i<3; ++i) {
2451  delta_state[i] = state7_correction_unprojected[i] - state7_correction_projected[i];
2452  }
2453 
2454  double Dist( sqrt(delta_state[0]*delta_state[0]
2455  + delta_state[1]*delta_state[1]
2456  + delta_state[2]*delta_state[2] ) );
2457 
2458  // sign: delta * a
2459  if (delta_state[0]*state7[3] + delta_state[1]*state7[4] + delta_state[2]*state7[5] > 0)
2460  Dist *= -1.;
2461 
2462  double correctionFactor( 1. + Dist / coveredDistance );
2463  flightTime *= correctionFactor;
2464  momLoss *= correctionFactor;
2465  coveredDistance = coveredDistance + Dist;
2466 
2467  if (debugLvl_ > 0) {
2468  debugOut << "correctionFactor-1 = " << correctionFactor-1. << "; Dist = " << Dist << "\n";
2469  debugOut << "corrected momLoss: " << momLoss << " GeV; relative: " << momLoss/fabs(charge/state7[6])
2470  << "; corrected coveredDistance = " << coveredDistance << "\n";
2471  }
2472  }
2473 
2474  // correct state7 with dx/dqop, dy/dqop ... Greatly improves extrapolation accuracy!
2475  double qop( charge/(fabs(charge/state7[6])-momLoss) );
2476  dqop = qop - state7[6];
2477  state7[6] = qop;
2478 
2479  for (unsigned int i=0; i<6; ++i) {
2480  state7[i] += 0.5 * dqop * J_MMT_[6*7 + i];
2481  }
2482  // normalize direction, just to make sure
2483  double norm( 1. / sqrt(state7[3]*state7[3] + state7[4]*state7[4] + state7[5]*state7[5]) );
2484  for (unsigned int i=3; i<6; ++i)
2485  state7[i] *= norm;
2486 
2487  }
2488  } // finished MatFX
2489 
2490 
2491  // fill ExtrapSteps_
2492  if (fillExtrapSteps) {
2493  static const ExtrapStep defaultExtrapStep;
2494  ExtrapSteps_.push_back(defaultExtrapStep);
2495  std::vector<ExtrapStep>::iterator lastStep = ExtrapSteps_.end() - 1;
2496 
2497  // Store Jacobian of this step for final calculation.
2498  lastStep->jac7_ = J_MMT_;
2499 
2500  if( checkJacProj == true ){
2501  //project the noise onto the destPlane
2502  RKTools::Np_N_NpT(noiseProjection_, noiseArray_);
2503 
2504  if (debugLvl_ > 1) {
2505  debugOut << "7D noise projected onto plane: \n";
2506  RKTools::printDim(noiseArray_.begin(), 7, 7);
2507  }
2508  }
2509 
2510  // Store this step's noise for final calculation.
2511  lastStep->noise7_ = noiseArray_;
2512 
2513  if (debugLvl_ > 2) {
2514  debugOut<<"ExtrapSteps \n";
2515  for (std::vector<ExtrapStep>::iterator it = ExtrapSteps_.begin(); it != ExtrapSteps_.end(); ++it){
2516  debugOut << "7D Jacobian: "; RKTools::printDim((it->jac7_.begin()), 5,5);
2517  debugOut << "7D noise: "; RKTools::printDim((it->noise7_.begin()), 5,5);
2518  }
2519  debugOut<<"\n";
2520  }
2521  }
2522 
2523 
2524 
2525  // check if at boundary
2526  if (stopAtBoundary and isAtBoundary) {
2527  if (debugLvl_ > 0) {
2528  debugOut << "stopAtBoundary -> break; \n ";
2529  }
2530  break;
2531  }
2532 
2533  if (onlyOneStep) {
2534  if (debugLvl_ > 0) {
2535  debugOut << "onlyOneStep -> break; \n ";
2536  }
2537  break;
2538  }
2539 
2540  //break if we arrived at destPlane
2541  if(atPlane) {
2542  if (debugLvl_ > 0) {
2543  debugOut << "arrived at destPlane with a distance of " << destPlane.distance(state7[0], state7[1], state7[2]) << " cm left. ";
2544  if (destPlane.isInActive(state7[0], state7[1], state7[2], state7[3], state7[4], state7[5]))
2545  debugOut << "In active area of destPlane. \n";
2546  else
2547  debugOut << "NOT in active area of plane. \n";
2548 
2549  debugOut << " position: "; TVector3(state7[0], state7[1], state7[2]).Print();
2550  debugOut << " direction: "; TVector3(state7[3], state7[4], state7[5]).Print();
2551  }
2552  break;
2553  }
2554 
2555  }
2556 
2557  if (fillExtrapSteps) {
2558  // propagate cov and add noise
2559  calcForwardJacobianAndNoise(startState7, startPlane, state7, destPlane);
2560 
2561  if (cov != nullptr) {
2562  cov->Similarity(fJacobian_);
2563  *cov += fNoise_;
2564  }
2565 
2566  if (debugLvl_ > 0) {
2567  if (cov != nullptr) {
2568  debugOut << "final covariance matrix after Extrap: "; cov->Print();
2569  }
2570  }
2571  }
2572 
2573  return coveredDistance;
2574 }
2575 
2576 
2577 void RKTrackRep::checkCache(const StateOnPlane& state, const SharedPlanePtr* plane) const {
2578 
2579  if (state.getRep() != this){
2580  Exception exc("RKTrackRep::checkCache ==> state is defined wrt. another TrackRep",__LINE__,__FILE__);
2581  exc.setFatal();
2582  throw exc;
2583  }
2584 
2585  if (dynamic_cast<const MeasurementOnPlane*>(&state) != nullptr) {
2586  Exception exc("RKTrackRep::checkCache - cannot extrapolate MeasurementOnPlane",__LINE__,__FILE__);
2587  exc.setFatal();
2588  throw exc;
2589  }
2590 
2591  cachePos_ = 0;
2592  RKStepsFXStart_ = 0;
2593  RKStepsFXStop_ = 0;
2594  ExtrapSteps_.clear();
2595  initArrays();
2596 
2597 
2598  if (plane &&
2599  lastStartState_.getPlane() &&
2600  lastEndState_.getPlane() &&
2601  state.getPlane() == lastStartState_.getPlane() &&
2602  state.getState() == lastStartState_.getState() &&
2603  (*plane)->distance(getPos(lastEndState_)) <= MINSTEP) {
2604  useCache_ = true;
2605 
2606  // clean up cache. Only use steps with same sign.
2607  double firstStep(0);
2608  for (unsigned int i=0; i<RKSteps_.size(); ++i) {
2609  if (i == 0) {
2610  firstStep = RKSteps_.at(0).matStep_.stepSize_;
2611  continue;
2612  }
2613  if (RKSteps_.at(i).matStep_.stepSize_ * firstStep < 0) {
2614  if (RKSteps_.at(i-1).matStep_.material_ == RKSteps_.at(i).matStep_.material_) {
2615  RKSteps_.at(i-1).matStep_.stepSize_ += RKSteps_.at(i).matStep_.stepSize_;
2616  }
2617  RKSteps_.erase(RKSteps_.begin()+i, RKSteps_.end());
2618  }
2619  }
2620 
2621  if (debugLvl_ > 0) {
2622  debugOut << "RKTrackRep::checkCache: use cached material and step values.\n";
2623  }
2624  }
2625  else {
2626 
2627  if (debugLvl_ > 0) {
2628  debugOut << "RKTrackRep::checkCache: can NOT use cached material and step values.\n";
2629 
2630  if (plane != nullptr) {
2631  if (state.getPlane() != lastStartState_.getPlane()) {
2632  debugOut << "state.getPlane() != lastStartState_.getPlane()\n";
2633  }
2634  else {
2635  if (! (state.getState() == lastStartState_.getState())) {
2636  debugOut << "state.getState() != lastStartState_.getState()\n";
2637  }
2638  else if (lastEndState_.getPlane().get() != nullptr) {
2639  debugOut << "distance " << (*plane)->distance(getPos(lastEndState_)) << "\n";
2640  }
2641  }
2642  }
2643  }
2644 
2645  useCache_ = false;
2646  RKSteps_.clear();
2647 
2648  lastStartState_.setStatePlane(state.getState(), state.getPlane());
2649  }
2650 }
2651 
2652 
2653 double RKTrackRep::momMag(const M1x7& state7) const {
2654  // FIXME given this interface this function cannot work for charge =/= +-1
2655  return fabs(1/state7[6]);
2656 }
2657 
2658 
2660  if (dynamic_cast<const RKTrackRep*>(other) == nullptr)
2661  return false;
2662 
2663  return true;
2664 }
2665 
2666 
2667 bool RKTrackRep::isSame(const AbsTrackRep* other) {
2668  if (getPDG() != other->getPDG())
2669  return false;
2670 
2671  return isSameType(other);
2672 }
2673 
2674 
2675 void RKTrackRep::Streamer(TBuffer &R__b)
2676 {
2677  // Stream an object of class genfit::RKTrackRep.
2678 
2679  //This works around a msvc bug and should be harmless on other platforms
2680  typedef ::genfit::RKTrackRep thisClass;
2681  UInt_t R__s, R__c;
2682  if (R__b.IsReading()) {
2683  ::genfit::AbsTrackRep::Streamer(R__b);
2684  Version_t R__v = R__b.ReadVersion(&R__s, &R__c); if (R__v) { }
2685  R__b.CheckByteCount(R__s, R__c, thisClass::IsA());
2686  lastStartState_.setRep(this);
2687  lastEndState_.setRep(this);
2688  } else {
2689  ::genfit::AbsTrackRep::Streamer(R__b);
2690  R__c = R__b.WriteVersion(thisClass::IsA(), kTRUE);
2691  R__b.SetByteCount(R__c, kTRUE);
2692  }
2693 }
2694 
2695 } /* End of namespace genfit */
Belle2::EvtPDLUtil::charge
double charge(int pdgCode)
Returns electric charge of a particle with given pdg code.
Definition: EvtPDLUtil.cc:46
genfit::Exception
Exception class for error handling in GENFIT (provides storage for diagnostic information)
Definition: Exception.h:48
genfit::StepLimits::setLimit
void setLimit(StepLimitType type, double value)
absolute of value will be taken! If limit is already lower, it will be set to value anyway.
Definition: StepLimits.h:89
genfit::SharedPlanePtr
std::shared_ptr< genfit::DetPlane > SharedPlanePtr
Shared Pointer to a DetPlane.
Definition: SharedPlanePtr.h:40
genfit::RKTrackRep::RKSteps_
std::vector< RKStep > RKSteps_
state where the last extrapolation has ended
Definition: RKTrackRep.h:294
genfit::Exception::setFatal
void setFatal(bool b=true)
Set fatal flag.
Definition: Exception.h:61
genfit::RKTrackRep::extrapolateToCone
virtual double extrapolateToCone(StateOnPlane &state, double radius, const TVector3 &linePoint=TVector3(0., 0., 0.), const TVector3 &lineDirection=TVector3(0., 0., 1.), bool stopAtBoundary=false, bool calcJacobianNoise=false) const override
Extrapolates the state to the cone surface, and returns the extrapolation length and,...
Definition: RKTrackRep.cc:476
genfit::RKTrackRep::setPosMomCov
virtual void setPosMomCov(MeasuredStateOnPlane &state, const TVector3 &pos, const TVector3 &mom, const TMatrixDSym &cov6x6) const override
Set position, momentum and covariance of state.
Definition: RKTrackRep.cc:1202
genfit::StepLimits::getLowestLimit
std::pair< StepLimitType, double > getLowestLimit(double margin=1.E-3) const
Get the lowest limit.
Definition: StepLimits.cc:44
genfit::AbsTrackRep::pdgCode_
int pdgCode_
Particle code.
Definition: AbsTrackRep.h:364
genfit::MeasuredStateOnPlane
#StateOnPlane with additional covariance matrix.
Definition: MeasuredStateOnPlane.h:39
genfit::RKTrackRep::getCharge
virtual double getCharge(const StateOnPlane &state) const override
Get the (fitted) charge of a state.
Definition: RKTrackRep.cc:859
genfit::RKTrackRep::RKPropagate
virtual double RKPropagate(M1x7 &state7, M7x7 *jacobian, M1x3 &SA, double S, bool varField=true, bool calcOnlyLastRowOfJ=false) const
The actual Runge Kutta propagation.
Definition: RKTrackRep.cc:1272
genfit::RKTrackRep::getPos
virtual TVector3 getPos(const StateOnPlane &state) const override
Get the cartesian position of a state.
Definition: RKTrackRep.cc:816
genfit::AbsTrackRep::getPDG
int getPDG() const
Get the pdg code.
Definition: AbsTrackRep.h:272
genfit::RKTrackRep::setChargeSign
virtual void setChargeSign(StateOnPlane &state, double charge) const override
Set the sign of the charge according to charge.
Definition: RKTrackRep.cc:1246
genfit::RKTrackRep::getSteps
std::vector< genfit::MatStep > getSteps() const override
Get stepsizes and material properties of crossed materials of the last extrapolation.
Definition: RKTrackRep.cc:1041
genfit::RKTrackRep::get6DCov
virtual TMatrixDSym get6DCov(const MeasuredStateOnPlane &state) const override
Get the 6D covariance.
Definition: RKTrackRep.cc:851
genfit::RKTrackRep::RKutta
bool RKutta(const M1x4 &SU, const DetPlane &plane, double charge, double mass, M1x7 &state7, M7x7 *jacobianT, M1x7 *J_MMT_unprojected_lastRow, double &coveredDistance, double &flightTime, bool &checkJacProj, M7x7 &noiseProjection, StepLimits &limits, bool onlyOneStep=false, bool calcOnlyLastRowOfJ=false) const
Propagates the particle through the magnetic field.
Definition: RKTrackRep.cc:1799
genfit::StateOnPlane
A state with arbitrary dimension defined in a DetPlane.
Definition: StateOnPlane.h:47
genfit
Defines for I/O streams used for error and debug printing.
Definition: AlignablePXDRecoHit.h:19
genfit::RKTrackRep::getRadiationLenght
virtual double getRadiationLenght() const override
Get the accumulated X/X0 (path / radiation length) of the material crossed in the last extrapolation.
Definition: RKTrackRep.cc:1061
genfit::FieldManager::getFieldVal
TVector3 getFieldVal(const TVector3 &position)
This does NOT use the cache!
Definition: FieldManager.h:63
genfit::RKTrackRep::getForwardJacobianAndNoise
virtual void getForwardJacobianAndNoise(TMatrixD &jacobian, TMatrixDSym &noise, TVectorD &deltaState) const override
Get the jacobian and noise matrix of the last extrapolation.
Definition: RKTrackRep.cc:977
genfit::AbsTrackRep
Abstract base class for a track representation.
Definition: AbsTrackRep.h:66
genfit::RKTrackRep::getMomMag
virtual double getMomMag(const StateOnPlane &state) const override
get the magnitude of the momentum in GeV.
Definition: RKTrackRep.cc:877
genfit::RKTrackRep::extrapolateBy
virtual double extrapolateBy(StateOnPlane &state, double step, bool stopAtBoundary=false, bool calcJacobianNoise=false) const override
Extrapolates the state by step (cm) and returns the extrapolation length and, via reference,...
Definition: RKTrackRep.cc:721
genfit::AbsTrackRep::getPDGCharge
double getPDGCharge() const
Get the charge of the particle of the pdg code.
Definition: AbsTrackRep.cc:93
genfit::RKTrackRep
AbsTrackRep with 5D track parameterization in plane coordinates: (q/p, u', v', u, v)
Definition: RKTrackRep.h:72
genfit::RKMatrix< 1, 7 >
genfit::RKTrackRep::Extrap
double Extrap(const DetPlane &startPlane, const DetPlane &destPlane, double charge, double mass, bool &isAtBoundary, M1x7 &state7, double &flightTime, bool fillExtrapSteps, TMatrixDSym *cov=nullptr, bool onlyOneStep=false, bool stopAtBoundary=false, double maxStep=1.E99) const
Handles propagation and material effects.
Definition: RKTrackRep.cc:2307
genfit::RKTrackRep::getMom
virtual TVector3 getMom(const StateOnPlane &state) const override
Get the cartesian momentum vector of a state.
Definition: RKTrackRep.cc:824
genfit::RKTrackRep::extrapolateToCylinder
virtual double extrapolateToCylinder(StateOnPlane &state, double radius, const TVector3 &linePoint=TVector3(0., 0., 0.), const TVector3 &lineDirection=TVector3(0., 0., 1.), bool stopAtBoundary=false, bool calcJacobianNoise=false) const override
Extrapolates the state to the cylinder surface, and returns the extrapolation length and,...
Definition: RKTrackRep.cc:351
genfit::RKTrackRep::extrapolateToSphere
virtual double extrapolateToSphere(StateOnPlane &state, double radius, const TVector3 &point=TVector3(0., 0., 0.), bool stopAtBoundary=false, bool calcJacobianNoise=false) const override
Extrapolates the state to the sphere surface, and returns the extrapolation length and,...
Definition: RKTrackRep.cc:610
genfit::RKTrackRep::extrapolateToPlane
virtual double extrapolateToPlane(StateOnPlane &state, const SharedPlanePtr &plane, bool stopAtBoundary=false, bool calcJacobianNoise=false) const override
Extrapolates the state to plane, and returns the extrapolation length and, via reference,...
Definition: RKTrackRep.cc:80
genfit::RKTrackRep::setPosMom
virtual void setPosMom(StateOnPlane &state, const TVector3 &pos, const TVector3 &mom) const override
Set position and momentum of state.
Definition: RKTrackRep.cc:1081
genfit::RKTrackRep::lastEndState_
StateOnPlane lastEndState_
state where the last extrapolation has started
Definition: RKTrackRep.h:290
genfit::RKTrackRep::isSameType
virtual bool isSameType(const AbsTrackRep *other) override
check if other is of same type (e.g. RKTrackRep).
Definition: RKTrackRep.cc:2659
genfit::AbsTrackRep::getMass
double getMass(const StateOnPlane &state) const
Get tha particle mass in GeV/c^2.
Definition: AbsTrackRep.cc:100
genfit::DetPlane::distance
double distance(const TVector3 &point) const
absolute distance from a point to the plane
Definition: DetPlane.cc:267
genfit::DetPlane::isInActive
bool isInActive(const TVector3 &point, const TVector3 &dir) const
intersect in the active area? C.f. AbsFinitePlane
Definition: DetPlane.h:144
genfit::RKTrackRep::getPosMom
virtual void getPosMom(const StateOnPlane &state, TVector3 &pos, TVector3 &mom) const override
Get cartesian position and momentum vector of a state.
Definition: RKTrackRep.cc:834
genfit::RKTrackRep::setPosMomErr
virtual void setPosMomErr(MeasuredStateOnPlane &state, const TVector3 &pos, const TVector3 &mom, const TVector3 &posErr, const TVector3 &momErr) const override
Set position and momentum and error of state.
Definition: RKTrackRep.cc:1160
genfit::StepLimits
Helper to store different limits on the stepsize for the RKTRackRep.
Definition: StepLimits.h:54
genfit::RKTrackRep::cachePos_
unsigned int cachePos_
use cached RKSteps_ for extrapolation
Definition: RKTrackRep.h:303
genfit::RKTrackRep::noiseProjection_
M7x7 noiseProjection_
noise matrix of the last extrapolation
Definition: RKTrackRep.h:309
genfit::RKTrackRep::isSame
virtual bool isSame(const AbsTrackRep *other) override
check if other is of same type (e.g. RKTrackRep) and has same pdg code.
Definition: RKTrackRep.cc:2667
genfit::RKTrackRep::getBackwardJacobianAndNoise
virtual void getBackwardJacobianAndNoise(TMatrixD &jacobian, TMatrixDSym &noise, TVectorD &deltaState) const override
Get the jacobian and noise matrix of the last extrapolation if it would have been done in opposite di...
Definition: RKTrackRep.cc:1001
genfit::ExtrapStep
Helper for RKTrackRep.
Definition: RKTrackRep.h:54
genfit::DetPlane
Detector plane.
Definition: DetPlane.h:59
genfit::RKTrackRep::getTime
double getTime(const StateOnPlane &state) const override
Get the time corresponding to the StateOnPlane. Extrapolation.
Definition: RKTrackRep.cc:921
genfit::RKTrackRep::getPosMomCov
virtual void getPosMomCov(const MeasuredStateOnPlane &state, TVector3 &pos, TVector3 &mom, TMatrixDSym &cov) const override
Translates MeasuredStateOnPlane into 3D position, momentum and 6x6 covariance.
Definition: RKTrackRep.cc:844
genfit::FieldManager::getInstance
static FieldManager * getInstance()
Get singleton instance.
Definition: FieldManager.h:119
genfit::RKTrackRep::fJacobian_
TMatrixD fJacobian_
steps made in Extrap during last extrapolation
Definition: RKTrackRep.h:299
genfit::RKTrackRep::getMomVar
virtual double getMomVar(const MeasuredStateOnPlane &state) const override
get the variance of the absolute value of the momentum .
Definition: RKTrackRep.cc:885
Belle2::DistanceTools::poca
TVector3 poca(TVector3 const &trackPos, TVector3 const &trackP, TVector3 const &vtxPos)
Returns the Point Of Closest Approach of a track to a vertex.
Definition: DistanceTools.cc:21
genfit::MeasurementOnPlane
Measured coordinates on a plane.
Definition: MeasurementOnPlane.h:46
genfit::RKTrackRep::setTime
void setTime(StateOnPlane &state, double time) const override
Set time at which the state was defined.
Definition: RKTrackRep.cc:1265
genfit::RKTrackRep::RKStepsFXStart_
int RKStepsFXStart_
RungeKutta steps made in the last extrapolation.
Definition: RKTrackRep.h:295
genfit::RKTrackRep::extrapolateToLine
virtual double extrapolateToLine(StateOnPlane &state, const TVector3 &linePoint, const TVector3 &lineDirection, bool stopAtBoundary=false, bool calcJacobianNoise=false) const override
Extrapolates the state to the POCA to a line, and returns the extrapolation length and,...
Definition: RKTrackRep.cc:135
genfit::debugOut
std::ostream debugOut
Default stream for debug output.
genfit::AbsTrackRep::propDir_
char propDir_
propagation direction (-1, 0, 1) -> (backward, auto, forward)
Definition: AbsTrackRep.h:366