View Javadoc

1   package org.lcsim.recon.tracking.trfxyp;
2   /**
3    * Propagates tracks from one XYPlane to another in a constant magnetic field.
4    * in the x^ direction.
5    *
6    * Propagation will fail if either the origin or destination is
7    * not an XYPlane.
8    */
9   import org.lcsim.recon.tracking.trfutil.TRFMath;
10  import org.lcsim.recon.tracking.trfutil.Assert;
11  
12  import org.lcsim.recon.tracking.trfbase.Propagator;
13  import org.lcsim.recon.tracking.trfbase.PropDirected;
14  import org.lcsim.recon.tracking.trfbase.PropDir;
15  import org.lcsim.recon.tracking.trfbase.PropStat;
16  import org.lcsim.recon.tracking.trfbase.VTrack;
17  import org.lcsim.recon.tracking.trfbase.Surface;
18  import org.lcsim.recon.tracking.trfbase.TrackVector;
19  import org.lcsim.recon.tracking.trfbase.TrackDerivative;
20  
21  
22  /**
23   * Propagates tracks from one XYPlane to another in a constant field.
24   * Magnetic field is in x^ direction
25   *<p>
26   * Propagation will fail if either the origin or destination is
27   * not an XYPlane.
28   *
29   *@author Norman A. Graf
30   *@version 1.0
31   *
32   */
33  
34  public class PropXYXYBX extends PropDirected
35  {
36      
37      // attributes
38      
39      private double _bfac;
40      
41      private static final int    IV = SurfXYPlane.IV;
42      private static final int   IZ   = SurfXYPlane.IZ;
43      private static final int   IDVDU = SurfXYPlane.IDVDU;
44      private static final int   IDZDU = SurfXYPlane.IDZDU;
45      private static final int   IQP  = SurfXYPlane.IQP;
46      
47      
48      private boolean debug;
49      
50      // static methods
51      
52      /**
53       *Return a String representation of the class' type name.
54       *Included for completeness with the C++ version.
55       *
56       * @return   A String representation of the class' type name.
57       */
58      public static String typeName()
59      {
60          return "PropXYXYBX";
61      }
62      
63      /**
64       *Return a String representation of the class' type name.
65       *Included for completeness with the C++ version.
66       *
67       * @return   A String representation of the class' type name.
68       */
69      public static String staticType()
70      {
71          return typeName();
72      }
73      
74      
75      
76      /**
77       *Construct an instance from a constant solenoidal magnetic field in Tesla.
78       *
79       * @param   bfield The magnetic field strength in Tesla.
80       */
81      public PropXYXYBX(double bfield)
82      {
83          _bfac = TRFMath.BFAC*bfield;
84      }
85      
86      /**
87       *Clone an instance.
88       *
89       * @return A Clone of this instance.
90       */
91      public Propagator newPropagator( )
92      {
93          return new PropXYXYBX( bField() );
94      }
95      
96      
97      /**
98       *Propagate a track without error in the specified direction
99       *and return the derivative matrix in deriv.
100      *
101      * @param   trv The VTrack to propagate.
102      * @param   srf The Surface to which to propagate.
103      * @param   dir The direction in which to propagate.
104      * @param   deriv The track derivatives to update at the surface srf.
105      * @return The propagation status.
106      */
107     public PropStat vecDirProp( VTrack trv, Surface srf,
108             PropDir dir,TrackDerivative deriv )
109     {
110         PropStat pstat = vecPropagateXYXYBX( _bfac, trv, srf, dir, deriv );
111         return pstat;
112     }
113     
114     /**
115      *Propagate a track without error in the specified direction.
116      *
117      * @param   trv The VTrack to propagate.
118      * @param   srf The Surface to which to propagate.
119      * @param   dir The direction in which to propagate.
120      * @return The propagation status.
121      */
122     public PropStat vecDirProp( VTrack trv, Surface srf,
123             PropDir dir)
124     {
125         TrackDerivative deriv = null;
126         return vecDirProp(trv, srf, dir, deriv);
127     }
128     
129     
130     /**
131      *Return the strength of the magnetic field in Tesla.
132      *
133      * @return The strength of the magnetic field in Tesla.
134      */
135     public double bField()
136     {
137         return _bfac/TRFMath.BFAC;
138     }
139     
140     /**
141      *Return a String representation of the class' type name.
142      *Included for completeness with the C++ version.
143      *
144      * @return   A String representation of the class' type name.
145      */
146     public String type()
147     {
148         return staticType();
149     }
150     
151     /**
152      *output stream
153      *
154      * @return  A String representation of this instance.
155      */
156     public String toString()
157     {
158         return "XYPlane-XYPlane propagation with constant "
159                 + bField() + " Tesla field in x^ direction";
160     }
161     
162     
163     // function to find t along the trajectory . B^ || x^
164     // Return -flag_forward if no solution can be found
165     
166     private double direction(int flag_forward,
167             double w,
168             double r_sinalf,double r_cosalf,
169             double b1, double u_n, double u,
170             int sign_du,
171             double sinphi, double cosphi)
172     {
173         
174         Assert.assertTrue(flag_forward == 1 || flag_forward == -1);
175         
176         // if( cosphi == 0. )  //cng 01/11/01
177         if (Math.abs(cosphi)<1.e-14)
178         {
179             double a1 = u_n - (b1 - r_sinalf)*sinphi;
180             double a2 = r_cosalf*sinphi;
181             double a3 = r_sinalf*sinphi;
182             if(w<0 )
183             {
184                 w = -w; // w is always greater than 0
185                 a2 = -a2;
186             }
187             if(flag_forward < 0)
188             {
189                 a2 = -a2;
190             }
191             // equation to solve is a1 - a2*sin(w*t) - a3*cos(w*t) = 0
192             double b = Math.sqrt(a2*a2+a3*a3);
193             double phi = Math.acos(-a3/b);
194             Assert.assertTrue(phi<=Math.PI && phi>=0.);
195             if(a2<0) phi = TRFMath.TWOPI - phi;
196             // equation to solve is b*cos(w*t+phi)  = -a1
197             if(Math.abs(a1)> b || b==0.)
198             {
199                 // no solution
200                 return -1.*flag_forward;
201             }
202             double phi1 = Math.acos(-a1/b);
203             Assert.assertTrue(phi1<=Math.PI && phi1>=0.);
204             
205             double t = (phi1-phi)/w;
206             if(t > 0) return t*flag_forward;
207             t = (TRFMath.TWOPI - phi1 - phi)/w;
208             if(t > 0) return t*flag_forward;
209             t = (TRFMath.TWOPI + phi1 - phi)/w;
210             Assert.assertTrue(t>=0.);
211             return t*flag_forward;
212         }
213         Assert.assertTrue(sign_du == 1 || sign_du == -1);
214         Assert.assertTrue(flag_forward == 1 || flag_forward == -1);
215         
216         double eps = 1.e-10; // precision of the solution
217         double x_start,x_var,x_fix;
218         double f_start,f_var,f_fix,f_deriv;
219         double t_start;
220         
221         // double next_zero(double);
222         // double next_min(double);
223         // double next_max(double);
224         // double next_1(double,double,double);
225         
226         double a1 = (u_n - u*cosphi - (b1 - r_sinalf)*sinphi)/(cosphi*sign_du);
227         double a2 = r_cosalf*sinphi / (cosphi*sign_du);
228         double a3 = r_sinalf*sinphi / (cosphi*sign_du);
229         
230         
231         if(flag_forward == -1)
232         {
233             a1 = -a1;
234             a3 = -a3;
235         }
236         if(w<0 )
237         {
238             w = -w; // w is always greater than 0
239             a2 = -a2;
240         }
241         // now equation to solve is t = f(t) = a1 - a2sin(wt) - a3cos(wt)
242         
243         double b = Math.sqrt(a2*a2+a3*a3);
244         
245         if(b==0.) return a1*flag_forward; // solution is very easy to find
246         
247         // now equation to solve is x = t - a1 = f(x) = bcos(w(x+a1) + phi)
248         // f(-a1) = b*cos(phi)
249         
250         if( -a1 > b)
251         {
252             // no solution
253             return -1.*flag_forward;
254         }
255         
256         double phi = Math.acos(-a3/b);
257         if(a2<0) phi = TRFMath.TWOPI - phi;
258         Assert.assertTrue(phi<=TRFMath.TWOPI && phi>=0.);
259         if( -a1 >= -b)
260         {
261             t_start = 0.;
262             f_start = -a3;
263             f_deriv = -a2*w;
264         }
265         else
266         {
267             t_start = a1 - b;
268             
269             phi = phi + w*t_start;
270             
271             for(;phi>=TRFMath.TWOPI;phi -= TRFMath.TWOPI);
272             
273             Assert.assertTrue(phi<=TRFMath.TWOPI && phi>=0.);
274             f_start =  b*Math.cos(phi);
275             f_deriv = -b*Math.sin(phi)*w;
276         }
277         
278         // now we start at t = - b + a1 , f(-b) = bcos(w(x+b) + phi) = bcos(phi)
279         
280         x_start = t_start - a1;
281         
282         if( (f_start - x_start)<=0 )
283         {
284             double dphi = next1(phi,b,w);
285             if(debug) System.out.println("dphi= "+dphi);
286             if(dphi ==-1.) return -1.*flag_forward; //no solution
287             x_var = x_start + dphi/w;
288             f_var = b*Math.cos((x_var-x_start)*w+phi);
289             x_fix = x_start;
290             f_fix = f_start;
291             if(f_deriv <= 1)
292             {
293                 dphi  = next1(phi+dphi,b,w);
294                 
295                 x_fix = x_var + dphi/w;
296                 f_fix = b*Math.cos((x_fix-x_start)*w+phi);
297             }
298             if( (f_fix - x_fix)*(f_var-x_var)>0) return -1.*flag_forward; //no solution
299         } // end of first case
300         else
301         {
302             double dphi = next1(phi,b,w);
303             if(debug) System.out.println("dphi= "+dphi);
304             if(dphi == -1.)
305             {
306                 x_var = x_start + nextMax(phi)/w;
307                 f_var = b;
308                 x_fix = x_start;
309                 f_fix = f_start;
310             } // end of case where f_deriv < 1 always
311             else
312             {
313                 x_var = x_start + dphi/w;
314                 f_var = b*Math.cos((x_var-x_start)*w+phi);
315                 x_fix = x_start;
316                 f_fix = f_start;
317                 // if((f_deriv >= 1)||(f_fix - x_fix)*(f_var-x_var)>0) //cng 01/11/01
318                 double tol = f_deriv-1;
319                 if(debug) System.out.println("tol= "+tol);
320                 if(debug) System.out.println((f_fix - x_fix)*(f_var-x_var));
321                 if( (tol>-1e-10)||(f_fix - x_fix)*(f_var-x_var)>0)
322                 {
323                     dphi  += next1(phi+dphi,b,w);
324                     
325                     x_fix = x_start + dphi/w;
326                     f_fix = b*Math.cos((x_fix-x_start)*w+phi);
327                 }
328                 if( (f_fix - x_fix)*(f_var-x_var)>0)
329                 {
330                     
331                     dphi  += next1(phi+dphi,b,w);
332                     x_var = x_start + dphi/w;
333                     f_var = b*Math.cos((x_var-x_start)*w+phi);
334                 }
335             } // end of case where f_deriv > 1 sometimes
336             if(debug) System.out.println("f_fx "+(f_fix - x_fix)*(f_var-x_var));
337             Assert.assertTrue( (f_fix - x_fix)*(f_var-x_var)<=0 ); //no solution
338         } // end of second case
339         int n = 0;
340         double x_var_prev,f_var_prev;
341         while ( Math.abs(f_var - x_var) > eps)
342         {
343             n++;
344             Assert.assertTrue(n < 1000);
345             x_var_prev = x_var;
346             f_var_prev = f_var;
347             Assert.assertTrue((x_fix-x_var+f_var-f_fix)!=0.);
348             x_var = (f_var*x_fix - f_fix*x_var)/((x_fix-x_var)-(f_fix - f_var));
349             f_var = b*Math.cos(w*(x_var-x_start)+phi);
350             if((f_fix - x_fix)*(f_var-x_var)>0 )
351             {
352                 x_fix = x_var_prev;
353                 f_fix = f_var_prev;
354             }
355             Assert.assertTrue((f_fix - x_fix)*(f_var-x_var)<=0 );
356         }
357         
358         Assert.assertTrue(x_var >= x_start);
359         // return t
360         return (x_var + a1)*flag_forward;
361     }
362     
363     
364     // Return delta_phi to next min
365     // -1 if something is wrong
366     
367     private double nextMin(double phi)
368     {
369         if(   (Math.PI - phi)> 0.) return (  Math.PI - phi);
370         if( (3*Math.PI - phi)> 0.) return (3*Math.PI - phi);
371         return -1.;
372     }
373     
374     // Return delta_phi to next max.
375     // -1 if something is wrong
376     
377     private double nextMax(double phi)
378     {
379         if((TRFMath.TWOPI - phi)> 0.) return ( TRFMath.TWOPI - phi);
380         return -1.;
381     }
382     
383     // Return delta_phi to next 0.
384     // -1 if something is wrong
385     
386     private double nextZero(double phi)
387     {
388         if(   (Math.PI/2. - phi)> 0.) return (  Math.PI/2. - phi);
389         if( (3*Math.PI/2. - phi)> 0.) return (3*Math.PI/2. - phi);
390         if( (5*Math.PI/2. - phi)> 0.) return (5*Math.PI/2. - phi);
391         return -1.;
392     }
393     
394     // Return delta_phi to next point where first derivative is 1.
395     // -1 if something is wrong
396     
397     private double next1(double phi,double amp,double w)
398     {
399         int n,si;
400         if(Math.abs(amp*w)<1.) return -1.;
401         if(debug) System.out.println("amp= "+amp+", w= "+w);
402         double phi1 = -Math.asin(1/(amp*w));
403         Assert.assertTrue(phi1>= -Math.PI/2. && phi1 <= Math.PI/2.);
404         
405         double delta = phi1-phi;
406         if(debug) System.out.println("phi1= "+phi1+", phi= "+phi+", delta= "+delta);
407                 /* si = -1;
408                 // for(n=1,si=-1; delta <= 0;n++,si *=-1)
409                 for(n = 1; delta<=0; n++)
410                 {
411                 Assert.assertTrue(n<10);
412                 delta = n*Math.PI + si*phi1 - phi;
413                 if(debug) System.out.println("n= "+n+", si= "+si+", delta= "+delta);
414                 si *= -1;
415                  
416                 }
417                  */
418         si = -1;
419         n = 1;
420         while (delta>0.)
421         {
422             Assert.assertTrue(n<10);
423             delta = n*Math.PI + si*phi1 - phi;
424             if(debug) System.out.println("n= "+n+", si= "+si+", delta= "+delta);
425             n++;
426             si *= -1;
427             
428         }
429         if(debug) System.out.println("delta= "+delta);
430         if(debug) System.out.println( "in next_1 "+Math.abs(-amp*Math.sin(phi+delta)*w ));
431         if(debug) System.out.println( "in next_1 "+Math.abs(-amp*Math.sin(phi+delta)*w - 1));
432         Assert.assertTrue( Math.abs(-amp*Math.sin(phi+delta)*w - 1) < 1.e-8);
433         return delta;
434     }
435     
436     
437     
438     // Private function to propagate a track without error
439     // The corresponding track parameters are:
440     // u (cm) is fixed
441     // 0 - v (cm)
442     // 1 - z (cm)
443     // 2 - dv/du
444     // 3 - dz/du
445     // 4 - q/p   p is momentum of a track, q is its charge
446     // If pderiv is nonzero, return the derivative matrix there.
447     
448     PropStat
449             vecPropagateXYXYBX( double B, VTrack trv, Surface srf,
450             PropDir dir,
451             TrackDerivative deriv  )
452     {
453         
454         // construct return status
455         PropStat pstat = new PropStat();
456         
457         // fetch the originating surface and vector
458         Surface srf1 = trv.surface();
459         // TrackVector vec1 = trv.get_vector();
460         
461         // Check origin is a XYPlane.
462         Assert.assertTrue( srf1.pureType().equals(SurfXYPlane.staticType()) );
463         if ( !srf1.pureType( ).equals(SurfXYPlane.staticType()) )
464             return pstat;
465         SurfXYPlane sxyp1 = ( SurfXYPlane ) srf1;
466         
467         // Check destination is a XYPlane.
468         Assert.assertTrue( srf.pureType().equals(SurfXYPlane.staticType()) );
469         if ( !srf.pureType( ).equals(SurfXYPlane.staticType()) )
470             return pstat;
471         SurfXYPlane sxyp2 = ( SurfXYPlane ) srf;
472         
473         // If surfaces are the same, we can return now.
474         if ( srf.pureEqual(srf1) )
475         {
476             if (deriv != null)
477             {
478                 deriv.setIdentity();
479             }
480             pstat.setSame();
481             return pstat;
482         }
483         
484         // Fetch the u's and phi's of the planes and the starting track vector.
485         int iphi  = SurfXYPlane.NORMPHI;
486         int idist = SurfXYPlane.DISTNORM;
487         double phi_0 = sxyp1.parameter(iphi);
488         
489         
490         double   u_0 = sxyp1.parameter(idist);
491         double phi_n = sxyp2.parameter(iphi);
492         double   u_n = sxyp2.parameter(idist);
493         TrackVector vec = trv.vector();
494         double b1_0 = vec.get(IV);                  // v
495         double b2_0 = vec.get(IZ);                  // z
496         double b3_0 = vec.get(IDVDU);               // dv/du
497         double b4_0 = vec.get(IDZDU);               // dz/du
498         double b5_0 = vec.get(IQP);                 // q/p
499         
500         // phi_x = 0 now
501         // phi_x is an angle of r.f where B^ || x^
502         
503         double phi_x = 0.;
504         
505         // cos and sin of the destination plane in r.f. where B^ || x^
506         // Now I think that I'm already in such r.f. (phi_0==0)
507         
508         double cosphi = Math.cos(phi_n - phi_x);
509         double sinphi = Math.sin(phi_n - phi_x);
510         
511         double phi_u = phi_0 - phi_x;
512         
513         double cosphi_u = Math.cos(phi_u);
514         double sinphi_u = Math.sin(phi_u);
515         
516         // check if du == 0 ( that is track moves parallel to the destination plane )
517         double du_du_0 = cosphi_u - b3_0*sinphi_u;
518         if(du_du_0==0.) return pstat;
519         
520         double a_hat_u = 1./du_du_0;
521         
522         double u  = u_0*cosphi_u - b1_0*sinphi_u;
523         double b1 = b1_0*cosphi_u + u_0*sinphi_u;
524         double b2 = b2_0;
525         double b3 = (b3_0*cosphi_u + sinphi_u)*a_hat_u;
526         double b4 = b4_0*a_hat_u;
527         double b5 = b5_0;
528         
529         int sign_du0 = 0;
530         if(trv.isForward())  sign_du0 =  1;
531         if(trv.isBackward()) sign_du0 = -1;
532         if(sign_du0 == 0)
533         {
534             System.out.println( "PropXYXYBX._vec_propagate: Unknown direction of a track ");
535             System.exit(1);
536         }
537         int sign_du =0;
538         if(du_du_0*sign_du0 > 0) sign_du =  1;
539         if(du_du_0*sign_du0 < 0) sign_du = -1;
540         
541         
542         // check that q/p != 0
543         Assert.assertTrue(b5 !=0. );
544         
545         double c_hat_b = Math.sqrt(1 + b3*b3 + b4*b4);
546         
547         double w = B*b5*c_hat_b;
548         double r_cosalf = 1/(B*b5)*b3*sign_du/c_hat_b;
549         double r_sinalf = 1/(B*b5)*b4*sign_du/c_hat_b;
550         
551         int flag_forward = 0;
552         double time = 0.;
553         
554         if( dir.equals(PropDir.NEAREST))
555         {
556             flag_forward = 1;
557             double time2 =
558                     direction(flag_forward,w,r_sinalf,r_cosalf,b1,u_n,u,sign_du, sinphi, cosphi);
559             
560             flag_forward = -1;
561             double time1 =
562                     direction(flag_forward,w,r_sinalf,r_cosalf,b1,u_n,u,sign_du, sinphi, cosphi);
563             
564             if(time2<-time1 && time2>0)
565             {
566                 time = time2;
567                 flag_forward = 1;
568             }
569             else if(-time1<time2 && time1<0)
570             {
571                 time = time1;
572                 flag_forward = -1;
573             }
574             else return pstat;
575         }
576         else if ( dir.equals(PropDir.FORWARD) )
577         {
578             flag_forward = 1;
579             time =
580                     direction(flag_forward,w,r_sinalf,r_cosalf,b1,u_n,u,sign_du, sinphi, cosphi);
581             if(time*flag_forward < 0) return pstat;
582         }
583         else if ( dir.equals(PropDir.BACKWARD) )
584         {
585             flag_forward = -1;
586             time =
587                     direction(flag_forward,w,r_sinalf,r_cosalf,b1,u_n,u,sign_du, sinphi, cosphi);
588             if(time*flag_forward < 0) return pstat;
589         }
590         else
591         {
592             System.out.println( "PropXYXYBX._vec_propagate: Unknown direction.");
593             System.exit(1);
594         }
595         
596         double coswt = Math.cos(w*time);
597         double sinwt = Math.sin(w*time);
598         
599         double  u_p = u + time*sign_du;
600         double b1_p = r_sinalf*(coswt-1.) + r_cosalf*sinwt + b1;
601         double b2_p = r_sinalf*sinwt + r_cosalf*(1.-coswt) + b2;
602         double b3_p = b3*coswt - b4*sinwt;
603         double b4_p = b4*coswt + b3*sinwt;
604         double b5_p = b5;
605         
606         double du_n_du = cosphi + b3_p*sinphi;
607         
608         if(du_n_du==0.) return pstat;
609         
610         double b1_n = b1_p*cosphi - u_p*sinphi;
611         double b2_n = b2_p;
612         double b3_n = (b3_p*cosphi - sinphi)/du_n_du;
613         double b4_n = b4_p/du_n_du;
614         double b5_n = b5_p;
615         
616         
617         int sign_dun = 0;
618         if(du_n_du*sign_du > 0) sign_dun =  1;
619         if(du_n_du*sign_du < 0) sign_dun = -1;
620         
621         vec.set(IV     ,b1_n);
622         vec.set(IZ     ,b2_n);
623         vec.set(IDVDU  ,b3_n);
624         vec.set(IDZDU  ,b4_n);
625         vec.set(IQP    ,b5_n);
626         
627         // Update trv
628         trv.setSurface( srf.newPureSurface() );
629         trv.setVector(vec);
630         
631         // set new direction of the track
632         if(sign_dun ==  1) trv.setForward();
633         if(sign_dun == -1) trv.setBackward();
634         
635         
636         // Calculate sT
637         
638         // initial and final position
639         
640         double cphi0 = Math.cos(phi_0);
641         double sphi0 = Math.sin(phi_0);
642         double y0 =  u_0*sphi0 + b1_0*cphi0;
643         double cphin = Math.cos(phi_n);
644         double sphin = Math.sin(phi_n);
645         double yn =  u_n*sphin + b1_n*cphin;
646         double dy = yn-y0;
647         
648         // track direction
649         
650         double du_ds = 1./Math.sqrt(1.+b3_n*b3_n+b4_n*b4_n);
651         if ( trv.isBackward() ) du_ds *= -1.0;
652         double dv_ds = b3_n*du_ds;
653         double dy_ds =  du_ds*sphin + b3_n*cphin;
654         double dz_ds = b4_n*du_ds;
655         double dx_ds =  du_ds*cphin - dv_ds*sphin;
656         double tlm2 = (dx_ds*dx_ds+dz_ds*dz_ds)/dy_ds/dy_ds;
657         
658         //  the distance
659         
660         double ds = ((double)flag_forward)*Math.abs(dy)*Math.sqrt(1+tlm2);
661         
662         // Set the return status.
663         pstat.setPathDistance(ds);
664         
665         // exit now if user did not ask for error matrix.
666         if ( deriv == null ) return pstat;
667         
668         // db1_n_db_p
669         
670         double db1_n_db1_p = cosphi;
671         double db1_n_du_p  = -sinphi;
672         
673         // db2_n_db_p
674         
675         //double db2_n_db2_p = 1.;
676         
677         // db3_n_db_p
678         
679         double du_n_du_2 = du_n_du*du_n_du;
680         
681         double db3_n_db3_p = 1./du_n_du_2;
682         
683         // db4_n_db_p
684         
685         double db4_n_db3_p = - b4_p*sinphi/du_n_du_2;
686         double db4_n_db4_p = 1./du_n_du;
687         
688         // db5_n_db_p
689         
690         //double db5_n_db5_p = 1.;
691         
692         // dw_db
693         
694         double dw_db3 = B*b5*b3/c_hat_b;
695         double dw_db4 = B*b5*b4/c_hat_b;
696         double dw_db5 = w/b5;
697         
698         // dr_cosalf_db
699         
700         double c_hat_b2 = c_hat_b*c_hat_b;
701         
702         double dr_cosalf_db3 =   sign_du/(b5*B)*(1 - b3*b3/c_hat_b2)/c_hat_b;
703         double dr_cosalf_db4 = - sign_du/(b5*B)*b3*b4/c_hat_b2/c_hat_b;
704         double dr_cosalf_db5 = - r_cosalf/b5;
705         
706         // dr_cosalf_db
707         
708         double dr_sinalf_db3 = - sign_du/(b5*B)*b3*b4/c_hat_b2/c_hat_b;
709         double dr_sinalf_db4 =   sign_du/(b5*B)*(1 - b4*b4/c_hat_b2)/c_hat_b;
710         double dr_sinalf_db5 = - r_sinalf/b5;
711         
712         // dtime_db
713         
714         double dtime_db1;
715         double dtime_db3;
716         double dtime_db4;
717         double dtime_db5;
718         double dtime_du;
719         {
720             double rsinalf_time = (coswt - 1.)*sinphi;
721             double rcosalf_time = sinphi*sinwt;
722             double w_time       = time*sinphi*(coswt*r_cosalf - sinwt*r_sinalf);
723             double down = (r_sinalf*sinwt - r_cosalf*coswt)*w*sinphi - sign_du*cosphi;
724             
725             Assert.assertTrue(down!=0);
726             dtime_db1 = sinphi / down;
727             dtime_db3 = (  dr_sinalf_db3*rsinalf_time + dr_cosalf_db3*rcosalf_time
728                     + dw_db3*w_time) / down;
729             dtime_db4 = (  dr_sinalf_db4*rsinalf_time + dr_cosalf_db4*rcosalf_time
730                     + dw_db4*w_time) / down;
731             dtime_db5 = (  dr_sinalf_db5*rsinalf_time + dr_cosalf_db5*rcosalf_time
732                     + dw_db5*w_time) / down;
733             dtime_du  = cosphi / down;
734         }
735         
736         // dcoswt_db
737         
738         double dcoswt_db1 = - sinwt* w*dtime_db1;
739         double dcoswt_db3 = - sinwt*(w*dtime_db3 + time*dw_db3);
740         double dcoswt_db4 = - sinwt*(w*dtime_db4 + time*dw_db4);
741         double dcoswt_db5 = - sinwt*(w*dtime_db5 + time*dw_db5);
742         double dcoswt_du  = - sinwt* w*dtime_du;
743         
744         // dsinwt_db
745         
746         double dsinwt_db1 = coswt* w*dtime_db1;
747         double dsinwt_db3 = coswt*(w*dtime_db3 + time*dw_db3);
748         double dsinwt_db4 = coswt*(w*dtime_db4 + time*dw_db4);
749         double dsinwt_db5 = coswt*(w*dtime_db5 + time*dw_db5);
750         double dsinwt_du  = coswt* w*dtime_du;
751         
752         // du_p_db
753         
754         double du_p_db1 = dtime_db1*sign_du;
755         double du_p_db3 = dtime_db3*sign_du;
756         double du_p_db4 = dtime_db4*sign_du;
757         double du_p_db5 = dtime_db5*sign_du;
758         double du_p_du  = dtime_du *sign_du + 1.;
759         
760         // db1_p_db
761         
762         double db1_p_db1 = 1. + r_sinalf*dcoswt_db1 + r_cosalf*dsinwt_db1;
763         double db1_p_db3 =   (coswt - 1.)*dr_sinalf_db3 + r_sinalf*dcoswt_db3
764                 + sinwt*dr_cosalf_db3 + r_cosalf*dsinwt_db3;
765         double db1_p_db4 =   (coswt - 1.)*dr_sinalf_db4 + r_sinalf*dcoswt_db4
766                 + sinwt*dr_cosalf_db4 + r_cosalf*dsinwt_db4;
767         double db1_p_db5 =   (coswt - 1.)*dr_sinalf_db5 + r_sinalf*dcoswt_db5
768                 + sinwt*dr_cosalf_db5 + r_cosalf*dsinwt_db5;
769         double db1_p_du  = r_sinalf*dcoswt_du + r_cosalf*dsinwt_du;
770         
771         // db2_p_db
772         
773         double db2_p_db1 = r_sinalf*dsinwt_db1 - r_cosalf*dcoswt_db1;
774         //double db2_p_db2 = 1.;
775         double db2_p_db3 =   r_sinalf*dsinwt_db3 + sinwt*dr_sinalf_db3
776                 - (coswt - 1.)*dr_cosalf_db3 - r_cosalf*dcoswt_db3;
777         double db2_p_db4 =   r_sinalf*dsinwt_db4 + sinwt*dr_sinalf_db4
778                 - (coswt - 1.)*dr_cosalf_db4 - r_cosalf*dcoswt_db4;
779         double db2_p_db5 =   r_sinalf*dsinwt_db5 + sinwt*dr_sinalf_db5
780                 - (coswt - 1.)*dr_cosalf_db5 - r_cosalf*dcoswt_db5;
781         double db2_p_du  = r_sinalf*dsinwt_du - r_cosalf*dcoswt_du;
782         
783         // db3_p_db
784         
785         double db3_p_db1 = b3*dcoswt_db1 - b4*dsinwt_db1;
786         double db3_p_db3 = b3*dcoswt_db3 - b4*dsinwt_db3 + coswt;
787         double db3_p_db4 = b3*dcoswt_db4 - b4*dsinwt_db4 - sinwt;
788         double db3_p_db5 = b3*dcoswt_db5 - b4*dsinwt_db5;
789         double db3_p_du  = b3*dcoswt_du  - b4*dsinwt_du;
790         
791         // db4_p_db
792         
793         double db4_p_db1 = b4*dcoswt_db1 + b3*dsinwt_db1;
794         double db4_p_db3 = b4*dcoswt_db3 + b3*dsinwt_db3 + sinwt;
795         double db4_p_db4 = b4*dcoswt_db4 + b3*dsinwt_db4 + coswt;
796         double db4_p_db5 = b4*dcoswt_db5 + b3*dsinwt_db5;
797         double db4_p_du  = b4*dcoswt_du  + b3*dsinwt_du;
798         
799         // db5_p_db
800         
801         //double db5_p_db5 = 1.;
802         
803         // db1_n_db
804         
805         double db1_n_db1 = db1_n_db1_p*db1_p_db1 + db1_n_du_p*du_p_db1;
806         double db1_n_db3 = db1_n_db1_p*db1_p_db3 + db1_n_du_p*du_p_db3;
807         double db1_n_db4 = db1_n_db1_p*db1_p_db4 + db1_n_du_p*du_p_db4;
808         double db1_n_db5 = db1_n_db1_p*db1_p_db5 + db1_n_du_p*du_p_db5;
809         double db1_n_du  = db1_n_db1_p*db1_p_du  + db1_n_du_p*du_p_du;
810         
811         // db2_n_db
812         
813         double db2_n_db1 = db2_p_db1;
814         // double db2_n_db2 = 1.;
815         double db2_n_db3 = db2_p_db3;
816         double db2_n_db4 = db2_p_db4;
817         double db2_n_db5 = db2_p_db5;
818         double db2_n_du  = db2_p_du;
819         
820         // db3_n_db
821         
822         double db3_n_db1 = db3_n_db3_p*db3_p_db1;
823         double db3_n_db3 = db3_n_db3_p*db3_p_db3;
824         double db3_n_db4 = db3_n_db3_p*db3_p_db4;
825         double db3_n_db5 = db3_n_db3_p*db3_p_db5;
826         double db3_n_du  = db3_n_db3_p*db3_p_du;
827         
828         // db4_n_db
829         
830         double db4_n_db1 = db4_n_db3_p*db3_p_db1 + db4_n_db4_p*db4_p_db1;
831         double db4_n_db3 = db4_n_db3_p*db3_p_db3 + db4_n_db4_p*db4_p_db3;
832         double db4_n_db4 = db4_n_db3_p*db3_p_db4 + db4_n_db4_p*db4_p_db4;
833         double db4_n_db5 = db4_n_db3_p*db3_p_db5 + db4_n_db4_p*db4_p_db5;
834         double db4_n_du  = db4_n_db3_p*db3_p_du  + db4_n_db4_p*db4_p_du;
835         
836         // db5_n_db
837         
838         //double db5n_db5 = 1.;
839         
840         // right now all these are 1
841         
842         // a_hat_u2 = 1/du_du_0^2 = 1/(cosphi_u - b3_0*sinphi_u)^2
843         double a_hat_u2 = a_hat_u*a_hat_u;
844         
845         // db1_db_0
846         
847         double db1_db1_0 = cosphi_u;
848         //double db1_du_0 = sinphi_u;
849         
850         // db2_db_0
851         
852         //double db2_db2_0 = 1.;
853         
854         // db3_db_0
855         
856         double db3_db3_0 = a_hat_u2;
857         
858         // db4_db_0
859         
860         double db4_db3_0 = b4_0*sinphi_u*a_hat_u2;
861         double db4_db4_0 = a_hat_u;
862         
863         // db5_db_0
864         
865         //double db5_db5_0 = 1.;
866         
867         // du_db_0
868         
869         double du_db1_0 = - sinphi_u;
870         //double du_du_0 = cosphi_u;
871         
872         // db1_n_db_0
873         
874         double db1_n_db1_0 = db1_n_db1*db1_db1_0 + db1_n_du*du_db1_0;
875         double db1_n_db2_0 = 0.;
876         double db1_n_db3_0 = db1_n_db3*db3_db3_0 + db1_n_db4*db4_db3_0;
877         double db1_n_db4_0 = db1_n_db4*db4_db4_0;
878         double db1_n_db5_0 = db1_n_db5;
879         
880         // db2_n_db_0
881         
882         double db2_n_db1_0 = db2_n_db1*db1_db1_0 + db2_n_du*du_db1_0;
883         double db2_n_db2_0 = 1.;
884         double db2_n_db3_0 = db2_n_db3*db3_db3_0 + db2_n_db4*db4_db3_0;
885         double db2_n_db4_0 = db2_n_db4*db4_db4_0;
886         double db2_n_db5_0 = db2_n_db5;
887         
888         // db3_n_db_0
889         
890         double db3_n_db1_0 = db3_n_db1*db1_db1_0 + db3_n_du*du_db1_0;
891         double db3_n_db2_0 = 0.;
892         double db3_n_db3_0 = db3_n_db3*db3_db3_0 + db3_n_db4*db4_db3_0;
893         double db3_n_db4_0 = db3_n_db4*db4_db4_0;
894         double db3_n_db5_0 = db3_n_db5;
895         
896         // db4_n_db_0
897         
898         double db4_n_db1_0 = db4_n_db1*db1_db1_0 + db4_n_du*du_db1_0;
899         double db4_n_db2_0 = 0.;
900         double db4_n_db3_0 = db4_n_db3*db3_db3_0 + db4_n_db4*db4_db3_0;
901         double db4_n_db4_0 = db4_n_db4*db4_db4_0;
902         double db4_n_db5_0 = db4_n_db5;
903         
904         // db5_n_db_0
905         
906         double db5_n_db1_0 = 0.;
907         double db5_n_db2_0 = 0.;
908         double db5_n_db3_0 = 0.;
909         double db5_n_db4_0 = 0.;
910         double db5_n_db5_0 = 1.;
911         
912         deriv.set(IV,IV       , db1_n_db1_0);
913         deriv.set(IV,IZ       , db1_n_db2_0);
914         deriv.set(IV,IDVDU    , db1_n_db3_0);
915         deriv.set(IV,IDZDU    , db1_n_db4_0);
916         deriv.set(IV,IQP      , db1_n_db5_0);
917         deriv.set(IZ,IV       , db2_n_db1_0);
918         deriv.set(IZ,IZ       , db2_n_db2_0);
919         deriv.set(IZ,IDVDU    , db2_n_db3_0);
920         deriv.set(IZ,IDZDU    , db2_n_db4_0);
921         deriv.set(IZ,IQP      , db2_n_db5_0);
922         deriv.set(IDVDU,IV    , db3_n_db1_0);
923         deriv.set(IDVDU,IZ    , db3_n_db2_0);
924         deriv.set(IDVDU,IDVDU , db3_n_db3_0);
925         deriv.set(IDVDU,IDZDU , db3_n_db4_0);
926         deriv.set(IDVDU,IQP   , db3_n_db5_0);
927         deriv.set(IDZDU,IV    , db4_n_db1_0);
928         deriv.set(IDZDU,IZ    , db4_n_db2_0);
929         deriv.set(IDZDU,IDVDU , db4_n_db3_0);
930         deriv.set(IDZDU,IDZDU , db4_n_db4_0);
931         deriv.set(IDZDU,IQP   , db4_n_db5_0);
932         deriv.set(IQP,IV      , db5_n_db1_0);
933         deriv.set(IQP,IZ      , db5_n_db2_0);
934         deriv.set(IQP,IDVDU   , db5_n_db3_0);
935         deriv.set(IQP,IDZDU   , db5_n_db4_0);
936         deriv.set(IQP,IQP     , db5_n_db5_0);
937         
938         return pstat;
939     }
940 }
941