G4MagHelicalStepper.cc

Go to the documentation of this file.
00001 //
00002 // ********************************************************************
00003 // * License and Disclaimer                                           *
00004 // *                                                                  *
00005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
00006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
00007 // * conditions of the Geant4 Software License,  included in the file *
00008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
00009 // * include a list of copyright holders.                             *
00010 // *                                                                  *
00011 // * Neither the authors of this software system, nor their employing *
00012 // * institutes,nor the agencies providing financial support for this *
00013 // * work  make  any representation or  warranty, express or implied, *
00014 // * regarding  this  software system or assume any liability for its *
00015 // * use.  Please see the license in the file  LICENSE  and URL above *
00016 // * for the full disclaimer and the limitation of liability.         *
00017 // *                                                                  *
00018 // * This  code  implementation is the result of  the  scientific and *
00019 // * technical work of the GEANT4 collaboration.                      *
00020 // * By using,  copying,  modifying or  distributing the software (or *
00021 // * any work based  on the software)  you  agree  to acknowledge its *
00022 // * use  in  resulting  scientific  publications,  and indicate your *
00023 // * acceptance of all terms of the Geant4 Software license.          *
00024 // ********************************************************************
00025 //
00026 //
00027 // $Id: G4MagHelicalStepper.cc 69786 2013-05-15 09:38:51Z gcosmo $
00028 //
00029 // --------------------------------------------------------------------
00030 
00031 #include "G4MagHelicalStepper.hh"
00032 #include "G4PhysicalConstants.hh"
00033 #include "G4SystemOfUnits.hh"
00034 #include "G4LineSection.hh"
00035 #include "G4Mag_EqRhs.hh"
00036 
00037 // given a purely magnetic field a better approach than adding a straight line
00038 // (as in the normal runge-kutta-methods) is to add helix segments to the
00039 // current position
00040 
00041 
00042 // Constant for determining unit conversion when using normal as integrand.
00043 //
00044 const G4double G4MagHelicalStepper::fUnitConstant = 0.299792458*(GeV/(tesla*m));
00045 
00046 
00047 G4MagHelicalStepper::G4MagHelicalStepper(G4Mag_EqRhs *EqRhs)
00048    : G4MagIntegratorStepper(EqRhs, 6), // integrate over 6 variables only !!
00049                                        // position & velocity
00050      fPtrMagEqOfMot(EqRhs), fAngCurve(0.), frCurve(0.), frHelix(0.)
00051 {
00052 }
00053 
00054 G4MagHelicalStepper::~G4MagHelicalStepper()
00055 {
00056 }
00057 
00058 void
00059 G4MagHelicalStepper::AdvanceHelix( const G4double  yIn[],
00060                                    G4ThreeVector   Bfld,    
00061                                    G4double  h,
00062                                    G4double  yHelix[],
00063                                    G4double  yHelix2[] )
00064 {
00065   // const G4int    nvar = 6;
00066  
00067   // OLD  const G4double approc_limit = 0.05;
00068   // OLD  approc_limit = 0.05 gives max.error=x^5/5!=(0.05)^5/5!=2.6*e-9
00069   // NEW  approc_limit = 0.005 gives max.error=x^5/5!=2.6*e-14
00070 
00071   const G4double approc_limit = 0.005;
00072   G4ThreeVector  Bnorm, B_x_P, vperp, vpar;
00073 
00074   G4double B_d_P;
00075   G4double B_v_P;
00076   G4double Theta;
00077   G4double R_1;
00078   G4double R_Helix;
00079   G4double CosT2, SinT2, CosT, SinT;
00080   G4ThreeVector positionMove, endTangent;
00081 
00082   G4double Bmag = Bfld.mag();
00083   const G4double *pIn = yIn+3;
00084   G4ThreeVector initVelocity= G4ThreeVector( pIn[0], pIn[1], pIn[2]);
00085   G4double      velocityVal = initVelocity.mag();
00086   G4ThreeVector initTangent = (1.0/velocityVal) * initVelocity;
00087   
00088   R_1=GetInverseCurve(velocityVal,Bmag);
00089 
00090   // for too small magnetic fields there is no curvature
00091   // (include momentum here) FIXME
00092 
00093   if( (std::fabs(R_1) < 1e-10)||(Bmag<1e-12) )
00094   {
00095     LinearStep( yIn, h, yHelix );
00096 
00097     // Store and/or calculate parameters for chord distance
00098 
00099     SetAngCurve(1.);     
00100     SetCurve(h);
00101     SetRadHelix(0.);
00102   }
00103   else
00104   {
00105     Bnorm = (1.0/Bmag)*Bfld;
00106 
00107     // calculate the direction of the force
00108     
00109     B_x_P = Bnorm.cross(initTangent);
00110 
00111     // parallel and perp vectors
00112 
00113     B_d_P = Bnorm.dot(initTangent); // this is the fraction of P parallel to B
00114 
00115     vpar = B_d_P * Bnorm;       // the component parallel      to B
00116     vperp= initTangent - vpar;  // the component perpendicular to B
00117     
00118     B_v_P  = std::sqrt( 1 - B_d_P * B_d_P); // Fraction of P perp to B
00119 
00120     // calculate  the stepping angle
00121   
00122     Theta   = R_1 * h; // * B_v_P;
00123 
00124     // Trigonometrix
00125       
00126     if( std::fabs(Theta) > approc_limit )
00127     {
00128        SinT     = std::sin(Theta);
00129        CosT     = std::cos(Theta);
00130     }
00131     else
00132     {
00133       G4double Theta2 = Theta*Theta;
00134       G4double Theta3 = Theta2 * Theta;
00135       G4double Theta4 = Theta2 * Theta2;
00136       SinT     = Theta - 1.0/6.0 * Theta3;
00137       CosT     = 1 - 0.5 * Theta2 + 1.0/24.0 * Theta4;
00138     }
00139 
00140     // the actual "rotation"
00141 
00142     G4double R = 1.0 / R_1;
00143 
00144     positionMove  = R * ( SinT * vperp + (1-CosT) * B_x_P) + h * vpar;
00145     endTangent    = CosT * vperp + SinT * B_x_P + vpar;
00146 
00147     // Store the resulting position and tangent
00148 
00149     yHelix[0]   = yIn[0] + positionMove.x(); 
00150     yHelix[1]   = yIn[1] + positionMove.y(); 
00151     yHelix[2]   = yIn[2] + positionMove.z();
00152     yHelix[3] = velocityVal * endTangent.x();
00153     yHelix[4] = velocityVal * endTangent.y();
00154     yHelix[5] = velocityVal * endTangent.z();
00155 
00156     // Store 2*h step Helix if exist
00157 
00158     if(yHelix2)
00159     {
00160       SinT2     = 2.0 * SinT * CosT;
00161       CosT2     = 1.0 - 2.0 * SinT * SinT;
00162       endTangent    = (CosT2 * vperp + SinT2 * B_x_P + vpar);
00163       positionMove  = R * ( SinT2 * vperp + (1-CosT2) * B_x_P) + h*2 * vpar;
00164       
00165       yHelix2[0]   = yIn[0] + positionMove.x(); 
00166       yHelix2[1]   = yIn[1] + positionMove.y(); 
00167       yHelix2[2]   = yIn[2] + positionMove.z(); 
00168       yHelix2[3] = velocityVal * endTangent.x();
00169       yHelix2[4] = velocityVal * endTangent.y();
00170       yHelix2[5] = velocityVal * endTangent.z();
00171     }
00172 
00173     // Store and/or calculate parameters for chord distance
00174 
00175     G4double ptan=velocityVal*B_v_P;
00176 
00177     G4double particleCharge = fPtrMagEqOfMot->FCof() / (eplus*c_light); 
00178     R_Helix =std::abs( ptan/(fUnitConstant  * particleCharge*Bmag));
00179        
00180     SetAngCurve(std::abs(Theta));
00181     SetCurve(std::abs(R));
00182     SetRadHelix(R_Helix);
00183   }
00184 }
00185 
00186 //
00187 //  Use the midpoint method to get an error estimate and correction
00188 //  modified from G4ClassicalRK4: W.Wander <wwc@mit.edu> 12/09/97
00189 //
00190 
00191 void
00192 G4MagHelicalStepper::Stepper( const G4double yInput[],
00193                               const G4double*,
00194                                     G4double hstep,
00195                                     G4double yOut[],
00196                                     G4double yErr[]  )
00197 {  
00198    const G4int nvar = 6;
00199 
00200    G4int i;
00201 
00202    // correction for Richardson Extrapolation.
00203    // G4double  correction = 1. / ( (1 << IntegratorOrder()) -1 );
00204    
00205    G4double      yTemp[7], yIn[7] ;
00206    G4ThreeVector Bfld_initial, Bfld_midpoint;
00207    
00208    //  Saving yInput because yInput and yOut can be aliases for same array
00209 
00210    for(i=0;i<nvar;i++) { yIn[i]=yInput[i]; }
00211 
00212    G4double h = hstep * 0.5; 
00213 
00214    MagFieldEvaluate(yIn, Bfld_initial) ;      
00215 
00216    // Do two half steps
00217 
00218    DumbStepper(yIn,   Bfld_initial,  h, yTemp);
00219    MagFieldEvaluate(yTemp, Bfld_midpoint) ;     
00220    DumbStepper(yTemp, Bfld_midpoint, h, yOut); 
00221 
00222    // Do a full Step
00223 
00224    h = hstep ;
00225    DumbStepper(yIn, Bfld_initial, h, yTemp);
00226 
00227    // Error estimation
00228 
00229    for(i=0;i<nvar;i++)
00230    {
00231      yErr[i] = yOut[i] - yTemp[i] ;
00232    }
00233    
00234    return;
00235 }
00236 
00237 G4double
00238 G4MagHelicalStepper::DistChord() const 
00239 {
00240   // Check whether h/R >  pi  !!
00241   // Method DistLine is good only for <  pi
00242 
00243   G4double Ang=GetAngCurve();
00244   if(Ang<=pi)
00245   {
00246     return GetRadHelix()*(1-std::cos(0.5*Ang));
00247   }
00248   else
00249   {
00250     if(Ang<twopi)
00251     {
00252       return GetRadHelix()*(1+std::cos(0.5*(twopi-Ang)));
00253     }
00254     else  // return Diameter of projected circle
00255     {
00256       return 2*GetRadHelix();
00257     }
00258   }
00259 }

Generated on Mon May 27 17:48:50 2013 for Geant4 by  doxygen 1.4.7