CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
SteppingHelixPropagator.cc
Go to the documentation of this file.
1 
11 //
12 // Original Author: Vyacheslav Krutelyov
13 // Created: Fri Mar 3 16:01:24 CST 2006
14 //
15 //
16 
17 
22 
26 
28 
31 
33 
35 
36 #include <sstream>
37 #include <typeinfo>
38 
41 {
42  field_ = 0;
43 }
44 
47  Propagator(dir),
48  unit55_(AlgebraicMatrixID())
49 {
50  field_ = field;
51  vbField_ = dynamic_cast<const VolumeBasedMagneticField*>(field_);
52  debug_ = false;
53  noMaterialMode_ = false;
54  noErrorPropagation_ = false;
55  applyRadX0Correction_ = true;
56  useMagVolumes_ = true;
57  useIsYokeFlag_ = true;
58  useMatVolumes_ = true;
59  useInTeslaFromMagField_ = false; //overrides behavior only if true
60  returnTangentPlane_ = true;
61  sendLogWarning_ = false;
62  useTuningForL2Speed_ = false;
63  for (int i = 0; i <= MAX_POINTS; i++){
64  svBuf_[i].p3 = Vector(0,0,0);
65  svBuf_[i].r3 = Point(0,0,0);
66  svBuf_[i].bf = Vector(0,0,0);
67  svBuf_[i].bfGradLoc = Vector(0,0,0);
68  svBuf_[i].covCurv = AlgebraicSymMatrix55();
69  svBuf_[i].matDCovCurv = AlgebraicSymMatrix55();
70  svBuf_[i].isComplete = true;
71  svBuf_[i].isValid_ = true;
72  svBuf_[i].hasErrorPropagated_ = !noErrorPropagation_;
73  }
74  defaultStep_ = 5.;
75 
76  ecShiftPos_ = 0;
77  ecShiftNeg_ = 0;
78 
79 }
80 
82 SteppingHelixPropagator::propagate(const FreeTrajectoryState& ftsStart, const Plane& pDest) const {
83  return propagateWithPath(ftsStart, pDest).first;
84 }
85 
87 SteppingHelixPropagator::propagate(const FreeTrajectoryState& ftsStart, const Cylinder& cDest) const
88 {
89  return propagateWithPath(ftsStart, cDest).first;
90 }
91 
93 SteppingHelixPropagator::propagate(const FreeTrajectoryState& ftsStart, const GlobalPoint& pDest) const
94 {
95  return propagateWithPath(ftsStart, pDest).first;
96 }
97 
99 SteppingHelixPropagator::propagate(const FreeTrajectoryState& ftsStart,
100  const GlobalPoint& pDest1, const GlobalPoint& pDest2) const
101 {
102  return propagateWithPath(ftsStart, pDest1, pDest2).first;
103 }
104 
106 SteppingHelixPropagator::propagate(const FreeTrajectoryState& ftsStart,
107  const reco::BeamSpot& beamSpot) const
108 {
109  return propagateWithPath(ftsStart, beamSpot).first;
110 }
111 
112 
113 std::pair<TrajectoryStateOnSurface, double>
114 SteppingHelixPropagator::propagateWithPath(const FreeTrajectoryState& ftsStart,
115  const Plane& pDest) const {
116 
117  setIState(SteppingHelixStateInfo(ftsStart));
118 
119  const StateInfo& svCurrent = propagate(svBuf_[0], pDest);
120 
121  return TsosPP(svCurrent.getStateOnSurface(pDest), svCurrent.path());
122 }
123 
124 std::pair<TrajectoryStateOnSurface, double>
125 SteppingHelixPropagator::propagateWithPath(const FreeTrajectoryState& ftsStart,
126  const Cylinder& cDest) const {
127 
128  setIState(SteppingHelixStateInfo(ftsStart));
129 
130  const StateInfo& svCurrent = propagate(svBuf_[0], cDest);
131 
132  return TsosPP(svCurrent.getStateOnSurface(cDest, returnTangentPlane_), svCurrent.path());
133 }
134 
135 
136 std::pair<FreeTrajectoryState, double>
137 SteppingHelixPropagator::propagateWithPath(const FreeTrajectoryState& ftsStart,
138  const GlobalPoint& pDest) const {
139  setIState(SteppingHelixStateInfo(ftsStart));
140 
141  const StateInfo& svCurrent = propagate(svBuf_[0], pDest);
142 
143  FreeTrajectoryState ftsDest;
144  svCurrent.getFreeState(ftsDest);
145 
146  return FtsPP(ftsDest, svCurrent.path());
147 }
148 
149 std::pair<FreeTrajectoryState, double>
150 SteppingHelixPropagator::propagateWithPath(const FreeTrajectoryState& ftsStart,
151  const GlobalPoint& pDest1, const GlobalPoint& pDest2) const {
152 
153  if ((pDest1-pDest2).mag() < 1e-10){
154  if (sendLogWarning_){
155  edm::LogWarning("SteppingHelixPropagator")<<"Can't propagate: the points should be at a bigger distance"
156  <<std::endl;
157  }
158  return FtsPP();
159  }
160  setIState(SteppingHelixStateInfo(ftsStart));
161 
162  const StateInfo& svCurrent = propagate(svBuf_[0], pDest1, pDest2);
163 
164  FreeTrajectoryState ftsDest;
165  svCurrent.getFreeState(ftsDest);
166 
167  return FtsPP(ftsDest, svCurrent.path());
168 }
169 
170 
171 std::pair<FreeTrajectoryState, double>
172 SteppingHelixPropagator::propagateWithPath(const FreeTrajectoryState& ftsStart,
173  const reco::BeamSpot& beamSpot) const {
174  GlobalPoint pDest1(beamSpot.x0(), beamSpot.y0(), beamSpot.z0());
175  GlobalPoint pDest2(pDest1.x() + beamSpot.dxdz()*1e3,
176  pDest1.y() + beamSpot.dydz()*1e3,
177  pDest1.z() + 1e3);
178  return propagateWithPath(ftsStart, pDest1, pDest2);
179 }
180 
182 SteppingHelixPropagator::propagate(const SteppingHelixStateInfo& sStart,
183  const Surface& sDest) const {
184 
185  if (! sStart.isValid()){
186  if (sendLogWarning_){
187  edm::LogWarning("SteppingHelixPropagator")<<"Can't propagate: invalid input state"
188  <<std::endl;
189  }
190  return invalidState_;
191  }
192 
193  const Plane* pDest = dynamic_cast<const Plane*>(&sDest);
194  if (pDest != 0) return propagate(sStart, *pDest);
195 
196  const Cylinder* cDest = dynamic_cast<const Cylinder*>(&sDest);
197  if (cDest != 0) return propagate(sStart, *cDest);
198 
199  throw PropagationException("The surface is neither Cylinder nor Plane");
200 
201 }
202 
204 SteppingHelixPropagator::propagate(const SteppingHelixStateInfo& sStart,
205  const Plane& pDest) const {
206 
207  if (! sStart.isValid()){
208  if (sendLogWarning_){
209  edm::LogWarning("SteppingHelixPropagator")<<"Can't propagate: invalid input state"
210  <<std::endl;
211  }
212  return invalidState_;
213  }
214  setIState(sStart);
215 
216  Point rPlane(pDest.position().x(), pDest.position().y(), pDest.position().z());
217  Vector nPlane(pDest.rotation().zx(), pDest.rotation().zy(), pDest.rotation().zz()); nPlane /= nPlane.mag();
218 
219  double pars[6] = { rPlane.x(), rPlane.y(), rPlane.z(),
220  nPlane.x(), nPlane.y(), nPlane.z() };
221 
222  propagate(PLANE_DT, pars);
223 
224  //(re)set it before leaving: dir =1 (-1) if path increased (decreased) and 0 if it didn't change
225  //need to implement this somewhere else as a separate function
226  double lDir = 0;
227  if (sStart.path() < svBuf_[cIndex_(nPoints_-1)].path()) lDir = 1.;
228  if (sStart.path() > svBuf_[cIndex_(nPoints_-1)].path()) lDir = -1.;
229  svBuf_[cIndex_(nPoints_-1)].dir = lDir;
230  return svBuf_[cIndex_(nPoints_-1)];
231 }
232 
234 SteppingHelixPropagator::propagate(const SteppingHelixStateInfo& sStart,
235  const Cylinder& cDest) const {
236 
237  if (! sStart.isValid()){
238  if (sendLogWarning_){
239  edm::LogWarning("SteppingHelixPropagator")<<"Can't propagate: invalid input state"
240  <<std::endl;
241  }
242  return invalidState_;
243  }
244  setIState(sStart);
245 
246  double pars[6] = {0,0,0,0,0,0};
247  pars[RADIUS_P] = cDest.radius();
248 
249 
250  propagate(RADIUS_DT, pars);
251 
252  //(re)set it before leaving: dir =1 (-1) if path increased (decreased) and 0 if it didn't change
253  //need to implement this somewhere else as a separate function
254  double lDir = 0;
255  if (sStart.path() < svBuf_[cIndex_(nPoints_-1)].path()) lDir = 1.;
256  if (sStart.path() > svBuf_[cIndex_(nPoints_-1)].path()) lDir = -1.;
257  svBuf_[cIndex_(nPoints_-1)].dir = lDir;
258  return svBuf_[cIndex_(nPoints_-1)];
259 }
260 
262 SteppingHelixPropagator::propagate(const SteppingHelixStateInfo& sStart,
263  const GlobalPoint& pDest) const {
264 
265  if (! sStart.isValid()){
266  if (sendLogWarning_){
267  edm::LogWarning("SteppingHelixPropagator")<<"Can't propagate: invalid input state"
268  <<std::endl;
269  }
270  return invalidState_;
271  }
272  setIState(sStart);
273 
274  double pars[6] = {pDest.x(), pDest.y(), pDest.z(), 0, 0, 0};
275 
276 
277  propagate(POINT_PCA_DT, pars);
278 
279  return svBuf_[cIndex_(nPoints_-1)];
280 }
281 
283 SteppingHelixPropagator::propagate(const SteppingHelixStateInfo& sStart,
284  const GlobalPoint& pDest1, const GlobalPoint& pDest2) const {
285 
286  if ((pDest1-pDest2).mag() < 1e-10 || !sStart.isValid()){
287  if (sendLogWarning_){
288  if ((pDest1-pDest2).mag() < 1e-10)
289  edm::LogWarning("SteppingHelixPropagator")<<"Can't propagate: points are too close"
290  <<std::endl;
291  if (!sStart.isValid())
292  edm::LogWarning("SteppingHelixPropagator")<<"Can't propagate: invalid input state"
293  <<std::endl;
294  }
295  return invalidState_;
296  }
297  setIState(sStart);
298 
299  double pars[6] = {pDest1.x(), pDest1.y(), pDest1.z(),
300  pDest2.x(), pDest2.y(), pDest2.z()};
301 
302  propagate(LINE_PCA_DT, pars);
303 
304  return svBuf_[cIndex_(nPoints_-1)];
305 }
306 
307 void SteppingHelixPropagator::setIState(const SteppingHelixStateInfo& sStart) const {
308  nPoints_ = 0;
309  svBuf_[cIndex_(nPoints_)] = sStart; //do this anyways to have a fresh start
310  if (sStart.isComplete ) {
311  svBuf_[cIndex_(nPoints_)] = sStart;
312  nPoints_++;
313  } else {
314  loadState(svBuf_[cIndex_(nPoints_)], sStart.p3, sStart.r3, sStart.q,
315  propagationDirection(), sStart.covCurv);
316  nPoints_++;
317  }
318  svBuf_[cIndex_(0)].hasErrorPropagated_ = sStart.hasErrorPropagated_ & !noErrorPropagation_;
319 }
320 
321 SteppingHelixPropagator::Result
322 SteppingHelixPropagator::propagate(SteppingHelixPropagator::DestType type,
323  const double pars[6], double epsilon) const{
324 
325  static const std::string metname = "SteppingHelixPropagator";
326  StateInfo* svCurrent = &svBuf_[cIndex_(nPoints_-1)];
327 
328  //check if it's going to work at all
329  double tanDist = 0;
330  double dist = 0;
331  PropagationDirection refDirection = anyDirection;
332  Result result = refToDest(type, (*svCurrent), pars, dist, tanDist, refDirection);
333 
334  if (result != SteppingHelixStateInfo::OK || fabs(dist) > 1e6){
335  svCurrent->status_ = result;
336  if (fabs(dist) > 1e6) svCurrent->status_ = SteppingHelixStateInfo::INACC;
337  svCurrent->isValid_ = false;
338  svCurrent->field = field_;
339  if (sendLogWarning_){
340  edm::LogWarning(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<" Failed after first refToDest check with status "
342  <<std::endl;
343  }
344  return result;
345  }
346 
348  bool makeNextStep = true;
349  double dStep = defaultStep_;
350  PropagationDirection dir,oldDir;
351  dir = propagationDirection();
352  oldDir = dir;
353  int nOsc = 0;
354 
355  double distMag = 1e12;
356  double tanDistMag = 1e12;
357 
358  double distMat = 1e12;
359  double tanDistMat = 1e12;
360 
361  double tanDistNextCheck = -0.1;//just need a negative start val
362  double tanDistMagNextCheck = -0.1;
363  double tanDistMatNextCheck = -0.1;
364  double oldDStep = 0;
365  PropagationDirection oldRefDirection = propagationDirection();
366 
367  Result resultToMat = SteppingHelixStateInfo::UNDEFINED;
368  Result resultToMag = SteppingHelixStateInfo::UNDEFINED;
369 
370  bool isFirstStep = true;
371  bool expectNewMagVolume = false;
372 
373  int loopCount = 0;
374  while (makeNextStep){
375  dStep = defaultStep_;
376  svCurrent = &svBuf_[cIndex_(nPoints_-1)];
377  double curZ = svCurrent->r3.z();
378  double curR = svCurrent->r3.perp();
379  if ( fabs(curZ) < 440 && curR < 260) dStep = defaultStep_*2;
380 
381  //more such ifs might be scattered around
382  //even though dStep is large, it will still make stops at each volume boundary
383  if (useTuningForL2Speed_){
384  dStep = 100.;
385  if (! useIsYokeFlag_ && fabs(curZ) < 667 && curR > 380 && curR < 850){
386  dStep = 5*(1+0.2*svCurrent->p3.mag());
387  }
388  }
389 
390  // refDirection = propagationDirection();
391 
392  tanDistNextCheck -= oldDStep;
393  tanDistMagNextCheck -= oldDStep;
394  tanDistMatNextCheck -= oldDStep;
395 
396  if (tanDistNextCheck < 0){
397  //use pre-computed values if it's the first step
398  if (! isFirstStep) refToDest(type, (*svCurrent), pars, dist, tanDist, refDirection);
399  // constrain allowed path for a tangential approach
400  if (fabs(tanDist) > 4.*(fabs(dist)) ) tanDist *= tanDist == 0 ? 0 :fabs(dist/tanDist*4.);
401 
402  tanDistNextCheck = fabs(tanDist)*0.5 - 0.5; //need a better guess (to-do)
403  //reasonable limit
404  if (tanDistNextCheck > defaultStep_*20. ) tanDistNextCheck = defaultStep_*20.;
405  oldRefDirection = refDirection;
406  } else {
407  tanDist = tanDist > 0. ? tanDist - oldDStep : tanDist + oldDStep;
408  refDirection = oldRefDirection;
409  if (debug_) LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Skipped refToDest: guess tanDist = "<<tanDist
410  <<" next check at "<<tanDistNextCheck<<std::endl;
411  }
413  double fastSkipDist = fabs(dist) > fabs(tanDist) ? tanDist : dist;
414 
415  if (propagationDirection() == anyDirection){
416  dir = refDirection;
417  } else {
418  dir = propagationDirection();
419  if (fabs(tanDist)<0.1 && refDirection != dir ){
420  //how did it get here? nOsc++;
421  dir = refDirection;
422  if (debug_) LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"NOTE: overstepped last time: switch direction (can do it if within 1 mm)"<<std::endl;
423  }
424  }
425 
426  if (useMagVolumes_ && ! (fabs(dist) < fabs(epsilon))){//need to know the general direction
427  if (tanDistMagNextCheck < 0){
428  resultToMag = refToMagVolume((*svCurrent), dir, distMag, tanDistMag, fabs(fastSkipDist), expectNewMagVolume, fabs(tanDist));
429  // constrain allowed path for a tangential approach
430  if (fabs(tanDistMag) > 4.*(fabs(distMag)) ) tanDistMag *= tanDistMag == 0 ? 0 : fabs(distMag/tanDistMag*4.);
431 
432  tanDistMagNextCheck = fabs(tanDistMag)*0.5-0.5; //need a better guess (to-do)
433  //reasonable limit; "turn off" checking if bounds are further than the destination
434  if (tanDistMagNextCheck > defaultStep_*20.
435  || fabs(dist) < fabs(distMag)
436  || resultToMag ==SteppingHelixStateInfo::INACC)
437  tanDistMagNextCheck = defaultStep_*20 > fabs(fastSkipDist) ? fabs(fastSkipDist) : defaultStep_*20;
438  if (resultToMag != SteppingHelixStateInfo::INACC
439  && resultToMag != SteppingHelixStateInfo::OK) tanDistMagNextCheck = -1;
440  } else {
441  // resultToMag = SteppingHelixStateInfo::OK;
442  tanDistMag = tanDistMag > 0. ? tanDistMag - oldDStep : tanDistMag + oldDStep;
443  if (debug_) LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Skipped refToMag: guess tanDistMag = "<<tanDistMag
444  <<" next check at "<<tanDistMagNextCheck;
445  }
446  }
447 
448  if (useMatVolumes_ && ! (fabs(dist) < fabs(epsilon))){//need to know the general direction
449  if (tanDistMatNextCheck < 0){
450  resultToMat = refToMatVolume((*svCurrent), dir, distMat, tanDistMat, fabs(fastSkipDist));
451  // constrain allowed path for a tangential approach
452  if (fabs(tanDistMat) > 4.*(fabs(distMat)) ) tanDistMat *= tanDistMat == 0 ? 0 : fabs(distMat/tanDistMat*4.);
453 
454  tanDistMatNextCheck = fabs(tanDistMat)*0.5-0.5; //need a better guess (to-do)
455  //reasonable limit; "turn off" checking if bounds are further than the destination
456  if (tanDistMatNextCheck > defaultStep_*20.
457  || fabs(dist) < fabs(distMat)
458  || resultToMat ==SteppingHelixStateInfo::INACC )
459  tanDistMatNextCheck = defaultStep_*20 > fabs(fastSkipDist) ? fabs(fastSkipDist) : defaultStep_*20;
460  if (resultToMat != SteppingHelixStateInfo::INACC
461  && resultToMat != SteppingHelixStateInfo::OK) tanDistMatNextCheck = -1;
462  } else {
463  // resultToMat = SteppingHelixStateInfo::OK;
464  tanDistMat = tanDistMat > 0. ? tanDistMat - oldDStep : tanDistMat + oldDStep;
465  if (debug_) LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Skipped refToMat: guess tanDistMat = "<<tanDistMat
466  <<" next check at "<<tanDistMatNextCheck;
467  }
468  }
469 
470  double rDotP = svCurrent->r3.dot(svCurrent->p3);
471  if ((fabs(curZ) > 1.5e3 || curR >800.)
472  && ((dir == alongMomentum && rDotP > 0)
473  || (dir == oppositeToMomentum && rDotP < 0) )
474  ){
475  dStep = fabs(tanDist) -1e-12;
476  }
477  double tanDistMin = fabs(tanDist);
478  if (tanDistMin > fabs(tanDistMag)+0.05 &&
479  (resultToMag == SteppingHelixStateInfo::OK || resultToMag == SteppingHelixStateInfo::WRONG_VOLUME)){
480  tanDistMin = fabs(tanDistMag)+0.05; //try to step into the next volume
481  expectNewMagVolume = true;
482  } else expectNewMagVolume = false;
483 
484  if (tanDistMin > fabs(tanDistMat)+0.05 && resultToMat == SteppingHelixStateInfo::OK){
485  tanDistMin = fabs(tanDistMat)+0.05; //try to step into the next volume
486  if (expectNewMagVolume) expectNewMagVolume = false;
487  }
488 
489  if (tanDistMin*fabs(svCurrent->dEdx) > 0.5*svCurrent->p3.mag()){
490  tanDistMin = 0.5*svCurrent->p3.mag()/fabs(svCurrent->dEdx);
491  if (expectNewMagVolume) expectNewMagVolume = false;
492  }
493 
494 
495 
496  double tanDistMinLazy = fabs(tanDistMin);
497  if ((type == POINT_PCA_DT || type == LINE_PCA_DT)
498  && fabs(tanDist) < 2.*fabs(tanDistMin) ){
499  //being lazy here; the best is to take into account the curvature
500  tanDistMinLazy = fabs(tanDistMin)*0.5;
501  }
502 
503  if (fabs(tanDistMinLazy) < dStep){
504  dStep = fabs(tanDistMinLazy);
505  }
506 
507  //keep this path length for the next step
508  oldDStep = dStep;
509 
510  if (dStep > 1e-10 && ! (fabs(dist) < fabs(epsilon))){
511  StateInfo* svNext = &svBuf_[cIndex_(nPoints_)];
512  makeAtomStep((*svCurrent), (*svNext), dStep, dir, HEL_AS_F);
513 // if (useMatVolumes_ && expectNewMagVolume
514 // && svCurrent->magVol == svNext->magVol){
515 // double tmpDist=0;
516 // double tmpDistMag = 0;
517 // if (refToMagVolume((*svNext), dir, tmpDist, tmpDistMag, fabs(dist)) != SteppingHelixStateInfo::OK){
518 // //the point appears to be outside, but findVolume claims the opposite
519 // dStep += 0.05*fabs(tanDistMag/distMag); oldDStep = dStep; //do it again with a bigger step
520 // if (debug_) LogTrace(metname)
521 // <<"Failed to get into new mag volume: will try with new bigger step "<<dStep<<std::endl;
522 // makeAtomStep((*svCurrent), (*svNext), dStep, dir, HEL_AS_F);
523 // }
524 // }
525  nPoints_++; svCurrent = &svBuf_[cIndex_(nPoints_-1)];
526  if (oldDir != dir){
527  nOsc++;
528  tanDistNextCheck = -1;//check dist after osc
529  tanDistMagNextCheck = -1;
530  tanDistMatNextCheck = -1;
531  }
532  oldDir = dir;
533  }
534 
535  if (nOsc>1 && fabs(dStep)>epsilon){
536  if (debug_) LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Ooops"<<std::endl;
537  }
538 
539  if (fabs(dist) < fabs(epsilon) ) result = SteppingHelixStateInfo::OK;
540 
541  if ((type == POINT_PCA_DT || type == LINE_PCA_DT )
542  && fabs(dStep) < fabs(epsilon) ){
543  //now check if it's not a branch point (peek ahead at 1 cm)
544  double nextDist = 0;
545  double nextTanDist = 0;
546  PropagationDirection nextRefDirection = anyDirection;
547  StateInfo* svNext = &svBuf_[cIndex_(nPoints_)];
548  makeAtomStep((*svCurrent), (*svNext), 1., dir, HEL_AS_F);
549  nPoints_++; svCurrent = &svBuf_[cIndex_(nPoints_-1)];
550  refToDest(type, (*svCurrent), pars, nextDist, nextTanDist, nextRefDirection);
551  if ( fabs(nextDist) > fabs(dist)){
552  nPoints_--; svCurrent = &svBuf_[cIndex_(nPoints_-1)];
554  if (debug_){
555  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Found real local minimum in PCA"<<std::endl;
556  }
557  } else {
558  //keep this trial point and continue
559  dStep = defaultStep_;
560  if (debug_){
561  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Found branch point in PCA"<<std::endl;
562  }
563  }
564  }
565 
566  if (nPoints_ > MAX_STEPS*1./defaultStep_ || loopCount > MAX_STEPS*100
567  || nOsc > 6 ) result = SteppingHelixStateInfo::FAULT;
568 
569  if (svCurrent->p3.mag() < 0.1 ) result = SteppingHelixStateInfo::RANGEOUT;
570 
571  curZ = svCurrent->r3.z();
572  curR = svCurrent->r3.perp();
573  if ( curR > 20000 || fabs(curZ) > 20000 ) result = SteppingHelixStateInfo::INACC;
574 
575  makeNextStep = result == SteppingHelixStateInfo::UNDEFINED;
576  svCurrent->status_ = result;
577  svCurrent->isValid_ = (result == SteppingHelixStateInfo::OK || makeNextStep );
578  svCurrent->field = field_;
579 
580  isFirstStep = false;
581  loopCount++;
582  }
583 
584  if (sendLogWarning_ && result != SteppingHelixStateInfo::OK){
585  edm::LogWarning(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<" Propagation failed with status "
587  <<std::endl;
588  if (result == SteppingHelixStateInfo::RANGEOUT)
589  edm::LogWarning(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<" Momentum at last point is too low (<0.1) p_last = "
590  <<svCurrent->p3.mag()
591  <<std::endl;
592  if (result == SteppingHelixStateInfo::INACC)
593  edm::LogWarning(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<" Went too far: the last point is at "<<svCurrent->r3
594  <<std::endl;
595  if (result == SteppingHelixStateInfo::FAULT && nOsc > 6)
596  edm::LogWarning(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<" Infinite loop condidtion detected: going in cycles. Break after 6 cycles"
597  <<std::endl;
598  if (result == SteppingHelixStateInfo::FAULT && nPoints_ > MAX_STEPS*1./defaultStep_)
599  edm::LogWarning(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<" Tired to go farther. Made too many steps: more than "
600  <<MAX_STEPS*1./defaultStep_
601  <<std::endl;
602 
603  }
604 
605  if (debug_){
606  switch (type) {
607  case RADIUS_DT:
608  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"going to radius "<<pars[RADIUS_P]<<std::endl;
609  break;
610  case Z_DT:
611  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"going to z "<<pars[Z_P]<<std::endl;
612  break;
613  case PATHL_DT:
614  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"going to pathL "<<pars[PATHL_P]<<std::endl;
615  break;
616  case PLANE_DT:
617  {
618  Point rPlane(pars[0], pars[1], pars[2]);
619  Vector nPlane(pars[3], pars[4], pars[5]);
620  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"going to plane r0:"<<rPlane<<" n:"<<nPlane<<std::endl;
621  }
622  break;
623  case POINT_PCA_DT:
624  {
625  Point rDest(pars[0], pars[1], pars[2]);
626  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"going to PCA to point "<<rDest<<std::endl;
627  }
628  break;
629  case LINE_PCA_DT:
630  {
631  Point rDest1(pars[0], pars[1], pars[2]);
632  Point rDest2(pars[3], pars[4], pars[5]);
633  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"going to PCA to line "<<rDest1<<" - "<<rDest2<<std::endl;
634  }
635  break;
636  default:
637  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"going to NOT IMPLEMENTED"<<std::endl;
638  break;
639  }
640  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Made "<<nPoints_-1<<" steps and stopped at(cur step) "<<svCurrent->r3<<" nOsc "<<nOsc<<std::endl;
641  }
642 
643  return result;
644 }
645 
646 void SteppingHelixPropagator::loadState(SteppingHelixPropagator::StateInfo& svCurrent,
648  const SteppingHelixPropagator::Point& r3, int charge,
650  const AlgebraicSymMatrix55& covCurv) const{
651  static const std::string metname = "SteppingHelixPropagator";
652 
653  svCurrent.q = charge;
654  svCurrent.p3 = p3;
655  svCurrent.r3 = r3;
656  svCurrent.dir = dir == alongMomentum ? 1.: -1.;
657 
658  svCurrent.path_ = 0; // this could've held the initial path
659  svCurrent.radPath_ = 0;
660 
661  GlobalPoint gPointNorZ(svCurrent.r3.x(), svCurrent.r3.y(), svCurrent.r3.z());
662 
663  float gpmag = gPointNorZ.mag2();
664  float pmag2 = p3.mag2();
665  if (gpmag > 1e20f ) {
666  LogTrace(metname)<<"Initial point is too far";
667  svCurrent.isValid_ = false;
668  return;
669  }
670  if (! (gpmag == gpmag) ) {
671  LogTrace(metname)<<"Initial point is a nan";
672  edm::LogWarning("SteppingHelixPropagatorNAN")<<"Initial point is a nan";
673  svCurrent.isValid_ = false;
674  return;
675  }
676  if (! (pmag2 == pmag2) ) {
677  LogTrace(metname)<<"Initial momentum is a nan";
678  edm::LogWarning("SteppingHelixPropagatorNAN")<<"Initial momentum is a nan";
679  svCurrent.isValid_ = false;
680  return;
681  }
682 
683  GlobalVector bf(0,0,0);
684  // = field_->inTesla(gPoint);
685  if (useMagVolumes_){
686  if (vbField_ ){
687  svCurrent.magVol = vbField_->findVolume(gPointNorZ);
688  if (useIsYokeFlag_){
689  double curRad = svCurrent.r3.perp();
690  if (curRad > 380 && curRad < 850 && fabs(svCurrent.r3.z()) < 667){
691  svCurrent.isYokeVol = isYokeVolume(svCurrent.magVol);
692  } else {
693  svCurrent.isYokeVol = false;
694  }
695  }
696  } else {
697  edm::LogWarning(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Failed to cast into VolumeBasedMagneticField: fall back to the default behavior"<<std::endl;
698  svCurrent.magVol = 0;
699  }
700  if (debug_){
701  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Got volume at "<<svCurrent.magVol<<std::endl;
702  }
703  }
704 
705  if (useMagVolumes_ && svCurrent.magVol != 0 && ! useInTeslaFromMagField_){
706  bf = svCurrent.magVol->inTesla(gPointNorZ);
707  if (debug_){
708  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Loaded bfield float: "<<bf
709  <<" at global float "<< gPointNorZ<<" double "<< svCurrent.r3<<std::endl;
710  LocalPoint lPoint(svCurrent.magVol->toLocal(gPointNorZ));
711  LocalVector lbf = svCurrent.magVol->fieldInTesla(lPoint);
712  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"\t cf in local locF: "<<lbf<<" at "<<lPoint<<std::endl;
713  }
714  svCurrent.bf.set(bf.x(), bf.y(), bf.z());
715  } else {
716  GlobalPoint gPoint(r3.x(), r3.y(), r3.z());
717  bf = field_->inTesla(gPoint);
718  svCurrent.bf.set(bf.x(), bf.y(), bf.z());
719  }
720  if (svCurrent.bf.mag2() < 1e-32) svCurrent.bf.set(0., 0., 1e-16);
721  if (debug_){
722  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific
723  <<"Loaded bfield double: "<<svCurrent.bf<<" from float: "<<bf
724  <<" at float "<< gPointNorZ<<" double "<< svCurrent.r3<<std::endl;
725  }
726 
727 
728 
729  double dEdXPrime = 0;
730  double dEdx = 0;
731  double radX0 = 0;
732  MatBounds rzLims;
733  dEdx = getDeDx(svCurrent, dEdXPrime, radX0, rzLims);
734  svCurrent.dEdx = dEdx; svCurrent.dEdXPrime = dEdXPrime;
735  svCurrent.radX0 = radX0;
736  svCurrent.rzLims = rzLims;
737 
738  svCurrent.covCurv =covCurv;
739 
740  svCurrent.isComplete = true;
741  svCurrent.isValid_ = true;
742 
743  if (debug_){
744  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Loaded at path: "<<svCurrent.path()<<" radPath: "<<svCurrent.radPath()
745  <<" p3 "<<" pt: "<<svCurrent.p3.perp()<<" phi: "<<svCurrent.p3.phi()
746  <<" eta: "<<svCurrent.p3.eta()
747  <<" "<<svCurrent.p3
748  <<" r3: "<<svCurrent.r3
749  <<" bField: "<<svCurrent.bf.mag()
750  <<std::endl;
751  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Input Covariance in Curvilinear RF "<<covCurv<<std::endl;
752  }
753 }
754 
755 void SteppingHelixPropagator::getNextState(const SteppingHelixPropagator::StateInfo& svPrevious,
756  SteppingHelixPropagator::StateInfo& svNext,
757  double dP, const SteppingHelixPropagator::Vector& tau,
758  const SteppingHelixPropagator::Vector& drVec, double dS, double dX0,
759  const AlgebraicMatrix55& dCovCurvTransform) const{
760  static const std::string metname = "SteppingHelixPropagator";
761  svNext.q = svPrevious.q;
762  svNext.dir = dS > 0.0 ? 1.: -1.;
763  svNext.p3 = tau; svNext.p3*=(svPrevious.p3.mag() - svNext.dir*fabs(dP));
764 
765  svNext.r3 = svPrevious.r3; svNext.r3 += drVec;
766 
767  svNext.path_ = svPrevious.path() + dS;
768  svNext.radPath_ = svPrevious.radPath() + dX0;
769 
770  GlobalPoint gPointNorZ(svNext.r3.x(), svNext.r3.y(), svNext.r3.z());
771 
772  GlobalVector bf(0,0,0);
773 
774  if (useMagVolumes_){
775  if (vbField_ != 0){
776  svNext.magVol = vbField_->findVolume(gPointNorZ);
777  if (useIsYokeFlag_){
778  double curRad = svNext.r3.perp();
779  if (curRad > 380 && curRad < 850 && fabs(svNext.r3.z()) < 667){
780  svNext.isYokeVol = isYokeVolume(svNext.magVol);
781  } else {
782  svNext.isYokeVol = false;
783  }
784  }
785  } else {
786  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Failed to cast into VolumeBasedMagneticField"<<std::endl;
787  svNext.magVol = 0;
788  }
789  if (debug_){
790  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Got volume at "<<svNext.magVol<<std::endl;
791  }
792  }
793 
794  if (useMagVolumes_ && svNext.magVol != 0 && ! useInTeslaFromMagField_){
795  bf = svNext.magVol->inTesla(gPointNorZ);
796  svNext.bf.set(bf.x(), bf.y(), bf.z());
797  } else {
798  GlobalPoint gPoint(svNext.r3.x(), svNext.r3.y(), svNext.r3.z());
799  bf = field_->inTesla(gPoint);
800  svNext.bf.set(bf.x(), bf.y(), bf.z());
801  }
802  if (svNext.bf.mag2() < 1e-32) svNext.bf.set(0., 0., 1e-16);
803 
804 
805  double dEdXPrime = 0;
806  double dEdx = 0;
807  double radX0 = 0;
808  MatBounds rzLims;
809  dEdx = getDeDx(svNext, dEdXPrime, radX0, rzLims);
810  svNext.dEdx = dEdx; svNext.dEdXPrime = dEdXPrime;
811  svNext.radX0 = radX0;
812  svNext.rzLims = rzLims;
813 
814  //update Emat only if it's valid
815  svNext.hasErrorPropagated_ = svPrevious.hasErrorPropagated_;
816  if (svPrevious.hasErrorPropagated_){
817  {
818  AlgebraicMatrix55 tmp = dCovCurvTransform*svPrevious.covCurv;
819  ROOT::Math::AssignSym::Evaluate(svNext.covCurv, tmp*ROOT::Math::Transpose(dCovCurvTransform));
820 
821  svNext.covCurv += svPrevious.matDCovCurv;
822  }
823  } else {
824  //could skip dragging along the unprop. cov later .. now
825  // svNext.cov = svPrevious.cov;
826  }
827 
828  if (debug_){
829  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Now at path: "<<svNext.path()<<" radPath: "<<svNext.radPath()
830  <<" p3 "<<" pt: "<<svNext.p3.perp()<<" phi: "<<svNext.p3.phi()
831  <<" eta: "<<svNext.p3.eta()
832  <<" "<<svNext.p3
833  <<" r3: "<<svNext.r3
834  <<" dPhi: "<<acos(svNext.p3.unit().dot(svPrevious.p3.unit()))
835  <<" bField: "<<svNext.bf.mag()
836  <<" dedx: "<<svNext.dEdx
837  <<std::endl;
838  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"New Covariance "<<svNext.covCurv<<std::endl;
839  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Transf by dCovTransform "<<dCovCurvTransform<<std::endl;
840  }
841 }
842 
843 void SteppingHelixPropagator::setRep(SteppingHelixPropagator::Basis& rep,
844  const SteppingHelixPropagator::Vector& tau) const{
845  Vector zRep(0., 0., 1.);
846  rep.lX = tau;
847  rep.lY = zRep.cross(tau); rep.lY *= 1./tau.perp();
848  rep.lZ = rep.lX.cross(rep.lY);
849 }
850 
851 bool SteppingHelixPropagator::makeAtomStep(SteppingHelixPropagator::StateInfo& svCurrent,
852  SteppingHelixPropagator::StateInfo& svNext,
853  double dS,
855  SteppingHelixPropagator::Fancy fancy) const{
856  static const std::string metname = "SteppingHelixPropagator";
857  if (debug_){
858  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Make atom step "<<svCurrent.path()<<" with step "<<dS<<" in direction "<<dir<<std::endl;
859  }
860 
861  AlgebraicMatrix55 dCCurvTransform(unit55_);
862 
863  double dP = 0;
864  double curP = svCurrent.p3.mag();
865  Vector tau = svCurrent.p3; tau *= 1./curP;
866  Vector tauNext(tau);
867  Vector drVec(0,0,0);
868 
869  dS = dir == alongMomentum ? fabs(dS) : -fabs(dS);
870 
871 
872  double radX0 = 1e24;
873 
874  switch (fancy){
875  case HEL_AS_F:
876  case HEL_ALL_F:{
877  double p0 = curP;// see above = svCurrent.p3.mag();
878  double p0Inv = 1./p0;
879  double b0 = svCurrent.bf.mag();
880 
881  //get to the mid-point first
882  double phi = (2.99792458e-3*svCurrent.q*b0*p0Inv)*dS/2.;
883  bool phiSmall = fabs(phi) < 1e-4;
884 
885  double cosPhi = 0;
886  double sinPhi = 0;
887 
888  double oneLessCosPhi=0;
889  double oneLessCosPhiOPhi=0;
890  double sinPhiOPhi=0;
891  double phiLessSinPhiOPhi=0;
892 
893  if (phiSmall){
894  double phi2 = phi*phi;
895  double phi3 = phi2*phi;
896  double phi4 = phi3*phi;
897  sinPhi = phi - phi3/6. + phi4*phi/120.;
898  cosPhi = 1. -phi2/2. + phi4/24.;
899  oneLessCosPhi = phi2/2. - phi4/24. + phi2*phi4/720.; // 0.5*phi*phi;//*(1.- phi*phi/12.);
900  oneLessCosPhiOPhi = 0.5*phi - phi3/24. + phi2*phi3/720.;//*(1.- phi*phi/12.);
901  sinPhiOPhi = 1. - phi*phi/6. + phi4/120.;
902  phiLessSinPhiOPhi = phi*phi/6. - phi4/120. + phi4*phi2/5040.;//*(1. - phi*phi/20.);
903  } else {
904  cosPhi = cos(phi);
905  sinPhi = sin(phi);
906  oneLessCosPhi = 1.-cosPhi;
907  oneLessCosPhiOPhi = oneLessCosPhi/phi;
908  sinPhiOPhi = sinPhi/phi;
909  phiLessSinPhiOPhi = 1 - sinPhiOPhi;
910  }
911 
912  Vector bHat = svCurrent.bf; bHat *= 1./b0; //bHat.mag();
913  // bool bAlongZ = fabs(bHat.z()) > 0.9999;
914 
915  Vector btVec(bHat.cross(tau)); // for balong z btVec.z()==0
916  double tauB = tau.dot(bHat);
917  Vector bbtVec(bHat*tauB - tau); // (-tau.x(), -tau.y(), 0)
918 
919  //don't need it here tauNext = tau + bbtVec*oneLessCosPhi - btVec*sinPhi;
920  drVec = bbtVec*phiLessSinPhiOPhi; drVec -= btVec*oneLessCosPhiOPhi; drVec += tau;
921  drVec *= dS/2.;
922 
923  double dEdx = svCurrent.dEdx;
924  double dEdXPrime = svCurrent.dEdXPrime;
925  radX0 = svCurrent.radX0;
926  dP = dEdx*dS;
927 
928  //improve with above values:
929  drVec += svCurrent.r3;
930  GlobalVector bfGV(0,0,0);
931  Vector bf(0,0,0);
932  if (useMagVolumes_ && svCurrent.magVol != 0 && ! useInTeslaFromMagField_){
933  bfGV = svCurrent.magVol->inTesla(GlobalPoint(drVec.x(), drVec.y(), drVec.z()));
934  bf.set(bfGV.x(), bfGV.y(), bfGV.z());
935  } else {
936  bfGV = field_->inTesla(GlobalPoint(drVec.x(), drVec.y(), drVec.z()));
937  bf.set(bfGV.x(), bfGV.y(), bfGV.z());
938  }
939  double b0Init = b0;
940  b0 = bf.mag();
941  if (b0 < 1e-16) {
942  b0 = 1e-16;
943  bf.set(0., 0., 1e-16);
944  }
945  if (debug_){
946  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Improved b "<<b0
947  <<" at r3 "<<drVec<<std::endl;
948  }
949 
950  if (fabs((b0-b0Init)*dS) > 1){
951  //missed the mag volume boundary?
952  if (debug_){
953  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Large bf*dS change "<<fabs((b0-svCurrent.bf.mag())*dS)
954  <<" --> recalc dedx"<<std::endl;
955  }
956  svNext.r3 = drVec;
957  svNext.bf = bf;
958  svNext.p3 = svCurrent.p3;
959  svNext.isYokeVol = svCurrent.isYokeVol;
960  MatBounds rzTmp;
961  dEdx = getDeDx(svNext, dEdXPrime, radX0, rzTmp);
962  dP = dEdx*dS;
963  if (debug_){
964  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"New dEdX= "<<dEdx
965  <<" dP= "<<dP
966  <<" for p0 "<<p0<<std::endl;
967  }
968  }
969  //p0 is mid-way and b0 from mid-point
970  p0 += dP/2.; if (p0 < 1e-2) p0 = 1e-2;
971  p0Inv = 1./p0;
972 
973  phi = (2.99792458e-3*svCurrent.q*b0*p0Inv)*dS;
974  phiSmall = fabs(phi) < 1e-4;
975 
976  if (phiSmall){
977  double phi2 = phi*phi;
978  double phi3 = phi2*phi;
979  double phi4 = phi3*phi;
980  sinPhi = phi - phi3/6. + phi4*phi/120.;
981  cosPhi = 1. -phi2/2. + phi4/24.;
982  oneLessCosPhi = phi2/2. - phi4/24. + phi2*phi4/720.; // 0.5*phi*phi;//*(1.- phi*phi/12.);
983  oneLessCosPhiOPhi = 0.5*phi - phi3/24. + phi2*phi3/720.;//*(1.- phi*phi/12.);
984  sinPhiOPhi = 1. - phi*phi/6. + phi4/120.;
985  phiLessSinPhiOPhi = phi*phi/6. - phi4/120. + phi4*phi2/5040.;//*(1. - phi*phi/20.);
986  }else {
987  cosPhi = cos(phi);
988  sinPhi = sin(phi);
989  oneLessCosPhi = 1.-cosPhi;
990  oneLessCosPhiOPhi = oneLessCosPhi/phi;
991  sinPhiOPhi = sinPhi/phi;
992  phiLessSinPhiOPhi = 1. - sinPhiOPhi;
993  }
994 
995  bHat = bf; bHat *= 1./b0;// as above =1./bHat.mag();
996  // bAlongZ = fabs(bHat.z()) > 0.9999;
997  btVec = bHat.cross(tau); // for b||z (-tau.y(), tau.x() ,0)
998  tauB = tau.dot(bHat);
999  bbtVec = bHat*tauB - tau; //bHat.cross(btVec); for b||z: (-tau.x(), -tau.y(), 0)
1000 
1001  tauNext = bbtVec*oneLessCosPhi; tauNext -= btVec*sinPhi; tauNext += tau; //for b||z tauNext.z() == tau.z()
1002  double tauNextPerpInv = 1./tauNext.perp();
1003  drVec = bbtVec*phiLessSinPhiOPhi; drVec -= btVec*oneLessCosPhiOPhi; drVec += tau;
1004  drVec *= dS;
1005 
1006 
1007  if (svCurrent.hasErrorPropagated_){
1008  double theta02 = 0;
1009  double dX0 = fabs(dS)/radX0;
1010 
1011  if (applyRadX0Correction_){
1012  // this provides the integrand for theta^2
1013  // if summed up along the path, should result in
1014  // theta_total^2 = Int_0^x0{ f(x)dX} = (13.6/p0)^2*x0*(1+0.036*ln(x0+1))
1015  // x0+1 above is to make the result infrared safe.
1016  double x0 = fabs(svCurrent.radPath());
1017  double alphaX0 = 13.6e-3*p0Inv; alphaX0 *= alphaX0;
1018  double betaX0 = 0.038;
1019  double logx0p1 = log(x0+1);
1020  theta02 = dX0*alphaX0*(1+betaX0*logx0p1)*(1 + betaX0*logx0p1 + 2.*betaX0*x0/(x0+1) );
1021  } else {
1022  theta02 = 196e-6* p0Inv * p0Inv * dX0; //14.e-3/p0*sqrt(fabs(dS)/radX0); // .. drop log term (this is non-additive)
1023  }
1024 
1025  double epsilonP0 = 1.+ dP/(p0-0.5*dP);
1026  // double omegaP0 = -dP/(p0-0.5*dP) + dS*dEdXPrime;
1027  // double dsp = dS/(p0-0.5*dP); //use the initial p0 (not the mid-point) to keep the transport properly additive
1028 
1029  Vector tbtVec(bHat - tauB*tau); // for b||z tau.z()*(-tau.x(), -tau.y(), 1.-tau.z())
1030 
1031  {
1032  //Slightly modified copy of the curvilinear jacobian (don't use the original just because it's in float precision
1033  // and seems to have some assumptions about the field values
1034  // notation changes: p1--> tau, p2-->tauNext
1035  // theta --> phi
1036  // Vector p1 = tau;
1037  // Vector p2 = tauNext;
1038  Point xStart = svCurrent.r3;
1039  Vector dx = drVec;
1040  //GlobalVector h = MagneticField::inInverseGeV(xStart);
1041  // Martijn: field is now given as parameter.. GlobalVector h = globalParameters.magneticFieldInInverseGeV(xStart);
1042 
1043  //double qbp = fts.signedInverseMomentum();
1044  double qbp = svCurrent.q*p0Inv;
1045  // double absS = dS;
1046 
1047  // calculate transport matrix
1048  // Origin: TRPRFN
1049  double t11 = tau.x(); double t12 = tau.y(); double t13 = tau.z();
1050  double t21 = tauNext.x(); double t22 = tauNext.y(); double t23 = tauNext.z();
1051  double cosl0 = tau.perp();
1052  // double cosl1 = 1./tauNext.perp(); //not quite a cos .. it's a cosec--> change to cosecl1 below
1053  double cosecl1 = tauNextPerpInv;
1054  //AlgebraicMatrix a(5,5,1);
1055  // define average magnetic field and gradient
1056  // at initial point - inlike TRPRFN
1057  Vector hn = bHat;
1058  // double qp = -2.99792458e-3*b0;
1059  // double q = -h.mag()*qbp;
1060 
1061  double q = -phi/dS; //qp*qbp; // -phi/dS
1062  // double theta = -phi;
1063  double sint = -sinPhi; double cost = cosPhi;
1064  double hn1 = hn.x(); double hn2 = hn.y(); double hn3 = hn.z();
1065  double dx1 = dx.x(); double dx2 = dx.y(); double dx3 = dx.z();
1066  // double hnDt1 = hn1*t11 + hn2*t12 + hn3*t13;
1067 
1068  double gamma = hn1*t21 + hn2*t22 + hn3*t23;
1069  double an1 = hn2*t23 - hn3*t22;
1070  double an2 = hn3*t21 - hn1*t23;
1071  double an3 = hn1*t22 - hn2*t21;
1072  // double auInv = sqrt(1.- t13*t13); double au = auInv>0 ? 1./auInv : 1e24;
1073  double auInv = cosl0; double au = auInv>0 ? 1./auInv : 1e24;
1074  // double auInv = sqrt(t11*t11 + t12*t12); double au = auInv>0 ? 1./auInv : 1e24;
1075  double u11 = -au*t12; double u12 = au*t11;
1076  double v11 = -t13*u12; double v12 = t13*u11; double v13 = auInv;//t11*u12 - t12*u11;
1077  auInv = sqrt(1. - t23*t23); au = auInv>0 ? 1./auInv : 1e24;
1078  // auInv = sqrt(t21*t21 + t22*t22); au = auInv>0 ? 1./auInv : 1e24;
1079  double u21 = -au*t22; double u22 = au*t21;
1080  double v21 = -t23*u22; double v22 = t23*u21; double v23 = auInv;//t21*u22 - t22*u21;
1081  // now prepare the transport matrix
1082  // pp only needed in high-p case (WA)
1083  // double pp = 1./qbp;
1085  // moved up (where -h.mag() is needed()
1086  // double qp = q*pp;
1087  double anv = -(hn1*u21 + hn2*u22 );
1088  double anu = (hn1*v21 + hn2*v22 + hn3*v23);
1089  double omcost = oneLessCosPhi; double tmsint = -phi*phiLessSinPhiOPhi;
1090 
1091  double hu1 = - hn3*u12;
1092  double hu2 = hn3*u11;
1093  double hu3 = hn1*u12 - hn2*u11;
1094 
1095  double hv1 = hn2*v13 - hn3*v12;
1096  double hv2 = hn3*v11 - hn1*v13;
1097  double hv3 = hn1*v12 - hn2*v11;
1098 
1099  // 1/p - doesn't change since |tau| = |tauNext| ... not. It changes now
1100  dCCurvTransform(0,0) = 1./(epsilonP0*epsilonP0)*(1. + dS*dEdXPrime);
1101 
1102  // lambda
1103 
1104  dCCurvTransform(1,0) = phi*p0/svCurrent.q*cosecl1*
1105  (sinPhi*bbtVec.z() - cosPhi*btVec.z());
1106  //was dCCurvTransform(1,0) = -qp*anv*(t21*dx1 + t22*dx2 + t23*dx3); //NOTE (SK) this was found to have an opposite sign
1107  //from independent re-calculation ... in fact the tauNext.dot.dR piece isnt reproduced
1108 
1109  dCCurvTransform(1,1) = cost*(v11*v21 + v12*v22 + v13*v23) +
1110  sint*(hv1*v21 + hv2*v22 + hv3*v23) +
1111  omcost*(hn1*v11 + hn2*v12 + hn3*v13) * (hn1*v21 + hn2*v22 + hn3*v23) +
1112  anv*(-sint*(v11*t21 + v12*t22 + v13*t23) +
1113  omcost*(v11*an1 + v12*an2 + v13*an3) -
1114  tmsint*gamma*(hn1*v11 + hn2*v12 + hn3*v13) );
1115 
1116  dCCurvTransform(1,2) = cost*(u11*v21 + u12*v22 ) +
1117  sint*(hu1*v21 + hu2*v22 + hu3*v23) +
1118  omcost*(hn1*u11 + hn2*u12 ) * (hn1*v21 + hn2*v22 + hn3*v23) +
1119  anv*(-sint*(u11*t21 + u12*t22 ) +
1120  omcost*(u11*an1 + u12*an2 ) -
1121  tmsint*gamma*(hn1*u11 + hn2*u12 ) );
1122  dCCurvTransform(1,2) *= cosl0;
1123 
1124  // Commented out in part for reproducibility purposes: these terms are zero in cart->curv
1125  // dCCurvTransform(1,3) = -q*anv*(u11*t21 + u12*t22 ); //don't show up in cartesian setup-->curv
1126  //why would lambdaNext depend explicitely on initial position ? any arbitrary init point can be chosen not
1127  // affecting the final state's momentum direction ... is this the field gradient in curvilinear coord?
1128  // dCCurvTransform(1,4) = -q*anv*(v11*t21 + v12*t22 + v13*t23); //don't show up in cartesian setup-->curv
1129 
1130  // phi
1131 
1132  dCCurvTransform(2,0) = - phi*p0/svCurrent.q*cosecl1*cosecl1*
1133  (oneLessCosPhi*bHat.z()*btVec.mag2() + sinPhi*btVec.z() + cosPhi*tbtVec.z()) ;
1134  //was dCCurvTransform(2,0) = -qp*anu*(t21*dx1 + t22*dx2 + t23*dx3)*cosecl1;
1135 
1136  dCCurvTransform(2,1) = cost*(v11*u21 + v12*u22 ) +
1137  sint*(hv1*u21 + hv2*u22 ) +
1138  omcost*(hn1*v11 + hn2*v12 + hn3*v13) *
1139  (hn1*u21 + hn2*u22 ) +
1140  anu*(-sint*(v11*t21 + v12*t22 + v13*t23) +
1141  omcost*(v11*an1 + v12*an2 + v13*an3) -
1142  tmsint*gamma*(hn1*v11 + hn2*v12 + hn3*v13) );
1143  dCCurvTransform(2,1) *= cosecl1;
1144 
1145  dCCurvTransform(2,2) = cost*(u11*u21 + u12*u22 ) +
1146  sint*(hu1*u21 + hu2*u22 ) +
1147  omcost*(hn1*u11 + hn2*u12 ) *
1148  (hn1*u21 + hn2*u22 ) +
1149  anu*(-sint*(u11*t21 + u12*t22 ) +
1150  omcost*(u11*an1 + u12*an2 ) -
1151  tmsint*gamma*(hn1*u11 + hn2*u12 ) );
1152  dCCurvTransform(2,2) *= cosecl1*cosl0;
1153 
1154  // Commented out in part for reproducibility purposes: these terms are zero in cart->curv
1155  // dCCurvTransform(2,3) = -q*anu*(u11*t21 + u12*t22 )*cosecl1;
1156  //why would lambdaNext depend explicitely on initial position ? any arbitrary init point can be chosen not
1157  // affecting the final state's momentum direction ... is this the field gradient in curvilinear coord?
1158  // dCCurvTransform(2,4) = -q*anu*(v11*t21 + v12*t22 + v13*t23)*cosecl1;
1159 
1160  // yt
1161 
1162  double pp = 1./qbp;
1163  // (SK) these terms seem to consistently have a sign opp from private derivation
1164  dCCurvTransform(3,0) = - pp*(u21*dx1 + u22*dx2 ); //NB: modified from the original: changed the sign
1165  dCCurvTransform(4,0) = - pp*(v21*dx1 + v22*dx2 + v23*dx3);
1166 
1167 
1168  dCCurvTransform(3,1) = (sint*(v11*u21 + v12*u22 ) +
1169  omcost*(hv1*u21 + hv2*u22 ) +
1170  tmsint*(hn1*u21 + hn2*u22 ) *
1171  (hn1*v11 + hn2*v12 + hn3*v13))/q;
1172 
1173  dCCurvTransform(3,2) = (sint*(u11*u21 + u12*u22 ) +
1174  omcost*(hu1*u21 + hu2*u22 ) +
1175  tmsint*(hn1*u21 + hn2*u22 ) *
1176  (hn1*u11 + hn2*u12 ))*cosl0/q;
1177 
1178  dCCurvTransform(3,3) = (u11*u21 + u12*u22 );
1179 
1180  dCCurvTransform(3,4) = (v11*u21 + v12*u22 );
1181 
1182  // zt
1183 
1184  dCCurvTransform(4,1) = (sint*(v11*v21 + v12*v22 + v13*v23) +
1185  omcost*(hv1*v21 + hv2*v22 + hv3*v23) +
1186  tmsint*(hn1*v21 + hn2*v22 + hn3*v23) *
1187  (hn1*v11 + hn2*v12 + hn3*v13))/q;
1188 
1189  dCCurvTransform(4,2) = (sint*(u11*v21 + u12*v22 ) +
1190  omcost*(hu1*v21 + hu2*v22 + hu3*v23) +
1191  tmsint*(hn1*v21 + hn2*v22 + hn3*v23) *
1192  (hn1*u11 + hn2*u12 ))*cosl0/q;
1193 
1194  dCCurvTransform(4,3) = (u11*v21 + u12*v22 );
1195 
1196  dCCurvTransform(4,4) = (v11*v21 + v12*v22 + v13*v23);
1197  // end of TRPRFN
1198  }
1199 
1200  if (debug_){
1201  Basis rep; setRep(rep, tauNext);
1202  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"rep X: "<<rep.lX<<" "<<rep.lX.mag()
1203  <<"\t Y: "<<rep.lY<<" "<<rep.lY.mag()
1204  <<"\t Z: "<<rep.lZ<<" "<<rep.lZ.mag();
1205  }
1206  //mind the sign of dS and dP (dS*dP < 0 allways)
1207  //covariance should grow no matter which direction you propagate
1208  //==> take abs values.
1209  //reset not needed: fill all below svCurrent.matDCov *= 0.;
1210  double mulRR = theta02*dS*dS/3.;
1211  double mulRP = theta02*fabs(dS)*p0/2.;
1212  double mulPP = theta02*p0*p0;
1213  double losPP = dP*dP*1.6/fabs(dS)*(1.0 + p0*1e-3);
1214  //another guess .. makes sense for 1 cm steps 2./dS == 2 [cm] / dS [cm] at low pt
1215  //double it by 1TeV
1216  //not gaussian anyways
1217  // derived from the fact that sigma_p/eLoss ~ 0.08 after ~ 200 steps
1218 
1219  //curvilinear
1220  double sinThetaInv = tauNextPerpInv;
1221  double p0Mat = p0+ 0.5*dP; // FIXME change this to p0 after it's clear that there's agreement in everything else
1222  double p0Mat2 = p0Mat*p0Mat;
1223  // with 6x6 formulation
1224  svCurrent.matDCovCurv*=0;
1225 
1226  svCurrent.matDCovCurv(0,0) = losPP/(p0Mat2*p0Mat2);
1227  // svCurrent.matDCovCurv(0,1) = 0;
1228  // svCurrent.matDCovCurv(0,2) = 0;
1229  // svCurrent.matDCovCurv(0,3) = 0;
1230  // svCurrent.matDCovCurv(0,4) = 0;
1231 
1232  // svCurrent.matDCovCurv(1,0) = 0;
1233  svCurrent.matDCovCurv(1,1) = mulPP/p0Mat2;
1234  // svCurrent.matDCovCurv(1,2) = 0;
1235  // svCurrent.matDCovCurv(1,3) = 0;
1236  svCurrent.matDCovCurv(1,4) = mulRP/p0Mat;
1237 
1238  // svCurrent.matDCovCurv(2,0) = 0;
1239  // svCurrent.matDCovCurv(2,1) = 0;
1240  svCurrent.matDCovCurv(2,2) = mulPP/p0Mat2*(sinThetaInv*sinThetaInv);
1241  svCurrent.matDCovCurv(2,3) = mulRP/p0Mat*sinThetaInv;
1242  // svCurrent.matDCovCurv(2,4) = 0;
1243 
1244  // svCurrent.matDCovCurv(3,0) = 0;
1245  // svCurrent.matDCovCurv(3,1) = 0;
1246  svCurrent.matDCovCurv(3,2) = mulRP/p0Mat*sinThetaInv;
1247  // svCurrent.matDCovCurv(3,0) = 0;
1248  svCurrent.matDCovCurv(3,3) = mulRR;
1249  // svCurrent.matDCovCurv(3,4) = 0;
1250 
1251  // svCurrent.matDCovCurv(4,0) = 0;
1252  svCurrent.matDCovCurv(4,1) = mulRP/p0Mat;
1253  // svCurrent.matDCovCurv(4,2) = 0;
1254  // svCurrent.matDCovCurv(4,3) = 0;
1255  svCurrent.matDCovCurv(4,4) = mulRR;
1256  }
1257  break;
1258  }
1259  default:
1260  break;
1261  }
1262 
1263  double pMag = curP;//svCurrent.p3.mag();
1264 
1265  if (dir == oppositeToMomentum) dP = fabs(dP);
1266  else if( dP < 0) { //the case of negative dP
1267  dP = -dP > pMag ? -pMag+1e-5 : dP;
1268  }
1269 
1270  getNextState(svCurrent, svNext, dP, tauNext, drVec, dS, dS/radX0,
1271  dCCurvTransform);
1272  return true;
1273 }
1274 
1275 double SteppingHelixPropagator::getDeDx(const SteppingHelixPropagator::StateInfo& sv,
1276  double& dEdXPrime, double& radX0,
1277  MatBounds& rzLims) const{
1278  radX0 = 1.e24;
1279  dEdXPrime = 0.;
1280  rzLims = MatBounds();
1281  if (noMaterialMode_) return 0;
1282 
1283  double dEdx = 0.;
1284 
1285  double lR = sv.r3.perp();
1286  double lZ = fabs(sv.r3.z());
1287 
1288  //assume "Iron" .. seems to be quite the same for brass/iron/PbW04
1289  //good for Fe within 3% for 0.2 GeV to 10PeV
1290 
1291  double dEdX_HCal = 0.95; //extracted from sim
1292  double dEdX_ECal = 0.45;
1293  double dEdX_coil = 0.35; //extracted from sim .. closer to 40% in fact
1294  double dEdX_Fe = 1;
1295  double dEdX_MCh = 0.053; //chambers on average
1296  double dEdX_Trk = 0.0114;
1297  double dEdX_Air = 2E-4;
1298  double dEdX_Vac = 0.0;
1299 
1300  double radX0_HCal = 1.44/0.8; //guessing
1301  double radX0_ECal = 0.89/0.7;
1302  double radX0_coil = 4.; //
1303  double radX0_Fe = 1.76;
1304  double radX0_MCh = 1e3; //
1305  double radX0_Trk = 320.;
1306  double radX0_Air = 3.e4;
1307  double radX0_Vac = 3.e9; //"big" number for vacuum
1308 
1309 
1310  //not all the boundaries are set below: this will be a default
1311  if (! (lR < 380 && lZ < 785)){
1312  if (lZ > 785 ) rzLims = MatBounds(0, 1e4, 785, 1e4);
1313  if (lZ < 785 ) rzLims = MatBounds(380, 1e4, 0, 785);
1314  }
1315 
1316  //this def makes sense assuming we don't jump into endcap volume from the other z-side in one step
1317  //also, it is a positive shift only (at least for now): can't move ec further into the detector
1318  double ecShift = sv.r3.z() > 0 ? fabs(ecShiftPos_) : fabs(ecShiftNeg_);
1319 
1320  //this should roughly figure out where things are
1321  //(numbers taken from Fig1.1.2 TDR and from geom xmls)
1322  if (lR < 2.9){ //inside beampipe
1323  dEdx = dEdX_Vac; radX0 = radX0_Vac;
1324  rzLims = MatBounds(0, 2.9, 0, 1E4);
1325  }
1326  else if (lR < 129){
1327  if (lZ < 294){
1328  rzLims = MatBounds(2.9, 129, 0, 294); //tracker boundaries
1329  dEdx = dEdX_Trk; radX0 = radX0_Trk;
1330  //somewhat empirical formula that ~ matches the average if going from 0,0,0
1331  //assuming "uniform" tracker material
1332  //doesn't really track material layer to layer
1333  double lEtaDet = fabs(sv.r3.eta());
1334  double scaleRadX = lEtaDet > 1.5 ? 0.7724 : 1./cosh(0.5*lEtaDet);//sin(2.*atan(exp(-0.5*lEtaDet)));
1335  scaleRadX *= scaleRadX;
1336  if (lEtaDet > 2 && lZ > 20) scaleRadX *= (lEtaDet-1.);
1337  if (lEtaDet > 2.5 && lZ > 20) scaleRadX *= (lEtaDet-1.);
1338  radX0 *= scaleRadX;
1339  }
1340  //endcap part begins here
1341  else if ( lZ < 294 + ecShift ){
1342  //gap in front of EE here, piece inside 2.9<R<129
1343  rzLims = MatBounds(2.9, 129, 294, 294 + ecShift);
1344  dEdx = dEdX_Air; radX0 = radX0_Air;
1345  }
1346  else if (lZ < 372 + ecShift){
1347  rzLims = MatBounds(2.9, 129, 294 + ecShift, 372 + ecShift); //EE here, piece inside 2.9<R<129
1348  dEdx = dEdX_ECal; radX0 = radX0_ECal;
1349  }//EE averaged out over a larger space
1350  else if (lZ < 398 + ecShift){
1351  rzLims = MatBounds(2.9, 129, 372 + ecShift, 398 + ecShift); //whatever goes behind EE 2.9<R<129 is air up to Z=398
1352  dEdx = dEdX_HCal*0.05; radX0 = radX0_Air;
1353  }//betw EE and HE
1354  else if (lZ < 555 + ecShift){
1355  rzLims = MatBounds(2.9, 129, 398 + ecShift, 555 + ecShift); //HE piece 2.9<R<129;
1356  dEdx = dEdX_HCal*0.96; radX0 = radX0_HCal/0.96;
1357  } //HE calor abit less dense
1358  else {
1359  // rzLims = MatBounds(2.9, 129, 555, 785);
1360  // set the boundaries first: they serve as stop-points here
1361  // the material is set below
1362  if (lZ < 568 + ecShift) rzLims = MatBounds(2.9, 129, 555 + ecShift, 568 + ecShift); //a piece of HE support R<129, 555<Z<568
1363  else if (lZ < 625 + ecShift){
1364  if (lR < 85 + ecShift) rzLims = MatBounds(2.9, 85, 568 + ecShift, 625 + ecShift);
1365  else rzLims = MatBounds(85, 129, 568 + ecShift, 625 + ecShift);
1366  } else if (lZ < 785 + ecShift) rzLims = MatBounds(2.9, 129, 625 + ecShift, 785 + ecShift);
1367  else if (lZ < 1500 + ecShift) rzLims = MatBounds(2.9, 129, 785 + ecShift, 1500 + ecShift);
1368  else rzLims = MatBounds(2.9, 129, 1500 + ecShift, 1E4);
1369 
1370  //iron .. don't care about no material in front of HF (too forward)
1371  if (! (lZ > 568 + ecShift && lZ < 625 + ecShift && lR > 85 ) // HE support
1372  && ! (lZ > 785 + ecShift && lZ < 850 + ecShift && lR > 118)) {dEdx = dEdX_Fe; radX0 = radX0_Fe; }
1373  else { dEdx = dEdX_MCh; radX0 = radX0_MCh; } //ME at eta > 2.2
1374  }
1375  }
1376  else if (lR < 287){
1377  if (lZ < 372 + ecShift && lR < 177){ // 129<<R<177
1378  if (lZ < 304) rzLims = MatBounds(129, 177, 0, 304); //EB 129<<R<177 0<Z<304
1379  else if (lZ < 343){ // 129<<R<177 304<Z<343
1380  if (lR < 135 ) rzLims = MatBounds(129, 135, 304, 343);// tk piece 129<<R<135 304<Z<343
1381  else if (lR < 172 ){ //
1382  if (lZ < 311 ) rzLims = MatBounds(135, 172, 304, 311);
1383  else rzLims = MatBounds(135, 172, 311, 343);
1384  } else {
1385  if (lZ < 328) rzLims = MatBounds(172, 177, 304, 328);
1386  else rzLims = MatBounds(172, 177, 328, 343);
1387  }
1388  }
1389  else if ( lZ < 343 + ecShift){
1390  rzLims = MatBounds(129, 177, 343, 343 + ecShift); //gap
1391  }
1392  else {
1393  if (lR < 156 ) rzLims = MatBounds(129, 156, 343 + ecShift, 372 + ecShift);
1394  else if ( (lZ - 343 - ecShift) > (lR - 156)*1.38 )
1395  rzLims = MatBounds(156, 177, 127.72 + ecShift, 372 + ecShift, atan(1.38), 0);
1396  else rzLims = MatBounds(156, 177, 343 + ecShift, 127.72 + ecShift, 0, atan(1.38));
1397  }
1398 
1399  if (!(lR > 135 && lZ <343 + ecShift && lZ > 304 )
1400  && ! (lR > 156 && lZ < 372 + ecShift && lZ > 343 + ecShift && ((lZ-343. - ecShift )< (lR-156.)*1.38)))
1401  {
1402  //the crystals are the same length, but they are not 100% of material
1403  double cosThetaEquiv = 0.8/sqrt(1.+lZ*lZ/lR/lR) + 0.2;
1404  if (lZ > 343) cosThetaEquiv = 1.;
1405  dEdx = dEdX_ECal*cosThetaEquiv; radX0 = radX0_ECal/cosThetaEquiv;
1406  } //EB
1407  else {
1408  if ( (lZ > 304 && lZ < 328 && lR < 177 && lR > 135)
1409  && ! (lZ > 311 && lR < 172) ) {dEdx = dEdX_Fe; radX0 = radX0_Fe; } //Tk_Support
1410  else if ( lZ > 343 && lZ < 343 + ecShift) { dEdx = dEdX_Air; radX0 = radX0_Air; }
1411  else {dEdx = dEdX_ECal*0.2; radX0 = radX0_Air;} //cables go here <-- will be abit too dense for ecShift > 0
1412  }
1413  }
1414  else if (lZ < 554 + ecShift){ // 129<R<177 372<Z<554 AND 177<R<287 0<Z<554
1415  if (lR < 177){ // 129<R<177 372<Z<554
1416  if ( lZ > 372 + ecShift && lZ < 398 + ecShift )rzLims = MatBounds(129, 177, 372 + ecShift, 398 + ecShift); // EE 129<R<177 372<Z<398
1417  else if (lZ < 548 + ecShift) rzLims = MatBounds(129, 177, 398 + ecShift, 548 + ecShift); // HE 129<R<177 398<Z<548
1418  else rzLims = MatBounds(129, 177, 548 + ecShift, 554 + ecShift); // HE gap 129<R<177 548<Z<554
1419  }
1420  else if (lR < 193){ // 177<R<193 0<Z<554
1421  if ((lZ - 307) < (lR - 177.)*1.739) rzLims = MatBounds(177, 193, 0, -0.803, 0, atan(1.739));
1422  else if ( lZ < 389) rzLims = MatBounds(177, 193, -0.803, 389, atan(1.739), 0.);
1423  else if ( lZ < 389 + ecShift) rzLims = MatBounds(177, 193, 389, 389 + ecShift); // air insert
1424  else if ( lZ < 548 + ecShift ) rzLims = MatBounds(177, 193, 389 + ecShift, 548 + ecShift);// HE 177<R<193 389<Z<548
1425  else rzLims = MatBounds(177, 193, 548 + ecShift, 554 + ecShift); // HE gap 177<R<193 548<Z<554
1426  }
1427  else if (lR < 264){ // 193<R<264 0<Z<554
1428  double anApex = 375.7278 - 193./1.327; // 230.28695599096
1429  if ( (lZ - 375.7278) < (lR - 193.)/1.327) rzLims = MatBounds(193, 264, 0, anApex, 0, atan(1./1.327)); //HB
1430  else if ( (lZ - 392.7278 ) < (lR - 193.)/1.327)
1431  rzLims = MatBounds(193, 264, anApex, anApex+17., atan(1./1.327), atan(1./1.327)); // HB-HE gap
1432  else if ( (lZ - 392.7278 - ecShift ) < (lR - 193.)/1.327)
1433  rzLims = MatBounds(193, 264, anApex+17., anApex+17. + ecShift, atan(1./1.327), atan(1./1.327)); // HB-HE gap air insert
1434  // HE (372,193)-(517,193)-(517,264)-(417.8,264)
1435  else if ( lZ < 517 + ecShift ) rzLims = MatBounds(193, 264, anApex+17. + ecShift, 517 + ecShift, atan(1./1.327), 0);
1436  else if (lZ < 548 + ecShift){ // HE+gap 193<R<264 517<Z<548
1437  if (lR < 246 ) rzLims = MatBounds(193, 246, 517 + ecShift, 548 + ecShift); // HE 193<R<246 517<Z<548
1438  else rzLims = MatBounds(246, 264, 517 + ecShift, 548 + ecShift); // HE gap 246<R<264 517<Z<548
1439  }
1440  else rzLims = MatBounds(193, 264, 548 + ecShift, 554 + ecShift); // HE gap 193<R<246 548<Z<554
1441  }
1442  else if ( lR < 275){ // 264<R<275 0<Z<554
1443  if (lZ < 433) rzLims = MatBounds(264, 275, 0, 433); //HB
1444  else if (lZ < 554 ) rzLims = MatBounds(264, 275, 433, 554); // HE gap 264<R<275 433<Z<554
1445  else rzLims = MatBounds(264, 275, 554, 554 + ecShift); // HE gap 264<R<275 554<Z<554 air insert
1446  }
1447  else { // 275<R<287 0<Z<554
1448  if (lZ < 402) rzLims = MatBounds(275, 287, 0, 402);// HB 275<R<287 0<Z<402
1449  else if (lZ < 554) rzLims = MatBounds(275, 287, 402, 554);// //HE gap 275<R<287 402<Z<554
1450  else rzLims = MatBounds(275, 287, 554, 554 + ecShift); //HE gap 275<R<287 554<Z<554 air insert
1451  }
1452 
1453  if ((lZ < 433 || lR < 264) && (lZ < 402 || lR < 275) && (lZ < 517 + ecShift || lR < 246) //notches
1454  //I should've made HE and HF different .. now need to shorten HE to match
1455  && lZ < 548 + ecShift
1456  && ! (lZ < 389 + ecShift && lZ > 335 && lR < 193 ) //not a gap EB-EE 129<R<193
1457  && ! (lZ > 307 && lZ < 335 && lR < 193 && ((lZ - 307) > (lR - 177.)*1.739)) //not a gap
1458  && ! (lR < 177 && lZ < 398 + ecShift) //under the HE nose
1459  && ! (lR < 264 && lR > 193 && fabs(441.5+0.5*ecShift - lZ + (lR - 269.)/1.327) < (8.5 + ecShift*0.5)) ) //not a gap
1460  { dEdx = dEdX_HCal; radX0 = radX0_HCal; //hcal
1461  }
1462  else if( (lR < 193 && lZ > 389 && lZ < 389 + ecShift ) || (lR > 264 && lR < 287 && lZ > 554 && lZ < 554 + ecShift)
1463  ||(lR < 264 && lR > 193 && fabs(441.5+8.5+0.5*ecShift - lZ + (lR - 269.)/1.327) < ecShift*0.5) ) {
1464  dEdx = dEdX_Air; radX0 = radX0_Air;
1465  }
1466  else {dEdx = dEdX_HCal*0.05; radX0 = radX0_Air; }//endcap gap
1467  }
1468  //the rest is a tube of endcap volume 129<R<251 554<Z<largeValue
1469  else if (lZ < 564 + ecShift){ // 129<R<287 554<Z<564
1470  if (lR < 251) {
1471  rzLims = MatBounds(129, 251, 554 + ecShift, 564 + ecShift); // HE support 129<R<251 554<Z<564
1472  dEdx = dEdX_Fe; radX0 = radX0_Fe;
1473  }//HE support
1474  else {
1475  rzLims = MatBounds(251, 287, 554 + ecShift, 564 + ecShift); //HE/ME gap 251<R<287 554<Z<564
1476  dEdx = dEdX_MCh; radX0 = radX0_MCh;
1477  }
1478  }
1479  else if (lZ < 625 + ecShift){ // ME/1/1 129<R<287 564<Z<625
1480  rzLims = MatBounds(129, 287, 564 + ecShift, 625 + ecShift);
1481  dEdx = dEdX_MCh; radX0 = radX0_MCh;
1482  }
1483  else if (lZ < 785 + ecShift){ //129<R<287 625<Z<785
1484  if (lR < 275) rzLims = MatBounds(129, 275, 625 + ecShift, 785 + ecShift); //YE/1 129<R<275 625<Z<785
1485  else { // 275<R<287 625<Z<785
1486  if (lZ < 720 + ecShift) rzLims = MatBounds(275, 287, 625 + ecShift, 720 + ecShift); // ME/1/2 275<R<287 625<Z<720
1487  else rzLims = MatBounds(275, 287, 720 + ecShift, 785 + ecShift); // YE/1 275<R<287 720<Z<785
1488  }
1489  if (! (lR > 275 && lZ < 720 + ecShift)) { dEdx = dEdX_Fe; radX0 = radX0_Fe; }//iron
1490  else { dEdx = dEdX_MCh; radX0 = radX0_MCh; }
1491  }
1492  else if (lZ < 850 + ecShift){
1493  rzLims = MatBounds(129, 287, 785 + ecShift, 850 + ecShift);
1494  dEdx = dEdX_MCh; radX0 = radX0_MCh;
1495  }
1496  else if (lZ < 910 + ecShift){
1497  rzLims = MatBounds(129, 287, 850 + ecShift, 910 + ecShift);
1498  dEdx = dEdX_Fe; radX0 = radX0_Fe;
1499  }//iron
1500  else if (lZ < 975 + ecShift){
1501  rzLims = MatBounds(129, 287, 910 + ecShift, 975 + ecShift);
1502  dEdx = dEdX_MCh; radX0 = radX0_MCh;
1503  }
1504  else if (lZ < 1000 + ecShift){
1505  rzLims = MatBounds(129, 287, 975 + ecShift, 1000 + ecShift);
1506  dEdx = dEdX_Fe; radX0 = radX0_Fe;
1507  }//iron
1508  else if (lZ < 1063 + ecShift){
1509  rzLims = MatBounds(129, 287, 1000 + ecShift, 1063 + ecShift);
1510  dEdx = dEdX_MCh; radX0 = radX0_MCh;
1511  }
1512  else if ( lZ < 1073 + ecShift){
1513  rzLims = MatBounds(129, 287, 1063 + ecShift, 1073 + ecShift);
1514  dEdx = dEdX_Fe; radX0 = radX0_Fe;
1515  }
1516  else if (lZ < 1E4 ) {
1517  rzLims = MatBounds(129, 287, 1073 + ecShift, 1E4);
1518  dEdx = dEdX_Air; radX0 = radX0_Air;
1519  }
1520  else {
1521 
1522  dEdx = dEdX_Air; radX0 = radX0_Air;
1523  }
1524  }
1525  else if (lR <380 && lZ < 667){
1526  if (lZ < 630){
1527  if (lR < 315) rzLims = MatBounds(287, 315, 0, 630);
1528  else if (lR < 341 ) rzLims = MatBounds(315, 341, 0, 630); //b-field ~linear rapid fall here
1529  else rzLims = MatBounds(341, 380, 0, 630);
1530  } else rzLims = MatBounds(287, 380, 630, 667);
1531 
1532  if (lZ < 630) { dEdx = dEdX_coil; radX0 = radX0_coil; }//a guess for the solenoid average
1533  else {dEdx = dEdX_Air; radX0 = radX0_Air; }//endcap gap
1534  }
1535  else {
1536  if (lZ < 667) {
1537  if (lR < 850){
1538  bool isIron = false;
1539  //sanity check in addition to flags
1540  if (useIsYokeFlag_ && useMagVolumes_ && sv.magVol != 0){
1541  isIron = sv.isYokeVol;
1542  } else {
1543  double bMag = sv.bf.mag();
1544  isIron = (bMag > 0.75 && ! (lZ > 500 && lR <500 && bMag < 1.15)
1545  && ! (lZ < 450 && lR > 420 && bMag < 1.15 ) );
1546  }
1547  //tell the material stepper where mat bounds are
1548  rzLims = MatBounds(380, 850, 0, 667);
1549  if (isIron) { dEdx = dEdX_Fe; radX0 = radX0_Fe; }//iron
1550  else { dEdx = dEdX_MCh; radX0 = radX0_MCh; }
1551  } else {
1552  rzLims = MatBounds(850, 1E4, 0, 667);
1553  dEdx = dEdX_Air; radX0 = radX0_Air;
1554  }
1555  }
1556  else if (lR > 750 ){
1557  rzLims = MatBounds(750, 1E4, 667, 1E4);
1558  dEdx = dEdX_Air; radX0 = radX0_Air;
1559  }
1560  else if (lZ < 667 + ecShift){
1561  rzLims = MatBounds(287, 750, 667, 667 + ecShift);
1562  dEdx = dEdX_Air; radX0 = radX0_Air;
1563  }
1564  //the rest is endcap piece with 287<R<750 Z>667
1565  else if (lZ < 724 + ecShift){
1566  if (lR < 380 ) rzLims = MatBounds(287, 380, 667 + ecShift, 724 + ecShift);
1567  else rzLims = MatBounds(380, 750, 667 + ecShift, 724 + ecShift);
1568  dEdx = dEdX_MCh; radX0 = radX0_MCh;
1569  }
1570  else if (lZ < 785 + ecShift){
1571  if (lR < 380 ) rzLims = MatBounds(287, 380, 724 + ecShift, 785 + ecShift);
1572  else rzLims = MatBounds(380, 750, 724 + ecShift, 785 + ecShift);
1573  dEdx = dEdX_Fe; radX0 = radX0_Fe;
1574  }//iron
1575  else if (lZ < 850 + ecShift){
1576  rzLims = MatBounds(287, 750, 785 + ecShift, 850 + ecShift);
1577  dEdx = dEdX_MCh; radX0 = radX0_MCh;
1578  }
1579  else if (lZ < 910 + ecShift){
1580  rzLims = MatBounds(287, 750, 850 + ecShift, 910 + ecShift);
1581  dEdx = dEdX_Fe; radX0 = radX0_Fe;
1582  }//iron
1583  else if (lZ < 975 + ecShift){
1584  rzLims = MatBounds(287, 750, 910 + ecShift, 975 + ecShift);
1585  dEdx = dEdX_MCh; radX0 = radX0_MCh;
1586  }
1587  else if (lZ < 1000 + ecShift){
1588  rzLims = MatBounds(287, 750, 975 + ecShift, 1000 + ecShift);
1589  dEdx = dEdX_Fe; radX0 = radX0_Fe;
1590  }//iron
1591  else if (lZ < 1063 + ecShift){
1592  if (lR < 360){
1593  rzLims = MatBounds(287, 360, 1000 + ecShift, 1063 + ecShift);
1594  dEdx = dEdX_MCh; radX0 = radX0_MCh;
1595  }
1596  //put empty air where me4/2 should be (future)
1597  else {
1598  rzLims = MatBounds(360, 750, 1000 + ecShift, 1063 + ecShift);
1599  dEdx = dEdX_Air; radX0 = radX0_Air;
1600  }
1601  }
1602  else if ( lZ < 1073 + ecShift){
1603  rzLims = MatBounds(287, 750, 1063 + ecShift, 1073 + ecShift);
1604  //this plate does not exist: air
1605  dEdx = dEdX_Air; radX0 = radX0_Air;
1606  }
1607  else if (lZ < 1E4 ) {
1608  rzLims = MatBounds(287, 750, 1073 + ecShift, 1E4);
1609  dEdx = dEdX_Air; radX0 = radX0_Air;
1610  }
1611  else {dEdx = dEdX_Air; radX0 = radX0_Air; }//air
1612  }
1613 
1614  //dEdx so far is a relative number (relative to iron)
1615  //scale by what's expected for iron (the function was fit from pdg table)
1616  //0.065 (PDG) --> 0.044 to better match with MPV
1617  double p0 = sv.p3.mag();
1618  double logp0 = log(p0);
1619  double p0powN33 = 0;
1620  if (p0>3.) {
1621  // p0powN33 = exp(-0.33*logp0); //calculate for p>3GeV
1622  double xx=1./p0; xx=sqrt(sqrt(sqrt(sqrt(xx)))); xx=xx*xx*xx*xx*xx; // this is (p0)**(-5/16), close enough to -0.33
1623  p0powN33 = xx;
1624  }
1625  double dEdX_mat = -(11.4 + 0.96*fabs(logp0+log(2.8)) + 0.033*p0*(1.0 - p0powN33) )*1e-3;
1626  //in GeV/cm .. 0.8 to get closer to the median or MPV
1627 
1628  dEdXPrime = dEdx == 0 ? 0 : -dEdx*(0.96/p0 + 0.033 - 0.022*p0powN33)*1e-3; //== d(dEdX)/dp
1629  dEdx *= dEdX_mat;
1630 
1631  return dEdx;
1632 }
1633 
1634 
1635 int SteppingHelixPropagator::cIndex_(int ind) const{
1636  int result = ind%MAX_POINTS;
1637  if (ind != 0 && result == 0){
1638  result = MAX_POINTS;
1639  }
1640  return result;
1641 }
1642 
1643 SteppingHelixPropagator::Result
1644 SteppingHelixPropagator::refToDest(SteppingHelixPropagator::DestType dest,
1645  const SteppingHelixPropagator::StateInfo& sv,
1646  const double pars[6],
1647  double& dist, double& tanDist,
1648  PropagationDirection& refDirection,
1649  double fastSkipDist) const{
1650  static const std::string metname = "SteppingHelixPropagator";
1652 
1653  switch (dest){
1654  case RADIUS_DT:
1655  {
1656  double curR = sv.r3.perp();
1657  dist = pars[RADIUS_P] - curR;
1658  if (fabs(dist) > fastSkipDist){
1660  break;
1661  }
1662  double curP2 = sv.p3.mag2();
1663  double curPtPos2 = sv.p3.perp2(); if(curPtPos2< 1e-16) curPtPos2=1e-16;
1664 
1665  double cosDPhiPR = (sv.r3.x()*sv.p3.x()+sv.r3.y()*sv.p3.y());//only the sign is needed cos((sv.r3.deltaPhi(sv.p3)));
1666  refDirection = dist*cosDPhiPR > 0 ?
1668  tanDist = dist*sqrt(curP2/curPtPos2);
1669  result = SteppingHelixStateInfo::OK;
1670  }
1671  break;
1672  case Z_DT:
1673  {
1674  double curZ = sv.r3.z();
1675  dist = pars[Z_P] - curZ;
1676  if (fabs(dist) > fastSkipDist){
1678  break;
1679  }
1680  double curP = sv.p3.mag();
1681  refDirection = sv.p3.z()*dist > 0. ?
1683  tanDist = dist/sv.p3.z()*curP;
1684  result = SteppingHelixStateInfo::OK;
1685  }
1686  break;
1687  case PLANE_DT:
1688  {
1689  Point rPlane(pars[0], pars[1], pars[2]);
1690  Vector nPlane(pars[3], pars[4], pars[5]);
1691 
1692 
1693  // unfortunately this doesn't work: the numbers are too large
1694  // bool pVertical = fabs(pars[5])>0.9999;
1695  // double dRDotN = pVertical? (sv.r3.z() - rPlane.z())*nPlane.z() :(sv.r3 - rPlane).dot(nPlane);
1696  double dRDotN = (sv.r3.x()-rPlane.x())*nPlane.x() + (sv.r3.y()-rPlane.y())*nPlane.y() + (sv.r3.z()-rPlane.z())*nPlane.z();//(sv.r3 - rPlane).dot(nPlane);
1697 
1698  dist = fabs(dRDotN);
1699  if (dist > fastSkipDist){
1701  break;
1702  }
1703  double curP = sv.p3.mag();
1704  double p0 = curP;
1705  double p0Inv = 1./p0;
1706  Vector tau(sv.p3); tau *=p0Inv;
1707  double tN = tau.dot(nPlane);
1708  refDirection = tN*dRDotN < 0. ?
1710  double b0 = sv.bf.mag();
1711  if (fabs(tN)>1e-24){
1712  tanDist = -dRDotN/tN;
1713  } else {
1714  tN = 1e-24;
1715  if (fabs(dRDotN)>1e-24) tanDist = 1e6;
1716  else tanDist = 1;
1717  }
1718  if (fabs(tanDist) > 1e4) tanDist = 1e4;
1719  if (b0>1.5e-6){
1720  double b0Inv = 1./b0;
1721  double tNInv = 1./tN;
1722  Vector bHat(sv.bf); bHat *=b0Inv;
1723  double bHatN = bHat.dot(nPlane);
1724  double cosPB = bHat.dot(tau);
1725  double kVal = 2.99792458e-3*sv.q*p0Inv*b0;
1726  double aVal = tanDist*kVal;
1727  Vector lVec = bHat.cross(tau);
1728  double bVal = lVec.dot(nPlane)*tNInv;
1729  if (fabs(aVal*bVal)< 0.3){
1730  double cVal = 1. - bHatN*cosPB*tNInv; // - sv.bf.cross(lVec).dot(nPlane)*b0Inv*tNInv; //1- bHat_n*bHat_tau/tau_n;
1731  double aacVal = cVal*aVal*aVal;
1732  if (fabs(aacVal)<1){
1733  double tanDCorr = bVal/2. + (bVal*bVal/2. + cVal/6)*aVal;
1734  tanDCorr *= aVal;
1735  //+ (-bVal/24. + 0.625*bVal*bVal*bVal + 5./12.*bVal*cVal)*aVal*aVal*aVal
1736  if (debug_) LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<tanDist<<" vs "
1737  <<tanDist*(1.+tanDCorr)<<" corr "<<tanDist*tanDCorr<<std::endl;
1738  tanDist *= (1.+tanDCorr);
1739  } else {
1740  if (debug_) LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"AACVal "<< fabs(aacVal)
1741  <<" = "<<aVal<<"**2 * "<<cVal<<" too large:: will not converge"<<std::endl;
1742  }
1743  } else {
1744  if (debug_) LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"ABVal "<< fabs(aVal*bVal)
1745  <<" = "<<aVal<<" * "<<bVal<<" too large:: will not converge"<<std::endl;
1746  }
1747  }
1748  result = SteppingHelixStateInfo::OK;
1749  }
1750  break;
1751  case CONE_DT:
1752  {
1753  Point cVertex(pars[0], pars[1], pars[2]);
1754  if (cVertex.perp2() < 1e-10){
1755  //assumes the cone axis/vertex is along z
1756  Vector relV3 = sv.r3 - cVertex;
1757  double relV3mag = relV3.mag();
1758  // double relV3Theta = relV3.theta();
1759  double theta(pars[3]);
1760  // double dTheta = theta-relV3Theta;
1761  double sinTheta = sin(theta);
1762  double cosTheta = cos(theta);
1763  double cosV3Theta = relV3.z()/relV3mag;
1764  if (cosV3Theta>1) cosV3Theta=1;
1765  if (cosV3Theta<-1) cosV3Theta=-1;
1766  double sinV3Theta = sqrt(1.-cosV3Theta*cosV3Theta);
1767 
1768  double sinDTheta = sinTheta*cosV3Theta - cosTheta*sinV3Theta;//sin(dTheta);
1769  double cosDTheta = cosTheta*cosV3Theta + sinTheta*sinV3Theta;//cos(dTheta);
1770  bool isInside = sinTheta > sinV3Theta && cosTheta*cosV3Theta > 0;
1771  dist = isInside || cosDTheta > 0 ? relV3mag*sinDTheta : relV3mag;
1772  if (fabs(dist) > fastSkipDist){
1774  break;
1775  }
1776 
1777  double relV3phi=relV3.phi();
1778  double normPhi = isInside ?
1779  Geom::pi() + relV3phi : relV3phi;
1780  double normTheta = theta > Geom::pi()/2. ?
1781  ( isInside ? 1.5*Geom::pi() - theta : theta - Geom::pi()/2. )
1782  : ( isInside ? Geom::pi()/2. - theta : theta + Geom::pi()/2 );
1783  //this is a normVector from the cone to the point
1784  Vector norm; norm.setRThetaPhi(fabs(dist), normTheta, normPhi);
1785  double curP = sv.p3.mag(); double cosp3theta = sv.p3.z()/curP;
1786  if (cosp3theta>1) cosp3theta=1;
1787  if (cosp3theta<-1) cosp3theta=-1;
1788  double sineConeP = sinTheta*cosp3theta - cosTheta*sqrt(1.-cosp3theta*cosp3theta);
1789 
1790  double sinSolid = norm.dot(sv.p3)/(fabs(dist)*curP);
1791  tanDist = fabs(sinSolid) > fabs(sineConeP) ? dist/fabs(sinSolid) : dist/fabs(sineConeP);
1792 
1793 
1794  refDirection = sinSolid > 0 ?
1796  if (debug_){
1797  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Cone pars: theta "<<theta
1798  <<" normTheta "<<norm.theta()
1799  <<" p3Theta "<<sv.p3.theta()
1800  <<" sinD: "<< sineConeP
1801  <<" sinSolid "<<sinSolid;
1802  }
1803  if (debug_){
1804  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"refToDest:toCone the point is "
1805  <<(isInside? "in" : "out")<<"side the cone"
1806  <<std::endl;
1807  }
1808  }
1809  result = SteppingHelixStateInfo::OK;
1810  }
1811  break;
1812  // case CYLINDER_DT:
1813  // break;
1814  case PATHL_DT:
1815  {
1816  double curS = fabs(sv.path());
1817  dist = pars[PATHL_P] - curS;
1818  if (fabs(dist) > fastSkipDist){
1820  break;
1821  }
1822  refDirection = pars[PATHL_P] > 0 ?
1824  tanDist = dist;
1825  result = SteppingHelixStateInfo::OK;
1826  }
1827  break;
1828  case POINT_PCA_DT:
1829  {
1830  Point pDest(pars[0], pars[1], pars[2]);
1831  double curP = sv.p3.mag();
1832  dist = (sv.r3 - pDest).mag()+ 1e-24;//add a small number to avoid 1/0
1833  tanDist = (sv.r3.dot(sv.p3) - pDest.dot(sv.p3))/curP;
1834  //account for bending in magnetic field (quite approximate)
1835  double b0 = sv.bf.mag();
1836  if (b0>1.5e-6){
1837  double p0 = curP;
1838  double kVal = 2.99792458e-3*sv.q/p0*b0;
1839  double aVal = fabs(dist*kVal);
1840  tanDist *= 1./(1.+ aVal);
1841  if (debug_) LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"corrected by aVal "<<aVal<<" to "<<tanDist;
1842  }
1843  refDirection = tanDist < 0 ?
1845  result = SteppingHelixStateInfo::OK;
1846  }
1847  break;
1848  case LINE_PCA_DT:
1849  {
1850  Point rLine(pars[0], pars[1], pars[2]);
1851  Vector dLine(pars[3], pars[4], pars[5]);
1852  dLine = (dLine - rLine);
1853  dLine *= 1./dLine.mag(); if (debug_) LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"dLine "<<dLine;
1854 
1855  Vector dR = sv.r3 - rLine;
1856  double curP = sv.p3.mag();
1857  Vector dRPerp = dR - dLine*(dR.dot(dLine));
1858  if (debug_) LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"dRperp "<<dRPerp;
1859 
1860  dist = dRPerp.mag() + 1e-24;//add a small number to avoid 1/0
1861  tanDist = dRPerp.dot(sv.p3)/curP;
1862  //angle wrt line
1863  double cosAlpha2 = dLine.dot(sv.p3)/curP; cosAlpha2 *= cosAlpha2;
1864  tanDist *= 1./sqrt(fabs(1.-cosAlpha2)+1e-96);
1865  //correct for dPhi in magnetic field: this isn't made quite right here
1866  //(the angle between the line and the trajectory plane is neglected .. conservative)
1867  double b0 = sv.bf.mag();
1868  if (b0>1.5e-6){
1869  double p0 = curP;
1870  double kVal = 2.99792458e-3*sv.q/p0*b0;
1871  double aVal = fabs(dist*kVal);
1872  tanDist *= 1./(1.+ aVal);
1873  if (debug_) LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"corrected by aVal "<<aVal<<" to "<<tanDist;
1874  }
1875  refDirection = tanDist < 0 ?
1877  result = SteppingHelixStateInfo::OK;
1878  }
1879  break;
1880  default:
1881  {
1882  //some large number
1883  dist = 1e12;
1884  tanDist = 1e12;
1885  refDirection = anyDirection;
1887  }
1888  break;
1889  }
1890 
1891  double tanDistConstrained = tanDist;
1892  if (fabs(tanDist) > 4.*fabs(dist) ) tanDistConstrained *= tanDist == 0 ? 0 : fabs(dist/tanDist*4.);
1893 
1894  if (debug_){
1895  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"refToDest input: dest"<<dest<<" pars[]: ";
1896  for (int i = 0; i < 6; i++){
1897  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<", "<<i<<" "<<pars[i];
1898  }
1899  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<std::endl;
1900  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"refToDest output: "
1901  <<"\t dist" << dist
1902  <<"\t tanDist "<< tanDist
1903  <<"\t tanDistConstr "<< tanDistConstrained
1904  <<"\t refDirection "<< refDirection
1905  <<std::endl;
1906  }
1907  tanDist = tanDistConstrained;
1908 
1909  return result;
1910 }
1911 
1912 SteppingHelixPropagator::Result
1913 SteppingHelixPropagator::refToMagVolume(const SteppingHelixPropagator::StateInfo& sv,
1915  double& dist, double& tanDist,
1916  double fastSkipDist, bool expectNewMagVolume, double maxStep) const{
1917 
1918  static const std::string metname = "SteppingHelixPropagator";
1920  const MagVolume* cVol = sv.magVol;
1921 
1922  if (cVol == 0) return result;
1923  const std::vector<VolumeSide>& cVolFaces(cVol->faces());
1924 
1925  double distToFace[6] = {0,0,0,0,0,0};
1926  double tanDistToFace[6] = {0,0,0,0,0,0};
1927  PropagationDirection refDirectionToFace[6] = {anyDirection, anyDirection, anyDirection, anyDirection, anyDirection, anyDirection};
1928  Result resultToFace[6] = {result, result, result, result, result, result};
1929  int iFDest = -1;
1930  int iDistMin = -1;
1931 
1932  unsigned int iFDestSorted[6] = {0,0,0,0,0,0};
1933  unsigned int nDestSorted =0;
1934  unsigned int nearParallels = 0;
1935 
1936  double curP = sv.p3.mag();
1937 
1938  if (debug_){
1939  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Trying volume "<<DDSolidShapesName::name(cVol->shapeType())
1940  <<" with "<<cVolFaces.size()<<" faces"<<std::endl;
1941  }
1942 
1943  unsigned int nFaces = cVolFaces.size();
1944  for (unsigned int iFace = 0; iFace < nFaces; ++iFace){
1945  if (iFace > 5){
1946  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Too many faces"<<std::endl;
1947  }
1948  if (debug_){
1949  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Start with face "<<iFace<<std::endl;
1950  }
1951 // const Plane* cPlane = dynamic_cast<const Plane*>(&cVolFaces[iFace].surface());
1952 // const Cylinder* cCyl = dynamic_cast<const Cylinder*>(&cVolFaces[iFace].surface());
1953 // const Cone* cCone = dynamic_cast<const Cone*>(&cVolFaces[iFace].surface());
1954  const Surface* cPlane = 0; //only need to know the loc->glob transform
1955  const Cylinder* cCyl = 0;
1956  const Cone* cCone = 0;
1957  if (typeid(cVolFaces[iFace].surface()) == typeid(const Plane&)){
1958  cPlane = &cVolFaces[iFace].surface();
1959  } else if (typeid(cVolFaces[iFace].surface()) == typeid(const Cylinder&)){
1960  cCyl = dynamic_cast<const Cylinder*>(&cVolFaces[iFace].surface());
1961  } else if (typeid(cVolFaces[iFace].surface()) == typeid(const Cone&)){
1962  cCone = dynamic_cast<const Cone*>(&cVolFaces[iFace].surface());
1963  } else {
1964  edm::LogWarning(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Could not cast a volume side surface to a known type"<<std::endl;
1965  }
1966 
1967  if (debug_){
1968  if (cPlane!=0) LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"The face is a plane at "<<cPlane<<std::endl;
1969  if (cCyl!=0) LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"The face is a cylinder at "<<cCyl<<std::endl;
1970  }
1971 
1972  double pars[6] = {0,0,0,0,0,0};
1973  DestType dType = UNDEFINED_DT;
1974  if (cPlane != 0){
1975  Point rPlane(cPlane->position().x(),cPlane->position().y(),cPlane->position().z());
1976  // = cPlane->toGlobal(LocalVector(0,0,1.)); nPlane = nPlane.unit();
1977  Vector nPlane(cPlane->rotation().zx(), cPlane->rotation().zy(), cPlane->rotation().zz()); nPlane /= nPlane.mag();
1978 
1979  pars[0] = rPlane.x(); pars[1] = rPlane.y(); pars[2] = rPlane.z();
1980  pars[3] = nPlane.x(); pars[4] = nPlane.y(); pars[5] = nPlane.z();
1981  dType = PLANE_DT;
1982  } else if (cCyl != 0){
1983  if (debug_){
1984  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Cylinder at "<<cCyl->position()
1985  <<" rorated by "<<cCyl->rotation()
1986  <<std::endl;
1987  }
1988  pars[RADIUS_P] = cCyl->radius();
1989  dType = RADIUS_DT;
1990  } else if (cCone != 0){
1991  if (debug_){
1992  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Cone at "<<cCone->position()
1993  <<" rorated by "<<cCone->rotation()
1994  <<" vertex at "<<cCone->vertex()
1995  <<" angle of "<<cCone->openingAngle()
1996  <<std::endl;
1997  }
1998  pars[0] = cCone->vertex().x(); pars[1] = cCone->vertex().y();
1999  pars[2] = cCone->vertex().z();
2000  pars[3] = cCone->openingAngle();
2001  dType = CONE_DT;
2002  } else {
2003  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Unknown surface"<<std::endl;
2004  resultToFace[iFace] = SteppingHelixStateInfo::UNDEFINED;
2005  continue;
2006  }
2007  resultToFace[iFace] =
2008  refToDest(dType, sv, pars,
2009  distToFace[iFace], tanDistToFace[iFace], refDirectionToFace[iFace], fastSkipDist);
2010 
2011 
2012  if (resultToFace[iFace] != SteppingHelixStateInfo::OK){
2013  if (resultToFace[iFace] == SteppingHelixStateInfo::INACC) result = SteppingHelixStateInfo::INACC;
2014  }
2015 
2016 
2017 
2018  //keep those in right direction for later use
2019  if (resultToFace[iFace] == SteppingHelixStateInfo::OK){
2020  double invDTFPosiF = 1./(1e-32+fabs(tanDistToFace[iFace]));
2021  double dSlope = fabs(distToFace[iFace])*invDTFPosiF;
2022  double maxStepL = maxStep> 100 ? 100 : maxStep; if (maxStepL < 10) maxStepL = 10.;
2023  bool isNearParallel = fabs(tanDistToFace[iFace]) + 100.*curP*dSlope < maxStepL //
2024  //a better choice is to use distance to next check of mag volume instead of 100cm; the last is for ~1.5arcLength(4T)+tandistance< maxStep
2025  && dSlope < 0.15 ; //
2026  if (refDirectionToFace[iFace] == dir || isNearParallel){
2027  if (isNearParallel) nearParallels++;
2028  iFDestSorted[nDestSorted] = iFace;
2029  nDestSorted++;
2030  }
2031  }
2032 
2033  //pick a shortest distance here (right dir only for now)
2034  if (refDirectionToFace[iFace] == dir){
2035  if (iDistMin == -1) iDistMin = iFace;
2036  else if (fabs(distToFace[iFace]) < fabs(distToFace[iDistMin])) iDistMin = iFace;
2037  }
2038  if (debug_)
2039  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<cVol<<" "<<iFace<<" "
2040  <<tanDistToFace[iFace]<<" "<<distToFace[iFace]<<" "<<refDirectionToFace[iFace]<<" "<<dir<<std::endl;
2041 
2042  }
2043 
2044  for (unsigned int i = 0;i<nDestSorted; ++i){
2045  unsigned int iMax = nDestSorted-i-1;
2046  for (unsigned int j=0;j<nDestSorted-i; ++j){
2047  if (fabs(tanDistToFace[iFDestSorted[j]]) > fabs(tanDistToFace[iFDestSorted[iMax]]) ){
2048  iMax = j;
2049  }
2050  }
2051  unsigned int iTmp = iFDestSorted[nDestSorted-i-1];
2052  iFDestSorted[nDestSorted-i-1] = iFDestSorted[iMax];
2053  iFDestSorted[iMax] = iTmp;
2054  }
2055 
2056  if (debug_){
2057  for (unsigned int i=0;i<nDestSorted;++i){
2058  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<cVol<<" "<<i<<" "<<iFDestSorted[i]<<" "<<tanDistToFace[iFDestSorted[i]]<<std::endl;
2059  }
2060  }
2061 
2062  //now go from the shortest to the largest distance hoping to get a point in the volume.
2063  //other than in case of a near-parallel travel this should stop after the first try
2064 
2065  for (unsigned int i=0; i<nDestSorted;++i){
2066  iFDest = iFDestSorted[i];
2067 
2068  double sign = dir == alongMomentum ? 1. : -1.;
2069  Point gPointEst(sv.r3);
2070  Vector lDelta(sv.p3); lDelta *= sign/curP*fabs(distToFace[iFDest]);
2071  gPointEst += lDelta;
2072  if (debug_){
2073  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Linear est point "<<gPointEst
2074  <<" for iFace "<<iFDest<<std::endl;
2075  }
2076  GlobalPoint gPointEstNorZ(gPointEst.x(), gPointEst.y(), gPointEst.z() );
2077  if ( cVol->inside(gPointEstNorZ) ){
2078  if (debug_){
2079  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"The point is inside the volume"<<std::endl;
2080  }
2081 
2082  result = SteppingHelixStateInfo::OK;
2083  dist = distToFace[iFDest];
2084  tanDist = tanDistToFace[iFDest];
2085  if (debug_){
2086  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Got a point near closest boundary -- face "<<iFDest<<std::endl;
2087  }
2088  break;
2089  }
2090  }
2091 
2092  if (result != SteppingHelixStateInfo::OK && expectNewMagVolume){
2093  double sign = dir == alongMomentum ? 1. : -1.;
2094 
2095  //check if it's a wrong volume situation
2096  if (nDestSorted-nearParallels > 0 ) result = SteppingHelixStateInfo::WRONG_VOLUME;
2097  else {
2098  //get here if all faces in the corr direction were skipped
2099  Point gPointEst(sv.r3);
2100  double lDist = iDistMin == -1 ? fastSkipDist : fabs(distToFace[iDistMin]);
2101  if (lDist > fastSkipDist) lDist = fastSkipDist;
2102  Vector lDelta(sv.p3); lDelta *= sign/curP*lDist;
2103  gPointEst += lDelta;
2104  if (debug_){
2105  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Linear est point to shortest dist "<<gPointEst
2106  <<" for iFace "<<iDistMin<<" at distance "<<lDist*sign<<std::endl;
2107  }
2108  GlobalPoint gPointEstNorZ(gPointEst.x(), gPointEst.y(), gPointEst.z() );
2109  if ( cVol->inside(gPointEstNorZ) ){
2110  if (debug_){
2111  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"The point is inside the volume"<<std::endl;
2112  }
2113 
2114  }else {
2116  }
2117  }
2118 
2119  if (result == SteppingHelixStateInfo::WRONG_VOLUME){
2120  dist = sign*0.05;
2121  tanDist = dist*1.01;
2122  if( debug_){
2123  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Wrong volume located: return small dist, tandist"<<std::endl;
2124  }
2125  }
2126  }
2127 
2128  if (result == SteppingHelixStateInfo::INACC){
2129  if (debug_) LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"All faces are too far"<<std::endl;
2130  } else if (result == SteppingHelixStateInfo::WRONG_VOLUME){
2131  if (debug_) LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Appear to be in a wrong volume"<<std::endl;
2132  } else if (result != SteppingHelixStateInfo::OK){
2133  if (debug_) LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Something else went wrong"<<std::endl;
2134  }
2135 
2136 
2137  return result;
2138 }
2139 
2140 
2141 SteppingHelixPropagator::Result
2142 SteppingHelixPropagator::refToMatVolume(const SteppingHelixPropagator::StateInfo& sv,
2144  double& dist, double& tanDist,
2145  double fastSkipDist) const{
2146 
2147  static const std::string metname = "SteppingHelixPropagator";
2149 
2150  double parLim[6] = {sv.rzLims.rMin, sv.rzLims.rMax,
2151  sv.rzLims.zMin, sv.rzLims.zMax,
2152  sv.rzLims.th1, sv.rzLims.th2 };
2153 
2154  double distToFace[4] = {0,0,0,0};
2155  double tanDistToFace[4] = {0,0,0,0};
2156  PropagationDirection refDirectionToFace[4] = {anyDirection, anyDirection, anyDirection, anyDirection};
2157  Result resultToFace[4] = {result, result, result, result};
2158  int iFDest = -1;
2159 
2160  double curP = sv.p3.mag();
2161 
2162  for (unsigned int iFace = 0; iFace < 4; iFace++){
2163  if (debug_){
2164  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Start with mat face "<<iFace<<std::endl;
2165  }
2166 
2167  double pars[6] = {0,0,0,0,0,0};
2168  DestType dType = UNDEFINED_DT;
2169  if (iFace > 1){
2170  if (fabs(parLim[iFace+2])< 1e-6){//plane
2171  if (sv.r3.z() < 0){
2172  pars[0] = 0; pars[1] = 0; pars[2] = -parLim[iFace];
2173  pars[3] = 0; pars[4] = 0; pars[5] = 1;
2174  } else {
2175  pars[0] = 0; pars[1] = 0; pars[2] = parLim[iFace];
2176  pars[3] = 0; pars[4] = 0; pars[5] = 1;
2177  }
2178  dType = PLANE_DT;
2179  } else {
2180  if (sv.r3.z() > 0){
2181  pars[0] = 0; pars[1] = 0;
2182  pars[2] = parLim[iFace];
2183  pars[3] = Geom::pi()/2. - parLim[iFace+2];
2184  } else {
2185  pars[0] = 0; pars[1] = 0;
2186  pars[2] = - parLim[iFace];
2187  pars[3] = Geom::pi()/2. + parLim[iFace+2];
2188  }
2189  dType = CONE_DT;
2190  }
2191  } else {
2192  pars[RADIUS_P] = parLim[iFace];
2193  dType = RADIUS_DT;
2194  }
2195 
2196  resultToFace[iFace] =
2197  refToDest(dType, sv, pars,
2198  distToFace[iFace], tanDistToFace[iFace], refDirectionToFace[iFace], fastSkipDist);
2199 
2200  if (resultToFace[iFace] != SteppingHelixStateInfo::OK){
2201  if (resultToFace[iFace] == SteppingHelixStateInfo::INACC) result = SteppingHelixStateInfo::INACC;
2202  continue;
2203  }
2204  if (refDirectionToFace[iFace] == dir || fabs(distToFace[iFace]) < 2e-2*fabs(tanDistToFace[iFace]) ){
2205  double sign = dir == alongMomentum ? 1. : -1.;
2206  Point gPointEst(sv.r3);
2207  Vector lDelta(sv.p3); lDelta *= sign*fabs(distToFace[iFace])/curP;
2208  gPointEst += lDelta;
2209  if (debug_){
2210  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Linear est point "<<gPointEst
2211  <<std::endl;
2212  }
2213  double lZ = fabs(gPointEst.z());
2214  double lR = gPointEst.perp();
2215  double tan4 = parLim[4] == 0 ? 0 : tan(parLim[4]);
2216  double tan5 = parLim[5] == 0 ? 0 : tan(parLim[5]);
2217  if ( (lZ - parLim[2]) > lR*tan4
2218  && (lZ - parLim[3]) < lR*tan5
2219  && lR > parLim[0] && lR < parLim[1]){
2220  if (debug_){
2221  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"The point is inside the volume"<<std::endl;
2222  }
2223  //OK, guessed a point still inside the volume
2224  if (iFDest == -1){
2225  iFDest = iFace;
2226  } else {
2227  if (fabs(tanDistToFace[iFDest]) > fabs(tanDistToFace[iFace])){
2228  iFDest = iFace;
2229  }
2230  }
2231  } else {
2232  if (debug_){
2233  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"The point is NOT inside the volume"<<std::endl;
2234  }
2235  }
2236  }
2237 
2238  }
2239  if (iFDest != -1){
2240  result = SteppingHelixStateInfo::OK;
2241  dist = distToFace[iFDest];
2242  tanDist = tanDistToFace[iFDest];
2243  if (debug_){
2244  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Got a point near closest boundary -- face "<<iFDest<<std::endl;
2245  }
2246  } else {
2247  if (debug_){
2248  LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Failed to find a dest point inside the volume"<<std::endl;
2249  }
2250  }
2251 
2252  return result;
2253 }
2254 
2255 
2256 bool SteppingHelixPropagator::isYokeVolume(const MagVolume* vol) const {
2257  static const std::string metname = "SteppingHelixPropagator";
2258  if (vol == 0) return false;
2259  /*
2260  const MFGrid* mGrid = reinterpret_cast<const MFGrid*>(vol->provider());
2261  std::vector<int> dims(mGrid->dimensions());
2262 
2263  LocalVector lVCen(mGrid->nodeValue(dims[0]/2, dims[1]/2, dims[2]/2));
2264  LocalVector lVZLeft(mGrid->nodeValue(dims[0]/2, dims[1]/2, dims[2]/5));
2265  LocalVector lVZRight(mGrid->nodeValue(dims[0]/2, dims[1]/2, (dims[2]*4)/5));
2266 
2267  double mag2VCen = lVCen.mag2();
2268  double mag2VZLeft = lVZLeft.mag2();
2269  double mag2VZRight = lVZRight.mag2();
2270 
2271  bool result = false;
2272  if (mag2VCen > 0.6 && mag2VZLeft > 0.6 && mag2VZRight > 0.6){
2273  if (debug_) LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Volume is magnetic, located at "<<vol->position()<<std::endl;
2274  result = true;
2275  } else {
2276  if (debug_) LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Volume is not magnetic, located at "<<vol->position()<<std::endl;
2277  }
2278 
2279  */
2280  bool result = vol->isIron();
2281  if (result){
2282  if (debug_) LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Volume is magnetic, located at "<<vol->position()<<std::endl;
2283  } else {
2284  if (debug_) LogTrace(metname)<<std::setprecision(17)<<std::setw(20)<<std::scientific<<"Volume is not magnetic, located at "<<vol->position()<<std::endl;
2285  }
2286 
2287  return result;
2288 }
type
Definition: HCALResponse.h:21
double z0() const
z coordinate
Definition: BeamSpot.h:68
int i
Definition: DBlmapReader.cc:9
string rep
Definition: cuy.py:1188
T mag2() const
Definition: PV3DBase.h:66
DDSolidShape shapeType() const
Definition: MagVolume.h:31
tuple pp
Definition: createTree.py:15
const std::string metname
ROOT::Math::Plane3D::Vector Vector
Definition: EcalHitMaker.cc:29
T mag() const
The vector magnitude. Equivalent to sqrt(vec.mag2())
ROOT::Math::SMatrixIdentity AlgebraicMatrixID
Sin< T >::type sin(const T &t)
Definition: Sin.h:22
Global3DPoint GlobalPoint
Definition: GlobalPoint.h:10
Geom::Theta< T > theta() const
T y() const
Definition: PV3DBase.h:63
AlgebraicSymMatrix55 covCurv
ROOT::Math::SMatrix< double, 5, 5, ROOT::Math::MatRepSym< double, 5 > > AlgebraicSymMatrix55
PropagationDirection
std::pair< double, double > Point
Definition: CaloEllipse.h:18
double charge(const std::vector< uint8_t > &Ampls)
Definition: Plane.h:17
tuple field
Definition: statics.py:62
T zx() const
double dydz() const
dydz slope
Definition: BeamSpot.h:84
T zz() const
static const char *const name(DDSolidShape s)
Definition: DDSolidShapes.h:21
virtual bool inside(const GlobalPoint &gp, double tolerance=0.) const =0
T sqrt(T t)
Definition: SSEVec.h:48
T z() const
Definition: PV3DBase.h:64
tuple result
Definition: query.py:137
Cos< T >::type cos(const T &t)
Definition: Cos.h:22
math::XYZPoint Point
Tan< T >::type tan(const T &t)
Definition: Tan.h:22
T zy() const
int j
Definition: DBlmapReader.cc:9
#define LogTrace(id)
double dxdz() const
dxdz slope
Definition: BeamSpot.h:82
bool isIron() const
Temporary hack to pass information on material. Will eventually be replaced!
Definition: MagVolume.h:51
virtual const std::vector< VolumeSide > & faces() const =0
Access to volume faces.
std::vector< std::vector< double > > tmp
Definition: MVATrainer.cc:100
double pi()
Definition: Pi.h:31
double y0() const
y coordinate
Definition: BeamSpot.h:66
const RotationType & rotation() const
dbl *** dir
Definition: mlp_gen.cc:35
const double epsilon
T x() const
Definition: PV3DBase.h:62
const PositionType & position() const
ROOT::Math::SMatrix< double, 5, 5, ROOT::Math::MatRepStd< double, 5, 5 > > AlgebraicMatrix55
static const std::string ResultName[MAX_RESULT]
double p3[4]
Definition: TauolaWrapper.h:91
double x0() const
x coordinate
Definition: BeamSpot.h:64
Definition: DDAxes.h:10