CMS 3D CMS Logo

BaseParticlePropagator.cc
Go to the documentation of this file.
1 //FAMOS headers
3 #include <array>
4 
6  rCyl(0.), rCyl2(0.), zCyl(0.), bField(0), properDecayTime(1E99)
7 {;}
8 
10  const RawParticle& myPart,double R, double Z, double B, double t ) :
11  particle_(myPart), rCyl(R), rCyl2(R*R), zCyl(Z), bField(B), properDecayTime(t)
12 {
13  init();
14 }
15 
17  const RawParticle& myPart,double R, double Z, double B) :
18  particle_(myPart), rCyl(R), rCyl2(R*R), zCyl(Z), bField(B), properDecayTime(1E99)
19 {
20  init();
21 }
22 
23 void
25 
26  // The status of the propagation
27  success = 0;
28  // Propagate only for the first half-loop
29  firstLoop = true;
30  //
31  fiducial = true;
32  // The particle has not yet decayed
33  decayed = false;
34  // The proper time is set to zero
35  properTime = 0.;
36  // The propagation direction is along the momentum
37  propDir = 1;
38  //
39  debug = false;
40 
41 }
42 
43 bool
45 
46 
47  //
48  // Check that the particle is not already on the cylinder surface
49  //
50  double rPos2 = particle_.R2();
51 
52  if ( onBarrel(rPos2) ) {
53  success = 1;
54  return true;
55  }
56  //
57  if ( onEndcap(rPos2) ) {
58  success = 2;
59  return true;
60  }
61  //
62  // Treat neutral particles (or no magnetic field) first
63  //
64  if ( fabs(particle_.charge()) < 1E-12 || bField < 1E-12 ) {
65 
66  //
67  // First check that the particle crosses the cylinder
68  //
69  double pT2 = particle_.Perp2();
70  // double pT2 = pT*pT;
71  // double b2 = rCyl * pT;
72  double b2 = rCyl2 * pT2;
73  double ac = fabs ( particle_.X()*particle_.Py() - particle_.Y()*particle_.Px() );
74  double ac2 = ac*ac;
75  //
76  // The particle never crosses (or never crossed) the cylinder
77  //
78  // if ( ac > b2 ) return false;
79  if ( ac2 > b2 ) return false;
80 
81  // double delta = std::sqrt(b2*b2 - ac*ac);
82  double delta = std::sqrt(b2 - ac2);
83  double tplus = -( particle_.X()*particle_.Px()+particle_.Y()*particle_.Py() ) + delta;
84  double tminus = -( particle_.X()*particle_.Px()+particle_.Y()*particle_.Py() ) - delta;
85  //
86  // Find the first (time-wise) intersection point with the cylinder
87  //
88 
89  double solution = tminus < 0 ? tplus/pT2 : tminus/pT2;
90  if ( solution < 0. ) return false;
91  //
92  // Check that the particle does (did) not exit from the endcaps first.
93  //
94  double zProp = particle_.Z() + particle_.Pz() * solution;
95  if ( fabs(zProp) > zCyl ) {
96  tplus = ( zCyl - particle_.Z() ) / particle_.Pz();
97  tminus = (-zCyl - particle_.Z() ) / particle_.Pz();
98  solution = tminus < 0 ? tplus : tminus;
99  if ( solution < 0. ) return false;
100  zProp = particle_.Z() + particle_.Pz() * solution;
101  success = 2;
102  }
103  else {
104  success = 1;
105  }
106 
107  //
108  // Check the decay time
109  //
110  double delTime = propDir * particle_.mass() * solution;
111  double factor = 1.;
112  properTime += delTime;
113  if ( properTime > properDecayTime ) {
114  factor = 1.-(properTime-properDecayTime)/delTime;
116  decayed = true;
117  }
118 
119  //
120  // Compute the coordinates of the RawParticle after propagation
121  //
122  double xProp = particle_.X() + particle_.Px() * solution * factor;
123  double yProp = particle_.Y() + particle_.Py() * solution * factor;
124  zProp = particle_.Z() + particle_.Pz() * solution * factor;
125  double tProp = particle_.T() + particle_.E() * solution * factor;
126 
127  //
128  // Last check : Although propagated to the endcaps, R could still be
129  // larger than rCyl because the cylinder was too short...
130  //
131  if ( success == 2 && xProp*xProp+yProp*yProp > rCyl2 ) {
132  success = -1;
133  return true;
134  }
135 
136  //
137  // ... and update the particle with its propagated coordinates
138  //
139  particle_.setVertex( XYZTLorentzVector(xProp,yProp,zProp,tProp) );
140 
141  return true;
142  }
143  //
144  // Treat charged particles with magnetic field next.
145  //
146  else {
147  //
148  // First check that the particle can cross the cylinder
149  //
150  double pT = particle_.Pt();
151  double radius = helixRadius(pT);
152  double phi0 = helixStartPhi();
153  double xC = helixCentreX(radius,phi0);
154  double yC = helixCentreY(radius,phi0);
155  double dist = helixCentreDistToAxis(xC,yC);
156  //
157  // The helix either is outside or includes the cylinder -> no intersection
158  //
159  if ( fabs ( fabs(radius) - dist ) > rCyl ) return false;
160  //
161  // The particle is already away from the endcaps, and will never come back
162  // Could be back-propagated, so warn the user that it is so.
163  //
164  if ( particle_.Z() * particle_.Pz() > zCyl * fabs(particle_.Pz()) ) {
165  success = -2;
166  return true;
167  }
168 
169  double pZ = particle_.Pz();
170  double phiProp, zProp;
171  //
172  // Does the helix cross the cylinder barrel ? If not, do the first half-loop
173  //
174  double rProp = std::min(fabs(radius)+dist-0.000001, rCyl);
175 
176  // Check for rounding errors in the ArcSin.
177  double sinPhiProp =
178  (rProp*rProp-radius*radius-dist*dist)/( 2.*dist*radius);
179 
180  //
181  double deltaPhi = 1E99;
182 
183  // Taylor development up to third order for large momenta
184  if ( 1.-fabs(sinPhiProp) < 1E-9 ) {
185 
186  double cphi0 = std::cos(phi0);
187  double sphi0 = std::sin(phi0);
188  double r0 = (particle_.X()*cphi0 + particle_.Y()*sphi0)/radius;
189  double q0 = (particle_.X()*sphi0 - particle_.Y()*cphi0)/radius;
190  double rcyl2 = (rCyl2 - particle_.X()*particle_.X() - particle_.Y()*particle_.Y())/(radius*radius);
191  double delta = r0*r0 + rcyl2*(1.-q0);
192 
193  // This is a solution of a second order equation, assuming phi = phi0 + epsilon
194  // and epsilon is small.
195  deltaPhi = radius > 0 ?
196  ( -r0 + std::sqrt(delta ) ) / (1.-q0) :
197  ( -r0 - std::sqrt(delta ) ) / (1.-q0);
198 
199  }
200 
201  // Use complete calculation otherwise, or if the delta phi is large anyway.
202  if ( fabs(deltaPhi) > 1E-3 ) {
203 
204  // phiProp = fabs(sinPhiProp) < 0.99999999 ?
205  // std::asin(sinPhiProp) : M_PI/2. * sinPhiProp;
206  phiProp = std::asin(sinPhiProp);
207 
208  //
209  // Compute phi after propagation (two solutions, but the asin definition
210  // (between -pi/2 and +pi/2) takes care of the wrong one.
211  //
212  phiProp = helixCentrePhi(xC,yC) +
213  ( inside(rPos2) || onSurface(rPos2) ? phiProp : M_PI-phiProp );
214 
215  //
216  // Solve the obvious two-pi ambiguities: more than one turn!
217  //
218  if ( fabs(phiProp - phi0) > 2.*M_PI )
219  phiProp += ( phiProp > phi0 ? -2.*M_PI : +2.*M_PI );
220 
221  //
222  // Check that the phi difference has the right sign, according to Q*B
223  // (Another two pi ambuiguity, slightly more subtle)
224  //
225  if ( (phiProp-phi0)*radius < 0.0 )
226  radius > 0.0 ? phiProp += 2 * M_PI : phiProp -= 2 * M_PI;
227 
228  } else {
229 
230  // Use Taylor
231  phiProp = phi0 + deltaPhi;
232 
233  }
234 
235  //
236  // Check that the particle does not exit from the endcaps first.
237  //
238  zProp = particle_.Z() + ( phiProp - phi0 ) * pZ * radius / pT ;
239  if ( fabs(zProp) > zCyl ) {
240 
241  zProp = zCyl * fabs(pZ)/pZ;
242  phiProp = phi0 + (zProp - particle_.Z()) / radius * pT / pZ;
243  success = 2;
244 
245  } else {
246 
247  //
248  // If the particle does not cross the barrel, either process the
249  // first-half loop only or propagate all the way down to the endcaps
250  //
251  if ( rProp < rCyl ) {
252 
253  if ( firstLoop || fabs(pZ)/pT < 1E-10 ) {
254 
255  success = 0;
256 
257  } else {
258 
259  zProp = zCyl * fabs(pZ)/pZ;
260  phiProp = phi0 + (zProp - particle_.Z()) / radius * pT / pZ;
261  success = 2;
262 
263  }
264  //
265  // The particle crossed the barrel
266  //
267  } else {
268 
269  success = 1;
270 
271  }
272  }
273  //
274  // Compute the coordinates of the RawParticle after propagation
275  //
276  //
277  // Check the decay time
278  //
279  double delTime = propDir * (phiProp-phi0)*radius*particle_.mass() / pT;
280  double factor = 1.;
281  properTime += delTime;
282  if ( properTime > properDecayTime ) {
283  factor = 1.-(properTime-properDecayTime)/delTime;
285  decayed = true;
286  }
287 
288  zProp = particle_.Z() + (zProp-particle_.Z())*factor;
289 
290  phiProp = phi0 + (phiProp-phi0)*factor;
291 
292  double sProp = std::sin(phiProp);
293  double cProp = std::cos(phiProp);
294  double xProp = xC + radius * sProp;
295  double yProp = yC - radius * cProp;
296  double tProp = particle_.T() + (phiProp-phi0)*radius*particle_.E()/pT;
297  double pxProp = pT * cProp;
298  double pyProp = pT * sProp;
299 
300  //
301  // Last check : Although propagated to the endcaps, R could still be
302  // larger than rCyl because the cylinder was too short...
303  //
304  if ( success == 2 && xProp*xProp+yProp*yProp > rCyl2 ) {
305  success = -1;
306  return true;
307  }
308  //
309  // ... and update the particle vertex and momentum
310  //
311  particle_.setVertex( XYZTLorentzVector(xProp,yProp,zProp,tProp) );
312  particle_.setMomentum(pxProp,pyProp,pZ,particle_.E());
313  // particle_.SetPx(pxProp);
314  // particle_.SetPy(pyProp);
315  return true;
316 
317  }
318 }
319 
320 bool
322 
323  // Backpropagate
326  propDir = -1;
327  bool done = propagate();
330  propDir = +1;
331 
332  return done;
333 }
334 
337  // Copy the input particle in a new instance
338  BaseParticlePropagator myPropPart(*this);
339  // Allow for many loops
340  myPropPart.firstLoop=false;
341  // Propagate the particle !
342  myPropPart.propagate();
343  // Back propagate if the forward propagation was not a success
344  if (myPropPart.success < 0 )
345  myPropPart.backPropagate();
346  // Return the new instance
347  return myPropPart;
348 }
349 
350 void
352  rCyl = R;
353  rCyl2 = R*R;
354  zCyl = Z;
355  firstLoop = f;
356 }
357 
358 bool
360 
361  // Pre-computed quantities
362  double pT = particle_.Pt();
363  double radius = helixRadius(pT);
364  double phi0 = helixStartPhi();
365 
366  // The Helix centre coordinates are computed wrt to the z axis
367  // Actually the z axis might be centred on 0,0: it's the beam spot position (x0,y0)!
368  double xC = helixCentreX(radius,phi0);
369  double yC = helixCentreY(radius,phi0);
370  double distz = helixCentreDistToAxis(xC-x0,yC-y0);
371  double dist0 = helixCentreDistToAxis(xC,yC);
372 
373  //
374  // Propagation to point of clostest approach to z axis
375  //
376  double rz,r0,z;
377  if ( particle_.charge() != 0.0 && bField != 0.0 ) {
378  rz = fabs ( fabs(radius) - distz ) + std::sqrt(x0*x0+y0*y0) + 0.0000001;
379  r0 = fabs ( fabs(radius) - dist0 ) + 0.0000001;
380  } else {
381  rz = fabs( particle_.Px() * (particle_.Y()-y0) - particle_.Py() * (particle_.X()-x0) ) / particle_.Pt();
382  r0 = fabs( particle_.Px() * particle_.Y() - particle_.Py() * particle_.X() ) / particle_.Pt();
383  }
384 
385  z = 999999.;
386 
387  // Propagate to the first interesection point
388  // with cylinder of radius sqrt(x0**2+y0**2)
389  setPropagationConditions(rz , z, first);
390  bool done = backPropagate();
391 
392  // Unsuccessful propagation - should not happen!
393  if ( !done ) return done;
394 
395  // The z axis is (0,0) - no need to go further
396  if ( fabs(rz-r0) < 1E-10 ) return done;
397  double dist1 = (particle_.X()-x0)*(particle_.X()-x0) + (particle_.Y()-y0)*(particle_.Y()-y0);
398 
399  // We are already at closest approach - no need to go further
400  if ( dist1 < 1E-10 ) return done;
401 
402  // Keep for later if it happens to be the right solution
403  XYZTLorentzVector vertex1 = particle_.vertex();
404  XYZTLorentzVector momentum1 = particle_.momentum();
405 
406  // Propagate to the distance of closest approach to (0,0)
407  setPropagationConditions(r0 , z, first);
408  done = backPropagate();
409  if ( !done ) return done;
410 
411  // Propagate to the first interesection point
412  // with cylinder of radius sqrt(x0**2+y0**2)
413  setPropagationConditions(rz , z, first);
414  done = backPropagate();
415  if ( !done ) return done;
416  double dist2 = (particle_.X()-x0)*(particle_.X()-x0) + (particle_.Y()-y0)*(particle_.Y()-y0);
417 
418  // Keep the good solution.
419  if ( dist2 > dist1 ) {
420  particle_.setVertex(vertex1);
421  particle_.setMomentum(momentum1.X(),momentum1.Y(),momentum1.Z(),momentum1.E());
422  dist2 = dist1;
423  }
424 
425  // Done
426  return done;
427 
428 }
429 
430 bool
432  //
433  // Propagation to Ecal (including preshower) after the
434  // last Tracker layer
435  // TODO: include proper geometry
436  // Geometry taken from CMS ECAL TDR
437  //
438  // First propagate to global barrel / endcap cylinder
439  // setPropagationConditions(1290. , 3045 , first);
440  // New position of the preshower as of CMSSW_1_7_X
441  setPropagationConditions(129.0 , 303.353 , first);
442  return propagate();
443 
444 }
445 
446 bool
448  //
449  // Propagation to Preshower Layer 1
450  // TODO: include proper geometry
451  // Geometry taken from CMS ECAL TDR
452  //
453  // First propagate to global barrel / endcap cylinder
454  // setPropagationConditions(1290., 3045 , first);
455  // New position of the preshower as of CMSSW_1_7_X
456  setPropagationConditions(129.0, 303.353 , first);
457  bool done = propagate();
458 
459  // Check that were are on the Layer 1
460  if ( done && (particle_.R2() > 125.0*125.0 || particle_.R2() < 45.0*45.0) )
461  success = 0;
462 
463  return done;
464 }
465 
466 bool
468  //
469  // Propagation to Preshower Layer 2
470  // TODO: include proper geometry
471  // Geometry taken from CMS ECAL TDR
472  //
473  // First propagate to global barrel / endcap cylinder
474  // setPropagationConditions(1290. , 3090 , first);
475  // New position of the preshower as of CMSSW_1_7_X
476  setPropagationConditions(129.0 , 307.838 , first);
477  bool done = propagate();
478 
479  // Check that we are on Layer 2
480  if ( done && (particle_.R2() > 125.0*125.0 || particle_.R2() < 45.0*45.0 ) )
481  success = 0;
482 
483  return done;
484 
485 }
486 
487 bool
489  //
490  // Propagation to ECAL entrance
491  // TODO: include proper geometry
492  // Geometry taken from CMS ECAL TDR
493  //
494  // First propagate to global barrel / endcap cylinder
495  setPropagationConditions(129.0 , 320.9,first);
496  bool done = propagate();
497 
498  // Go to endcap cylinder in the "barrel cut corner"
499  // eta = 1.479 -> cos^2(theta) = 0.81230
500  // if ( done && eta > 1.479 && success == 1 ) {
501  if ( done && particle_.cos2ThetaV() > 0.81230 && success == 1 ) {
502  setPropagationConditions(152.6 , 320.9, first);
503  done = propagate();
504  }
505 
506  // We are not in the ECAL acceptance
507  // eta = 3.0 -> cos^2(theta) = 0.99013
508  if ( particle_.cos2ThetaV() > 0.99014 ) success = 0;
509 
510  return done;
511 }
512 
513 bool
515  //
516  // Propagation to HCAL entrance
517  // TODO: include proper geometry
518  // Geometry taken from CMSSW_3_1_X xml (Sunanda)
519  //
520 
521  // First propagate to global barrel / endcap cylinder
522  setPropagationConditions(177.5 , 335.0, first);
523  propDir = 0;
524  bool done = propagate();
525  propDir = 1;
526 
527  // If went through the bottom of HB cylinder -> re-propagate to HE surface
528  if (done && success == 2) {
529  setPropagationConditions(300.0, 400.458, first);
530  propDir = 0;
531  done = propagate();
532  propDir = 1;
533  }
534 
535 
536  // out of the HB/HE acceptance
537  // eta = 3.0 -> cos^2(theta) = 0.99014
538  if ( done && particle_.cos2ThetaV() > 0.99014 ) success = 0;
539 
540  return done;
541 }
542 
543 bool
545  //
546  // Propagation to VFCAL entrance
547  // TODO: include proper geometry
548  // Geometry taken from DAQ TDR Chapter 13
549 
550  setPropagationConditions(400.0 , 1110.0, first);
551  propDir = 0;
552  bool done = propagate();
553  propDir = 1;
554 
555  if (!done) success = 0;
556 
557  // We are not in the VFCAL acceptance
558  // eta = 3.0 -> cos^2(theta) = 0.99014
559  // eta = 5.2 -> cos^2(theta) = 0.9998755
560  double c2teta = particle_.cos2ThetaV();
561  if ( done && ( c2teta < 0.99014 || c2teta > 0.9998755 ) ) success = 0;
562 
563  return done;
564 }
565 
566 bool
568  //
569  // Propagation to HCAL exit
570  // TODO: include proper geometry
571  // Geometry taken from CMSSW_3_1_X xml (Sunanda)
572  //
573 
574  // Approximate it to a single cylinder as it is not that crucial.
575  setPropagationConditions(263.9 , 554.1, first);
576  // this->rawPart().particle_.setCharge(0.0); ?? Shower Propagation ??
577  propDir = 0;
578  bool done = propagate();
579  propDir = 1;
580 
581  return done;
582 }
583 
584 bool
586  //
587  // Propagation to Layer0 of HO (Ring-0)
588  // TODO: include proper geometry
589  // Geometry taken from CMSSW_3_1_X xml (Sunanda)
590  //
591 
592  // Approximate it to a single cylinder as it is not that crucial.
593  setPropagationConditions(387.6, 1000.0, first); //Dia is the middle of HO \sqrt{384.8**2+46.2**2}
594  // setPropagationConditions(410.2, 1000.0, first); //sqrt{406.6**2+54.2**2} //for outer layer
595  // this->rawPart().setCharge(0.0); ?? Shower Propagation ??
596  propDir = 0;
597  bool done = propagate();
598  propDir = 1;
599 
600  if ( done && std::abs(particle_.Z()) > 700.25) success = 0;
601 
602  return done;
603 }
604 
605 
606 bool
608 {
609 
610 
611  // Not implemented for neutrals (used for electrons only)
612  if ( particle_.charge() == 0. || bField == 0.) return false;
613 
614  // Define the proper pT direction to meet the point (vx,vy) in (x,y)
615  double dx = particle_.X()-v.X();
616  double dy = particle_.Y()-v.Y();
617  double phi = std::atan2(dy,dx) + std::asin ( std::sqrt(dx*dx+dy*dy)/(2.*helixRadius()) );
618 
619  // The absolute pT (kept to the original value)
620  double pT = particle_.pt();
621 
622  // Set the new pT
623  particle_.SetPx(pT*std::cos(phi));
624  particle_.SetPy(pT*std::sin(phi));
625 
626  return propagateToClosestApproach(v.X(),v.Y());
627 
628 }
629 
630 bool
632 {
633 
634  // For neutral (or BField = 0, simply check that the track passes through the cylinder
635  if ( particle_.charge() == 0. || bField == 0.)
636  return fabs( particle_.Px() * particle_.Y() - particle_.Py() * particle_.X() ) / particle_.Pt() < radius;
637 
638  // Now go to the charged particles
639 
640  // A few needed intermediate variables (to make the code understandable)
641  // The inner cylinder
642  double r = radius;
643  double r2 = r*r;
644  double r4 = r2*r2;
645  // The two hits
646  double dx = particle_.X()-v.X();
647  double dy = particle_.Y()-v.Y();
648  double dz = particle_.Z()-v.Z();
649  double Sxy = particle_.X()*v.X() + particle_.Y()*v.Y();
650  double Dxy = particle_.Y()*v.X() - particle_.X()*v.Y();
651  double Dxy2 = Dxy*Dxy;
652  double Sxy2 = Sxy*Sxy;
653  double SDxy = dx*dx + dy*dy;
654  double SSDxy = std::sqrt(SDxy);
655  double ATxy = std::atan2(dy,dx);
656  // The coefficients of the second order equation for the trajectory radius
657  double a = r2 - Dxy2/SDxy;
658  double b = r * (r2 - Sxy);
659  double c = r4 - 2.*Sxy*r2 + Sxy2 + Dxy2;
660 
661  // Here are the four possible solutions for
662  // 1) The trajectory radius
663  std::array<double,4> helixRs = {{0.}};
664  helixRs[0] = (b - std::sqrt(b*b - a*c))/(2.*a);
665  helixRs[1] = (b + std::sqrt(b*b - a*c))/(2.*a);
666  helixRs[2] = -helixRs[0];
667  helixRs[3] = -helixRs[1];
668  // 2) The azimuthal direction at the second point
669  std::array<double,4> helixPhis = {{0.}};
670  helixPhis[0] = std::asin ( SSDxy/(2.*helixRs[0]) );
671  helixPhis[1] = std::asin ( SSDxy/(2.*helixRs[1]) );
672  helixPhis[2] = -helixPhis[0];
673  helixPhis[3] = -helixPhis[1];
674  // Only two solutions are valid though
675  double solution1=0.;
676  double solution2=0.;
677  double phi1=0.;
678  double phi2=0.;
679  // Loop over the four possibilities
680  for ( unsigned int i=0; i<4; ++i ) {
681  helixPhis[i] = ATxy + helixPhis[i];
682  // The centre of the helix
683  double xC = helixCentreX(helixRs[i],helixPhis[i]);
684  double yC = helixCentreY(helixRs[i],helixPhis[i]);
685  // The distance of that centre to the origin
686  double dist = helixCentreDistToAxis(xC, yC);
687  /*
688  std::cout << "Solution "<< i << " = " << helixRs[i] << " accepted ? "
689  << fabs(fabs(helixRs[i]) - dist ) << " - " << radius << " = "
690  << fabs(fabs(helixRs[i]) - dist ) - fabs(radius) << " "
691  << ( fabs( fabs(fabs(helixRs[i]) - dist) -fabs(radius) ) < 1e-6) << std::endl;
692  */
693  // Check that the propagation will lead to a trajectroy tangent to the inner cylinder
694  if ( fabs( fabs(fabs(helixRs[i]) - dist) -fabs(radius) ) < 1e-6 ) {
695  // Fill first solution
696  if ( solution1 == 0. ) {
697  solution1 = helixRs[i];
698  phi1 = helixPhis[i];
699  // Fill second solution (ordered)
700  } else if ( solution2 == 0. ) {
701  if ( helixRs[i] < solution1 ) {
702  solution2 = solution1;
703  solution1 = helixRs[i];
704  phi2 = phi1;
705  phi1 = helixPhis[i];
706  } else {
707  solution2 = helixRs[i];
708  phi2 = helixPhis[i];
709  }
710  // Must not happen!
711  } else {
712  std::cout << "warning !!! More than two solutions for this track !!! " << std::endl;
713  }
714  }
715  }
716 
717  // Find the largest possible pT compatible with coming from within the inne cylinder
718  double pT = 0.;
719  double helixPhi = 0.;
720  double helixR = 0.;
721  // This should not happen
722  if ( solution1*solution2 == 0. ) {
723  std::cout << "warning !!! Less than two solution for this track! "
724  << solution1 << " " << solution2 << std::endl;
725  return false;
726  // If the two solutions have opposite sign, it means that pT = infinity is a possibility.
727  } else if ( solution1*solution2 < 0. ) {
728  pT = 1000.;
729  double norm = pT/SSDxy;
730  particle_.setCharge(+1.);
731  particle_.setMomentum(dx*norm,dy*norm,dz*norm,0.);
732  particle_.SetE(std::sqrt(particle_.momentum().Vect().Mag2()));
733  // Otherwise take the solution that gives the largest transverse momentum
734  } else {
735  if (solution1<0.) {
736  helixR = solution1;
737  helixPhi = phi1;
738  particle_.setCharge(+1.);
739  } else {
740  helixR = solution2;
741  helixPhi = phi2;
742  particle_.setCharge(-1.);
743  }
744  pT = fabs(helixR) * 1e-5 * c_light() *bField;
745  double norm = pT/SSDxy;
746  particle_.setMomentum(pT*std::cos(helixPhi),pT*std::sin(helixPhi),dz*norm,0.);
747  particle_.SetE(std::sqrt(particle_.momentum().Vect().Mag2()));
748  }
749 
750  // Propagate to closest approach to get the Z value (a bit of an overkill)
752 
753 }
754 
755 double
756 BaseParticlePropagator::xyImpactParameter(double x0, double y0) const {
757 
758  double ip=0.;
759  double pT = particle_.Pt();
760 
761  if ( particle_.charge() != 0.0 && bField != 0.0 ) {
762  double radius = helixRadius(pT);
763  double phi0 = helixStartPhi();
764 
765  // The Helix centre coordinates are computed wrt to the z axis
766  double xC = helixCentreX(radius,phi0);
767  double yC = helixCentreY(radius,phi0);
768  double distz = helixCentreDistToAxis(xC-x0,yC-y0);
769  ip = distz - fabs(radius);
770  } else {
771  ip = fabs( particle_.Px() * (particle_.Y()-y0) - particle_.Py() * (particle_.X()-x0) ) / pT;
772  }
773 
774  return ip;
775 
776 }
dbl * delta
Definition: mlp_gen.cc:36
double zCyl
Half-height of the cylinder (centred at 0,0,0) to which propagation is done.
void setMomentum(const XYZTLorentzVector &vtx)
set the momentum
Definition: RawParticle.h:347
void setCharge(float q)
set the MEASURED charge
Definition: RawParticle.cc:67
double helixRadius() const
The helix Radius.
double helixCentrePhi() const
The azimuth if the vector joining the cylinder and the helix axes.
bool propagateToPreshowerLayer1(bool first=true)
double pt() const
transverse momentum
Definition: RawParticle.h:328
double rCyl
Simulated particle that is to be resp has been propagated.
bool propagateToNominalVertex(const XYZTLorentzVector &hit2=XYZTLorentzVector(0., 0., 0., 0.))
void init()
Initialize internal switches and quantities.
double Perp2() const
perpendicular momentum squared
Definition: RawParticle.h:330
bool firstLoop
Do only the first half-loop.
int success
0:propagation still be done, 1:reached &#39;barrel&#39;, 2:reached &#39;endcaps&#39;
double properTime
The proper time of the particle.
Sin< T >::type sin(const T &t)
Definition: Sin.h:22
BaseParticlePropagator()
Default c&#39;tor.
bool propagateToBeamCylinder(const XYZTLorentzVector &v, double radius=0.)
void setPropagationConditions(double r, double z, bool firstLoop=true)
Set the propagation characteristics (rCyl, zCyl and first loop only)
void SetE(double)
Definition: RawParticle.h:353
double mass() const
get the MEASURED mass
Definition: RawParticle.h:314
double c_light() const
The speed of light in mm/ns (!) without clhep (yeaaahhh!)
double R2() const
vertex radius**2
Definition: RawParticle.h:310
bool propagateToEcal(bool first=true)
bool propagateToClosestApproach(double x0=0., double y0=0, bool first=true)
double helixCentreX() const
The x coordinate of the helix axis.
bool propagateToVFcalEntrance(bool first=true)
const XYZTLorentzVector & momentum() const
the momentum fourvector
Definition: RawParticle.h:340
double helixCentreDistToAxis() const
The distance between the cylinder and the helix axes.
double properDecayTime
The proper decay time of the particle.
T sqrt(T t)
Definition: SSEVec.h:18
bool propagateToHcalExit(bool first=true)
double cos2ThetaV() const
Definition: RawParticle.h:300
Cos< T >::type cos(const T &t)
Definition: Cos.h:22
double Y() const
y of vertex
Definition: RawParticle.h:306
double Py() const
y of the momentum
Definition: RawParticle.h:319
double Pt() const
transverse momentum
Definition: RawParticle.h:327
double Z() const
z of vertex
Definition: RawParticle.h:307
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
double f[11][100]
T min(T a, T b)
Definition: MathUtil.h:58
static const std::string B
double Pz() const
z of the momentum
Definition: RawParticle.h:322
double charge() const
get the MEASURED charge
Definition: RawParticle.h:313
void SetPx(double)
Definition: RawParticle.h:350
int propDir
The propagation direction.
bool propagateToEcalEntrance(bool first=true)
#define M_PI
void SetPy(double)
Definition: RawParticle.h:351
const XYZTLorentzVector & vertex() const
the vertex fourvector
Definition: RawParticle.h:339
bool onEndcap() const
Is the vertex already on the cylinder endcap ?
bool decayed
The particle decayed while propagated !
BaseParticlePropagator propagated() const
double helixCentreY() const
The y coordinate of the helix axis.
bool inside() const
Is the vertex inside the cylinder ? (stricly inside : true)
double b
Definition: hdecay.h:120
bool onSurface() const
Is the vertex already on the cylinder surface ?
double X() const
x of vertex
Definition: RawParticle.h:305
bool debug
The debug level.
double helixStartPhi() const
The azimuth of the momentum at the vertex.
bool propagateToHcalEntrance(bool first=true)
double a
Definition: hdecay.h:121
double Px() const
x of the momentum
Definition: RawParticle.h:316
double E() const
energy of the momentum
Definition: RawParticle.h:325
double bField
Magnetic field in the cylinder, oriented along the Z axis.
double T() const
vertex time
Definition: RawParticle.h:308
bool propagateToHOLayer(bool first=true)
bool onBarrel() const
Is the vertex already on the cylinder barrel ?
bool propagateToPreshowerLayer2(bool first=true)
void setVertex(const XYZTLorentzVector &vtx)
set the vertex
Definition: RawParticle.h:344
double xyImpactParameter(double x0=0., double y0=0.) const
Transverse impact parameter.
bool fiducial
The particle traverses some real material.
math::XYZTLorentzVector XYZTLorentzVector
Definition: RawParticle.h:27