CMS 3D CMS Logo

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