1 /* 2 * PropZCyl_Test.java 3 * 4 * Created on July 24, 2007, 10:42 PM 5 * 6 * $Id: PropZCyl_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 PropZCyl_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 = 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 // compare two tracks without errors 51 52 private double compare(VTrack trv1,VTrack trv2) 53 { 54 Surface srf = trv2.surface(); 55 56 Assert.assertTrue(trv1.surface().equals(srf)); 57 58 double diff = srf.vecDiff(trv2.vector(),trv1.vector()).amax(); 59 60 return diff; 61 } 62 63 //********************************************************************** 64 // compare two tracks with errors 65 66 private double[] compare(ETrack trv1,ETrack trv2 ) 67 { 68 double[] tmp = new double[2]; 69 Surface srf = trv2.surface(); 70 71 Assert.assertTrue(trv1.surface().equals(srf)); 72 73 tmp[0] = srf.vecDiff(trv2.vector(),trv1.vector()).amax(); 74 75 TrackError dfc = trv2.error().minus(trv1.error()); 76 tmp[1] = dfc.amax(); 77 78 79 return tmp; 80 } 81 /** Creates a new instance of PropZCyl_Test */ 82 public void testPropZCyl() 83 { 84 String ok_prefix = "PropZCyl (I): "; 85 String error_prefix = "PropZCyl test (E): "; 86 87 if(debug) System.out.println( ok_prefix 88 + "-------- Testing component PropZCyl. --------" ); 89 { 90 if(debug) System.out.println( ok_prefix + "Test constructor." ); 91 double BFIELD = 2.0; 92 PropZCyl prop = new PropZCyl(BFIELD); 93 if(debug) System.out.println( prop ); 94 PropZCyl_Test tst = new PropZCyl_Test(); 95 //******************************************************************** 96 97 // Here we propagate some tracks both forward and backward and then 98 // the same track forward and backward but using method 99 // that we checked very thoroughly before. 100 101 if(debug) System.out.println( ok_prefix + "Check against correct propagation." ); 102 103 PropZCyl propzcyl = new PropZCyl(BFIELD/TRFMath.BFAC); 104 105 double z1[] ={10., 10., 10., 10., 10., 10. }; 106 107 int sign_dz[] ={ -1, 1, -1, 1, 1, -1 }; 108 double x[] ={ -2., 2., 5., 5., -2., -2. }; 109 double y[] ={ 3., 3., 3., 3., 3., 3. }; 110 double dxdz[] ={ 1.5, -2.3, 0., 1.5, -1.5, 1.5 }; 111 double dydz[] ={ 2.3, -1.5, -2.3, 0., -2.3, 0. }; 112 double qp[] ={ 0.01, -0.01, 0.01, -0.01, -0.01, 0.01 }; 113 114 double rcyl2[] ={ 20., 20., 20., 20., 20., 20. }; 115 double rcyl2b[] ={ 20., 20., 20., 20., 20., 20. }; 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 126 PropStat pstat = new PropStat(); 127 128 SurfZPlane szp1 = new SurfZPlane(z1[i]); 129 SurfCylinder scy2 = new SurfCylinder(rcyl2[i]); 130 SurfCylinder scy2b = new SurfCylinder(rcyl2b[i]); 131 132 TrackVector vec1 = new TrackVector(); 133 134 vec1.set(IX , x[i]); // x 135 vec1.set(IY , y[i]); // y 136 vec1.set(IDXDZ , dxdz[i]); // dx/dz 137 vec1.set(IDYDZ , dydz[i]); // dy/dz 138 vec1.set(IQP_Z , qp[i]); // q/p 139 140 VTrack trv1 = new VTrack(szp1.newPureSurface(),vec1); 141 if (sign_dz[i]==1) trv1.setForward(); 142 else trv1.setBackward(); 143 144 if(debug) System.out.println( "\n starting: " + trv1 ); 145 146 VTrack trv2f = new VTrack(trv1); 147 pstat = propzcyl.vecDirProp(trv2f,scy2,PropDir.FORWARD); 148 Assert.assertTrue( pstat.forward() ); 149 if(debug) System.out.println( "\n forward: " + trv2f ); 150 151 VTrack trv2f_my = new VTrack(trv1); 152 pstat = tst.vec_propzcyl(BFIELD,trv2f_my,scy2,PropDir.FORWARD); 153 Assert.assertTrue( pstat.forward() ); 154 if(debug) System.out.println( "\n forward my: " + trv2f_my ); 155 diff = tst.compare(trv2f_my,trv2f); 156 157 if(debug) System.out.println( "\n diff: " + diff ); 158 Assert.assertTrue( diff < maxdiff ); 159 160 VTrack trv2b = new VTrack(trv1); 161 pstat = propzcyl.vecDirProp(trv2b,scy2b,PropDir.BACKWARD); 162 Assert.assertTrue( pstat.backward() ); 163 if(debug) System.out.println( "\n backward: " + trv2b ); 164 165 VTrack trv2b_my = new VTrack(trv1); 166 pstat = tst.vec_propzcyl(BFIELD,trv2b_my,scy2b,PropDir.BACKWARD); 167 Assert.assertTrue( pstat.backward() ); 168 if(debug) System.out.println( "\n backward my: " + trv2b_my ); 169 diff = tst.compare(trv2b_my,trv2b); 170 171 if(debug) System.out.println( "\n diff: " + diff ); 172 Assert.assertTrue( diff < maxdiff ); 173 174 } 175 //******************************************************************** 176 177 // Repeat the above with errors. 178 if(debug) System.out.println( ok_prefix + "Check against correct propagation with errors." ); 179 180 double exx[] = { 0.01, 0.01, 0.01, 0.01, 0.01, 0.01 }; 181 double exy[] = { 0.01, -0.01, 0.01, -0.01, 0.01, -0.01 }; 182 double eyy[] = { 0.25, 0.25, 0.25, 0.25, 0.25, 0.25 }; 183 double exdx[] = { 0.004, -0.004, 0.004, -0.004, 0.004, -0.004 }; 184 double eydx[] = { 0.004, -0.004, 0.004, -0.004, 0.004, -0.004 }; 185 double edxdx[] = { 0.01, 0.01, 0.01, 0.01, 0.01, 0.01 }; 186 double exdy[] = { 0.004, -0.004, 0.004, -0.004, 0.004, -0.004 }; 187 double edxdy[] = { 0.004, -0.004, 0.004, -0.004, 0.004, -0.004 }; 188 double eydy[] = { 0.04, -0.04, 0.04, -0.04, 0.04, -0.04 }; 189 double edydy[] = { 0.02, 0.02, 0.02, 0.02, 0.02, 0.02 }; 190 double exqp[] = { 0.004, -0.004, 0.004, -0.004, 0.004, -0.004 }; 191 double eyqp[] = { 0.004, -0.004, 0.004, -0.004, 0.004, -0.004 }; 192 double edxqp[] = { 0.004, -0.004, 0.004, -0.004, 0.004, -0.004 }; 193 double edyqp[] = { 0.004, -0.004, 0.004, -0.004, 0.004, -0.004 }; 194 double eqpqp[] = { 0.01, 0.01, 0.01, 0.01, 0.01, 0.01 }; 195 196 maxdiff = 1.e-8; 197 double ediff; 198 ntrk = 6; 199 200 for ( i=0; i<ntrk; ++i ) 201 { 202 if(debug) System.out.println( "********** Propagate track " + i + ". **********" ); 203 204 PropStat pstat = new PropStat(); 205 206 SurfZPlane szp1 = new SurfZPlane(z1[i]); 207 SurfCylinder scy2 = new SurfCylinder(rcyl2[i]); 208 SurfCylinder scy2b = new SurfCylinder(rcyl2b[i]); 209 210 TrackVector vec1 = new TrackVector(); 211 212 vec1.set(IX , x[i]); // x 213 vec1.set(IY , y[i]); // y 214 vec1.set(IDXDZ , dxdz[i]); // dx/dz 215 vec1.set(IDYDZ , dydz[i]); // dy/dz 216 vec1.set(IQP_Z , qp[i]); // q/p 217 218 TrackError err1 = new TrackError(); 219 220 err1.set(IX,IX , exx[i]); 221 err1.set(IX,IY , exy[i]); 222 err1.set(IY,IY , eyy[i]); 223 err1.set(IX,IDXDZ , exdx[i]); 224 err1.set(IY,IDXDZ , eydx[i]); 225 err1.set(IDXDZ,IDXDZ , edxdx[i]); 226 err1.set(IX,IDYDZ , exdy[i]); 227 err1.set(IY,IDYDZ , eydy[i]); 228 err1.set(IDXDZ,IDYDZ , edxdy[i]); 229 err1.set(IDYDZ,IDYDZ , edydy[i]); 230 err1.set(IX,IQP_Z , exqp[i]); 231 err1.set(IY,IQP_Z , eyqp[i]); 232 err1.set(IDXDZ,IQP_Z , edxqp[i]); 233 err1.set(IDYDZ,IQP_Z , edyqp[i]); 234 err1.set(IQP_Z,IQP_Z , eqpqp[i]); 235 236 ETrack trv1 = new ETrack(szp1.newPureSurface(),vec1,err1); 237 if (sign_dz[i]==1)trv1.setForward(); 238 else trv1.setBackward(); 239 240 if(debug) System.out.println( "\n starting: " + trv1 ); 241 242 ETrack trv2f = new ETrack(trv1); 243 pstat = propzcyl.errDirProp(trv2f,scy2,PropDir.FORWARD); 244 Assert.assertTrue( pstat.forward() ); 245 if(debug) System.out.println( "\n forward: " + trv2f ); 246 247 ETrack trv2f_my = new ETrack(trv1); 248 TrackDerivative deriv = new TrackDerivative(); 249 pstat = tst.vec_propzcyl(BFIELD,trv2f_my,scy2,PropDir.FORWARD,deriv); 250 Assert.assertTrue( pstat.forward() ); 251 TrackError err = trv2f_my.error(); 252 trv2f_my.setError( err.Xform(deriv) ); 253 if(debug) System.out.println( "\n forward my: " + trv2f_my ); 254 double[] diffs = tst.compare(trv2f_my,trv2f); 255 256 if(debug) System.out.println( "\n diff: " + diffs[0] + ' ' + "ediff: "+ diffs[1] ); 257 Assert.assertTrue( diffs[0] < maxdiff ); 258 Assert.assertTrue( diffs[1] < maxdiff ); 259 260 261 ETrack trv2b = new ETrack(trv1); 262 pstat = propzcyl.errDirProp(trv2b,scy2b,PropDir.BACKWARD); 263 Assert.assertTrue( pstat.backward() ); 264 if(debug) System.out.println( "\n backward: " + trv2b ); 265 266 267 ETrack trv2b_my = new ETrack(trv1); 268 pstat = tst.vec_propzcyl(BFIELD,trv2b_my,scy2b,PropDir.BACKWARD,deriv); 269 Assert.assertTrue( pstat.backward() ); 270 err = trv2b_my.error(); 271 trv2b_my.setError( err.Xform(deriv) ); 272 if(debug) System.out.println( "\n backward my: " + trv2b_my ); 273 diffs = tst.compare(trv2b_my,trv2b); 274 275 if(debug) System.out.println( "\n diff: " + diffs[0] + ' ' + "ediff: "+ diffs[1] ); 276 Assert.assertTrue( diffs[0] < maxdiff ); 277 Assert.assertTrue( diffs[1] < maxdiff ); 278 279 } 280 281 //******************************************************************** 282 283 if(debug) System.out.println( ok_prefix + "Test cloning." ); 284 Assert.assertTrue( prop.newPropagator() != null ); 285 286 //******************************************************************** 287 288 if(debug) System.out.println( ok_prefix + "Test the field." ); 289 Assert.assertTrue( prop.bField() == 2.0 ); 290 291 292 } 293 //******************************************************************** 294 295 if(debug) System.out.println( ok_prefix + "Test Zero Field Propagation." ); 296 { 297 PropZCyl prop0 = new PropZCyl(0.0); 298 if(debug) System.out.println( prop0 ); 299 Assert.assertTrue( prop0.bField() == 0. ); 300 301 double z=10.; 302 Surface srf = new SurfZPlane(z); 303 VTrack trv0 = new VTrack(srf); 304 TrackVector vec = new TrackVector(); 305 vec.set(SurfZPlane.IX, 2.); 306 vec.set(SurfZPlane.IY, 10.); 307 vec.set(SurfZPlane.IDXDZ, 4.); 308 vec.set(SurfZPlane.IDYDZ, 2.); 309 trv0.setVector(vec); 310 trv0.setForward(); 311 Surface srf_to = new SurfCylinder(13.0); 312 313 VTrack trv = new VTrack(trv0); 314 VTrack trv_der = new VTrack(trv); 315 PropStat pstat = prop0.vecDirProp(trv,srf_to,PropDir.NEAREST); 316 Assert.assertTrue( pstat.success() ); 317 318 Assert.assertTrue( pstat.forward() ); 319 Assert.assertTrue(trv.surface().pureEqual(srf_to)); 320 321 check_zero_propagation(trv0,trv,pstat); 322 check_derivatives(prop0,trv_der,srf_to); 323 if(debug) System.out.println("\n**trv= \n"+trv+"\n trv_der= \n"+trv_der); 324 325 srf_to = new SurfCylinder(trv0.spacePoint().rxy()); 326 if(debug) System.out.println("\n**trv0.spacePoint()= "+trv0.spacePoint() ); 327 if(debug) System.out.println("\n**trv0.spacePoint().rxy()= "+trv0.spacePoint().rxy()); 328 329 trv = new VTrack(trv0); 330 trv_der = new VTrack(trv); 331 pstat = prop0.vecDirProp(trv,srf_to,PropDir.NEAREST); 332 Assert.assertTrue( pstat.success() ); 333 334 Assert.assertTrue( pstat.same() ); 335 Assert.assertTrue(trv.surface().pureEqual(srf_to)); 336 if(debug) System.out.println("\n**trv= \n"+trv+"\n trv_der= \n"+trv_der); 337 338 check_zero_propagation(trv0,trv,pstat); 339 check_derivatives(prop0,trv_der,srf_to); 340 341 trv0.setBackward(); 342 trv = new VTrack(trv0); 343 trv_der = new VTrack(trv); 344 pstat = prop0.vecDirProp(trv,srf_to,PropDir.NEAREST); 345 Assert.assertTrue( pstat.success() ); 346 347 Assert.assertTrue( pstat.same() ); 348 Assert.assertTrue(trv.surface().pureEqual(srf_to)); 349 350 check_zero_propagation(trv0,trv,pstat); 351 check_derivatives(prop0,trv_der,srf_to); 352 } 353 354 if(debug) System.out.println( ok_prefix 355 + "------------- All tests passed. -------------" ); 356 } 357 358 //******************************************************************** 359 // Very well tested Z-Cyl propagator. Each new one can be tested against it 360 361 //********************************************************************** 362 // helpers 363 //********************************************************************** 364 365 //********************************************************************** 366 // The track parameters for a cylinder are: 367 // phi z alpha tan(lambda) curvature 368 // (NOT [. . . lambda .] as in TRF and earlier version of TRF++.) 369 // 370 // If pderiv is nonzero, return the derivative matrix there. 371 // On Cylinder: 372 // r (cm) is fixed 373 // 0 - phi 374 // 1 - z (cm) 375 // 2 - alp 376 // 3 - tlam 377 // 4 - q/pt pt is transverse momentum of a track, q is its charge 378 // On ZPlane: 379 // 0 - x (cm) 380 // 1 - y (cm) 381 // 2 - dx/dz 382 // 3 - dy/dz 383 // 4 - q/p p is momentum of a track, q is its charge 384 // If pderiv is nonzero, return the derivative matrix there. 385 386 PropStat 387 vec_propzcyl( double B, VTrack trv, Surface srf, 388 PropDir dir) 389 { 390 TrackDerivative deriv = null; 391 return vec_propzcyl(B, trv, srf, dir, deriv); 392 } 393 394 395 396 PropStat 397 vec_propzcyl( double B, VTrack trv, Surface srf, 398 PropDir dir, 399 TrackDerivative deriv ) 400 { 401 402 // construct return status 403 PropStat pstat = new PropStat(); 404 405 // fetch the originating surface and vector 406 Surface srf1 = trv.surface(); 407 //TrackVector vec1 = trv.vector(); 408 409 // Check origin is a Zplane. 410 Assert.assertTrue( srf1.pureType().equals(SurfZPlane.staticType()) ); 411 if ( !srf1.pureType( ).equals(SurfZPlane.staticType()) ) 412 return pstat; 413 SurfZPlane szp1 = ( SurfZPlane) srf1; 414 415 // Check destination is a cylinder. 416 Assert.assertTrue( srf.pureType().equals(SurfCylinder.staticType()) ); 417 if ( ! srf.pureType( ).equals(SurfCylinder.staticType()) ) 418 return pstat; 419 SurfCylinder scy2 = ( SurfCylinder) srf; 420 421 422 // Fetch the z of the plane and the starting track vector. 423 int iz = SurfZPlane.ZPOS; 424 double z = szp1.parameter(iz); 425 426 TrackVector vec = trv.vector(); 427 double x = vec.get(IX); // v 428 double y = vec.get(IY); // z 429 double b = vec.get(IDXDZ); // dv/du 430 double a = vec.get(IDYDZ); // dz/du 431 double e = vec.get(IQP_Z); // q/p 432 433 // Fetch the radii and the starting track vector. 434 int irad = SurfCylinder.RADIUS; 435 double r2 = scy2.parameter(irad); 436 437 int sign_dz = 0; 438 if(trv.isForward()) sign_dz = 1; 439 if(trv.isBackward()) sign_dz = -1; 440 if(sign_dz == 0) 441 { 442 if(debug) System.out.println("PropZCyl._vec_propagate: Unknown direction of a track "); 443 System.exit(1); 444 } 445 446 // Calculate cylindrical coordinates 447 448 double cnst1=x>0?0.:Math.PI; 449 double cnst2=Math.PI; 450 if(a>0.&&b>0.&&sign_dz>0.) cnst2=0.; 451 if(a<0.&&b>0.&&sign_dz>0.) cnst2=0.; 452 if(a>0.&&b<0.&&sign_dz<0.) cnst2=0.; 453 if(a<0.&&b<0.&&sign_dz<0.) cnst2=0.; 454 455 double sign_y= y>0 ? 1.:-1; 456 double sign_a= a>0 ? 1.:-1; 457 if(y==0) sign_y=0.; 458 if(a==0) sign_a=0.; 459 double atnxy=(x!=0.?Math.atan(y/x):sign_y*Math.PI/2.); 460 double atnab=(b!=0.?Math.atan(a/b):sign_a*Math.PI/2.); 461 462 double phi1= TRFMath.fmod2(atnxy+cnst1,TRFMath.TWOPI); 463 double r1=Math.sqrt(x*x+y*y); 464 double z1=z; 465 double alp1= TRFMath.fmod2(atnab-phi1+cnst2,TRFMath.TWOPI); 466 double tlm1= sign_dz/Math.sqrt(a*a+b*b); 467 double qpt1=e*Math.sqrt((1+a*a+b*b)/(a*a+b*b)); 468 469 470 471 // Check alpha range. 472 alp1 = TRFMath.fmod2( alp1, TRFMath.TWOPI ); 473 Assert.assertTrue( Math.abs(alp1) <= Math.PI ); 474 475 //if ( trv.is_forward() ) Assert.assertTrue( Math.abs(alp1) <= TRFMath.PI2 ); 476 //else Assert.assertTrue( Math.abs(alp1) > TRFMath.PI2 ); 477 478 // Calculate the cosine of lambda. 479 //double clam1 = 1.0/Math.sqrt(1+tlm1*tlm1); 480 481 // Calculate curvature: C = _bfac*(q/p)/cos(lambda) 482 // and its derivatives 483 // Assert.assertTrue( clam1 != 0.0 ); 484 // double dcrv1_dqp1 = B/clam1; 485 // double crv1 = dcrv1_dqp1*qp1; 486 // double dcrv1_dtlm1 = crv1*clam1*clam1*tlm1; 487 488 // Calculate the curvature = _bfac*(q/pt) 489 double dcrv1_dqpt1 = B; 490 double crv1 = dcrv1_dqpt1*qpt1; 491 //double dcrv1_dtlm1 = 0.0; 492 493 // Evaluate the new track vector. 494 // See dla log I-044 495 496 // lambda and curvature do not change 497 double tlm2 = tlm1; 498 double crv2 = crv1; 499 double qpt2 = qpt1; 500 501 // We can evaluate sin(alp2), leaving two possibilities for alp2 502 // 1st solution: alp21, phi21, phid21, tht21 503 // 2nd solution: alp22, phi22, phid22, tht22 504 // evaluate phi2 to choose 505 double salp1 = Math.sin( alp1 ); 506 double calp1 = Math.cos( alp1 ); 507 double salp2 = r1/r2*salp1 + 0.5*crv1/r2*(r2*r2-r1*r1); 508 // if salp2 > 1, track does not cross cylinder 509 if ( Math.abs(salp2) > 1.0 ) return pstat; 510 double alp21 = Math.asin( salp2 ); 511 double alp22 = alp21>0 ? Math.PI-alp21 : -Math.PI-alp21; 512 double calp21 = Math.cos( alp21 ); 513 double calp22 = Math.cos( alp22 ); 514 double phi20 = phi1 + Math.atan2( salp1-r1*crv1, calp1 ); 515 double phi21 = phi20 - Math.atan2( salp2-r2*crv2, calp21 ); // phi position 516 double phi22 = phi20 - Math.atan2( salp2-r2*crv2, calp22 ); 517 // Construct an sT object for each solution. 518 STCalcZ_CHECK sto1 = new STCalcZ_CHECK(r1,phi1,alp1,crv1,r2,phi21,alp21); 519 STCalcZ_CHECK sto2 = new STCalcZ_CHECK(r1,phi1,alp1,crv1,r2,phi22,alp22); 520 // Check the two solutions are nonzero and have opposite sign 521 // or at least one is nonzero. 522 523 // Choose the correct solution 524 boolean use_first_solution = false; 525 526 if (dir.equals(PropDir.NEAREST)) 527 { 528 use_first_solution = Math.abs(sto2.st()) > Math.abs(sto1.st()); 529 } 530 else if (dir.equals(PropDir.FORWARD)) 531 { 532 use_first_solution = sto1.st() > 0.0; 533 } 534 else if (dir.equals(PropDir.BACKWARD)) 535 { 536 use_first_solution = sto1.st() < 0.0; 537 } 538 else 539 { 540 if(debug) System.out.println("PropCyl._vec_propagate: Unknown direction." ); 541 System.exit(1); 542 } 543 544 // Assign phi2, alp2 and sto2 for the chosen solution. 545 double phi2, alp2; 546 STCalcZ_CHECK sto; 547 double calp2; 548 if ( use_first_solution ) 549 { 550 sto = sto1; 551 phi2 = phi21; 552 alp2 = alp21; 553 calp2 = calp21; 554 } 555 else 556 { 557 sto = sto2; 558 phi2 = phi22; 559 alp2 = alp22; 560 calp2 = calp22; 561 } 562 563 // fetch sT. 564 double st = sto.st(); 565 566 // use sT to evaluate z2 567 double z2 = z1 + tlm1*st; 568 569 // Check alpha range. 570 Assert.assertTrue( Math.abs(alp2) <= Math.PI ); 571 572 // put new values in vec 573 vec.set(IPHI , phi2); 574 vec.set(IZ , z2); 575 vec.set(IALF , alp2); 576 vec.set(ITLM , tlm2); 577 vec.set(IQPT , qpt2); 578 579 // Update trv 580 trv.setSurface(srf.newPureSurface()); 581 trv.setVector(vec); 582 if ( Math.abs(alp2) <= TRFMath.PI2 ) trv.setForward(); 583 else trv.setBackward(); 584 585 // Set the return status. 586 if (st > 0) pstat.setForward() ; 587 else pstat.setBackward(); 588 589 // exit now if user did not ask for error matrix. 590 if ( deriv == null) return pstat; 591 592 // Calculate derivatives. 593 // dphi1 594 595 double dphi1_dx= -y/(x*x+y*y); 596 double dphi1_dy= x/(x*x+y*y); 597 598 // dz1 599 600 //double dz1_dz=0.; 601 602 // dalf1 603 604 double dalp1_da= b/(a*a+b*b); 605 double dalp1_db= -a/(a*a+b*b); 606 double dalp1_dy= -dphi1_dy; 607 double dalp1_dx= -dphi1_dx; 608 609 // dr1 610 611 double dr1_dx= x/Math.sqrt(x*x+y*y); 612 double dr1_dy= y/Math.sqrt(x*x+y*y); 613 614 // dtlm1 615 616 double dtlm1_da= -sign_dz*a/Math.sqrt(a*a+b*b)/(a*a+b*b); 617 double dtlm1_db= -sign_dz*b/(a*a+b*b)/Math.sqrt(a*a+b*b); 618 619 // dcrv1 620 621 double dcrv1_de= Math.sqrt((1+a*a+b*b)/(a*a+b*b))*B; 622 double dcrv1_da= -a*e/Math.sqrt((a*a+b*b)*(1+a*a+b*b))/(a*a+b*b)*B; 623 double dcrv1_db= -e*b/Math.sqrt(1+a*a+b*b)/Math.sqrt(a*a+b*b)/(a*a+b*b)*B; 624 625 // alpha_2 626 double da2da1 = r1*calp1/r2/calp2; 627 double da2dc1 = (r2*r2-r1*r1)*0.5/r2/calp2; 628 double da2dr1 = (salp1-crv2*r1)/r2/calp2; 629 630 // phi2 631 double rcsal1 = r1*crv1*salp1; 632 double rcsal2 = r2*crv2*salp2; 633 double den1 = 1.0 + r1*r1*crv1*crv1 - 2.0*rcsal1; 634 double den2 = 1.0 + r2*r2*crv2*crv2 - 2.0*rcsal2; 635 double dp2dp1 = 1.0; 636 double dp2da1 = (1.0-rcsal1)/den1 - (1.0-rcsal2)/den2*da2da1; 637 double dp2dc1 = -r1*calp1/den1 + r2*calp2/den2 638 - (1.0-rcsal2)/den2*da2dc1; 639 double dp2dr1= -crv1*calp1/den1-(1.0-rcsal2)*da2dr1/den2; 640 641 // z2 642 //double dz2dz1 = 1.0; 643 double dz2dl1 = st; 644 double dz2da1 = tlm1*sto.d_st_dalp1(dp2da1, da2da1); 645 double dz2dc1 = tlm1*sto.d_st_dcrv1(dp2dc1, da2dc1); 646 double dz2dr1 = tlm1*sto.d_st_dr1( dp2dr1, da2dr1); 647 648 649 // final derivatives 650 651 // phi2 652 double dphi2_dx=dp2dp1*dphi1_dx+dp2da1*dalp1_dx+dp2dr1*dr1_dx; 653 double dphi2_dy=dp2dp1*dphi1_dy+dp2da1*dalp1_dy+dp2dr1*dr1_dy; 654 double dphi2_db=dp2da1*dalp1_db+dp2dc1*dcrv1_db; 655 double dphi2_da=dp2da1*dalp1_da+dp2dc1*dcrv1_da; 656 double dphi2_de=dp2dc1*dcrv1_de; 657 658 // alp2 659 double dalp2_dx= da2da1*dalp1_dx+da2dr1*dr1_dx; 660 double dalp2_dy= da2da1*dalp1_dy+da2dr1*dr1_dy; 661 double dalp2_db= da2da1*dalp1_db+da2dc1*dcrv1_db; 662 double dalp2_da= da2da1*dalp1_da+da2dc1*dcrv1_da; 663 double dalp2_de= da2dc1*dcrv1_de; 664 665 // crv2 666 double dcrv2_da=dcrv1_da; 667 double dcrv2_db=dcrv1_db; 668 double dcrv2_de=dcrv1_de; 669 670 // tlm2 671 double dtlm2_da= dtlm1_da; 672 double dtlm2_db= dtlm1_db; 673 674 // z2 675 double dz2_dx= dz2dr1*dr1_dx+dz2da1*dalp1_dx; 676 double dz2_dy= dz2dr1*dr1_dy+dz2da1*dalp1_dy; 677 double dz2_db= dz2da1*dalp1_db+dz2dl1*dtlm1_db+dz2dc1*dcrv1_db; 678 double dz2_da= dz2da1*dalp1_da+dz2dl1*dtlm1_da+dz2dc1*dcrv1_da; 679 double dz2_de= dz2dc1*dcrv1_de; 680 681 682 // Build derivative matrix. 683 684 deriv.set(IPHI,IX , dphi2_dx); 685 deriv.set(IPHI,IY , dphi2_dy); 686 deriv.set(IPHI,IDXDZ, dphi2_db); 687 deriv.set(IPHI,IDYDZ, dphi2_da); 688 deriv.set(IPHI,IQP_Z, dphi2_de); 689 deriv.set(IZ,IX , dz2_dx); 690 deriv.set(IZ,IY , dz2_dy); 691 deriv.set(IZ,IDXDZ , dz2_db); 692 deriv.set(IZ,IDYDZ , dz2_da); 693 deriv.set(IZ,IQP_Z, dz2_de); 694 deriv.set(IALF,IX , dalp2_dx); 695 deriv.set(IALF,IY , dalp2_dy); 696 deriv.set(IALF,IDXDZ , dalp2_db); 697 deriv.set(IALF,IDYDZ , dalp2_da); 698 deriv.set(IALF,IQP_Z , dalp2_de); 699 deriv.set(ITLM,IDXDZ , dtlm2_db); 700 deriv.set(ITLM,IDYDZ , dtlm2_da); 701 deriv.set(IQPT,IDXDZ , dcrv2_db/B); 702 deriv.set(IQPT,IDYDZ , dcrv2_da/B); 703 deriv.set(IQPT,IQP_Z , dcrv2_de/B); 704 705 return pstat; 706 707 } 708 709 710 // Private class STCalcZ_CHECK. 711 // 712 // An STCalcZ_CHECK_ object calculates sT (the signed transverse path length) 713 // and its derivatives w.r.t. alf1 and crv1. It is constructed from 714 // the starting (r1, phi1, alf1, crv1) and final track parameters 715 // (r2, phi2, alf2) assuming these are consistent. Methods are 716 // provided to retrieve sT and the two derivatives. 717 718 private class STCalcZ_CHECK 719 { 720 721 private boolean _big_crv; 722 private double _st; 723 private double _dst_dphi21; 724 private double _dst_dcrv1; 725 private double _dst_dr1; 726 private double _cnst1,_cnst2; 727 public double _crv1; 728 729 // constructor 730 public STCalcZ_CHECK() 731 { 732 } 733 public STCalcZ_CHECK(double r1, double phi1, double alf1, double crv1, 734 double r2, double phi2, double alf2) 735 { 736 _crv1 = crv1; 737 Assert.assertTrue( r1 > 0.0 ); 738 Assert.assertTrue( r2 > 0.0 ); 739 double rmax = r1+r2; 740 741 // Calculate the change in xy direction 742 double phi_dir_diff = TRFMath.fmod2(phi2+alf2-phi1-alf1,TRFMath.TWOPI); 743 Assert.assertTrue( Math.abs(phi_dir_diff) <= Math.PI ); 744 745 // Evaluate whether |C| is" big" 746 _big_crv = rmax*Math.abs(crv1) > 0.001; 747 748 // If the curvature is big we can use 749 // sT = (phi_dir2 - phi_dir1)/crv1 750 if ( _big_crv ) 751 { 752 Assert.assertTrue( crv1 != 0.0 ); 753 _st = phi_dir_diff/crv1; 754 } 755 756 // Otherwise, we calculate the straight-line distance 757 // between the points and use an approximate correction 758 // for the (small) curvature. 759 else 760 { 761 762 // evaluate the distance 763 double d = Math.sqrt( r1*r1 + r2*r2 - 2.0*r1*r2*Math.cos(phi2-phi1) ); 764 double arg = 0.5*d*crv1; 765 double arg2 = arg*arg; 766 double st_minus_d = d*arg2*( 1.0/6.0 + 3.0/40.0*arg2 ); 767 _st = d + st_minus_d; 768 769 // evaluate the sign 770 // We define a metric xsign = abs( (dphid-d*C)/(d*C) ). 771 // Because sT*C = dphid and d = abs(sT): 772 // xsign = 0 for sT > 0 773 // xsign = 2 for sT < 0 774 // Numerical roundoff will smear these predictions. 775 double xsign = Math.abs( (phi_dir_diff - _st*crv1) / (_st*crv1) ); 776 double sign = 0.0; 777 if ( crv1 != 0 ) 778 { 779 if ( xsign < 0.5 ) sign = 1.0; 780 if ( xsign > 1.5 && xsign < 3.0 ) sign = -1.0; 781 } 782 // If the above is indeterminate, assume zero curvature. 783 // In this case abs(alpha) decreases monotonically 784 // with sT. Track passing through origin has alpha = 0 on one 785 // side and alpha = +/-pi on the other. If both points are on 786 // the same side, we use dr/ds > 0 for |alpha|<pi/2. 787 if ( sign == 0) 788 { 789 sign = 1.0; 790 if ( Math.abs(alf2) > Math.abs(alf1) ) sign = -1.0; 791 if ( Math.abs(alf2) == Math.abs(alf1) ) 792 { 793 if ( Math.abs(alf2) < TRFMath.PI2 ) 794 { 795 if ( r2 < r1 ) sign = -1.0; 796 } 797 else 798 { 799 if ( r2 > r1 ) sign = -1.0; 800 } 801 } 802 } 803 804 // Correct _st using the above sign. 805 Assert.assertTrue( Math.abs(sign) == 1.0 ); 806 _st = sign*_st; 807 808 // save derivatives 809 _dst_dcrv1 = sign*d*d*arg*( 1.0/6.0 + 3.0/20.0*arg2); 810 double root = (1.0 + 0.5*arg*arg + 3.0/8.0*arg*arg*arg*arg ); 811 _dst_dphi21 = sign*(r1*r2*Math.sin(phi2-phi1))*root/d; 812 _dst_dr1= (1.+arg2/2.*(1+3./4.*arg2))/d*sign; 813 _cnst1=r1-r2*Math.cos(phi2-phi1); 814 _cnst2=r1*r2*Math.sin(phi2-phi1); 815 } 816 817 } 818 public double st() 819 { return _st; }; 820 public double d_st_dalp1(double d_phi2_dalf1, double d_alf2_dalf1 ) 821 { 822 if ( _big_crv ) return ( d_phi2_dalf1 + d_alf2_dalf1 - 1.0 ) / _crv1; 823 else return _dst_dphi21 * d_phi2_dalf1; 824 } 825 public double d_st_dcrv1(double d_phi2_dcrv1, double d_alf2_dcrv1 ) 826 { 827 if ( _big_crv ) return ( d_phi2_dcrv1 + d_alf2_dcrv1 - _st ) / _crv1; 828 else return _dst_dcrv1 + _dst_dphi21*d_phi2_dcrv1; 829 830 } 831 public double d_st_dr1( double d_phi2_dr1, double d_alf2_dr1 ) 832 { 833 if ( _big_crv ) return ( d_phi2_dr1 + d_alf2_dr1 ) / _crv1; 834 else return _dst_dr1*(_cnst1+_cnst2*d_phi2_dr1); 835 836 } 837 838 } 839 840 private static void check_zero_propagation( VTrack trv0, VTrack trv, PropStat pstat) 841 { 842 843 SpacePoint sp = trv.spacePoint(); 844 SpacePoint sp0 = trv0.spacePoint(); 845 846 SpacePath sv = trv.spacePath(); 847 SpacePath sv0 = trv0.spacePath(); 848 849 Assert.assertTrue( Math.abs(sv0.dx() - sv.dx())<1e-7 ); 850 Assert.assertTrue( Math.abs(sv0.dy() - sv.dy())<1e-7 ); 851 Assert.assertTrue( Math.abs(sv0.dz() - sv.dz())<1e-7 ); 852 853 double x0 = sp0.x(); 854 double y0 = sp0.y(); 855 double z0 = sp0.z(); 856 double x1 = sp.x(); 857 double y1 = sp.y(); 858 double z1 = sp.z(); 859 860 double dx = sv.dx(); 861 double dy = sv.dy(); 862 double dz = sv.dz(); 863 864 double prod = dx*(x1-x0)+dy*(y1-y0)+dz*(z1-z0); 865 double moda = Math.sqrt((x1-x0)*(x1-x0)+(y1-y0)*(y1-y0) + (z1-z0)*(z1-z0)); 866 double modb = Math.sqrt(dx*dx+dy*dy+dz*dz); 867 double st = pstat.pathDistance(); 868 Assert.assertTrue( Math.abs(prod-st) < 1.e-7 ); 869 Assert.assertTrue( Math.abs(Math.abs(prod) - moda*modb) < 1.e-7 ); 870 } 871 872 private static void check_derivatives( Propagator prop, VTrack trv0, Surface srf) 873 { 874 for(int i=0;i<4;++i) 875 for(int j=0;j<4;++j) 876 check_derivative(prop,trv0,srf,i,j); 877 } 878 879 private static void check_derivative( Propagator prop, VTrack trv0, Surface srf,int i,int j) 880 { 881 882 double dx = 1.e-3; 883 VTrack trv = new VTrack(trv0); 884 TrackVector vec = trv.vector(); 885 boolean forward = trv0.isForward(); 886 887 VTrack trv_0 = new VTrack(trv0); 888 TrackDerivative der = new TrackDerivative(); 889 PropStat pstat = prop.vecProp(trv_0,srf,der); 890 Assert.assertTrue(pstat.success()); 891 892 TrackVector tmp = new TrackVector(vec); 893 tmp.set(j, tmp.get(j)+dx); 894 trv.setVector(tmp); 895 if(forward) trv.setForward(); 896 else trv.setBackward(); 897 898 VTrack trv_pl = new VTrack(trv); 899 pstat = prop.vecProp(trv_pl,srf); 900 Assert.assertTrue(pstat.success()); 901 902 TrackVector vecpl = trv_pl.vector(); 903 904 tmp = new TrackVector(vec); 905 tmp.set(j, tmp.get(j)-dx); 906 trv.setVector(tmp); 907 if(forward) trv.setForward(); 908 else trv.setBackward(); 909 910 VTrack trv_mn = new VTrack(trv); 911 pstat = prop.vecProp(trv_mn,srf); 912 Assert.assertTrue(pstat.success()); 913 914 TrackVector vecmn = trv_mn.vector(); 915 916 double dy = (vecpl.get(i)-vecmn.get(i))/2.; 917 918 double dydx = dy/dx; 919 920 double didj = der.get(i,j); 921 922 if( Math.abs(didj) > 1e-10 ) 923 { 924 if( Math.abs((dydx - didj)/didj) >= 1e-4 ) 925 System.out.println("i="+ i +" j="+ j + " "+dydx + " "+ didj+'\n'); 926 Assert.assertTrue( Math.abs((dydx - didj)/didj) < 1e-4 ); 927 } 928 else 929 { 930 if( Math.abs((dydx - didj)/didj) >= 1e-4 ) 931 System.out.println("i="+ i +" j="+ j + " "+dydx + " "+ didj+'\n'); 932 933 Assert.assertTrue( Math.abs(dydx) < 1e-4 ) ; 934 } 935 } 936 937 }