View Javadoc

1   /*
2    * PropCylZ_Test.java
3    *
4    * Created on July 24, 2007, 10:51 PM
5    *
6    * $Id: PropCylZ_Test.java,v 1.1.1.1 2010/04/08 20:38:00 jeremy Exp $
7    */
8   
9   package org.lcsim.recon.tracking.trfcylplane;
10  
11  import junit.framework.TestCase;
12  import org.lcsim.recon.tracking.spacegeom.SpacePath;
13  import org.lcsim.recon.tracking.spacegeom.SpacePoint;
14  import org.lcsim.recon.tracking.trfbase.ETrack;
15  import org.lcsim.recon.tracking.trfbase.PropDir;
16  import org.lcsim.recon.tracking.trfbase.PropStat;
17  import org.lcsim.recon.tracking.trfbase.Propagator;
18  import org.lcsim.recon.tracking.trfbase.Surface;
19  import org.lcsim.recon.tracking.trfbase.TrackDerivative;
20  import org.lcsim.recon.tracking.trfbase.TrackError;
21  import org.lcsim.recon.tracking.trfbase.TrackVector;
22  import org.lcsim.recon.tracking.trfbase.VTrack;
23  import org.lcsim.recon.tracking.trfcyl.SurfCylinder;
24  import org.lcsim.recon.tracking.trfutil.Assert;
25  import org.lcsim.recon.tracking.trfutil.TRFMath;
26  import org.lcsim.recon.tracking.trfzp.SurfZPlane;
27  
28  /**
29   *
30   * @author Norman Graf
31   */
32  public class PropCylZ_Test extends TestCase
33  {
34      private boolean debug;
35      
36      // Assign track parameter indices.
37      private static final int   IX = SurfZPlane.IX;
38      private static final int   IY   = SurfZPlane.IY;
39      private static final int   IDXDZ = SurfZPlane.IDXDZ;
40      private static final int   IDYDZ = SurfZPlane.IDYDZ;
41      private static final int   IQP_Z  = SurfZPlane.IQP;
42      
43      private static final int   IPHI = SurfCylinder.IPHI;
44      private static final int   IZ_CYL = SurfCylinder.IZ;
45      private static final int   IALF = SurfCylinder.IALF;
46      private static final int   ITLM = SurfCylinder.ITLM;
47      private static final int   IQPT  = SurfCylinder.IQPT;
48      
49      //************************************************************************
50      
51      // compare two tracks  without errors
52      
53      private double compare(VTrack trv1,VTrack trv2)
54      {
55          Surface srf = trv2.surface();
56          
57          Assert.assertTrue(trv1.surface().equals(srf));
58          
59          double diff = srf.vecDiff(trv2.vector(),trv1.vector()).amax();
60          
61          return diff;
62      }
63      
64      //**********************************************************************
65      // compare two tracks  with errors
66      
67      private double[] compare(ETrack trv1,ETrack trv2 )
68      {
69          double[] tmp = new double[2];
70          Surface srf = trv2.surface();
71          
72          Assert.assertTrue(trv1.surface().equals(srf));
73          
74          tmp[0] = srf.vecDiff(trv2.vector(),trv1.vector()).amax();
75          
76          TrackError dfc = trv2.error().minus(trv1.error());
77          tmp[1] = dfc.amax();
78          
79          
80          return tmp;
81      }
82      /** Creates a new instance of PropCylZ_Test */
83      public void testPropCylZ()
84      {
85          String ok_prefix = "PropCylZ (I): ";
86          String error_prefix = "PropCylZ test (E): ";
87          
88          if(debug) System.out.println( ok_prefix
89                  + "-------- Testing component PropCylZ. --------" );
90          {
91              if(debug) System.out.println( ok_prefix + "Test constructor." );
92              double BFIELD = 2.0;
93              PropCylZ prop = new PropCylZ(BFIELD);
94              if(debug) System.out.println( prop );
95              
96              PropCylZ_Test tst = new PropCylZ_Test();
97              
98              //********************************************************************
99              
100             // Here we propagate some tracks both forward and backward and then
101             // the same track forward and backward but using method
102             // that we checked very thoroughly before.
103             
104             if(debug) System.out.println( ok_prefix + "Check against correct propagation." );
105             
106             PropCylZ propcylz = new PropCylZ(BFIELD/TRFMath.BFAC);
107             
108             double phi[]   ={  Math.PI/5,   Math.PI/6,   Math.PI/6,   4/3*Math.PI,  5/3*Math.PI,  5/3*Math.PI };
109             double z[]     ={  1.5,   -2.3,    0.,     1.5,    -1.5,    -1.5    };
110             double alpha[] ={  0.1,   -0.1,    0.,     0.2,    -0.2,     0.     };
111             double tlm[]   ={  2.3,   -1.5,   -2.3,    2.3,    -2.3,     2.3    };
112             double qpt[]   ={  0.01,  -0.01,   0.01,  -0.01,   -0.01,    0.01   };
113             
114             double z2[]    ={  5.5,   -6.0,   -5.0,    6.0,    -5.7,     4.0    };
115             double z2b[]   ={ -4.0,    4.0,    5.0,   -3.0,     3.0,    -6.0    };
116             
117             double maxdiff = 1.e-10;
118             double diff;
119             int ntrk = 6;
120             int i;
121             
122             for ( i=0; i<ntrk; ++i )
123             {
124                 if(debug) System.out.println( "********** Propagate track " + i + ". **********" );
125                 PropStat pstat = new PropStat();
126                 SurfCylinder scy1 = new SurfCylinder(10.);
127                 SurfZPlane   szp2 = new SurfZPlane(z2[i]);
128                 SurfZPlane   szp2b = new SurfZPlane(z2b[i]);
129                 
130                 TrackVector vec1 = new TrackVector();
131                 
132                 vec1.set(IPHI   , phi[i]);            // phi
133                 vec1.set(IZ_CYL , z[i]);              // z
134                 vec1.set(IALF   , alpha[i]);          // alpha
135                 vec1.set(ITLM   , tlm[i]);            // tan(lambda)
136                 vec1.set(IQPT   , qpt[i]);            // q/pt
137                 
138                 VTrack trv1 = new VTrack(scy1.newPureSurface(),vec1);
139                 
140                 if(debug) System.out.println( "\n starting: " + trv1 );
141                 
142                 VTrack trv2f = new VTrack(trv1);
143                 pstat = propcylz.vecDirProp(trv2f,szp2,PropDir.FORWARD);
144                 Assert.assertTrue( pstat.forward() );
145                 if(debug) System.out.println( "\n  forward: " + trv2f );
146                 
147                 VTrack trv2f_my = new VTrack(trv1);
148                 pstat = tst.vec_propcylz(BFIELD,trv2f_my,szp2,PropDir.FORWARD);
149                 Assert.assertTrue( pstat.forward() );
150                 if(debug) System.out.println( "\n  forward my: " + trv2f_my );
151                 diff = tst.compare(trv2f_my,trv2f);
152                 
153                 if(debug) System.out.println( "\n diff: " + diff );
154                 Assert.assertTrue( diff < maxdiff );
155                 
156                 VTrack trv2b = new VTrack(trv1);
157                 pstat = propcylz.vecDirProp(trv2b,szp2b,PropDir.BACKWARD);
158                 Assert.assertTrue( pstat.backward() );
159                 if(debug) System.out.println( "\n  backward: " + trv2b );
160                 
161                 VTrack trv2b_my = new VTrack(trv1);
162                 pstat = tst.vec_propcylz(BFIELD,trv2b_my,szp2b,PropDir.BACKWARD);
163                 Assert.assertTrue( pstat.backward() );
164                 if(debug) System.out.println( "\n  backward my: " + trv2b_my );
165                 diff = tst.compare(trv2b_my,trv2b);
166                 
167                 if(debug) System.out.println( "\n diff: " + diff );
168                 Assert.assertTrue( diff < maxdiff );
169                 
170             }
171             //********************************************************************
172             
173             // Repeat the above with errors.
174             if(debug) System.out.println( ok_prefix + "Check against correct propagation with errors." );
175             
176             double epp[] = {  0.01,   0.01,   0.01,   0.01,   0.01,   0.01,   0.01  };
177             double epz[] = {  0.01,  -0.01,   0.01,  -0.01,   0.01,  -0.01,   0.01  };
178             double ezz[] = {  0.25,   0.25,   0.25,   0.25,   0.25,   0.25,   0.25  };
179             double epa[] = {  0.003, -0.003,  0.003, -0.003,  0.003, -0.003,  0.003 };
180             double eza[] = {  0.004, -0.004,  0.004, -0.004,  0.004, -0.004,  0.004 };
181             double eaa[] = {  0.01,   0.01,   0.01,   0.01,   0.01,   0.01,   0.01  };
182             double epl[] = {  0.004, -0.004,  0.004, -0.004,  0.004, -0.004,  0.004 };
183             double eal[] = {  0.004, -0.004,  0.004, -0.004,  0.004, -0.004,  0.004 };
184             double ezl[] = {  0.04,  -0.04,   0.04,  -0.04,   0.04,  -0.04,   0.04  };
185             double ell[] = {  0.02,   0.02,   0.02,   0.02,   0.02,   0.02,   0.02  };
186             double epc[] = {  0.004, -0.004,  0.004, -0.004,  0.004, -0.004,  0.004 };
187             double ezc[] = {  0.004, -0.004,  0.004, -0.004,  0.004, -0.004,  0.004 };
188             double eac[] = {  0.004, -0.004,  0.004, -0.004,  0.004, -0.004,  0.004 };
189             double elc[] = {  0.004, -0.004,  0.004, -0.004,  0.004, -0.004,  0.004 };
190             double ecc[] = {  0.01,   0.01,   0.01,   0.01,   0.01,   0.01,   0.01  };
191             
192             maxdiff = 1.e-8;
193             double ediff;
194             ntrk = 6;
195             
196             for ( i=0; i<ntrk; ++i )
197             {
198                 if(debug) System.out.println( "********** Propagate track " + i + ". **********" );
199                 PropStat pstat = new PropStat();
200                 SurfCylinder scy1 = new SurfCylinder(10.);
201                 SurfZPlane   szp2 = new SurfZPlane(z2[i]);
202                 SurfZPlane   szp2b = new SurfZPlane(z2b[i]);
203                 
204                 TrackVector vec1 = new TrackVector();
205                 
206                 vec1.set(IPHI  ,  phi[i]);            // phi
207                 vec1.set(IZ_CYL,  z[i]);              // z
208                 vec1.set(IALF  ,  alpha[i]);          // alpha
209                 vec1.set(ITLM  ,  tlm[i]);            // tan(lambda)
210                 vec1.set(IQPT  ,  qpt[i]);            // q/pt
211                 
212                 TrackError err1 = new TrackError();
213                 
214                 err1.set(IPHI,IPHI    ,  epp[i]);
215                 err1.set(IPHI,IZ_CYL  ,  epz[i]);
216                 err1.set(IZ_CYL,IZ_CYL,  ezz[i]);
217                 err1.set(IPHI,IALF    ,  epa[i]);
218                 err1.set(IZ_CYL,IALF  ,  eza[i]);
219                 err1.set(IALF,IALF    ,  eaa[i]);
220                 err1.set(IPHI,ITLM    ,  epl[i]);
221                 err1.set(IZ_CYL,ITLM  ,  ezl[i]);
222                 err1.set(IALF,ITLM    ,  eal[i]);
223                 err1.set(ITLM,ITLM    ,  ell[i]);
224                 err1.set(IPHI,IQPT    ,  epc[i]);
225                 err1.set(IZ_CYL,IQPT  ,  ezc[i]);
226                 err1.set(IALF,IQPT    ,  eac[i]);
227                 err1.set(ITLM,IQPT    ,  elc[i]);
228                 err1.set(IQPT,IQPT    ,  ecc[i]);
229                 
230                 ETrack trv1 = new ETrack(scy1.newPureSurface(),vec1,err1);
231                 
232                 if(debug) System.out.println( "\n starting: " + trv1 );
233                 
234                 ETrack trv2f = new ETrack(trv1);
235                 pstat = propcylz.errDirProp(trv2f,szp2,PropDir.FORWARD);
236                 Assert.assertTrue( pstat.forward() );
237                 if(debug) System.out.println( "\n  forward: " + trv2f );
238                 
239                 ETrack trv2f_my = new ETrack(trv1);
240                 TrackDerivative deriv = new TrackDerivative();
241                 pstat = tst.vec_propcylz(BFIELD,trv2f_my,szp2,PropDir.FORWARD,deriv);
242                 Assert.assertTrue( pstat.forward() );
243                 TrackError err = trv2f_my.error();
244                 trv2f_my.setError( err.Xform(deriv) );
245                 if(debug) System.out.println( "\n  forward my: " + trv2f_my );
246                 double[] diffs = tst.compare(trv2f_my,trv2f);
247                 
248                 if(debug) System.out.println( "\n diff: " + diffs[0] + ' ' + "ediff: "+ diffs[1] );
249                 Assert.assertTrue( diffs[0] < maxdiff );
250                 Assert.assertTrue( diffs[1] < maxdiff );
251                 
252                 
253                 ETrack trv2b = new ETrack(trv1);
254                 pstat = propcylz.errDirProp(trv2b,szp2b,PropDir.BACKWARD);
255                 Assert.assertTrue( pstat.backward() );
256                 if(debug) System.out.println( "\n  backward: " + trv2b );
257                 
258                 ETrack trv2b_my = new ETrack(trv1);
259                 pstat = tst.vec_propcylz(BFIELD,trv2b_my,szp2b,PropDir.BACKWARD,deriv);
260                 Assert.assertTrue( pstat.backward() );
261                 err = trv2b_my.error();
262                 trv2b_my.setError( err.Xform(deriv) );
263                 if(debug) System.out.println( "\n  backward my: " + trv2b_my );
264                 diffs = tst.compare(trv2b_my,trv2b);
265                 
266                 if(debug) System.out.println( "\n diff: " + diffs[0] + ' ' + "ediff: "+ diffs[1] );
267                 Assert.assertTrue( diffs[0] < maxdiff );
268                 Assert.assertTrue( diffs[1] < maxdiff );
269                 
270             }
271             
272             //********************************************************************
273             
274             if(debug) System.out.println( ok_prefix + "Test cloning." );
275             Assert.assertTrue( prop.newPropagator() != null );
276             
277             //********************************************************************
278             
279             if(debug) System.out.println( ok_prefix + "Test the field." );
280             Assert.assertTrue( prop.bField() == 2.0 );
281             
282         }
283                 
284                 
285                 //********************************************************************
286                 
287                 if(debug) System.out.println( ok_prefix + "Test Zero Field Propagation." );
288                 {
289                     PropCylZ prop0 = new PropCylZ(0.0);
290                     if(debug) System.out.println( prop0 );
291                     Assert.assertTrue( prop0.bField() == 0. );
292                     
293                     double z=6.;
294                     Surface srf = new SurfCylinder(13.0);
295                     VTrack trv0 = new VTrack(srf);
296                     TrackVector vec = new TrackVector();
297                     vec.set(SurfCylinder.IPHI, 0.1);
298                     vec.set(SurfCylinder.IZ, 10.);
299                     vec.set(SurfCylinder.IALF, 0.1);
300                     vec.set(SurfCylinder.ITLM, 2.);
301                     vec.set(SurfCylinder.IQPT, 0.);
302                     trv0.setVector(vec);
303                     trv0.setForward();
304                     Surface srf_to = new SurfZPlane(z);
305                     
306                     VTrack trv = new VTrack(trv0);
307                     VTrack trv_der = new VTrack(trv);
308                     PropStat pstat = prop0.vecDirProp(trv,srf_to,PropDir.NEAREST);
309                     if(debug) System.out.println(trv);
310                     Assert.assertTrue( pstat.success() );
311                     
312                     Assert.assertTrue( pstat.backward() );
313                     Assert.assertTrue(trv.surface().pureEqual(srf_to));
314                     
315                     check_zero_propagation(trv0,trv,pstat);
316                     check_derivatives(prop0,trv_der,srf_to);
317                     
318                     srf_to = new SurfZPlane(10.);
319                     trv = new VTrack(trv0);
320                     trv_der = new VTrack(trv);
321                     pstat = prop0.vecDirProp(trv,srf_to,PropDir.NEAREST);
322                     if(debug) System.out.println(trv);
323                     Assert.assertTrue( pstat.success() );
324                     
325                     Assert.assertTrue( pstat.same() );
326                     Assert.assertTrue(trv.surface().pureEqual(srf_to));
327                     
328                     check_zero_propagation(trv0,trv,pstat);
329                     check_derivatives(prop0,trv_der,srf_to);
330                     
331                 }
332                 
333                 //********************************************************************
334                 
335                 if(debug) System.out.println( ok_prefix
336                         + "------------- All tests passed. -------------" );
337                 //********************************************************************
338     }
339     
340     
341     // Very well tested Cyl-Z propagator. Each new one can be tested against it
342     private PropStat
343             vec_propcylz( double B, VTrack trv,  Surface srf,
344             PropDir dir )
345     {
346         TrackDerivative deriv = null;
347         return vec_propcylz(B, trv, srf, dir, deriv);
348     }
349     private PropStat
350             vec_propcylz( double B, VTrack trv,  Surface srf,
351             PropDir dir,
352             TrackDerivative deriv  )
353     {
354         
355         // phi, z, alpha=phi_dir-phi, tan(lambda)=pz/pt, q/pt
356         // c1   c2   c3                c4                 c5
357         //
358         // x   y   dx/dz dy/dz q/p
359         // a1  a2  a3    a4    a5
360         //
361         // phi is polar angle of track momentum, R radius of the track in field B
362         // dphi is angle of rotation of momentum
363         // Rcyl is cylinder radius
364         //
365         // a1n = a1 + Rsin_phi*(cos_dphi - 1) + Rcos_phi*sin_dphi;
366         // a2n = a2 - Rcos_phi*(cos_dphi - 1) + Rsin_phi*sin_dphi;
367         // a3n = a3*cos_dphi - a4*sin_dphi;
368         // a4n = a3*sin_dphi + a4*cos_dphi;
369         // a5n = a5;
370         
371         // a1 = Rcyl*cos_c1;
372         // a2 = Rcyl*sin_c1;
373         // a3 = cos(c1+c3)/c4;
374         // a4 = sin(c1+c3)/c4;
375         // a5 = c5/sqrt(1+c4*c4);
376         //
377         // dz = zpos - c2
378         
379         
380         // construct return status
381         PropStat pstat = new PropStat();;
382         // fetch the originating surface and vector
383         Surface srf1 = trv.surface();
384         // TrackVector vec1 = trv.vector();
385         
386         // Check origin is a Cylinder.
387         Assert.assertTrue( srf1.pureType().equals(SurfCylinder.staticType()) );
388         if ( ! srf1.pureType( ).equals(SurfCylinder.staticType()) )
389             return pstat;
390         SurfCylinder scy1 = (SurfCylinder) srf1;
391         
392         
393         // Fetch the R of the cylinder and the starting track vector.
394         int ir  = SurfCylinder.RADIUS;
395         double Rcyl = scy1.parameter(ir);
396         
397         TrackVector vec = trv.vector();
398         double c1 = vec.get(IPHI);                 // phi
399         double c2 = vec.get(IZ_CYL);               // z
400         double c3 = vec.get(IALF);                 // alpha
401         double c4 = vec.get(ITLM);                 // tan(lambda)
402         double c5 = vec.get(IQPT);                 // q/pt
403         
404         // check that dz != 0
405         if(c4 == 0.) return pstat;
406         
407         double cos_c1 = Math.cos(c1);
408         double sin_c1 = Math.sin(c1);
409         double cos_dir = Math.cos(c1+c3);
410         double sin_dir = Math.sin(c1+c3);
411         double c4_hat2 = 1+c4*c4;
412         double c4_hat  = Math.sqrt(c4_hat2);
413         
414         double a1 = Rcyl*cos_c1;
415         double a2 = Rcyl*sin_c1;
416         double a3 = cos_dir/c4;
417         double a4 = sin_dir/c4;
418         double a5 = c5/c4_hat;
419         
420         
421         // if tan(lambda)=dz/dst > 0 : dz>0; dzdst < 0 dz<0
422         
423         int sign_dz = 0;
424         if(c4 > 0) sign_dz =  1;
425         if(c4 < 0) sign_dz = -1;
426         
427         
428         // Check destination is a ZPlane.
429         Assert.assertTrue( srf.pureType().equals(SurfZPlane.staticType()) );
430         if ( ! srf.pureType( ).equals(SurfZPlane.staticType()) )
431             return pstat;
432         SurfZPlane szp2 = (SurfZPlane) srf;
433         
434         // Fetch the zpos's of the planes.
435         int izpos  = SurfZPlane.ZPOS;
436         
437         double zpos = szp2.parameter(izpos);
438         
439         double dz = zpos - c2;
440         
441         
442         if (dir.equals(PropDir.NEAREST))
443         {
444             
445             if(debug) System.out.println("vec_propcylz: Propagation in NEAREST direction is undefined");
446             System.exit(1);
447         }
448         else if (dir.equals(PropDir.FORWARD))
449         {
450             //   cyl-z propagation failed
451             if(sign_dz*dz<0.)  return pstat;
452         }
453         else if (dir.equals(PropDir.BACKWARD))
454         {
455             //   cyl-z propagation failed
456             if(sign_dz*dz>0.) return pstat;
457         }
458         else
459         {
460             if(debug) System.out.println("vec_propcylz: Unknown direction." );
461             System.exit(1);
462         }
463         
464         double a34_hat = sign_dz*Math.sqrt(a3*a3 + a4*a4);
465         double a34_hat2 = a34_hat*a34_hat;
466         double dphi = B*dz*a5*Math.sqrt(1.+a34_hat2)*sign_dz;
467         double cos_dphi = Math.cos(dphi);
468         double sin_dphi = Math.sin(dphi);
469         
470         double Rcos_phi = 1./(B*a5)*a3/Math.sqrt(1.+a34_hat2)*sign_dz;
471         double Rsin_phi = 1./(B*a5)*a4/Math.sqrt(1.+a34_hat2)*sign_dz;
472         
473         double a1n = a1 + Rsin_phi*(cos_dphi - 1) + Rcos_phi*sin_dphi;
474         double a2n = a2 - Rcos_phi*(cos_dphi - 1) + Rsin_phi*sin_dphi;
475         double a3n =  a3*cos_dphi - a4*sin_dphi;
476         double a4n =  a3*sin_dphi + a4*cos_dphi;
477         double a5n = a5;
478         
479         vec.set(IX    , a1n);
480         vec.set(IY    , a2n);
481         vec.set(IDXDZ , a3n);
482         vec.set(IDYDZ , a4n);
483         vec.set(IQP_Z , a5n);
484         
485         // Update trv
486         trv.setSurface(srf.newPureSurface());
487         trv.setVector(vec);
488         
489         // set new direction of the track
490         
491         if(sign_dz ==  1) trv.setForward();
492         if(sign_dz == -1) trv.setBackward();
493         
494         // Set the return status.
495         
496         if (dir.equals(PropDir.FORWARD))
497         {
498             pstat.setForward();
499         }
500         else if (dir.equals(PropDir.BACKWARD))
501         {
502             pstat.setBackward();
503         }
504         
505         // exit now if user did not ask for error matrix.
506         if ( deriv == null ) return pstat;
507         
508         //da34_hat
509         
510         double da34_hat_da3 = 0.;
511         double da34_hat_da4 = 0.;
512         if(Math.abs(a3)>=Math.abs(a4))
513         {
514             int sign3=1;
515             if(a3<0) sign3 = -1;
516             if(a3 !=0.)
517             {
518                 da34_hat_da3 = sign_dz*sign3/Math.sqrt(1.+(a4/a3)*(a4/a3) );
519                 da34_hat_da4 = sign_dz*(a4/Math.abs(a3))/Math.sqrt(1.+(a4/a3)*(a4/a3) );
520             }
521             else
522             {
523                 da34_hat_da3 = 0.;
524                 da34_hat_da4 = 0.;
525             }
526         }
527         if(Math.abs(a4)>Math.abs(a3))
528         {
529             int sign4=1;
530             if(a4<0) sign4 = -1;
531             if(a4 !=0.)
532             {
533                 da34_hat_da3 = sign_dz*(a3/Math.abs(a4))/Math.sqrt(1.+(a3/a4)*(a3/a4) );
534                 da34_hat_da4 = sign_dz*sign4/Math.sqrt(1.+(a3/a4)*(a3/a4) );
535             }
536             else
537             {
538                 da34_hat_da3 = 0.;
539                 da34_hat_da4 = 0.;
540             }
541         }
542         
543         // ddphi / da
544         
545         double ddphi_da3 = B*dz*a5*a34_hat*sign_dz/Math.sqrt(1.+a34_hat2)*da34_hat_da3;
546         double ddphi_da4 = B*dz*a5*a34_hat*sign_dz/Math.sqrt(1.+a34_hat2)*da34_hat_da4;
547         double ddphi_da5 = B*dz*Math.sqrt(a34_hat2+1.)*sign_dz;
548         
549         // dRsin_phi
550         
551         double dRsin_phi_da3 = -Rsin_phi*a34_hat/(1.+a34_hat2)*da34_hat_da3;
552         double dRsin_phi_da4 = -Rsin_phi*a34_hat/(1.+a34_hat2)*da34_hat_da4 +
553                 sign_dz/(B*a5)/Math.sqrt(1.+a34_hat2);
554         double dRsin_phi_da5 = -Rsin_phi/a5;
555         
556         // dRcos_phi
557         
558         double dRcos_phi_da3 = -Rcos_phi*a34_hat/(1.+a34_hat2)*da34_hat_da3 +
559                 sign_dz/(B*a5)/Math.sqrt(1.+a34_hat2);
560         double dRcos_phi_da4 = -Rcos_phi*a34_hat/(1.+a34_hat2)*da34_hat_da4;
561         double dRcos_phi_da5 = -Rcos_phi/a5;
562         
563         // da1n first two are simple because dR,dphi _da1,_da2 = 0.
564         
565         // double da1n_da1 = 1.;
566         double da1n_da3 = dRsin_phi_da3*(cos_dphi-1.) + dRcos_phi_da3*sin_dphi
567                 - Rsin_phi*sin_dphi*ddphi_da3 + Rcos_phi*cos_dphi*ddphi_da3;
568         double da1n_da4 = dRsin_phi_da4*(cos_dphi-1.) + dRcos_phi_da4*sin_dphi
569                 - Rsin_phi*sin_dphi*ddphi_da4 + Rcos_phi*cos_dphi*ddphi_da4;
570         double da1n_da5 = dRsin_phi_da5*(cos_dphi-1.) + dRcos_phi_da5*sin_dphi
571                 - Rsin_phi*sin_dphi*ddphi_da5 + Rcos_phi*cos_dphi*ddphi_da5;
572         
573         // da2n first two are simple because dR,dphi _da1,_da2 = 0.
574         
575         // double da2n_da2 = 1.;
576         double da2n_da3 = -dRcos_phi_da3*(cos_dphi-1.) + dRsin_phi_da3*sin_dphi
577                 + Rcos_phi*sin_dphi*ddphi_da3 + Rsin_phi*cos_dphi*ddphi_da3;
578         double da2n_da4 = -dRcos_phi_da4*(cos_dphi-1.) + dRsin_phi_da4*sin_dphi
579                 + Rcos_phi*sin_dphi*ddphi_da4 + Rsin_phi*cos_dphi*ddphi_da4;
580         double da2n_da5 = -dRcos_phi_da5*(cos_dphi-1.) + dRsin_phi_da5*sin_dphi
581                 + Rcos_phi*sin_dphi*ddphi_da5 + Rsin_phi*cos_dphi*ddphi_da5;
582         
583         // da3n first two are simple because dphi _da1,_da2 = 0.
584         
585         double da3n_da3 = cos_dphi - a3*sin_dphi*ddphi_da3 - a4*cos_dphi*ddphi_da3;
586         double da3n_da4 = - sin_dphi - a3*sin_dphi*ddphi_da4 - a4*cos_dphi*ddphi_da4;
587         double da3n_da5 = - a3*sin_dphi*ddphi_da5 - a4*cos_dphi*ddphi_da5;
588         
589         // da4n first two are simple because dphi _da1,_da2 = 0.
590         
591         double da4n_da3 =   sin_dphi + a3*cos_dphi*ddphi_da3 - a4*sin_dphi*ddphi_da3;
592         double da4n_da4 =   cos_dphi + a3*cos_dphi*ddphi_da4 - a4*sin_dphi*ddphi_da4;
593         double da4n_da5 =   a3*cos_dphi*ddphi_da5 - a4*sin_dphi*ddphi_da5;
594         
595         // da5n
596         
597         // double da5n_da5 = 1.;
598         
599         // ddphi / dc
600         
601         double ddphi_dc2 = -B*a5*Math.sqrt(a34_hat2+1.)*sign_dz;
602         
603         // da1 / dc
604         
605         double da1_dc1 = -Rcyl*sin_c1;
606         
607         // da2 / dc
608         
609         double da2_dc1 =  Rcyl*cos_c1;
610         
611         // da3 / dc
612         
613         double da3_dc1 = -sin_dir/c4;
614         double da3_dc3 = -sin_dir/c4;
615         double da3_dc4 = -cos_dir/(c4*c4);
616         
617         // da4 / dc
618         
619         double da4_dc1 =  cos_dir/c4;
620         double da4_dc3 =  cos_dir/c4;
621         double da4_dc4 = -sin_dir/(c4*c4);
622         
623         // da5 / dc
624         
625         double da5_dc4 =  -c5*c4/(c4_hat*c4_hat2);
626         double da5_dc5 =   1./c4_hat;
627         
628         // da1n/ dc
629         
630         double da1n_dc1 = da1_dc1 + da1n_da3*da3_dc1 + da1n_da4*da4_dc1;
631         double da1n_dc2 = -Rsin_phi*sin_dphi*ddphi_dc2 + Rcos_phi*cos_dphi*ddphi_dc2;
632         double da1n_dc3 = da1n_da3*da3_dc3 + da1n_da4*da4_dc3;
633         double da1n_dc4 = da1n_da3*da3_dc4 + da1n_da4*da4_dc4 + da1n_da5*da5_dc4;
634         double da1n_dc5 = da1n_da5*da5_dc5;
635         
636         // da2n/ dc
637         
638         double da2n_dc1 = da2_dc1 + da2n_da3*da3_dc1 + da2n_da4*da4_dc1;
639         double da2n_dc2 = Rcos_phi*sin_dphi*ddphi_dc2 + Rsin_phi*cos_dphi*ddphi_dc2;
640         double da2n_dc3 = da2n_da3*da3_dc3 + da2n_da4*da4_dc3;
641         double da2n_dc4 = da2n_da3*da3_dc4 + da2n_da4*da4_dc4 + da2n_da5*da5_dc4;
642         double da2n_dc5 = da2n_da5*da5_dc5;
643         
644         // da3n/ dc
645         
646         double da3n_dc1 = da3n_da3*da3_dc1 + da3n_da4*da4_dc1;
647         double da3n_dc2 = -a3*sin_dphi*ddphi_dc2 - a4*cos_dphi*ddphi_dc2;
648         double da3n_dc3 = da3n_da3*da3_dc3 + da3n_da4*da4_dc3;
649         double da3n_dc4 = da3n_da3*da3_dc4 + da3n_da4*da4_dc4 + da3n_da5*da5_dc4;
650         double da3n_dc5 = da3n_da5*da5_dc5;
651         
652         // da4n/ dc
653         
654         double da4n_dc1 = da4n_da3*da3_dc1 + da4n_da4*da4_dc1;
655         double da4n_dc2 = a3*cos_dphi*ddphi_dc2 - a4*sin_dphi*ddphi_dc2;
656         double da4n_dc3 = da4n_da3*da3_dc3 + da4n_da4*da4_dc3;
657         double da4n_dc4 = da4n_da3*da3_dc4 + da4n_da4*da4_dc4 + da4n_da5*da5_dc4;
658         double da4n_dc5 = da4n_da5*da5_dc5;
659         
660         // da5n/ dc
661         
662         double da5n_dc1 = 0.;
663         double da5n_dc2 = 0.;
664         double da5n_dc3 = 0.;
665         double da5n_dc4 = da5_dc4;
666         double da5n_dc5 = da5_dc5;
667         
668         deriv.set(IX,IPHI      , da1n_dc1);
669         deriv.set(IX,IZ_CYL    , da1n_dc2);
670         deriv.set(IX,IALF      , da1n_dc3);
671         deriv.set(IX,ITLM      , da1n_dc4);
672         deriv.set(IX,IQPT      , da1n_dc5);
673         deriv.set(IY,IPHI      , da2n_dc1);
674         deriv.set(IY,IZ_CYL    , da2n_dc2);
675         deriv.set(IY,IALF      , da2n_dc3);
676         deriv.set(IY,ITLM      , da2n_dc4);
677         deriv.set(IY,IQPT      , da2n_dc5);
678         deriv.set(IDXDZ,IPHI   , da3n_dc1);
679         deriv.set(IDXDZ,IZ_CYL , da3n_dc2);
680         deriv.set(IDXDZ,IALF   , da3n_dc3);
681         deriv.set(IDXDZ,ITLM   , da3n_dc4);
682         deriv.set(IDXDZ,IQPT   , da3n_dc5);
683         deriv.set(IDYDZ,IPHI   , da4n_dc1);
684         deriv.set(IDYDZ,IZ_CYL , da4n_dc2);
685         deriv.set(IDYDZ,IALF   , da4n_dc3);
686         deriv.set(IDYDZ,ITLM   , da4n_dc4);
687         deriv.set(IDYDZ,IQPT   , da4n_dc5);
688         deriv.set(IQP_Z,IPHI   , da5n_dc1);
689         deriv.set(IQP_Z,IZ_CYL , da5n_dc2);
690         deriv.set(IQP_Z,IALF   , da5n_dc3);
691         deriv.set(IQP_Z,ITLM   , da5n_dc4);
692         deriv.set(IQP_Z,IQPT   , da5n_dc5);
693         
694         return pstat;
695     }
696     
697     private static void  check_zero_propagation( VTrack trv0, VTrack trv, PropStat pstat)
698     {
699         
700         SpacePoint sp = trv.spacePoint();
701         SpacePoint sp0 = trv0.spacePoint();
702         
703         SpacePath sv = trv.spacePath();
704         SpacePath sv0 = trv0.spacePath();
705         
706         Assert.assertTrue( Math.abs(sv0.dx() - sv.dx())<1e-7 );
707         Assert.assertTrue( Math.abs(sv0.dy() - sv.dy())<1e-7 );
708         Assert.assertTrue( Math.abs(sv0.dz() - sv.dz())<1e-7 );
709         
710         double x0 = sp0.x();
711         double y0 = sp0.y();
712         double z0 = sp0.z();
713         double x1 = sp.x();
714         double y1 = sp.y();
715         double z1 = sp.z();
716         
717         double dx = sv.dx();
718         double dy = sv.dy();
719         double dz = sv.dz();
720         
721         double prod = dx*(x1-x0)+dy*(y1-y0)+dz*(z1-z0);
722         double moda = Math.sqrt((x1-x0)*(x1-x0)+(y1-y0)*(y1-y0) + (z1-z0)*(z1-z0));
723         double modb = Math.sqrt(dx*dx+dy*dy+dz*dz);
724         double st = pstat.pathDistance();
725         Assert.assertTrue( Math.abs(prod-st) < 1.e-7 );
726         Assert.assertTrue( Math.abs(Math.abs(prod) - moda*modb) < 1.e-7 );
727     }
728     
729     private static void check_derivatives( Propagator prop, VTrack trv0, Surface srf)
730     {
731         for(int i=0;i<4;++i)
732             for(int j=0;j<4;++j)
733                 check_derivative(prop,trv0,srf,i,j);
734     }
735     
736     private static void check_derivative( Propagator prop, VTrack trv0, Surface srf,int i,int j)
737     {
738         
739         double dx = 1.e-3;
740         VTrack trv = new VTrack(trv0);
741         TrackVector vec = trv.vector();
742         boolean forward = trv0.isForward();
743         
744         VTrack trv_0 = new VTrack(trv0);
745         TrackDerivative der = new TrackDerivative();
746         PropStat pstat = prop.vecProp(trv_0,srf,der);
747         Assert.assertTrue(pstat.success());
748         
749         TrackVector tmp = new TrackVector(vec);
750         tmp.set(j, tmp.get(j)+dx);
751         trv.setVector(tmp);
752         if(forward) trv.setForward();
753         else trv.setBackward();
754         
755         VTrack trv_pl = new VTrack(trv);
756         pstat = prop.vecProp(trv_pl,srf);
757         Assert.assertTrue(pstat.success());
758         
759         TrackVector vecpl = trv_pl.vector();
760         
761         tmp = new TrackVector(vec);
762         tmp.set(j, tmp.get(j)-dx);
763         trv.setVector(tmp);
764         if(forward) trv.setForward();
765         else trv.setBackward();
766         
767         VTrack trv_mn = new VTrack(trv);
768         pstat = prop.vecProp(trv_mn,srf);
769         Assert.assertTrue(pstat.success());
770         
771         TrackVector vecmn = trv_mn.vector();
772         
773         double dy = (vecpl.get(i)-vecmn.get(i))/2.;
774         
775         double dydx = dy/dx;
776         
777         double didj = der.get(i,j);
778         
779         if( Math.abs(didj) > 1e-10 )
780             Assert.assertTrue( Math.abs((dydx - didj)/didj) < 1e-4 );
781         else
782             Assert.assertTrue( Math.abs(dydx) < 1e-4 );
783     }
784     
785 }