/scratch0/jsnuveri/BDSIM/BDSIMgit/bdsim/src/BDSSolenoidStepper.cc

00001 #include "BDSSolenoidStepper.hh"
00002 #include "BDSDebug.hh"
00003 
00004 #include "G4ThreeVector.hh"
00005 #include "G4TransportationManager.hh"
00006 #include "G4Navigator.hh"
00007 #include "G4AffineTransform.hh"
00008 #include "G4ClassicalRK4.hh"
00009 
00010 extern G4double BDSLocalRadiusOfCurvature;
00011 
00012 BDSSolenoidStepper::BDSSolenoidStepper(G4Mag_EqRhs *EqRhs)
00013   : G4MagIntegratorStepper(EqRhs,6),  // integrate over 6 variables only !!
00014                                       // position & velocity
00015     itsBField(0.0), itsDist(0.0), nvar(6)
00016 {
00017   fPtrMagEqOfMot    = EqRhs;
00018   SolenoidNavigator = new G4Navigator();
00019   backupStepper     = new G4ClassicalRK4(EqRhs,6);
00020 }
00021 
00022 void BDSSolenoidStepper::AdvanceHelix( const G4double  yIn[],
00023                                        const G4double dydx[],
00024                                        G4ThreeVector,
00025                                        G4double  h,
00026                                        G4double  yOut[],
00027                                        G4double  yErr[])
00028 {
00029   const G4double *pIn      = yIn+3;
00030   G4ThreeVector GlobalR    = G4ThreeVector( yIn[0], yIn[1], yIn[2]);
00031   G4ThreeVector GlobalP    = G4ThreeVector( pIn[0], pIn[1], pIn[2]);
00032   G4ThreeVector InitMomDir = GlobalP.unit();
00033   G4double      InitPMag   = GlobalP.mag();
00034   G4double      kappa      = - 0.5*fPtrMagEqOfMot->FCof()*itsBField/InitPMag;
00035   G4double      h2 = h*h;
00036   
00037 #ifdef BDSDEBUG
00038   G4double charge = (fPtrMagEqOfMot->FCof())/CLHEP::c_light;
00039   G4cout << "BDSSolenoidStepper: step = " << h/CLHEP::m << " m" << G4endl
00040          << " x  = " << yIn[0]/CLHEP::m   << " m"     << G4endl
00041          << " y  = " << yIn[1]/CLHEP::m   << " m"     << G4endl
00042          << " z  = " << yIn[2]/CLHEP::m   << " m"     << G4endl
00043          << " px = " << yIn[3]/CLHEP::GeV << " GeV/c" << G4endl
00044          << " py = " << yIn[4]/CLHEP::GeV << " GeV/c" << G4endl
00045          << " pz = " << yIn[5]/CLHEP::GeV << " GeV/c" << G4endl
00046          << " q  = " << charge/CLHEP::eplus << "e" << G4endl
00047          << " Bz = " << itsBField/(CLHEP::tesla/CLHEP::m) << " T" << G4endl
00048          << " k  = " << kappa/(1./CLHEP::m2) << " m^-2" << G4endl
00049          << G4endl; 
00050 #endif
00051   
00052   // setup our own navigator for calculating transforms
00053   SolenoidNavigator->SetWorldVolume(G4TransportationManager::GetTransportationManager()->GetNavigatorForTracking()->GetWorldVolume()); 
00054   SolenoidNavigator->LocateGlobalPointAndSetup(GlobalR);
00055 
00056   // get the transform
00057   G4AffineTransform GlobalAffine = SolenoidNavigator->
00058     GetGlobalToLocalTransform();
00059   
00060   G4ThreeVector LocalR  = GlobalAffine.TransformPoint(GlobalR); 
00061   G4ThreeVector LocalRp = GlobalAffine.TransformAxis(InitMomDir);
00062 
00063   G4double x1,xp1,y1,yp1,z1,zp1; //output coordinates to be
00064   
00065   if (fabs(kappa)<1e-12)
00066     {
00067       // very low strength - treat as a drift
00068       G4ThreeVector positionMove = h * InitMomDir;
00069 
00070       yOut[0] = yIn[0] + positionMove.x(); 
00071       yOut[1] = yIn[1] + positionMove.y(); 
00072       yOut[2] = yIn[2] + positionMove.z(); 
00073                                 
00074       yOut[3] = GlobalP.x();
00075       yOut[4] = GlobalP.y();
00076       yOut[5] = GlobalP.z();
00077       
00078       yErr[0] = 0; // 0 error as a drift
00079       yErr[1] = 0; // must set here as we return after this
00080       yErr[2] = 0;
00081       yErr[3] = 0;
00082       yErr[4] = 0;
00083       yErr[5] = 0;
00084 
00085       itsDist=0;
00086       return;
00087     }
00088   
00089   // finite strength - treat as a solenoid
00090   G4double x0  = LocalR.x();
00091   G4double y0  = LocalR.y();
00092   G4double z0  = LocalR.z();
00093   G4double xp0 = LocalRp.x();
00094   G4double yp0 = LocalRp.y();
00095   G4double zp0 = LocalRp.z();
00096   
00097   // local r'' (for curvature)
00098   G4ThreeVector LocalRpp;
00099   LocalRpp.setX(-zp0*x0);
00100   LocalRpp.setY( zp0*y0);
00101   LocalRpp.setZ( x0*xp0 - y0*yp0);
00102   LocalRpp *= kappa;
00103   
00104   // determine effective curvature 
00105   G4double R_1 = LocalRpp.mag();
00106 #ifdef BDSDEBUG 
00107   G4cout << " curvature= " << R_1*CLHEP::m << "m^-1" << G4endl;
00108 #endif
00109 
00110   if (R_1<1e-15)
00111     {
00112       // very large radius of curvature - treat as drift
00113       G4ThreeVector positionMove = h * InitMomDir;
00114       
00115       yOut[0] = yIn[0] + positionMove.x(); 
00116       yOut[1] = yIn[1] + positionMove.y(); 
00117       yOut[2] = yIn[2] + positionMove.z(); 
00118       
00119       yOut[3] = GlobalP.x();
00120       yOut[4] = GlobalP.y();
00121       yOut[5] = GlobalP.z();
00122 
00123       yErr[0] = 0; // 0 error as a drift
00124       yErr[1] = 0; // must set here as we return after this
00125       yErr[2] = 0;
00126       yErr[3] = 0;
00127       yErr[4] = 0;
00128       yErr[5] = 0;
00129 
00130       itsDist=0;
00131       return;
00132     }
00133 
00134 #ifdef BDSDEBUG
00135   G4cout << __METHOD_NAME__ << " using thick lens matrix " << G4endl;
00136 #endif
00137   
00138   // Save for Synchrotron Radiation calculations
00139   G4double R=1./R_1;
00140   BDSLocalRadiusOfCurvature=R;
00141   
00142   // chord distance (simple quadratic approx)
00143   itsDist= h2/(8*R);
00144 
00145   // check for paraxial approximation:
00146   if(fabs(zp0)>0.9)
00147     {
00148       // RMatrix - from Andy Wolszki's Linear Dynamics lectures (#5, slide 43)
00149       // http://pcwww.liv.ac.uk/~awolski/main_teaching_Cockcroft_LinearDynamics.htm
00150       // note this is actually for one step through the whole solenoid as focussing
00151       // comes from edge effects - may need to reconsider this in the future...
00152       // maximum step size is set to full length in BDSSolenoid.cc
00153       // ( cos^2 (wL)     , (1/2w)sin(2wL)  , (1/2)sin(2wL)  , (1/w)sin^2(wL) ) (x )
00154       // ( (w/2)sin(2wL)  , cos^2(wL)       ,  -w sin^2(wL)  , (1/2)sin(2wL)  ) (x')
00155       // ( -(1/2)sin(2wL) , (-1/w)sin^2(wL) , cos^2(wL)      , (1/2w)sin(2wL) ) (y )
00156       // ( w sin^2(wL)    , (-1/2)sin(2wL)  , (-w/2)sin(2wL) , cos^2(wL)      ) (y')
00157       
00158       G4double w       = kappa;
00159       //need the length along curvlinear s -> project h on z
00160       G4ThreeVector positionMove = h * InitMomDir; 
00161       G4double dz      = positionMove.z();
00162       G4double wL      = kappa*dz; 
00163       G4double cosOL   = cos(wL); // w is really omega - so use 'O' to describe - OL = omega*L
00164       G4double cosSqOL = cosOL*cosOL;
00165       G4double sinOL   = sin(wL);
00166       G4double sin2OL  = sin(2.0*wL);
00167       G4double sinSqOL = sinOL*sinOL;
00168       
00169       // calculate thick lens transfer matrix
00170       x1  = x0*cosSqOL + (0.5*xp0/w)*sin2OL + (0.5*y0)*sin2OL + (yp0/w)*sinSqOL;
00171       xp1 = (0.5*x0*w)*sin2OL + xp0*cosSqOL - (w*y0)*sinSqOL + (0.5*yp0)*sin2OL;
00172       y1  = (-0.5*x0)*sin2OL - (xp0/w)*sinSqOL + y0*cosSqOL + (0.5*yp0/w)*sin2OL;
00173       yp1 = x0*w*sinSqOL - (0.5*xp0)*sin2OL - (0.5*w*y0)*sin2OL + yp0*cosSqOL;  
00174       
00175       // ensure normalisation for vector
00176       zp1 = sqrt(1 - xp1*xp1 -yp1*yp1);
00177       
00178       // calculate deltas to existing coords
00179       G4double dx = x1-x0;
00180       G4double dy = y1-y0;
00181       
00182       // check for precision problems
00183       G4double ScaleFac = (dx*dx+dy*dy+dz*dz)/h2;
00184 #ifdef BDSDEBUG
00185       G4cout << "Ratio of calculated to proposed step length: " << ScaleFac << G4endl;
00186 #endif
00187       if(ScaleFac>1.0000001)
00188         {
00189 #ifdef BDSDEBUG
00190           G4cout << __METHOD_NAME__ << " normalising to conserve step length" << G4endl;
00191 #endif
00192           ScaleFac = sqrt(ScaleFac);
00193           dx /= ScaleFac;
00194           dy /= ScaleFac;
00195           dz /= ScaleFac;
00196           x1 =  x0+dx;
00197           y1 =  y0+dy;
00198         }
00199       z1 = z0+dz;
00200 
00201       //write the final coordinates
00202       LocalR.setX(x1);
00203       LocalR.setY(y1);
00204       LocalR.setZ(z1);
00205       LocalRp.setX(xp1);
00206       LocalRp.setY(yp1);
00207       LocalRp.setZ(zp1);
00208       
00209 #ifdef BDSDEBUG 
00210       G4cout << "BDSSolenoidStepper: final point in local coordinates:" << G4endl
00211              << " x  = " << LocalR[0]/CLHEP::m << " m" << G4endl
00212              << " y  = " << LocalR[1]/CLHEP::m << " m" << G4endl
00213              << " z  = " << LocalR[2]/CLHEP::m << " m" << G4endl
00214              << " x' = " << LocalRp[0]         << G4endl
00215              << " y' = " << LocalRp[1]         << G4endl
00216              << " z' = " << LocalRp[2]         << G4endl
00217              << G4endl; 
00218 #endif
00219       
00220       G4AffineTransform LocalAffine = SolenoidNavigator-> 
00221         GetLocalToGlobalTransform();
00222       
00223       GlobalR = LocalAffine.TransformPoint(LocalR); 
00224       GlobalP = InitPMag*LocalAffine.TransformAxis(LocalRp);
00225       
00226       yOut[0] = GlobalR.x(); 
00227       yOut[1] = GlobalR.y(); 
00228       yOut[2] = GlobalR.z(); 
00229       
00230       yOut[3] = GlobalP.x();
00231       yOut[4] = GlobalP.y();
00232       yOut[5] = GlobalP.z();
00233 
00234       for(G4int i=0;i<nvar;i++) yErr[i]=0; //set error to be zero - not strictly correct
00235     }
00236   else
00237     // perform local helical steps (paraxial approx not safe)
00238     {
00239 #ifdef BDSDEBUG
00240       G4cout << __METHOD_NAME__ << " local helical steps - using G4ClassicalRK4" << G4endl;
00241 #endif
00242       // use a classical Runge Kutta stepper here
00243       backupStepper->Stepper(yIn, dydx, h, yOut, yErr);
00244     }  
00245 }
00246 
00247 
00248 void BDSSolenoidStepper::Stepper( const G4double yInput[],
00249                                   const G4double dydx[],
00250                                   const G4double hstep,
00251                                   G4double yOut[],
00252                                   G4double yErr[]      )
00253 { 
00254   //simply perform one step here
00255   AdvanceHelix(yInput,dydx,(G4ThreeVector)0,hstep,yOut,yErr);
00256 }
00257 
00258 G4double BDSSolenoidStepper::DistChord()   const 
00259 {
00260   return itsDist;
00261   // This is a class method that gives distance of Mid 
00262   //  from the Chord between the Initial and Final points.
00263 }
00264 
00265 BDSSolenoidStepper::~BDSSolenoidStepper()
00266 {}

Generated on 28 Jun 2015 for BDSIM by  doxygen 1.4.7