View Javadoc

1   package org.lcsim.recon.tracking.trfzp;
2   
3   import org.lcsim.recon.tracking.magfield.AbstractMagneticField;
4   import org.lcsim.recon.tracking.trfbase.*;
5   
6   import static java.lang.Math.sqrt;
7   import static java.lang.Math.abs;
8   import static java.lang.Math.max;
9   import static java.lang.Math.pow;
10  import org.lcsim.recon.tracking.spacegeom.CartesianPoint;
11  import org.lcsim.recon.tracking.spacegeom.SpacePointTensor;
12  import org.lcsim.recon.tracking.spacegeom.SpacePointVector;
13  import org.lcsim.recon.tracking.trfutil.Assert;
14  import org.lcsim.recon.tracking.trfutil.TRFMath;
15  
16  /**
17   *
18   * @author Norman A Graf
19   *
20   * @version $Id:
21   */
22  public class PropZZRK extends PropDirected
23  {
24  
25      private AbstractMagneticField _bfield;
26      // Assign track parameter indices.
27      private static final int IX = SurfZPlane.IX;
28      private static final int IY = SurfZPlane.IY;
29      private static final int IDXDZ = SurfZPlane.IDXDZ;
30      private static final int IDYDZ = SurfZPlane.IDYDZ;
31      private static final int IQP = SurfZPlane.IQP;
32      private double _precision;
33      private double _derivprec;
34  
35      public PropZZRK(AbstractMagneticField bfield, double precision, double derivprecision)
36      {
37          _bfield = bfield;
38          _precision = precision;
39          _derivprec = derivprecision;
40          assert (_precision > 0. && _precision <= 0.01);
41          assert (_derivprec > 0. && _derivprec <= 0.1);
42      }
43      
44      public PropZZRK(AbstractMagneticField bfield)
45      {
46          _precision = 1.e-7;
47          _derivprec = 1.e-7;
48          _bfield = bfield;
49      }
50  
51      @Override
52      public Propagator newPropagator()
53      {
54          throw new UnsupportedOperationException("Not supported yet.");
55      }
56  
57      // Equations of motion in terms of track parameters x, y, dxdz, dydz,
58      // curvature (q/p), and path length and the magnetic field.
59      double[] motion(double[] par, double z, double crv, double sign_dz,
60                      AbstractMagneticField bfield)
61      {
62  
63          double[] result = new double[par.length];
64          boolean deriv = par.length > 5;
65  
66          // Extract track parameters.
67  
68          double x = par[0];
69          double y = par[1];
70          double xv = par[2];
71          double yv = par[3];
72          double s = par[4];
73  
74          // Declare derivative matrix.
75  
76          double dxdx0 = 0.;
77          double dxdy0 = 0.;
78          double dxdxv0 = 0.;
79          double dxdyv0 = 0.;
80          double dxdcrv = 0.;
81  
82          double dydx0 = 0.;
83          double dydy0 = 0.;
84          double dydxv0 = 0.;
85          double dydyv0 = 0.;
86          double dydcrv = 0.;
87  
88          double dxvdx0 = 0.;
89          double dxvdy0 = 0.;
90          double dxvdxv0 = 0.;
91          double dxvdyv0 = 0.;
92          double dxvdcrv = 0.;
93  
94          double dyvdx0 = 0.;
95          double dyvdy0 = 0.;
96          double dyvdxv0 = 0.;
97          double dyvdyv0 = 0.;
98          double dyvdcrv = 0.;
99  
100         if (deriv) {
101 
102             // Extract derivative matrix.
103 
104             dxdx0 = par[5];
105             dxdy0 = par[6];
106             dxdxv0 = par[7];
107             dxdyv0 = par[8];
108             dxdcrv = par[9];
109 
110             dydx0 = par[10];
111             dydy0 = par[11];
112             dydxv0 = par[12];
113             dydyv0 = par[13];
114             dydcrv = par[14];
115 
116             dxvdx0 = par[15];
117             dxvdy0 = par[16];
118             dxvdxv0 = par[17];
119             dxvdyv0 = par[18];
120             dxvdcrv = par[19];
121 
122             dyvdx0 = par[20];
123             dyvdy0 = par[21];
124             dyvdxv0 = par[22];
125             dyvdyv0 = par[23];
126             dyvdcrv = par[24];
127         }
128         double dmax = 1.e30;
129         if (!(xv < dmax && xv > -dmax)) {
130             throw new RuntimeException("Floating point exception");
131         }
132         if (!(yv < dmax && yv > -dmax)) {
133             throw new RuntimeException("Floating point exception");
134         }
135         double dsdz2 = 1. + xv * xv + yv * yv;
136         double dsdz = sign_dz * sqrt(dsdz2);
137 
138         // Get Cartesian components of magnetic field & derivatives.
139 
140         double bx = 0.;
141         double by = 0.;
142         double bz = 0.;
143         double dbxdx = 0.;
144         double dbxdy = 0.;
145         double dbydx = 0.;
146         double dbydy = 0.;
147         double dbzdx = 0.;
148         double dbzdy = 0.;
149         SpacePointVector bf;
150         if (deriv) {
151             SpacePointTensor t = new SpacePointTensor();
152             bf = bfield.field(new CartesianPoint(x, y, z), t);
153             dbxdx = t.t_x_x();
154             dbxdy = t.t_x_y();
155             dbydx = t.t_y_x();
156             dbydy = t.t_y_y();
157             dbzdx = t.t_z_x();
158             dbzdy = t.t_z_y();
159         } else {
160             bf = bfield.field(new CartesianPoint(x, y, z));
161         }
162         bx = bf.v_x();
163         by = bf.v_y();
164         bz = bf.v_z();
165 
166         // dx/dz.
167 
168         result[0] = xv;
169 
170         // dy/dz.
171 
172         result[1] = yv;
173 
174         // dxv/dz.
175 
176         double dxvdz_nocrv = TRFMath.BFAC * dsdz * (xv * yv * bx - (1. + xv * xv) * by + yv * bz);
177         result[2] = dxvdz_nocrv * crv;
178 
179         // dyv/dz.
180 
181         double dyvdz_nocrv = TRFMath.BFAC * dsdz * ((1. + yv * yv) * bx - xv * yv * by - xv * bz);
182         result[3] = dyvdz_nocrv * crv;
183 
184         // ds/dz.
185 
186         result[4] = dsdz;
187 
188         if (deriv) {
189 
190             // d(dx/d x0)/dz.
191 
192             result[5] = dxvdx0;
193 
194             // d(dx/d y0)/dz.
195 
196             result[6] = dxvdy0;
197 
198             // d(dx/d xv0)/dz.
199 
200             result[7] = dxvdxv0;
201 
202             // d(dx/d yv0)/dz.
203 
204             result[8] = dxvdyv0;
205 
206             // d(dx/d crv)/dz.
207 
208             result[9] = dxvdcrv;
209 
210             // d(dy/d x0)/dz.
211 
212             result[10] = dyvdx0;
213 
214             // d(dy/d y0)/dz.
215 
216             result[11] = dyvdy0;
217 
218             // d(dy/d xv0)/dz.
219 
220             result[12] = dyvdxv0;
221 
222             // d(dy/d yv0)/dz.
223 
224             result[13] = dyvdyv0;
225 
226             // d(dy/d crv)/dz.
227 
228             result[14] = dyvdcrv;
229 
230             // d(d xv/d x0)/dz.
231 
232             result[15] = result[2] * (xv * dxvdx0 + yv * dyvdx0) / dsdz2
233                     + TRFMath.BFAC * crv * dsdz
234                     * (dxvdx0 * yv * bx + xv * dyvdx0 * bx + xv * yv * (dbxdx * dxdx0 + dbxdy * dydx0)
235                     - 2. * xv * dxvdx0 * by - (1. + xv * xv) * (dbydx * dxdx0 + dbydy * dydx0)
236                     + dyvdx0 * bz + yv * (dbzdx * dxdx0 + dbzdy * dydx0));
237 
238             // d(d xv/d y0)/dz.
239 
240             result[16] = result[2] * (xv * dxvdy0 + yv * dyvdy0) / dsdz2
241                     + TRFMath.BFAC * crv * dsdz
242                     * (dxvdy0 * yv * bx + xv * dyvdy0 * bx + xv * yv * (dbxdx * dxdy0 + dbxdy * dydy0)
243                     - 2. * xv * dxvdy0 * by - (1. + xv * xv) * (dbydx * dxdy0 + dbydy * dydy0)
244                     + dyvdy0 * bz + yv * (dbzdx * dxdy0 + dbzdy * dydy0));
245 
246             // d(d xv/d xv0)/dz.
247 
248             result[17] = result[2] * (xv * dxvdxv0 + yv * dyvdxv0) / dsdz2
249                     + TRFMath.BFAC * crv * dsdz
250                     * (dxvdxv0 * yv * bx + xv * dyvdxv0 * bx + xv * yv * (dbxdx * dxdxv0 + dbxdy * dydxv0)
251                     - 2. * xv * dxvdxv0 * by - (1. + xv * xv) * (dbydx * dxdxv0 + dbydy * dydxv0)
252                     + dyvdxv0 * bz + yv * (dbzdx * dxdxv0 + dbzdy * dydxv0));
253 
254             // d(d xv/d yv0)/dz.
255 
256             result[18] = result[2] * (xv * dxvdyv0 + yv * dyvdyv0) / dsdz2
257                     + TRFMath.BFAC * crv * dsdz
258                     * (dxvdyv0 * yv * bx + xv * dyvdyv0 * bx + xv * yv * (dbxdx * dxdyv0 + dbxdy * dydyv0)
259                     - 2. * xv * dxvdyv0 * by - (1. + xv * xv) * (dbydx * dxdyv0 + dbydy * dydyv0)
260                     + dyvdyv0 * bz + yv * (dbzdx * dxdyv0 + dbzdy * dydyv0));
261 
262             // d(d xv/d crv)/dz.
263 
264             result[19] = dxvdz_nocrv * (1. + crv * (xv * dxvdcrv + yv * dyvdcrv) / dsdz2)
265                     + TRFMath.BFAC * crv * dsdz
266                     * (dxvdcrv * yv * bx + xv * dyvdcrv * bx + xv * yv * (dbxdx * dxdcrv + dbxdy * dydcrv)
267                     - 2. * xv * dxvdcrv * by - (1. + xv * xv) * (dbydx * dxdcrv + dbydy * dydcrv)
268                     + dyvdcrv * bz + yv * (dbzdx * dxdcrv + dbzdy * dydcrv));
269 
270 
271             // d(d yv/d x0)/dr
272 
273             result[20] = result[3] * (xv * dxvdx0 + yv * dyvdx0) / dsdz2
274                     + TRFMath.BFAC * crv * dsdz
275                     * (2. * yv * dyvdx0 * bx + (1. + yv * yv) * (dbxdx * dxdx0 + dbxdy * dydx0)
276                     - dxvdx0 * yv * by - xv * dyvdx0 * by - xv * yv * (dbydx * dxdx0 + dbydy * dydx0)
277                     - dxvdx0 * bz - xv * (dbzdx * dxdx0 + dbzdy * dydx0));
278 
279             // d(d yv/d y0)/dr
280 
281             result[21] = result[3] * (xv * dxvdy0 + yv * dyvdy0) / dsdz2
282                     + TRFMath.BFAC * crv * dsdz
283                     * (2. * yv * dyvdy0 * bx + (1. + yv * yv) * (dbxdx * dxdy0 + dbxdy * dydy0)
284                     - dxvdy0 * yv * by - xv * dyvdy0 * by - xv * yv * (dbydx * dxdy0 + dbydy * dydy0)
285                     - dxvdy0 * bz - xv * (dbzdx * dxdy0 + dbzdy * dydy0));
286 
287             // d(d yv/d xv0)/dr
288 
289             result[22] = result[3] * (xv * dxvdxv0 + yv * dyvdxv0) / dsdz2
290                     + TRFMath.BFAC * crv * dsdz
291                     * (2. * yv * dyvdxv0 * bx + (1. + yv * yv) * (dbxdx * dxdxv0 + dbxdy * dydxv0)
292                     - dxvdxv0 * yv * by - xv * dyvdxv0 * by - xv * yv * (dbydx * dxdxv0 + dbydy * dydxv0)
293                     - dxvdxv0 * bz - xv * (dbzdx * dxdxv0 + dbzdy * dydxv0));
294 
295             // d(d yv/d yv0/dr
296 
297             result[23] = result[3] * (xv * dxvdyv0 + yv * dyvdyv0) / dsdz2
298                     + TRFMath.BFAC * crv * dsdz
299                     * (2. * yv * dyvdyv0 * bx + (1. + yv * yv) * (dbxdx * dxdyv0 + dbxdy * dydyv0)
300                     - dxvdyv0 * yv * by - xv * dyvdyv0 * by - xv * yv * (dbydx * dxdyv0 + dbydy * dydyv0)
301                     - dxvdyv0 * bz - xv * (dbzdx * dxdyv0 + dbzdy * dydyv0));
302 
303             // d(d yv/d crv)/dr
304 
305             result[24] = dyvdz_nocrv * (1. + crv * (xv * dxvdcrv + yv * dyvdcrv) / dsdz2)
306                     + TRFMath.BFAC * crv * dsdz
307                     * (2. * yv * dyvdcrv * bx + (1. + yv * yv) * (dbxdx * dxdcrv + dbxdy * dydcrv)
308                     - dxvdcrv * yv * by - xv * dyvdcrv * by - xv * yv * (dbydx * dxdcrv + dbydy * dydcrv)
309                     - dxvdcrv * bz - xv * (dbzdx * dxdcrv + dbzdy * dydcrv));
310         }
311         return result;
312     }
313 
314     // Function to evolve track paramters using a single fourth order 
315     // Runge-Kutta step from z1 to z2.
316     void rk4(double[] par, double[] z, double h, double crv, double sign_dz,
317              AbstractMagneticField bfield, double[] k1, boolean reuse)
318     {
319         int size = par.length;
320         double[] k2 = new double[size];
321         double[] k3 = new double[size];
322         double[] k4 = new double[size];
323         if (!reuse) //    k1 = h * motion(par, z[0], crv, sign_dz, bfield);
324         //    k2 = h * motion(par + 0.5*k1, z + 0.5*h, crv, sign_dz, bfield);
325         //    k3 = h * motion(par + 0.5*k2, z + 0.5*h, crv, sign_dz, bfield);
326         //    k4 = h * motion(par + k3, z + h, crv, sign_dz, bfield);
327         {
328             scale(motion(par, z[0], crv, sign_dz, bfield), h, k1);
329         }
330         scale(motion(add(par, 0.5, k1), z[0] + 0.5 * h, crv, sign_dz, bfield), h, k2);
331         scale(motion(add(par, 0.5, k2), z[0] + 0.5 * h, crv, sign_dz, bfield), h, k3);
332         scale(motion(add(par, 1.0, k3), z[0] + h, crv, sign_dz, bfield), h, k4);
333 //        par += (1. / 6.) * (k1 + 2. * k2 + 2. * k3 + k4);
334         sum(k1, k2, k3, k4, par);
335         z[0] += h;
336         double dmax = 1.e30;
337         for (int i = 0; i < par.length; ++i) {
338             double x = par[i];
339             if (!(x < dmax && x > -dmax)) {
340                 throw new RuntimeException("Floating point exception");
341             }
342         }
343     }
344 
345     // Function to calculate the relative difference between two sets
346     // of track parameters.  The result is scaled so that a difference
347     // of less than one is "good."
348     double pardiff(double[] par1, double[] par2,
349                    double derivscale)
350     {
351         int n = par1.length;
352         assert (par2.length == n);
353         double epsmax = 0.;
354         for (int i = 0; i < n; ++i) {
355             double p1 = par1[i];
356             double p2 = par2[i];
357             double eps = abs(p2 - p1) / max(max(abs(p1), abs(p2)), 10.);
358             if (i >= 5) {
359                 eps *= derivscale;
360             }
361             if (eps > epsmax) {
362                 epsmax = eps;
363             }
364         }
365         return epsmax;
366     }
367 
368     // Function to evolve track parameters using fourth order Runge-Kutta
369     // with a variable step size.  The starting step size is as specified,
370     // which may be reduced until the error is estimated to be small enough.
371     // The z coordinate is updated to reflect the actual step size.  The 
372     // estimated next step size is returned as the value of the function.
373     double rkv(double[] par, double[] z, double h, double crv, double sign_dz,
374                AbstractMagneticField bfield, double precision,
375                double derivprec)
376     {
377 
378         double derivscale = precision / derivprec;
379 
380         // Calculate the minimum allowed step, which is the lesser of 
381         // either 1 cm or the initial step.
382 
383         double hmin = abs(h) / h;
384         if (abs(hmin) > abs(h)) {
385             hmin = h;
386         }
387         double hnext = h;
388         for (;;) {
389 
390             // Reduce the target precision for short steps to control the 
391             // accumulation of roundoff error.
392 
393             double maxdiff = precision * sqrt(0.1 * abs(h));
394             double[] par1 = new double[par.length];
395             System.arraycopy(par,0,par1,0,par.length);
396             double[] par2 = new double[par.length];
397             System.arraycopy(par,0,par2,0,par.length);;
398             
399 
400             // Try step using h.
401 
402             double[] z1 = new double[1];
403             z1[0] = z[0];
404             double[] k1 = new double[par.length];
405             rk4(par1, z1, h, crv, sign_dz, bfield, k1, false);
406 
407             // In short hop situations, quit here.
408 
409             if (abs(hmin) <= 0.01) {
410                 System.arraycopy(par1, 0, par, 0, par1.length);
411                 z[0] = z1[0];
412                 break;
413             }
414 
415             // Try two steps using hh.
416 
417             double[] z2 = new double[1];
418             z2[0] = z[0];
419             double hh = 0.5 * h;
420 //      k1 = 0.5 * k1;
421             for (int i = 0; i < k1.length; ++i) {
422                 k1[i] = 0.5 * k1[i];
423             }
424             rk4(par2, z2, hh, crv, sign_dz, bfield, k1, true);
425             rk4(par2, z2, hh, crv, sign_dz, bfield, k1, false);
426 
427             // Calculate difference and get the next step size.
428 
429             double eps = pardiff(par1, par2, derivscale);
430             if (eps <= maxdiff || abs(h) <= abs(hmin)) {
431 
432                 // Check for catastrophic loss of accuracy.
433 
434                 //	if(eps > 100000.*maxdiff)
435                 //	  throw new RuntimeException("Catastrophic loss of accuracy");
436 
437                 // Current step is accurate enough.  Adjust the step size.
438                 // and return current propagation.
439 
440                 if (eps != 0) {
441                     hnext = 0.8 * h * pow(maxdiff / eps, 0.25);
442                     if (abs(hnext) > 4. * abs(h)) {
443                         hnext = 4. * h;
444                     }
445                 } else {
446                     hnext = 4. * h;
447                 }
448 //                par = (16. / 15.) * par2 - (1. / 15.) * par1;
449                 subtract(par, par2, par1);
450                 z[0] = z1[0];
451                 break;
452             } else {
453 
454                 // Not accurate enough.  Shrink the step size and try again.
455                 // Don't let the step get too small.
456 
457                 hnext = 0.8 * h * pow(maxdiff / eps, 0.25);
458                 if (abs(hnext) < abs(hmin)) {
459                     hnext = hmin;
460                 }
461                 h = hnext;
462             }
463         }
464 
465         // Final check on minimum step size.
466 
467         if (abs(hnext) < abs(hmin)) {
468             hnext = hmin;
469         }
470         return hnext;
471     }
472 //
473     // This routine uses adaptive step size control to make the specified
474     // step using one or several steps.
475 
476     void rka(double[] par, double[] z, double h, double crv, double sign_dz,
477              AbstractMagneticField bfield, double precision,
478              double derivprec)
479     {
480         assert (h != 0);
481         double htry = h;
482         double hnext;
483         double z2 = z[0] + h;
484         while (h > 0 && z[0] < z2 || h < 0 && z[0] > z2) {
485             double hmax = abs(z2 - z[0]);
486             if (abs(htry) > hmax) {
487                 htry = z2 - z[0];
488             }
489             hnext = rkv(par, z, htry, crv, sign_dz, bfield, precision, derivprec);
490             assert (hnext * htry > 0);
491             assert (z[0] + hnext != z[0]);
492             htry = hnext;
493         }
494     }
495 
496 // 
497     private void scale(double[] a, double s, double[] b)
498     {
499         for (int i = 0; i < a.length; i++) {
500             b[i] = a[i] * s;
501         }
502     }
503 
504     private double[] add(double[] a, double s, double[] b)
505     {
506         double[] f = new double[a.length];
507         for (int i = 0; i < a.length; i++) {
508             f[i] = a[i] + s * b[i];
509         }
510         return f;
511     }
512 
513     private void sum(double[] k1, double[] k2, double[] k3, double[] k4, double[] p)
514     {
515         for (int i = 0; i < p.length; ++i) {
516             p[i] += (1. / 6.) * (k1[i] + 2. * k2[i] + 2. * k3[i] + k4[i]);
517         }
518     }
519 
520     private void subtract(double[] par, double[] par2, double[] par1)
521     {
522         for (int i = 0; i < par.length; ++i) {
523             par[i] = (16. / 15.) * par2[i] - (1. / 15.) * par1[i];
524         }
525     }
526 
527 // Propagator interface here
528 // Propagate a track without error in the specified direction.
529 //
530 // The track parameters for a z-plane are:
531 // x y dx/dz dy/dz curvature=q/p
532 //
533 // If pder is nonzero, return the derivative matrix there.
534     public PropStat vecDirProp(VTrack trv, Surface srf, PropDir dir,
535                                TrackDerivative deriv)
536     {
537 
538         // construct return status
539         PropStat pstat = new PropStat();
540 
541         // fetch the originating surface.
542         Surface srf1 = trv.surface();
543 
544         // Check origin is a z plane.
545         Assert.assertTrue(srf1.pureType().equals(SurfZPlane.staticType()));
546         if (!srf1.pureType().equals(SurfZPlane.staticType())) {
547             return pstat;
548         }
549 
550         SurfZPlane sz1 = (SurfZPlane) srf1;
551 
552         // Check destination is a z plane.
553         Assert.assertTrue(srf.pureType().equals(SurfZPlane.staticType()));
554         if (!srf.pureType().equals(SurfZPlane.staticType())) {
555             return pstat;
556         }
557         SurfZPlane sz2 = (SurfZPlane) srf;
558 
559         // Separate the move status from the direction.
560         PropDir rdir = dir; // need to check constness
561         boolean move = Propagator.reduceDirection(rdir);
562 
563         // This flag indicates the new surface is only a short hop away.
564         boolean short_hop = false;
565 
566         // If surfaces are the same and move is not set, then we leave the
567         // track where it is.
568         if (srf.pureEqual(srf1) && !move) {
569             if (deriv != null) {
570                 deriv.setIdentity();
571             }
572             pstat.setSame();
573             return pstat;
574         }
575 
576         // Fetch the z coordinates.
577         int iz = SurfZPlane.ZPOS;
578         double z1 = sz1.parameter(iz);
579         double z2 = sz2.parameter(iz);
580 
581         // Fetch the starting track vector.
582         TrackVector vec = trv.vector();
583         double x1 = vec.get(IX);                   // x
584         double y1 = vec.get(IY);                   // y
585         double xv1 = vec.get(IDXDZ);               // dx/dz
586         double yv1 = vec.get(IDYDZ);               // dy/dz
587         double crv = vec.get(IQP);                 // q/p
588         double sign_dz = 0.;
589         if (trv.isForward()) {
590             sign_dz = 1.;
591         } else if (trv.isBackward()) {
592             sign_dz = -1.;
593         }
594         if (sign_dz == 0.) {
595             return pstat;
596         }
597 
598         // Check the consistency of the initial and final z positions, the track 
599         // direction and the propagation direction.  Four of the eight possible
600         // forward/backward combinations are illegal.  
601 
602         if (z2 == z1) {
603             if (move) {
604                 System.out.println("PropZZRK: Invalid move");
605                 return pstat;
606             }
607         } else if (z2 > z1) {
608             if (rdir == PropDir.FORWARD && trv.isBackward()
609                     || rdir == PropDir.BACKWARD && trv.isForward()) {
610                 System.out.println("PropZZRK: Wrong direction");
611                 return pstat;
612             }
613         } else {  // z2 < z1
614             if (rdir == PropDir.FORWARD && trv.isForward()
615                     || rdir == PropDir.BACKWARD && trv.isBackward()) {
616                 System.out.println("PropZZRK: Wrong direction");
617                 return pstat;
618             }
619         }
620 
621         // We have all non-trivial mathematical operations in a try block
622         // so we can catch floating point exceptions.
623 
624         {
625 
626             // Fill initial parameter vector.
627 
628             int size = 5;
629             if (deriv != null) {
630                 size = 25;
631             }
632             double[] par = new double[size];
633             par[0] = x1;       // x
634             par[1] = y1;       // y
635             par[2] = xv1;      // dx/dz
636             par[3] = yv1;      // dy/dz
637             par[4] = 0.;       // Path length.
638             if (deriv != null) {
639                 par[5] = 1.;     // d x / d x0
640                 par[11] = 1.;    // d y / d y0
641                 par[17] = 1.;    // d xv / d xv0
642                 par[23] = 1.;    // d yv / d yv0
643             }
644 
645             // Propagate parameter vector.
646 
647             double[] z = new double[1];
648             z[0] = z1;
649             double h = z2 - z1;
650             if (abs(h) < 1.e-10) {
651                 z[0] = z2;
652             } else {
653                 rka(par, z, h, crv, sign_dz, _bfield, _precision, _derivprec);
654             }
655 
656             // Calculate final parameters and put them back into vec.
657 
658             double dmax = 1.e30;
659             double x2 = par[0];
660             double y2 = par[1];
661             double xv2 = par[2];
662             double yv2 = par[3];
663             double s = par[4];
664             vec.set(IX, x2);
665             vec.set(IY, y2);
666             vec.set(IDXDZ, xv2);
667             vec.set(IDYDZ, yv2);
668             vec.set(IQP, crv);
669             if (!(x2 < dmax && x2 > -dmax)) {
670                 throw new RuntimeException("Floating point exception");
671             }
672             if (!(y2 < dmax && y2 > -dmax)) {
673                 throw new RuntimeException("Floating point exception");
674             }
675             if (!(xv2 < dmax && xv2 > -dmax)) {
676                 throw new RuntimeException("Floating point exception");
677             }
678             if (!(yv2 < dmax && yv2 > -dmax)) {
679                 throw new RuntimeException("Floating point exception");
680             }
681             if (!(s < dmax && s > -dmax)) {
682                 throw new RuntimeException("Floating point exception");
683             }
684             if (deriv != null) {
685 
686                 // Calculate final derivative matrix.
687 
688 
689                 deriv.set(0, 0, par[5]);                // dx / d x0
690                 deriv.set(0, 1, par[6]);                // dx / d y0
691                 deriv.set(0, 2, par[7]);                // dx / d xv0
692                 deriv.set(0, 3, par[8]);                // dx / d yv0
693                 deriv.set(0, 4, par[9]);                // dx / d crv
694                 deriv.set(1, 0, par[10]);               // dy / d x0
695                 deriv.set(1, 1, par[11]);               // dy / d y0
696                 deriv.set(1, 2, par[12]);               // dy / d xv0
697                 deriv.set(1, 3, par[13]);               // dy / d yv0
698                 deriv.set(1, 4, par[14]);               // dy / d crv
699                 deriv.set(2, 0, par[15]);               // d xv / d x0
700                 deriv.set(2, 1, par[16]);               // d xv / d y0
701                 deriv.set(2, 2, par[17]);               // d xv / d xv0
702                 deriv.set(2, 3, par[18]);               // d xv / d yv0
703                 deriv.set(2, 4, par[19]);               // d xv / d crv
704                 deriv.set(3, 0, par[20]);               // d yv / d x0
705                 deriv.set(3, 1, par[21]);               // d yv / d y0
706                 deriv.set(3, 2, par[22]);               // d yv / d xv0
707                 deriv.set(3, 3, par[23]);               // d yv / d yv0
708                 deriv.set(3, 4, par[24]);               // d yv / d crv
709                 deriv.set(4, 0, 0.);                    // d crv / d x0
710                 deriv.set(4, 1, 0.);                    // d crv / d y0
711                 deriv.set(4, 2, 0.);                    // d crv / d xv0
712                 deriv.set(4, 3, 0.);                    // d crv / d yv0
713                 deriv.set(4, 4, 1.);                    // d crv / d crv
714                 for (int i = 0; i < 4; ++i) {
715                     for (int j = 0; j < 5; ++j) {
716                         double x = deriv.get(i, j);
717                         if (!(x < dmax && x > -dmax)) {
718                             throw new RuntimeException("Floating point exception");
719                         }
720                     }
721                 }
722             }
723 
724             // Update trv
725             boolean forward = trv.isForward();
726             boolean backward = trv.isBackward();
727             assert (forward || backward);
728             assert (!(forward && backward));
729             trv.setSurface(srf.newPureSurface());
730             trv.setVector(vec);
731             if (forward) {
732                 trv.setForward();
733             } else if (backward) {
734                 trv.setBackward();
735             }
736 
737             // Set the return status.
738             pstat.setPathDistance(s);
739         }
740         return pstat;
741     }
742     
743     public String toString()
744     {
745         StringBuffer sb = new StringBuffer( "Z Plane RK propagation with magnetic field: \n");
746          sb.append(" "+_bfield+"\n");
747 	 sb.append(" precision = " + _precision);
748 	 sb.append(", derivprec = " + _derivprec+"\n");
749          return sb.toString();
750     }
751 }