Import Geant4 0.0.0 source tree

This commit is contained in:
Gabriele Cosmo
2016-06-01 15:25:35 +02:00
parent 54d6b71f95
commit b97f8d0df7
3237 changed files with 807095 additions and 0 deletions
@@ -0,0 +1,288 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4CashKarpRKF45.cc,v 2.7 1998/11/19 20:57:05 japost Exp $
// GEANT4 tag $Name: geant4-00 $
//
// The Cash-Karp Runge-Kutta-Fehlberg 4/5 method is an embedded fourth
// order method (giving fifth-order accuracy) for the solution
// of an ODE. Two different fourth order estimates are calculated;
// their difference gives an error estimate.
// (We use it to integrate the equations of the motion of a particle
// in a magnetic field. )
//
// Similar to Numerical Recipes, .... put REFerence here!
//
#include "G4CashKarpRKF45.hh"
/////////////////////////////////////////////////////////////////////
//
// Constructor
G4CashKarpRKF45::G4CashKarpRKF45(G4Mag_EqRhs *EqRhs, G4int numberOfVariables):
G4MagIntegratorStepper(EqRhs)
{
fNumberOfVariables = numberOfVariables ;
ak2 = new G4double[fNumberOfVariables] ;
ak3 = new G4double[fNumberOfVariables] ;
ak4 = new G4double[fNumberOfVariables] ;
ak5 = new G4double[fNumberOfVariables] ;
ak6 = new G4double[fNumberOfVariables] ;
yTemp = new G4double[fNumberOfVariables] ;
yIn = new G4double[fNumberOfVariables] ;
}
/////////////////////////////////////////////////////////////////////
//
// Destructor
G4CashKarpRKF45::~G4CashKarpRKF45()
{
delete ak2;
delete ak3;
delete ak4;
delete ak5;
delete ak6;
delete ak7;
delete yTemp;
delete yIn;
}
//////////////////////////////////////////////////////////////////////
//
// Given values for n = 6 variables yIn[0,...,n-1]
// known at x, use the fifth-order Cash-Karp Runge-
// Kutta-Fehlberg-4-5 method to advance the solution over an interval
// Step and return the incremented variables as yOut[0,...,n-1]. Also
// return an estimate of the local truncation error yErr[] using the
// embedded 4th-order method. The user supplies routine
// RightHandSide(y,dydx), which returns derivatives dydx for y .
void
G4CashKarpRKF45::Stepper(const G4double yInput[],
const G4double dydx[],
const G4double Step,
G4double yOut[],
G4double yErr[])
{
// const G4int nvar = 6 ;
G4int i;
const G4double a2 = 0.2 , a3 = 0.3 , a4 = 0.6 , a5 = 1.0 , a6 = 0.875 ,
b21 = 0.2 ,
b31 = 3.0/40.0 , b32 = 9.0/40.0 ,
b41 = 0.3 , b42 = -0.9 , b43 = 1.2 ,
b51 = -11.0/54.0 , b52 = 2.5 , b53 = -70.0/27.0 ,
b54 = 35.0/27.0 ,
b61 = 1631.0/55296.0 , b62 = 175.0/512.0 ,
b63 = 575.0/13824.0 , b64 = 44275.0/110592.0 ,
b65 = 253.0/4096.0 ,
c1 = 37.0/378.0 , c3 = 250.0/621.0 , c4 = 125.0/594.0 ,
c6 = 512.0/1771.0 ,
dc5 = -277.0/14336.0 ;
const G4double dc1 = c1 - 2825.0/27648.0 , dc3 = c3 - 18575.0/48384.0 ,
dc4 = c4 - 13525.0/55296.0 , dc6 = c6 - 0.25 ;
// Saving yInput because yInput and yOut can be aliases for same array
for(i=0;i<fNumberOfVariables;i++)
{
yIn[i]=yInput[i];
}
// RightHandSide(yIn, dydx) ; // 1st Step
for(i=0;i<fNumberOfVariables;i++)
{
yTemp[i] = yIn[i] + b21*Step*dydx[i] ;
}
RightHandSide(yTemp, ak2) ; // 2nd Step
for(i=0;i<fNumberOfVariables;i++)
{
yTemp[i] = yIn[i] + Step*(b31*dydx[i] + b32*ak2[i]) ;
}
RightHandSide(yTemp, ak3) ; // 3rd Step
for(i=0;i<fNumberOfVariables;i++)
{
yTemp[i] = yIn[i] + Step*(b41*dydx[i] + b42*ak2[i] + b43*ak3[i]) ;
}
RightHandSide(yTemp, ak4) ; // 4th Step
for(i=0;i<fNumberOfVariables;i++)
{
yTemp[i] = yIn[i] + Step*(b51*dydx[i] + b52*ak2[i] + b53*ak3[i] +
b54*ak4[i]) ;
}
RightHandSide(yTemp, ak5) ; // 5th Step
for(i=0;i<fNumberOfVariables;i++)
{
yTemp[i] = yIn[i] + Step*(b61*dydx[i] + b62*ak2[i] + b63*ak3[i] +
b64*ak4[i] + b65*ak5[i]) ;
}
RightHandSide(yTemp, ak6) ; // 6th Step
for(i=0;i<fNumberOfVariables;i++)
{
// Accumulate increments with proper weights
yOut[i] = yIn[i] + Step*(c1*dydx[i] + c3*ak3[i] + c4*ak4[i] + c6*ak6[i]) ;
// Estimate error as difference between 4th and
// 5th order methods
yErr[i] = Step*(dc1*dydx[i] + dc3*ak3[i] + dc4*ak4[i] +
dc5*ak5[i] + dc6*ak6[i]) ;
}
// NormaliseTangentVector( yOut ); // Not wanted
return ;
} // end of Stepper .......................................................
void
G4CashKarpRKF45::StepWithEst(const G4double yInput[],
const G4double dydx[],
const G4double Step,
G4double yOut[],
G4double& alpha2,
G4double& beta2,
const G4double B1[],
G4double B2[] )
{
G4Exception("G4CashKarpRKF45::StepWithEst ERROR: This Method is no longer used.");
#if 0
// const G4int nvar = 6 ;
G4int i;
// Saving yInput because yInput and yOut can be aliases for same array
for(i=0;i<fNumberOfVariables;i++)
{
yIn[i]=yInput[i];
}
const G4double a2 = 0.2 , a3 = 0.3 , a4 = 0.6 , a5 = 1.0 , a6 = 0.875 ,
b21 = 0.2 ,
b31 = 3.0/40.0 , b32 = 9.0/40.0 ,
b41 = 0.3 , b42 = -0.9 , b43 = 1.2 ,
b51 = -11.0/54.0 , b52 = 2.5 , b53 = -70.0/27.0 ,
b54 = 35.0/27.0 ,
b61 = 1631.0/55296.0 , b62 = 175.0/512.0 ,
b63 = 575.0/13824.0 , b64 = 44275.0/110592.0 ,
b65 = 253.0/4096.0 ,
c1 = 37.0/378.0 , c3 = 250.0/621.0 , c4 = 125.0/594.0 ,
c6 = 512.0/1771.0 ,
dc5 = -277.0/14336.0 ;
const G4double dc1 = c1 - 2825.0/27648.0 , dc3 = c3 - 18575.0/48384.0 ,
dc4 = c4 - 13525.0/55296.0 , dc6 = c6 - 0.25 ;
alpha2 = 0 ;
beta2 = 0 ;
// RightHandSide(yIn, dydx) ; // 1st Step
for(i=0;i<3;i++)
{
alpha2 += B1[i]*B1[i] ;
beta2 += dydx[i+3]*dydx[i+3] ;
}
for(i=0;i<fNumberOfVariables;i++)
{
yTemp[i] = yIn[i] + b21*Step*dydx[i] ;
}
GetEquationOfMotion()->EvaluateRhsReturnB(yTemp,ak2,B2) ; // Calculates yderive &
// returns B too!
for(i=0;i<3;i++)
{
alpha2 += B2[i]*B2[i] ;
beta2 += ak2[i+3]*ak2[i+3] ;
}
for(i=0;i<fNumberOfVariables;i++)
{
yTemp[i] = yIn[i] + Step*(b31*dydx[i] + b32*ak2[i]) ;
}
GetEquationOfMotion()->EvaluateRhsReturnB(yTemp,ak3,B2) ;
for(i=0;i<3;i++)
{
alpha2 += B2[i]*B2[i] ;
beta2 += ak3[i+3]*ak3[i+3] ;
}
for(i=0;i<fNumberOfVariables;i++)
{
yTemp[i] = yIn[i] + Step*(b41*dydx[i] + b42*ak2[i] + b43*ak3[i]) ;
}
GetEquationOfMotion()->EvaluateRhsReturnB(yTemp,ak4,B2) ;
for(i=0;i<3;i++)
{
alpha2 += B2[i]*B2[i] ;
beta2 += ak4[i+3]*ak4[i+3] ;
}
for(i=0;i<fNumberOfVariables;i++)
{
yTemp[i] = yIn[i] + Step*(b51*dydx[i] + b52*ak2[i] + b53*ak3[i] +
b54*ak4[i]) ;
}
GetEquationOfMotion()->EvaluateRhsReturnB(yTemp,ak5,B2) ;
for(i=0;i<3;i++)
{
alpha2 += B2[i]*B2[i] ;
beta2 += ak5[i+3]*ak5[i+3] ;
}
for(i=0;i<fNumberOfVariables;i++)
{
yTemp[i] = yIn[i] + Step*(b61*dydx[i] + b62*ak2[i] + b63*ak3[i] +
b64*ak4[i] + b65*ak5[i]) ;
}
GetEquationOfMotion()->EvaluateRhsReturnB(yTemp,ak6,B2) ;
for(i=0;i<3;i++)
{
alpha2 += B2[i]*B2[i] ;
beta2 += ak6[i+3]*ak6[i+3] ;
}
for(i=0;i<fNumberOfVariables;i++)
{
// Accumulate increments with proper weights
yOut[i] = yIn[i] + Step*(c1*dydx[i] + c3*ak3[i] + c4*ak4[i] + c6*ak6[i]) ;
}
alpha2 *= sqr(GetEquationOfMotion()->FCof()*Step)/6.0 ;
beta2 *= (Step*Step)/6.0 ;
// NormaliseTangentVector( yOut );
#endif
return ;
} // end of StepWithEst ....................................................
@@ -0,0 +1,279 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4ChordFinder.cc,v 2.6 1998/11/13 14:30:21 japost Exp $
// GEANT4 tag $Name: geant4-00 $
//
//
// 25.02.97 John Apostolakis, desigh and implimentation
// 05.03.97 V. Grichine , makeup to G4 'standard'
#include "G4ChordFinder.hh"
#include "G4MagIntegratorDriver.hh"
#include "G4Mag_UsualEqRhs.hh"
#include "G4ClassicalRK4.hh"
// #include "G4Field.hh"
// #include "G4MagIntegratorStepper.hh"
#include "G4MagIntegratorDriver.hh"
// For the moment fDeltaChord is a constant!
const G4double G4ChordFinder::fDefaultDeltaChord = 3. * mm;
// ..........................................................................
G4ChordFinder::G4ChordFinder( G4MagneticField* theMagField,
G4double stepMinimum,
G4MagIntegratorStepper* pItsStepper ) // A default one
: fDeltaChord( fDefaultDeltaChord )
{
// Construct the Chord Finder
// by creating in inverse order the Driver, the Stepper and EqRhs ...
// G4Mag_EqRhs *
fEquation = new G4Mag_UsualEqRhs(theMagField); // Should move q, p to
//G4FieldTrack ??
// --->> Charge Q = 0
// --->> Momentum P = 1 NOMINAL VALUES !!!!!!!!!!!!!!!!!!
if( pItsStepper == 0 )
{
pItsStepper = fDriversStepper = new G4ClassicalRK4(fEquation);
fAllocatedStepper= true;
}
else
{
fAllocatedStepper= false;
}
fIntgrDriver = new G4MagInt_Driver(stepMinimum, pItsStepper);
}
// ......................................................................
G4ChordFinder::~G4ChordFinder()
{
delete fEquation; // fIntgrDriver->pIntStepper->theEquation_Rhs;
if( fAllocatedStepper)
{
delete fDriversStepper;
} // fIntgrDriver->pIntStepper;}
delete fIntgrDriver;
}
// ......................................................................
G4double
G4ChordFinder::AdvanceChordLimited( G4FieldTrack& yCurrent,
const G4double stepMax,
const G4double epsStep )
{
G4double stepPossible;
G4double dyErr;
G4FieldTrack yEnd( yCurrent);
G4bool dbg= false;
#ifdef G4VERBOSE
if( dbg )
G4cerr << "Entered FindNextChord Limited with:\n yCurrent: " << yCurrent
<< " and initial Step=stepMax=" << stepMax << " mm. " << endl;
#endif
stepPossible= FindNextChord(yCurrent, stepMax, yEnd, dyErr, epsStep);
if ( dyErr < epsStep * stepPossible )
{
// Accept this accuracy.
yCurrent = yEnd;
}
else
{
// Advance more accurately to "end of chord"
#ifdef G4VERBOSE
if (dbg) G4cerr << "Accurate advance to end of chord needed\n";
#endif
fIntgrDriver->AccurateAdvance(yCurrent, stepPossible, epsStep);
}
#ifdef G4VERBOSE
if( dbg ) G4cerr << "Exiting FindNextChord Limited with:\n yCurrent: "
<< yCurrent<< endl;
#endif
return stepPossible;
}
// ..............................................................................
G4double
G4ChordFinder::FindNextChord( const G4FieldTrack yStart,
const G4double stepMax,
G4FieldTrack& yEnd, // Endpoint
G4double& dyErr, // Error of endpoint
G4double epsStep )
// Returns Length of Step taken
{
// G4int stepRKnumber=0;
G4FieldTrack yCurrent= yStart;
G4double stepTrial= stepMax;
G4double dydx[G4FieldTrack::ncompSVEC];
// 1.) Try to "leap" to end of interval
// 2.) Evaluate if resulting chord gives d_chord that is good enough.
// 2a.) If d_chord is not good enough, find one that is.
G4bool validEndPoint= false, dbg= false;
G4double dChordStep;
fIntgrDriver-> GetDerivatives( yCurrent, dydx ) ;
do
{
yCurrent = yStart; // Always start from initial point
fIntgrDriver->QuickAdvance( yCurrent, dydx, stepTrial, dChordStep, dyErr);
#ifdef G4VERBOSE
if( dbg ) {
G4cerr << "Returned from QuickAdvance with: yCur=" << yCurrent << endl;
G4cerr << " dChordStep= "<< dChordStep <<" dyErr=" << dyErr << endl;
}
#endif
// We check whether the criterion is met here.
validEndPoint = AcceptableMissDist(dChordStep);
if( ! validEndPoint ) {
// This is needed to decide new step size until QuickAdvance does it
stepTrial = NewStep(stepTrial, dChordStep );
// Get the driver to calculate the new step size, if it is needed
// stepTrial= fIntgrDriver->ComputeNewStepSize( dyErr/epsStep, stepTrial);
#ifdef G4VERBOSE
if( dbg )
G4cerr << "Dchord too big. Trying new hstep=" << stepTrial << endl;
#endif
}
}
while( ! validEndPoint ); // End of do-while RKD
yEnd= yCurrent;
return stepTrial;
}
// ...........................................................................
G4double G4ChordFinder::NewStep(
const G4double stepTrialOld,
const G4double dChordStep ) // Current dchord achieved.
{
G4double stepTrial;
if ( dChordStep > 1000. * fDeltaChord ){
stepTrial= stepTrialOld * 0.03;
}else{
if ( dChordStep > 100. * fDeltaChord ){
stepTrial= stepTrialOld * 0.1;
}else{
// Keep halving the length until dChordStep OK
stepTrial= stepTrialOld * 0.5;
}
}
// A more sophisticated chord-finder could figure out a better
// stepTrial, from dChordStep and the required d_geometry
// eg
// Calculate R, r_helix (eg at orig point)
// if( stepTrial < 2 pi R )
// stepTrial = R arc_cos( 1 - fDeltaChord / r_helix )
// else
// ??
return stepTrial;
}
//
// G4FieldTrack G4NewMagTr::ApproxCurvePointV(
// const G4FieldTrack& CurveA_PointVelocity,
// const G4FieldTrack& CurveB_PointVelocity,
// const G4ThreeVector& CurrentE_Point,
// const G4double eps_step)
//
// Given a starting curve point A (CurveA_PointVelocity), a later
// curve point B (CurveB_PointVelocity) and a point E which is (generally)
// not on the curve, find and return a point F which is on the curve and
// which is close to E. While advancing towards F utilise eps_step
// as a measure of the relative accuracy of each Step.
G4FieldTrack G4ChordFinder::ApproxCurvePointV(
const G4FieldTrack& CurveA_PointVelocity,
const G4FieldTrack& CurveB_PointVelocity,
const G4ThreeVector& CurrentE_Point,
const G4double eps_step)
{
// 1st implementation:
// if r=|AE|/|AB|, and s=true path lenght (AB)
// return the point that is r*s along the curve!
G4FieldTrack Current_PointVelocity= CurveA_PointVelocity;
G4ThreeVector CurveA_Point= CurveA_PointVelocity.Position();
G4ThreeVector CurveB_Point= CurveB_PointVelocity.Position();
G4ThreeVector ChordAB_Vector= CurveB_Point - CurveA_Point;
G4ThreeVector ChordAE_Vector= CurrentE_Point - CurveA_Point;
G4double ABdist= ChordAB_Vector.mag();
G4double curve_length; // A curve length of AB
G4double AE_fraction;
curve_length=
CurveB_PointVelocity.CurveS() - CurveA_PointVelocity.CurveS();
#ifdef DEBUG
const G4double per_million=1e-6;
if( ABdist * > curve_length * (1. + per_million ) ){
G4cerr << " Error in ApproxCurvePoint \n" <<
" The two points are further apart than the curve length " << endl <<
" Dist = " << ABdist <<
" curve length = " << curve_length << endl;
}
#endif
G4double new_st_length;
if ( ABdist > 0.0 ){
AE_fraction = ChordAE_Vector.mag() / ABdist;
new_st_length= AE_fraction * curve_length;
}else{
G4cerr << " Error in ApproxCurvePoint: A and B are the same point\n" <<
" Chord AB length = " << ChordAE_Vector.mag() << endl << endl;
AE_fraction = 0.5; // Guess .. ?;
new_st_length= AE_fraction * curve_length; // Is this correct ??
}
if( (AE_fraction> 1.0 + perMillion) || (AE_fraction< 0.) ){
G4cerr << " Error in ApproxCurvePoint: AE > AB or AE/AB <= 0 " << endl <<
" AE_fraction = " << AE_fraction << endl <<
" Chord AE length = " << ChordAE_Vector.mag() << endl <<
" Chord AB length = " << ABdist << endl << endl;
}
if ( AE_fraction > 0.0 ) {
G4bool good_advance =
fIntgrDriver->AccurateAdvance(Current_PointVelocity,
new_st_length,
eps_step/AE_fraction ); // Relative accuracy
}
// If there was a memory of the step_length actually require at the start
// of the integration Step, this could be re-used ...
return Current_PointVelocity;
}
@@ -0,0 +1,164 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4ClassicalRK4.cc,v 2.8 1998/11/17 18:20:10 japost Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4ClassicalRK4.hh"
#include "G4ThreeVector.hh"
//////////////////////////////////////////////////////////////////
//
// Constructor sets the number of variables (default = 6)
G4ClassicalRK4:: G4ClassicalRK4(G4Mag_EqRhs *EqRhs, G4int numberOfVariables):
G4MagErrorStepper(EqRhs, numberOfVariables),
fNumberOfVariables(numberOfVariables)
{
dydxm = new G4double[fNumberOfVariables];
dydxt = new G4double[fNumberOfVariables];
yt = new G4double[fNumberOfVariables];
}
////////////////////////////////////////////////////////////////
//
// Destructor
G4ClassicalRK4:: ~G4ClassicalRK4()
{
delete[] dydxm;
delete[] dydxt;
delete[] yt;
}
//////////////////////////////////////////////////////////////////////
//
// Given values for the variables y[0,..,n-1] and their derivatives
// dydx[0,...,n-1] known at x, use the classical 4th Runge-Kutta
// method to advance the solution over an interval h and return the
// incremented variables as yout[0,...,n-1], which not be a distinct
// array from y. The user supplies the routine RightHandSide(x,y,dydx),
// which returns derivatives dydx at x. The source is routine rk4 from
// NRC p. 712-713 .
void
G4ClassicalRK4::DumbStepper( const G4double yIn[],
const G4double dydx[],
const G4double h,
G4double yOut[])
{
const G4int nvar = fNumberOfVariables; // GetNumberOfVariables();
G4int i;
G4double hh = h*0.5 , h6 = h/6.0 ;
for(i=0;i<nvar;i++)
{
yt[i] = yIn[i] + hh*dydx[i] ; // 1st Step K1=h*dydx
}
RightHandSide(yt,dydxt) ; // 2nd Step K2=h*dydxt
for(i=0;i<nvar;i++)
{
yt[i] = yIn[i] + hh*dydxt[i] ;
}
RightHandSide(yt,dydxm) ; // 3rd Step K3=h*dydxm
for(i=0;i<nvar;i++)
{
yt[i] = yIn[i] + h*dydxm[i] ;
dydxm[i] += dydxt[i] ; // now dydxm=(K2+K3)/h
}
RightHandSide(yt,dydxt) ; // 4th Step K4=h*dydxt
for(i=0;i<nvar;i++) // Final RK4 output
{
yOut[i] = yIn[i] + h6*(dydx[i]+dydxt[i]+2.0*dydxm[i]); //+K1/6+K4/6+(K2+K3)/3
}
// NormaliseTangentVector( yOut );
return ;
} // end of DumbStepper ....................................................
////////////////////////////////////////////////////////////////////
//
//
void
G4ClassicalRK4::StepWithEst( const G4double yIn[],
const G4double dydx[],
const G4double h,
G4double yOut[],
G4double& alpha2,
G4double& beta2,
const G4double B1[],
G4double B2[] )
{
G4Exception(" G4ClassicalRK4::StepWithEst ERROR: this Method is no longer used.");
#if 0 // const G4int nvar = 6 ;
const G4int nvar = GetNumberOfVariables();
G4int i;
G4double hh = h*0.5 , h6 = h/6.0 ;
G4double B[3] ;
alpha2 = 0 ;
beta2 = 0 ;
for(i=0;i<nvar;i++)
{
yt[i] = yIn[i] + hh*dydx[i] ; // 1st Step K1=h*dydx
}
GetEquationOfMotion()->EvaluateRhsReturnB(yt,dydxt,B) ; // Calculates yderive &
// returns B too!
// RightHandSide(yt,dydxt) ; // 2nd Step K2=h*dydxt
for(i=0;i<nvar;i++)
{
yt[i] = yIn[i] + hh*dydxt[i] ;
}
GetEquationOfMotion()->EvaluateRhsReturnB(yt,dydxm,B2) ;
// RightHandSide(yt,dydxm) ; // 3rd Step K3=h*dydxm
for(i=0;i<3;i++)
{
beta2 += dydx[i+3] *dydx[i+3]
+ dydxt[i+3]*dydxt[i+3]
+ dydxm[i+3]*dydxm[i+3] ;
alpha2 += B1[i]*B1[i] + B[i]*B[i] + B2[i]*B2[i] ;
}
for(i=0;i<nvar;i++)
{
yt[i] = yIn[i] + h*dydxm[i] ;
dydxm[i] += dydxt[i] ; // now dydxm=(K2+K3)/h
}
GetEquationOfMotion()->EvaluateRhsReturnB(yt,dydxt,B2) ;
// RightHandSide(yt,dydxt) ; // 4th Step K4=h*dydxt
for(i=0;i<nvar;i++) // Final RK4 output
{
yOut[i] = yIn[i] + h6*(dydx[i]+dydxt[i]+2.0*dydxm[i]); //+K1/6+K4/6+(K2+K3)/3
}
for(i=0;i<3;i++)
{
beta2 += dydxt[i+3]*dydxt[i+3] ;
alpha2 += B2[i]*B2[i] ;
}
beta2 *= 0.25*h*h;
alpha2 *= sqr(GetEquationOfMotion()->FCof()*h)*0.25 ;
// NormaliseTangentVector( yOut );
#endif
return ;
} // end of StepWithEst ......................................................
@@ -0,0 +1,57 @@
//
// This is the standard right-hand side for equation of motion.
//
// The only case another is required is when using a moving reference
// frame ... or extending the class to include additional Forces,
// eg an electric field
//
// 10.11.98 V.Grichine
//
#include "G4EqMagElectricField.hh"
void
G4EqMagElectricField::
SetChargeMomentumMass( const G4double particleCharge, // e+ units
const G4double MomentumXc,
const G4double particleMass)
{
fElectroMagCof = eplus*c_squared ;
fElectroMagCof *= particleCharge/particleMass;
}
void
G4EqMagElectricField::EvaluateRhsGivenB( const G4double y[],
const G4double Field[],
G4double dydx[] ) const
{
// Components of y:
// 0-2 dr/ds,
// 3-5 dv/ds
// FCof() = charge/mass
G4double vSquared = y[3]*y[3] + y[4]*y[4] + y[5]*y[5] ;
G4double vModule = sqrt(vSquared) ;
G4double vDotE = y[3]*Field[3] + y[4]*Field[4] + y[5]*Field[5] ;
G4double gammaReci = sqrt(1 - vSquared/c_squared) ;
dydx[0] = y[3]/vModule ;
dydx[1] = y[4]/vModule ;
dydx[2] = y[5]/vModule ;
dydx[3] = fElectroMagCof*(Field[3] + (y[4]*Field[2] - y[5]*Field[1])/c_light -
y[3]*vDotE/c_light/c_light )*gammaReci/vModule ;
dydx[4] = fElectroMagCof*(Field[4] + (y[5]*Field[0] - y[3]*Field[2])/c_light -
y[4]*vDotE/c_light/c_light )*gammaReci/vModule ;
dydx[5] = fElectroMagCof*(Field[5] + (y[3]*Field[1] - y[4]*Field[0])/c_light -
y[5]*vDotE/c_light/c_light)*gammaReci/vModule ;
return ;
}
@@ -0,0 +1,39 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4EquationOfMotion.cc,v 2.3 1998/11/12 19:48:23 japost Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4EquationOfMotion.hh"
static const int G4maximum_number_of_field_components = 16;
void
G4EquationOfMotion::RightHandSide( const G4double y[],
G4double dydx[] ) const
{
G4double Field[G4maximum_number_of_field_components];
GetFieldValue(y, Field) ;
EvaluateRhsGivenB( y, Field, dydx );
}
void
G4EquationOfMotion::EvaluateRhsReturnB( const G4double y[],
G4double dydx[],
G4double Field[] ) const
{
GetFieldValue(y, Field) ;
EvaluateRhsGivenB( y, Field, dydx );
}
#if HELP_THE_COMPILER
void
G4EquationOfMotion::doNothing()
{
}
#endif
@@ -0,0 +1,67 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4ExplicitEuler.cc,v 2.6 1998/11/12 16:16:10 japost Exp $
// GEANT4 tag $Name: geant4-00 $
//
//
// Explicit Euler: x_1 = x_0 + h * dx_0
//
// most simple approach for solving linear differential equations.
// Take the current derivative and add it to the current position.
//
// W.Wander <wwc@mit.edu> 12/09/97
#include "G4ExplicitEuler.hh"
#include "G4ThreeVector.hh"
//////////////////////////////////////////////////////////////////////////
//
// Constructor
G4ExplicitEuler::G4ExplicitEuler(G4Mag_EqRhs *EqRhs,
G4int numberOfVariables) :
G4MagErrorStepper(EqRhs, numberOfVariables),
fNumberOfVariables(numberOfVariables)
{
}
///////////////////////////////////////////////////////////////////////
//
// Destructor
G4ExplicitEuler::~G4ExplicitEuler()
{
;
}
///////////////////////////////////////////////////////////////////////
//
//
void
G4ExplicitEuler::DumbStepper( const G4double yIn[],
const G4double dydx[],
const G4double h,
G4double yOut[] )
{
// const G4int nvar = 6 ;
G4int i;
for(i=0;i<fNumberOfVariables;i++)
{
yOut[i] = yIn[i] + h*dydx[i] ; // 1st and only Step
}
// NormaliseTangentVector( yOut ); // this could harm more than
// it helps - FIXME ???
return ;
}
@@ -0,0 +1,40 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4FieldManager.cc,v 2.1 1998/07/12 02:55:15 urbi Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4FieldManager.hh"
G4FieldManager::G4FieldManager()
{
fDetectorField= 0;
fAllocatedChordFinder= false;
}
G4FieldManager::G4FieldManager(G4MagneticField *detectorField)
{
fDetectorField= detectorField;
this->CreateChordFinder(detectorField);
}
G4FieldManager::~G4FieldManager()
{
if( fAllocatedChordFinder ){
delete fChordFinder;
}
}
void
G4FieldManager::CreateChordFinder(G4MagneticField *detectorMagField)
{
fChordFinder= new G4ChordFinder( detectorMagField );
fAllocatedChordFinder= true;
}
@@ -0,0 +1,20 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4FieldTrack.cc,v 2.3 1998/11/11 10:46:50 japost Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4FieldTrack.hh"
ostream& operator<<( ostream& os, G4FieldTrack& SixVec)
{
G4double *SixV = SixVec.SixVector;
os << " X= " << SixV[0] << " " << SixV[1] << " " << SixV[2] << " ";
os << " V= " << SixV[3] << " " << SixV[4] << " " << SixV[5] << " ";
os << " l= " << SixVec.CurveS();
return os;
}
@@ -0,0 +1,36 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4HelixExplicitEuler.cc,v 2.3 1998/11/13 14:30:21 japost Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4HelixExplicitEuler.hh"
#include "G4ThreeVector.hh"
//
// Helix Explicit Euler: x_1 = x_0 + helix(h)
// with helix(h) being a helix piece of length h
// W.Wander <wwc@mit.edu> 12/09/97
//
// -------------------------------------------------------------------------
// most simple approach for solving linear differential equations.
// Take the current derivative and add it to the current position.
//
void
G4HelixExplicitEuler::DumbStepper( const G4double yIn[],
const G4double dydx[],
const G4double h,
G4double yOut[])
{
AdvanceHelix(yIn, dydx, h, yOut);
// NormaliseTangentVector( yOut ); // this could harm more than it helps
return ;
}
@@ -0,0 +1,56 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4HelixHeum.cc,v 2.3 1998/11/10 18:17:14 japost Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4HelixHeum.hh"
#include "G4ThreeVector.hh"
//
// Simple Heum:
// x_1 = x_0 + h *
// 1/4 * dx(t0,x0) +
// 3/4 * dx(t0+2/3*h, x0+2/3*h*(dx(t0+h/3,x0+h/3*dx(t0,x0))))
// W.Wander <wwc@mit.edu> 12/09/97
//
// -------------------------------------------------------------------------
// third order solver
//
void
G4HelixHeum::DumbStepper( const G4double yIn[],
const G4double dydx[],
const G4double h,
G4double yOut[])
{
const G4int nvar = 6 ;
G4double dydxTemp[6], dydxTemp2[6];
G4double yTemp[6], yAdd1[6], yAdd2[6] , yTemp2[6];
G4int i;
AdvanceHelix( yIn, dydx, h, yAdd1 );
AdvanceHelix( yIn, dydx, h/3.0, yTemp );
RightHandSide(yTemp,dydxTemp);
AdvanceHelix( yIn, dydxTemp, (2.0 / 3.0) * h, yTemp2 );
RightHandSide(yTemp2,dydxTemp2);
AdvanceHelix( yIn, dydxTemp2, h, yAdd2 );
for( i = 0; i < nvar; i++ ) {
yOut[i] = ( 0.25 * yAdd1[i] + 0.75 * yAdd2[i]);
}
// NormaliseTangentVector( yOut );
return ;
}
@@ -0,0 +1,57 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4HelixImplicitEuler.cc,v 2.2 1998/11/10 18:17:14 japost Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4HelixImplicitEuler.hh"
#include "G4ThreeVector.hh"
//
// Helix Implicit Euler:
// x_1 = x_0 + 1/2 * ( helix(h,t_0,x_0)
// + helix(h,t_0+h,x_0+helix(h,t0,x0) ) )
// W.Wander <wwc@mit.edu> 12/09/97
//
// -------------------------------------------------------------------------
// second order solver
// Take the current derivative and add it to the current position.
// Take the output and its derivative. Add the mean of both derivatives
// to form the final output
//
void
G4HelixImplicitEuler::DumbStepper( const G4double yIn[],
const G4double dydx[],
const G4double h,
G4double yOut[])
{
const G4int nvar = 6 ;
G4double dydxTemp[6];
G4double yTemp[6], yTemp2[6];
G4int i;
// Step forward like in the explicit euler case
AdvanceHelix( yIn, dydx, h, yTemp);
// now obtain the new field value at the new point
RightHandSide(yTemp,dydxTemp);
// and also advance along a helix for this field value
AdvanceHelix( yIn, dydxTemp, h, yTemp2);
// we take the average
for( i = 0; i < nvar; i++ )
yOut[i] = 0.5 * ( yTemp[i] + yTemp2[i] );
// NormaliseTangentVector( yOut );
return ;
}
@@ -0,0 +1,46 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4HelixSimpleRunge.cc,v 2.3 1998/11/13 14:30:22 japost Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4HelixSimpleRunge.hh"
#include "G4ThreeVector.hh"
//
// Simple Runge:
// x_1 = x_0 + h * ( dx( t_0+h/2, x_0 + h/2 * dx( t_0, x_0) ) )
// W.Wander <wwc@mit.edu> 12/09/97
//
// -------------------------------------------------------------------------
// second order solver
// take the derivative at a position to be assumed at the middle of the
// Step and add it to the current position.
//
void
G4HelixSimpleRunge::DumbStepper( const G4double yIn[],
const G4double dydx[],
const G4double h,
G4double yOut[])
{
const G4int nvar = 6 ;
G4double dydxTemp[nvar];
G4double yTemp[nvar]; // , yAdd[nvar];
AdvanceHelix( yIn, dydx, 0.5 * h, yTemp);
RightHandSide(yTemp,dydxTemp);
AdvanceHelix( yIn, dydxTemp, h, yOut);
// NormaliseTangentVector( yOut );
return ;
}
@@ -0,0 +1,80 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4ImplicitEuler.cc,v 2.6 1998/11/12 16:16:10 japost Exp $
// GEANT4 tag $Name: geant4-00 $
//
//
// Implicit Euler:
//
// x_1 = x_0 + h/2 * ( dx(t_0,x_0) + dx(t_0+h,x_0+h*dx(t_0,x_0) ) )
//
// second order solver
// Take the current derivative and add it to the current position.
// Take the output and its derivative. Add the mean of both derivatives
// to form the final output
//
// W.Wander <wwc@mit.edu> 12/09/97
// 6.11.98 V.Grichine, new constructor, fNumberOfVariables
//
#include "G4ImplicitEuler.hh"
#include "G4ThreeVector.hh"
/////////////////////////////////////////////////////////////////////////
//
// Constructor
G4ImplicitEuler::G4ImplicitEuler(G4Mag_EqRhs *EqRhs,
G4int numberOfVariables):
G4MagErrorStepper(EqRhs, numberOfVariables),
fNumberOfVariables(numberOfVariables)
{
}
////////////////////////////////////////////////////////////////////////
//
// Destructor
G4ImplicitEuler::~G4ImplicitEuler()
{
;
}
//////////////////////////////////////////////////////////////////////
//
//
void
G4ImplicitEuler::DumbStepper( const G4double yIn[],
const G4double dydx[],
const G4double h,
G4double yOut[])
{
// const G4int nvar = 6 ;
G4double* dydxTemp = new G4double[fNumberOfVariables] ;
G4double* yTemp = new G4double[fNumberOfVariables] ;
G4int i;
for( i = 0; i < fNumberOfVariables; i++ )
{
yTemp[i] = yIn[i] + h*dydx[i] ;
}
RightHandSide(yTemp,dydxTemp);
for( i = 0; i < fNumberOfVariables; i++ )
{
yOut[i] = yIn[i] + 0.5 * h * ( dydx[i] + dydxTemp[i] );
}
// NormaliseTangentVector( yOut );
return ;
}
@@ -0,0 +1,67 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4LineSection.cc,v 2.1 1998/07/12 02:55:20 urbi Exp $
// GEANT4 tag $Name: geant4-00 $
//
// typedef double G4double;
#include "G4LineSection.hh"
G4LineSection::G4LineSection( const G4ThreeVector& PntA,
const G4ThreeVector& PntB )
{
EndpointA= PntA;
VecAtoB=PntB-PntA;
inverse_square_distAB=1.0 / VecAtoB.mag2();
}
G4double G4LineSection::Dist( G4ThreeVector OtherPnt ) const
{
G4double dist_sq;
G4ThreeVector VecAZ;
G4double sq_VecAZ, inner_prod, unit_projection ;
VecAZ= OtherPnt - EndpointA;
sq_VecAZ = VecAZ.mag2();
inner_prod= VecAtoB.dot( VecAZ );
// Determine Projection(AZ on AB) / Length(AB)
//
unit_projection= inner_prod * InvsqDistAB();
if( (0. <= unit_projection ) && (unit_projection <= 1.0 ) )
dist_sq= sq_VecAZ - unit_projection * inner_prod;
else{
// The perpendicular from the point to the line AB meets the line
// in a point outside the line segment!
//
if( unit_projection < 0. ) {
// A is the closest point
dist_sq= sq_VecAZ;
}else{
// B is the closest point
G4ThreeVector EndpointB = EndpointA + VecAtoB;
G4ThreeVector VecBZ = OtherPnt - EndpointB;
dist_sq = VecBZ.mag2();
}
}
return sqrt(dist_sq);
}
G4double G4LineSection::Distline( const G4ThreeVector& OtherPnt,
const G4ThreeVector& LinePntA,
const G4ThreeVector& LinePntB )
{
G4LineSection LineAB( LinePntA, LinePntB ); // Line from A to B
return LineAB.Dist( OtherPnt );
}
@@ -0,0 +1,74 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4MagErrorStepper.cc,v 2.3 1998/11/12 16:17:33 japost Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4MagErrorStepper.hh"
#include "G4ThreeVector.hh"
#include "G4LineSection.hh"
void
G4MagErrorStepper::Stepper( const G4double yInput[],
const G4double dydx[],
const G4double hstep,
G4double yOut[],
G4double yErr[] )
{
const G4int nvar = 6 ;
G4int i;
// correction for Richardson Extrapolation.
G4double correction = 1. / ( (1 << IntegratorOrder()) -1 );
G4double yTemp[7], dydxTemp[6], yIn[7] ;
// Saving yInput because yInput and yOut can be aliases for same array
for(i=0;i<nvar;i++) yIn[i]=yInput[i];
G4double h = hstep * 0.5;
// Do two half steps
DumbStepper(yIn,dydx,h,yTemp);
RightHandSide(yTemp,dydxTemp) ;
DumbStepper(yTemp,dydxTemp,h,yOut);
// Store midpoint, chord calculation
yMidPoint = G4ThreeVector( yTemp[0], yTemp[1], yTemp[2]);
// Do a full Step
h = hstep ;
DumbStepper(yIn,dydx,h,yTemp);
for(i=0;i<nvar;i++) {
yErr[i] = yOut[i] - yTemp[i] ;
yOut[i] += yErr[i]*correction ; // Provides by 1 increased
// order of accuracy
// Richardson Extrapolation
}
yInitial = G4ThreeVector( yIn[0], yIn[1], yIn[2]);
yFinal = G4ThreeVector( yOut[0], yOut[1], yOut[2]);
return ;
}
G4double
G4MagErrorStepper::DistChord() const
{
// Soon: must check whether h/R > 2 pi !!
// Method below is good only for < 2 pi
return G4LineSection::Distline( yMidPoint, yInitial, yFinal );
// This is a class method that gives distance of Mid
// from the Chord between the Initial and Final points.
}
@@ -0,0 +1,183 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4MagHelicalStepper.cc,v 2.7 1998/11/13 14:30:23 japost Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4MagHelicalStepper.hh"
#include "G4ThreeVector.hh"
#include "G4LineSection.hh"
// #include "G4MagneticField.hh"
#include "G4Mag_EqRhs.hh"
// given a purely magnetic field a better approach than adding a straight line
// (as in the normal runge-kutta-methods) is to add helix segments to the
// current position
G4MagHelicalStepper::G4MagHelicalStepper(G4Mag_EqRhs *EqRhs)
: G4MagIntegratorStepper(EqRhs)
{
fPtrMagEqOfMot = EqRhs;
}
void
G4MagHelicalStepper::AdvanceHelix( const G4double yIn[],
const G4double Barr[],
const G4double h,
G4double yHelix[])
{
// const G4int nvar = 6;
const G4double approc_limit = 0.05;
G4ThreeVector Bfld, Bnorm, B_x_P, vperp, vpar;
// G4double norm;
G4double B_d_P; // B_perp;
G4double Theta; // , Theta_1;
G4double R_1;
G4double CosT2, SinT2, CosT, SinT;
G4ThreeVector positionMove, endTangent;
Bfld= G4ThreeVector( Barr[0], Barr[1], Barr[2]);
G4double Bmag = Bfld.mag();
const G4double *pIn = yIn+3;
G4ThreeVector initTangent= G4ThreeVector( pIn[0], pIn[1], pIn[2]);
// for too small magnetic fields there is no curvature
// (include momentum here) FIXME
if( Bmag < 1e-12 ) {
LinearStep( yIn, h, yHelix );
} else {
// Bnorm = Bfld.unit();
Bnorm = (1.0/Bmag)*Bfld;
// calculate the direction of the force
B_x_P = Bnorm.cross(initTangent);
// parallel and perp vectors
B_d_P = Bnorm.dot(initTangent); // this is the fraction of P parallel to B
vpar = B_d_P * Bnorm; // the component parallel to B
vperp= initTangent - vpar; // the component perpendicular to B
// B_v_P = sqrt( 1 - B_d_P * B_d_P); // Fraction of P perp to B
// calculate the radius^-1 of the helix and the stepping angle
R_1 = - fPtrMagEqOfMot->FCof() * Bmag; // / B_v_P - but this cancels
// again in Theta - so we don't need it.
if( fabs(R_1) < 1e-10 ) {
LinearStep( yIn, h, yHelix );
} else {
Theta = R_1 * h; // * B_v_P;
// Trigonometrix
if( Theta < - approc_limit || Theta > approc_limit ) {
SinT2 = sin(0.5 * Theta);
CosT2 = cos(0.5 * Theta);
// SinT = sin(Theta);
// CosT = cos(Theta);
SinT = 2.0 * SinT2 * CosT2;
CosT = 1.0 - 2.0 * SinT2 * SinT2;
} else {
G4double Theta2 = Theta*Theta;
G4double Theta3 = Theta2 * Theta;
G4double Theta4 = Theta2 * Theta2;
SinT = Theta - 1.0/6.0 * Theta3;
CosT = 1 - 0.5 * Theta2 + 1.0/24.0 * Theta4;
SinT2 = 0.5 * Theta - 1.0/48.0 * Theta3;
CosT2 = 1 - 0.125 * Theta2 + 1.0/384 * Theta4;
}
// the actual "rotation"
positionMove = h * ( CosT2 * vperp +
SinT2 * B_x_P + vpar );
endTangent = (CosT * vperp + SinT * B_x_P + vpar);
// Store the resulting position and tangent
yHelix[0] = yIn[0] + positionMove.x();
yHelix[1] = yIn[1] + positionMove.y();
yHelix[2] = yIn[2] + positionMove.z();
yHelix[3] = endTangent.x();
yHelix[4] = endTangent.y();
yHelix[5] = endTangent.z();
// Store and/or calculate parameters for chord distance.
}
}
}
//
// Use the midpoint method to get an error estimate and correction
// modified from G4ClassicalRK4: W.Wander <wwc@mit.edu> 12/09/97
//
void
G4MagHelicalStepper::Stepper( const G4double yInput[],
const G4double dydx[],
const G4double hstep,
G4double yOut[],
G4double yErr[] )
{
const G4int nvar = 6 ;
G4int i;
// correction for Richardson Extrapolation.
G4double correction = 1. / ( (1 << IntegratorOrder()) -1 );
G4double yTemp[7], dydxTemp[6], yIn[7] ;
// Saving yInput because yInput and yOut can be aliases for same array
for(i=0;i<nvar;i++) yIn[i]=yInput[i];
G4double h = hstep * 0.5;
// Do two half steps
DumbStepper(yIn,dydx,h,yTemp);
MagFieldEvaluate(yTemp,dydxTemp) ; // Was : RightHandSide(,)
DumbStepper(yTemp,dydxTemp,h,yOut);
// Store midpoint, chord calculation
yMidPoint = G4ThreeVector( yTemp[0], yTemp[1], yTemp[2]);
// Do a full Step
h = hstep ;
DumbStepper(yIn,dydx,h,yTemp);
for(i=0;i<nvar;i++) {
yErr[i] = yOut[i] - yTemp[i] ;
yOut[i] += yErr[i]*correction ; // Provides by 1 increased
// order of accuracy
// Richardson Extrapolation
}
yInitial = G4ThreeVector( yIn[0], yIn[1], yIn[2]);
yFinal = G4ThreeVector( yOut[0], yOut[1], yOut[2]);
return ;
}
G4double
G4MagHelicalStepper::DistChord() const
{
// Soon: must check whether h/R > 2 pi !!
// Method below is good only for < 2 pi
return G4LineSection::Distline( yMidPoint, yInitial, yFinal );
// This is a class method that gives distance of Mid
// from the Chord between the Initial and Final points.
}
@@ -0,0 +1,305 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4MagIntegratorDriver.cc,v 2.4 1998/11/11 18:51:48 japost Exp $
// GEANT4 tag $Name: geant4-00 $
//
//
//
// Implementation for class G4MagInt_Driver
// Tracking in space dependent magnetic field
//
// History of major changes:
// 7 Oct 96 V. Grichine First version
// 28 Jan 98 W. Wander: Added ability for low order integrators
// 30 Jan 98 J. Apostolakis: Made method parameters into instance variables
#include <math.h>
#include "G4ios.hh"
#include "G4MagIntegratorDriver.hh"
#include "G4FieldTrack.hh"
// Stepsize can increase by no more than 5.0
// and decrease by no more than 1/10. = 0.1
//
const G4double G4MagInt_Driver::max_stepping_increase = 5.0;
const G4double G4MagInt_Driver::max_stepping_decrease = 0.1;
G4bool
G4MagInt_Driver::AccurateAdvance(
G4FieldTrack& y_current,
const G4double hstep,
const G4double eps
)
// const G4double dydx[6], // We could may add this ??
// Runge-Kutta driver with adaptive stepsize control. Integrate starting
// values at y_current over hstep x2 with accuracy eps.
// On output ystart is replaced by values at the end of the integration
// interval.
// RightHandSide is the right-hand side of ODE system.
// The source is similar to odeint routine from NRC p.721-722 .
// OLD:
// The value h1 should be set as a guessed first stepsize, Hmin is the
// minimum allowed stepsize. On output nOK and nBAD are the numbers of
// good and bad (but retried and fixed) steps taken.
{
static const G4int maxstp = 5000;
G4int nstp, i ;
G4double x, hnext, hdid, h ;
// G4double yscal[ncompSVEC];
G4double y[G4FieldTrack::ncompSVEC], dydx[G4FieldTrack::ncompSVEC];
G4double ystart[G4FieldTrack::ncompSVEC];
G4double x1, x2;
G4bool succeeded = true;
// Assume that hstep > 0
// ystart = y_current.PosVelVec();
y_current.DumpToArray( ystart );
x1= y_current.GetCurveLength();
x2= x1 + hstep;
// // Initial Step size "h" is half the interval
// h = 0.5 * hstep;
// Initial Step size "h" is the full interval
h = hstep;
x = x1;
G4int nOK =0, nBAD = 0 ;
for(i=0;i<nvar;i++) y[i] = ystart[i] ;
nstp=1;
do{
pIntStepper->RightHandSide( y, dydx );
if( x+h > x2 ) h = x2 - x ; // When stepsize overshoots, decrease it!
OneGoodStep(y,dydx,x,h,eps,hdid,hnext) ;
if(hdid == h) nOK++ ; else nBAD++ ;
if(fabs(hnext) <= Hmin())
{
succeeded = false;
// If simply a very small interval is being integrated, ...
if( (fabs(hstep) > Hmin()) || (hnext > h) ){
G4cerr<< " Warning (G4MagIntergratorDriver): The stepsize for the "
" next iteration=" << hnext << " is too small - in Step number "
<<nstp << " . Minimum for driver = "<< Hmin() << endl ;
}
}
h = hnext ;
}while (((nstp++)<=maxstp) &&
(x < x2) // Have we reached the end ?
// --> a better test might be x-x2 > an_epsilon
);
for(i=0;i<nvar;i++) ystart[i] = y[i] ;
if(nstp > maxstp){
G4cerr << " Warning (G4MagIntergratorDriver): The number of steps "
<< "used in the Integration driver (Runge-Kutta) is too many. "
<< endl ;
G4cerr << "Integration of the interval was not completed - only a "
<< (x-x1)*100/(x2-x1)<<" % fraction of it was Done." << endl;
succeeded = false;
}
// Put back the values.
y_current.LoadFromArray( ystart );
y_current.SetCurveLength( x );
return succeeded;
} // end of AccurateAdvance ...........................
// ---------------------------------------------------------
void
G4MagInt_Driver::OneGoodStep( G4double y[],
const G4double dydx[],
G4double& x,
const G4double htry,
const G4double eps,
G4double& hdid,
G4double& hnext )
// Driver for one Runge-Kutta Step with monitoring of local truncation error
// to ensure accuracy and adjust stepsize. Input are dependent variable
// array y[0,...,5] and its derivative dydx[0,...,5] at the
// starting value of the independent variable x . Also input are stepsize
// to be attempted htry, and the required accuracy eps. On output y and x
// are replaced by their new values, hdid is the stepsize that was actually
// accomplished, and hnext is the estimated next stepsize.
// This is similar to the function rkqs from the book:
// Numerical Recipes in C: The Art of Scientific Computing (NRC), Second
// Edition, by William H. Press, Saul A. Teukolsky, William T.
// Vetterling, and Brian P. Flannery (Cambridge University Press 1992),
// 16.2 Adaptive StepSize Control for Runge-Kutta, p. 719
{
G4double errmax, h, htemp, xnew ;
G4int i;
G4double yerr[G4FieldTrack::ncompSVEC], ytemp[G4FieldTrack::ncompSVEC];
h = htry ; // Set stepsize to the initial trial value
for (;;)
{
pIntStepper-> Stepper(y,dydx,h,ytemp,yerr) ;
// Evaluate accuracy
//
errmax = sqrt( sqr(yerr[0]) + sqr(yerr[1]) + sqr(yerr[2]) );
errmax /= eps; // Scale relative to required tolerance
if(errmax <= 1.0 ) break ; // Step succeeded.
// Step failed; compute the size of retrial Step.
htemp = GetSafety()*h*pow(errmax,GetPshrnk()) ;
if(htemp >= 0.1*h) h = htemp ; // Truncation error too large,
else h = 0.1*h ; // reduce stepsize, but no more
// than a factor of 10
xnew = x + h ;
if(xnew == x) {
G4cerr<<"Stepsize underflow in Stepper "<<endl ;
break;
}
}
// Compute size of next Step
if(errmax > errcon) hnext = GetSafety()*h*pow(errmax,GetPgrow()) ;
else hnext = max_stepping_increase*h ;
// No more than a factor of 5 increase
x += (hdid = h) ;
for(i=0;i<nvar;i++) y[i] = ytemp[i] ;
// delete[] ytemp ;
// delete[] yerr ;
return ;
} // end of OneGoodStep .............................
//----------------------------------------------------------------------
// QuickAdvance just tries one Step - it does not ensure accuracy
//
G4bool G4MagInt_Driver::QuickAdvance(
G4FieldTrack& y_posvel, // INOUT
const G4double dydx[],
G4double hstep, // In
G4double& dchord_step,
G4double& dyerr_len )
{
G4double yerr_vec[G4FieldTrack::ncompSVEC], yarrin[G4FieldTrack::ncompSVEC], yarrout[G4FieldTrack::ncompSVEC];
G4double s_start;
// Move data into array
y_posvel.DumpToArray( yarrin ); // yarrin <== y_posvel
s_start = y_posvel.GetCurveLength();
// Do an Integration Step
pIntStepper-> Stepper(yarrin, dydx, hstep, yarrout, yerr_vec) ;
// Estimate curve-chord distance
dchord_step= pIntStepper-> DistChord();
// Put back the values.
y_posvel.LoadFromArray( yarrout ); // yarrout ==> y_posvel
y_posvel.SetCurveLength( s_start + hstep );
// A single measure of the error
// TO-DO : account for tangent vector, energy, spin, ... ?
dyerr_len= sqrt( sqr(yerr_vec[0])+sqr(yerr_vec[1])+sqr(yerr_vec[2]));
#ifdef RETURN_A_NEW_STEP_LENGTH
// The following step cannot be done here because "eps" is not known.
dyerr_len /= eps;
// Look at the velocity deviation ?
// sqr(yerr_vec[3])+sqr(yerr_vec[4])+sqr(yerr_vec[5]));
// Look at the change in the velocity (squared maybe ..)
G4double veloc_square = y_posvel.GetVelocity().mag2();
// Set suggested new step
hstep= ComputeNewStepSize( dyerr_len, hstep);
#endif
return true;
}
// --------------------------------------------------------------------------
// This method computes new step sizes - but does not limit changes to
// within certain factors
//
G4double
G4MagInt_Driver::ComputeNewStepSize(
G4double errMaxNorm, // max error (normalised)
G4double hstepCurrent) // current step size
{
G4double hnew;
// Compute size of next Step for a failed step
if(errMaxNorm > 1.0 ) {
// Step failed; compute the size of retrial Step.
hnew = GetSafety()*hstepCurrent*pow(errMaxNorm,GetPshrnk()) ;
}else{
// Compute size of next Step for a successful step
hnew = GetSafety()*hstepCurrent*pow(errMaxNorm,GetPgrow()) ;
}
return hnew;
}
// --------------------------------------------------------------------------
// This method computes new step sizes - but does not limit changes to
// within certain factors
//
// It shares its logic with AccurateAdvance, so they should eventually
// be merged ??
G4double
G4MagInt_Driver::ComputeNewStepSize_WithinLimits(
G4double errMaxNorm, // max error (normalised)
G4double hstepCurrent) // current step size
{
G4double hnew;
// Compute size of next Step for a failed step
if(errMaxNorm > 1.0 ) {
// Step failed; compute the size of retrial Step.
hnew = GetSafety()*hstepCurrent*pow(errMaxNorm,GetPshrnk()) ;
if(hnew < max_stepping_decrease*hstepCurrent)
hnew = max_stepping_decrease*hstepCurrent ;
// reduce stepsize, but no more
// than this factor (value= 1/10)
}else{
// Compute size of next Step for a successful step
if(errMaxNorm > errcon) hnew = GetSafety()*hstepCurrent*pow(errMaxNorm,GetPgrow()) ;
else hnew = max_stepping_increase * hstepCurrent ;
// No more than a factor of 5 increase
}
return hnew;
}
@@ -0,0 +1,23 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4MagIntegratorStepper.cc,v 2.0 1998/07/02 16:56:24 gunter Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4MagIntegratorStepper.hh"
// Constructor for creation of coefficient in Lorentz motion equation
// as well as initialisation of geometry constants.
// particleCharge is the particle charge in the elementary charge
// momentumXc is the particle momentum multiplied by the speed of light in MeV,
//
G4MagIntegratorStepper::G4MagIntegratorStepper(G4Mag_EqRhs *EqRhs)
{
theEquation_Rhs= EqRhs;
}
@@ -0,0 +1,42 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Mag_EqRhs.cc,v 2.3 1998/11/12 16:19:40 japost Exp $
// GEANT4 tag $Name: geant4-00 $
//
// This is the standard right-hand side for equation of motion
// in a pure Magnetic Field .
//
// Other that might be required are:
// i) is when using a moving reference frame ... or
// ii) extending for other forces, eg an electric field
//
// J. Apostolakis, January 13th, 1997
//
#include "G4MagneticField.hh"
#include "G4Mag_EqRhs.hh"
#include "G4EquationOfMotion.hh"
const G4double G4Mag_EqRhs::fUnitConstant = 0.299792458 * (GeV/(tesla*m));
// Constructor Implementation
//
G4Mag_EqRhs::G4Mag_EqRhs( G4MagneticField *magField )
: G4EquationOfMotion(magField)
{
}
void
G4Mag_EqRhs::SetChargeMomentumMass( const G4double particleCharge, // e+ units
const G4double MomentumXc,
const G4double particleMass)
{
fCof_val = fUnitConstant*particleCharge/MomentumXc; // B must be in Tesla
// fMass = particleMass;
}
G4Mag_EqRhs::~G4Mag_EqRhs() { }
@@ -0,0 +1,38 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Mag_UsualEqRhs.cc,v 2.2 1998/11/18 21:11:38 japost Exp $
// GEANT4 tag $Name: geant4-00 $
//
//
// This is the standard right-hand side for equation of motion.
//
// The only case another is required is when using a moving reference
// frame ... or extending the class to include additional Forces,
// eg an electric field
//
// J. Apostolakis, January 13th, 1997
//
#include "G4Mag_UsualEqRhs.hh"
void
G4Mag_UsualEqRhs::EvaluateRhsGivenB( const G4double y[],
const G4double B[3],
G4double dydx[] ) const
{
G4double velocity_mag_square = sqr(y[3]) + sqr(y[4]) + sqr(y[5]);
G4double inv_velocity_magnitude = 1.0 / sqrt( velocity_mag_square );
dydx[0] = y[3] * inv_velocity_magnitude; // (d/ds)x = Vx/V
dydx[1] = y[4] * inv_velocity_magnitude; // (d/ds)y = Vy/V
dydx[2] = y[5] * inv_velocity_magnitude; // (d/ds)z = Vz/V
dydx[3] = FCof()*(y[4]*B[2] - y[5]*B[1]) ; // Ax = a*(Vy*Bz - Vz*By)
dydx[4] = FCof()*(y[5]*B[0] - y[3]*B[2]) ; // Ay = a*(Vz*Bx - Vx*Bz)
dydx[5] = FCof()*(y[3]*B[1] - y[4]*B[0]) ; // Az = a*(Vx*By - Vy*Bx)
return ;
}
@@ -0,0 +1,567 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4PropagatorInField.cc,v 2.11 1998/11/24 19:17:32 japost Exp $
// GEANT4 tag $Name: geant4-00 $
//
//
//
// This routine implements an algorithm to track a particle in a //
// non-uniform magnetic field. It utilises an ODE solver (with //
// the Runge - Kutta method) to evolve the particle, and drives it //
// until the particle has traveled a set distance or it enters a new
// volume.
//
// Caveat: tracking is not exact - volumes can be missed!
//
//
// 14.10.96 John Apostolakis, design and implementation
// 17.03.97 John Apostolakis, renaming new set functions being added
//
#include "G4PropagatorInField.hh"
#include "G4ios.hh"
#include <iomanip.h>
const G4double G4PropagatorInField::delta_intersection_val= 0.1 * mm;
const G4double G4PropagatorInField::delta_one_step_val = 0.25 * mm;
G4double
G4PropagatorInField::
ComputeStep(const G4ThreeVector & StartPointA,
const G4ThreeVector & Velocity, // Unit or non
G4double CurrentProposedStepLength,
G4double &currentSafety, // In/Out
G4VPhysicalVolume *pPhysVol )
// Compute the next geometric Step for simple magnetic field
{
G4FieldTrack aFieldTrack =
G4FieldTrack( StartPointA,
Velocity,
0.0, // length of path
0.0, // energy
0.0, // lab tof
0.0, // proper tof
0 );
// Do the Transport in the field (non recti-linear)
return this->ComputeStep( aFieldTrack,
CurrentProposedStepLength,
currentSafety );
}
G4double
G4PropagatorInField::
ComputeStep(G4FieldTrack& pFieldTrack,
G4double CurrentProposedStepLength,
G4double& currentSafety, // IN/OUT
G4VPhysicalVolume *pPhysVol)
// Compute the next geometric Step
{
// Parameters for adaptive Runge-Kutta integration
//
G4double h_TrialStepSize; // 1st Step Size
G4double TruePathLength;
G4double StepTaken= 0.0;
G4double s_length_taken;
G4bool intersects;
G4bool first_substep= true;
G4double NewSafety;
fParticleIsLooping= false;
G4FieldTrack CurrentState(pFieldTrack);
#if 0
CurrentState.SetVelocity( pFieldTrack.GetMomentumDir() );
// For now, must utilize unit "velocity" J.A. Nov 17, 98
// Problem in setting the energy in this case .... (and in E field)
#endif
G4FieldTrack OriginalState= CurrentState;
// If the Step length is "infinite", then an approximate-maximum Step lenght
// (used to calculate the relative accuracy) must be guessed.
//
if( CurrentProposedStepLength >= kInfinity ){
G4ThreeVector StartPointA, VelocityUnit;
StartPointA = pFieldTrack.GetPosition();
VelocityUnit= pFieldTrack.GetMomentumDir();
CurrentProposedStepLength= 1.e3 * ( 10.0 * cm +
fNavigator->GetWorldVolume()->GetLogicalVolume()->
GetSolid()->DistanceToOut(StartPointA, VelocityUnit) ) ;
}
this->SetEpsilonStep( DeltaOneStep() / CurrentProposedStepLength);
G4int do_loop_count=0;
do
{
do_loop_count++;
G4FieldTrack SubStepStartState= CurrentState;
G4ThreeVector SubStartPoint= CurrentState.GetPosition();
// WAS = G4Navigator::Locate...
if( !first_substep)
{
fNavigator->LocateGlobalPointWithinVolume( SubStartPoint );
}
// First figure out how far to evolve the particle !
// -------------------------------------------------
// and (later) with what accuracy to calculate this path.
//
h_TrialStepSize= CurrentProposedStepLength - StepTaken ;
// Next evolve it as far as this allows.
// ---------------------------------------
//
// B <- Integrator - limited by the "chord miss" rule.
//
s_length_taken= GetChordFinder()->AdvanceChordLimited(
CurrentState, // Position & velocity
h_TrialStepSize,
GetEpsilonStep() );
// On Exit:
// CurrentState is updated with the final position and velocity.
G4ThreeVector EndPointB= CurrentState.Position();
// Calculate the direction and length of the chord AB
G4ThreeVector ChordAB_Vector= EndPointB - SubStartPoint;
G4double ChordAB_Length= ChordAB_Vector.mag(); // Magnitude (norm)
G4ThreeVector ChordAB_Dir= ChordAB_Vector.unit();
// Check whether any volumes are encountered by the chord AB
G4double LinearStepLength =
fNavigator->ComputeStep( SubStartPoint, ChordAB_Dir,
ChordAB_Length, NewSafety);
if( first_substep )
{
currentSafety= NewSafety;
}
// It might also be possible to update safety in other steps, but
// it must be Done with care. J.Apostolakis August 5th, 1997
intersects= (LinearStepLength <= ChordAB_Length);
// G4Navigator contracts to return k_infinity if len==asked
// and it did not find a surface boundary at that length
LinearStepLength = min( LinearStepLength, ChordAB_Length);
if( intersects )
{
// E <- Intersection Point of chord AB and either volume A's surface
// or a daughter volume's surface ..
G4ThreeVector pointE= SubStartPoint + LinearStepLength * ChordAB_Dir;
G4FieldTrack IntersectPointVelct_G(CurrentState); // FT-Def-Construct
// Find the intersection point of AB true path with the surface
// of vol(A) given our current "estimate" point E.
G4bool found_intersection=
LocateIntersectionPoint( SubStepStartState, CurrentState,
pointE, IntersectPointVelct_G );
if( found_intersection )
{
// G is our EndPoint ...
G4ThreeVector IntersectPoint_G = IntersectPointVelct_G.Position();
End_PointAndTangent= IntersectPointVelct_G;
G4ThreeVector NewChord= IntersectPoint_G - SubStartPoint;
// LinearStepLength= NewChord.mag();
StepTaken =
TruePathLength= IntersectPointVelct_G.CurveS()
- OriginalState.CurveS(); // which is Zero now.
#ifdef G4VERBOSE
if( Verbose() > 0 ){
G4cout << " Found an intersection after a Step of length " <<
StepTaken << endl;
}
#endif
// TruePathLength= StepTaken;
}
else
{
// "Minor" chords do not intersect
intersects= false;
}
}
if( ! intersects )
{
StepTaken += s_length_taken;
}
first_substep= false;
#ifdef G4VERBOSE
if( Verbose() > 0 )
printStatus( SubStepStartState, // or OriginalState,
CurrentState,
CurrentProposedStepLength,
NewSafety,
do_loop_count,
pPhysVol);
#endif
}
while( (!intersects ) && (StepTaken < CurrentProposedStepLength)
&& ( do_loop_count < GetMaxLoopCount() ) );
#ifdef G4VERBOSE
if( do_loop_count >= GetMaxLoopCount() ){
// G4cerr << "G4PropagateInField: Particle is looping - must be killed" << endl;
G4cerr << "G4PropagateInField: Particle is looping - "
<< " tracking in field will be stopped. " << endl;
G4cerr << " Has performed " << do_loop_count << " steps in Field "
<< " while a maximum of " << GetMaxLoopCount() << " are allowed. "
<< endl;
//G4cerr << " In future this will be treated better/quicker. " << endl;
fParticleIsLooping= true;
}
#endif
if( ! intersects )
{
// Chord AB or "minor chords" do not intersect
// B is the endpoint Step of the current Step.
// [ But if we were angle limited we could use B
// as a new starting point ? ]
// On return we specify the endpoint, point B
End_PointAndTangent= CurrentState;
// LinearStepLength= ChordAB_Length;
TruePathLength= StepTaken;
} // end if(!intersects)
// Set pFieldTrack to the return value
pFieldTrack =End_PointAndTangent;
#ifdef G4VERBOSE
// Check that "s" is correct
if( fabs(OriginalState.CurveS() + TruePathLength
- End_PointAndTangent.CurveS()) > 3.e-4 * TruePathLength )
{
G4cerr << " Error in G4PropagatorInField: Curve lenght mis-match, is advancement wrong ? ";
G4cerr << " The curve length of the endpoint should be "
<< OriginalState.CurveS() + TruePathLength
<< " and is " << End_PointAndTangent.CurveS()
<< " a difference of "
<< OriginalState.CurveS() + TruePathLength
- End_PointAndTangent.CurveS() << endl;
}
#endif
return TruePathLength;
}
// --------------------------------------------------------------------------
// G4bool
// G4PropagatorInField::LocateIntersectionPoint(
// const G4FieldTrack& CurveStartPointVelocity, // A
// const G4FieldTrack& CurveEndPointVelocity, // B
// const G4ThreeVector& TrialPoint, // E
// G4FieldTrack& IntersectPointVelocity) // Output
// --------------------------------------------------------------------------
//
// Function that returns the intersection of the true path with the surface
// of the current volume (either the external one or the inner one with one
// of the daughters
//
// A = Initial point
// B = another point
//
// Both A and B are assumed to be on the true path.
//
// E is the first point of intersection of the chord AB with
// a volume other than A (on the surface of A or of a daughter)
//
// First Version: October 16th, 1996 John Apostolakis, CERN CN/ASD
// Modified: January 22nd, 1997 J.A. IT/ASD
//
// Convention of Use :
// i) If it returns "true", then IntersectionPointVelocity is set
// to the approximate intersection point.
// ii) If it returns "false", no intersection was found and
// IntersectionPointVelocity is invalid.
// --------------------------------------------------------------------------
G4bool
G4PropagatorInField::LocateIntersectionPoint(
const G4FieldTrack& CurveStartPointVelocity, // A
const G4FieldTrack& CurveEndPointVelocity, // B
const G4ThreeVector& TrialPoint, // E
G4FieldTrack& IntersectPointVelocity) // Output
{
// Find Intersection Point ( A, B, E ) of true path AB - start at E.
G4bool found_approximate_intersection = false;
G4bool there_is_no_intersection = false;
G4FieldTrack CurrentA_PointVelocity= CurveStartPointVelocity;
G4FieldTrack CurrentB_PointVelocity= CurveEndPointVelocity;
G4ThreeVector CurrentE_Point= TrialPoint;
G4FieldTrack ApproxIntersecPointV(CurveEndPointVelocity); // FT-Def-Construct
G4double NewSafety;
G4bool first_step= true;
G4int substep_no= 0;
G4VPhysicalVolume *pPhysVol;
do{ // REPEAT
G4ThreeVector Point_A= CurrentA_PointVelocity.Position();
G4ThreeVector Point_B= CurrentB_PointVelocity.Position();
// F = a point on true AB path close to point E (the closest if possible)
//
ApproxIntersecPointV= GetChordFinder()->ApproxCurvePointV(
CurrentA_PointVelocity,
CurrentB_PointVelocity,
CurrentE_Point,
this->GetEpsilonStep() );
// The above function is the most difficult part ...
//
// Another approach would be for the curved true path
// to be an object and this should be a member function.
// -> The Curve Start and End point would not be needed as arguments.
//
G4ThreeVector CurrentF_Point= ApproxIntersecPointV.Position();
// First check whether EF is small - then F is a good approx. point
//
// Calculate the length and direction of the chord AF
// ChordEF_Vector= Chord_Vector(CurrentE_Point, CurrentF_Point);
// ------------
G4ThreeVector ChordEF_Vector = CurrentF_Point - CurrentE_Point;
if ( ChordEF_Vector.mag2() <= sqr(DeltaIntersection()) ){
found_approximate_intersection = true;
// Create the "point" return value
// IntersectPointVelocity.SetCurvePnt(
// CurrentE_Point,
// ApproxIntersecPointV.GetVelocity(),
// ApproxIntersecPointV.CurveS() );
IntersectPointVelocity = ApproxIntersecPointV;
IntersectPointVelocity.SetPosition( CurrentE_Point );
// Note: in order to return a point on the boundary,
// we must return E. But it is F on the curve.
// So we must "cheat": we are using the position at point E and
// the velocity at point F !!!
//
// This must limit the length we can allow for displacement!
}else{ // E is NOT close enough to the curve (ie point F).
if( !first_step){
// Check whether any volumes are encountered by the chord AF
//----------------------------------------------------------
fNavigator->LocateGlobalPointWithinVolume( Point_A );
// This locate is needed in all cases except for the
// original point A, because - presumably - that was
// called at the start of the physical Step
}
first_step= false;
// Calculate the length and direction of the chord AF
G4ThreeVector ChordAF_Vector= CurrentF_Point - Point_A;
G4double ChordAF_Length= ChordAF_Vector.mag();
G4ThreeVector ChordAF_Dir= ChordAF_Vector.unit();
G4double stepLength =
fNavigator->ComputeStep( Point_A, ChordAF_Dir,
ChordAF_Length, NewSafety);
G4bool Intersects_AF = (stepLength <= ChordAF_Length);
stepLength = min(stepLength, ChordAF_Length);
if( Intersects_AF ){
// There is an intersection of AF with a volume boundary
// G <- First Intersection of Chord AF
//
G4ThreeVector PointG= Point_A + stepLength * ChordAF_Dir;
// G is our new Candidate for the intersection point.
// It replaces "E" and we will repeat the test to see if
// it is a good enough approximate point for us.
// B <- F
// E <- G
CurrentB_PointVelocity= ApproxIntersecPointV;
CurrentE_Point= PointG;
// Else (not Intersects_AF)
}else{
// In this case:
// There is NO intersection of AF with a volume boundary.
// We must continue the search in the segment FB!
// Check whether any volumes are encountered by the chord FB
//----------------------------------------------------------
// Calculate the length and direction of the chord AF
G4ThreeVector ChordFB_Vector= Point_B - CurrentF_Point;
G4double ChordFB_Length= ChordFB_Vector.mag();
G4ThreeVector ChordFB_Dir= ChordFB_Vector.unit();
fNavigator->LocateGlobalPointWithinVolume( CurrentF_Point );
G4double stepLength =
fNavigator->ComputeStep( CurrentF_Point, ChordFB_Dir,
ChordFB_Length, NewSafety);
G4bool Intersects_FB = stepLength <= ChordFB_Length;
stepLength = min(stepLength, ChordFB_Length);
if( Intersects_FB ) {
// There is an intersection of FB with a volume boundary
// H <- First Intersection of Chord FB
//
G4ThreeVector PointH= CurrentF_Point + stepLength * ChordFB_Dir;
// H is our new Candidate for the intersection point.
// It replaces "E" and we will repeat the test to see if
// it is a good enough approximate point for us.
// Note that F must be in volume volA (the same as A)
// (otherwise AF would meet a volume boundary!)
// A <- F
// E <- H
CurrentA_PointVelocity= ApproxIntersecPointV;
CurrentE_Point= PointH;
}else{ // (not Intersects_FB)
//
// There is NO intersection of FB with a volume boundary
// This means that somehow a volume intersected the original
// chord but misses the chord (or series of chords)
// we have used.
//
there_is_no_intersection= true;
//
// the value of IntersectPointVelocity returned is not valid
} // Endif (Intersects_FB)
} // Endif (Intersects_AF)
} // EndIf ( E is close enough to the curve, ie point F. )
// tests ChordAF_Vector.mag() <= maximum_lateral_displacement
#ifdef G4VERBOSE
if( Verbose() > 1 )
printStatus( CurveStartPointVelocity, CurveEndPointVelocity,
-1.0, NewSafety, substep_no, 0); // startVolume);
#endif
substep_no++;
} while ( ( ! found_approximate_intersection ) &&
( ! there_is_no_intersection ) ); // UNTIL found or failed
return !there_is_no_intersection ; // Success or failure
}
void G4PropagatorInField::printStatus(
const G4FieldTrack& StartFT,
const G4FieldTrack& CurrentFT,
G4double requestStep,
G4double safety,
G4int Step,
G4VPhysicalVolume* startVolume)
// G4VPhysicalVolume* endVolume)
{
const G4int verboseLevel=1;
const G4ThreeVector StartPosition= StartFT.GetPosition();
const G4ThreeVector StartUnitVelocity= StartFT.GetMomentumDir();
const G4ThreeVector CurrentPosition= CurrentFT.GetPosition();
const G4ThreeVector CurrentUnitVelocity= CurrentFT.GetMomentumDir();
G4double step_len= CurrentFT.GetCurveLength()
- StartFT.GetCurveLength();
if( (Step == 0) && (verboseLevel <= 3) )
{
G4cout.precision(3);
// G4cout.setf(ios_base::fixed,ios_base::floatfield);
G4cout << setw( 6) << " "
<< setw( 25) << " Current Position and Direction" << " "
<< endl;
G4cout << setw( 5) << "Step#" << " "
<< setw( 9) << "X(mm)" << " "
<< setw( 9) << "Y(mm)" << " "
<< setw( 9) << "Z(mm)" << " "
<< setw( 7) << " N_x " << " "
<< setw( 7) << " N_y " << " "
<< setw( 7) << " N_z " << " "
// << setw( 9) << "KinE(MeV)" << " "
// << setw( 9) << "dE(MeV)" << " "
<< setw( 9) << "StepLen" << " "
<< setw( 9) << "PhsStep" << " "
<< setw(12) << "StartSafety" << " "
<< setw(18) << "NextVolume" << " "
<< endl;
}
//
if( verboseLevel > 3 )
{
// G4cout << "Current Position is " << CurrentPosition << endl
// << " and UnitVelocity is " << CurrentUnitVelocity << endl;
G4cout << "Step taken was " << step_len
<< " out of PhysicalStep= " << requestStep << endl;
G4cout << "Final safety is: " << safety << endl;
G4cout << "Chord length = " << (CurrentPosition-StartPosition).mag() << endl;
G4cout << endl;
}
else // if( verboseLevel > 0 )
{
G4cout.precision(3);
G4cout << setw( 5) << Step << " "
<< setw( 9) << CurrentPosition.x() << " "
<< setw( 9) << CurrentPosition.y() << " "
<< setw( 9) << CurrentPosition.z() << " "
<< setw( 7) << CurrentUnitVelocity.x() << " "
<< setw( 7) << CurrentUnitVelocity.y() << " "
<< setw( 7) << CurrentUnitVelocity.z() << " "
// << setw( 9) << KineticEnergy << " "
// << setw( 9) << EnergyDifference << " "
<< setw( 9) << step_len << " "
<< setw( 9) << requestStep << " "
<< setw(12) << safety << " ";
if( startVolume != 0) {
G4cout << setw(12) << startVolume->GetName() << " ";
} else {
G4cout << setw(12) << "OutOfWorld" << " ";
}
#if 0
if( CurrentVolume != 0)
{
G4cout << setw(12) << CurrentVolume()->GetName() << " ";
}
else
{
G4cout << setw(12) << "OutOfWorld or Unknown" << " ";
}
#endif
G4cout << endl;
}
}
@@ -0,0 +1,239 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4RKG3_Stepper.cc,v 2.4 1998/11/12 17:20:41 japost Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4RKG3_Stepper.hh"
#include "G4ThreeVector.hh"
#include "G4LineSection.hh"
void G4RKG3_Stepper::Stepper( const G4double yInput[7],
const G4double dydx[7],
const G4double Step,
G4double yOut[7],
G4double yErr[])
{
G4double B[3];
// G4double yderiv[6];
// G4double alpha2, beta2;
const G4int nvar = 6 ;
// G4double beTemp2, beta2=0;
G4int i;
G4double by15 = 1. / 15. ; // was 0.066666666 ;
G4double yTemp[7], dydxTemp[6], yIn[7] ;
// Saving yInput because yInput and yOut can be aliases for same array
for(i=0;i<nvar;i++) yIn[i]=yInput[i];
G4double h = Step * 0.5;
// Do two half steps
// To obtain B1 ...
// GetEquationOfMotion()->GetFieldValue(yIn,B);
// G4RKG3_Stepper::StepWithEst(yIn, dydx, Step, yOut,alpha2, beta2, B1, B2 );
StepNoErr(yIn, dydx,h, yTemp,B) ;
// RightHandSide(yTemp,dydxTemp) ;
GetEquationOfMotion()->EvaluateRhsGivenB(yTemp,B,dydxTemp) ;
StepNoErr(yTemp,dydxTemp,h,yOut,B); // ,beTemp2) ;
// beta2 += beTemp2;
// beta2 *= 0.5;
// Store midpoint, chord calculation
fyMidPoint = G4ThreeVector( yTemp[0], yTemp[1], yTemp[2]);
// Do a full Step
h *= 2 ;
StepNoErr(yIn,dydx,h,yTemp,B); // ,beTemp2) ;
for(i=0;i<nvar;i++)
{
yErr[i] = yOut[i] - yTemp[i] ;
yOut[i] += yErr[i]*by15 ; // Provides 5th order of accuracy
}
// for(i=0;i<ncomp;i++)
// {
// fyInitial[i] = yIn[i];
// fyFinal[i] = yOut[i];
// }
fyInitial = G4ThreeVector( yIn[0], yIn[1], yIn[2]);
fyFinal = G4ThreeVector( yOut[0], yOut[1], yOut[2]);
// beta2 += beTemp2 ;
// beta2 *= 0.5 ;
// NormaliseTangentVector( yOut ); // Deleted
return ;
}
// ---------------------------------------------------------------------------
// Integrator for RK from G3 with evaluation of error in solution and delta
// geometry based on naive similarity with the case of uniform magnetic field.
// B1[3] is input and is the first magnetic field values
// B2[3] is output and is the final magnetic field values.
void G4RKG3_Stepper::StepWithEst( const G4double tIn[7],
const G4double dydx[7],
const G4double Step,
G4double tOut[7],
G4double& alpha2,
G4double& beta2,
const G4double B1[3],
G4double B2[3]) // const
{
G4Exception(" G4ClassicalRK4::StepWithEst ERROR: this Method is no longer used.");
#if 0
// const G4int nvar = 6 ;
G4double K1[7],K2[7],K3[7],K4[7] ;
G4double tTemp[7], yderiv[6] ;
G4double B[3];
G4int i ;
alpha2 = 0 ;
beta2 = 0 ;
// GetEquationOfMotion()->EvaluateRhsReturnB(tIn,dydx,B1) ;
for(i=0;i<3;i++)
{
K1[i] = Step * dydx[i+3];
tTemp[i] = tIn[i] + Step*(0.5*tIn[i+3] + 0.125*K1[i]) ;
tTemp[i+3] = tIn[i+3] + 0.5*K1[i] ;
alpha2 += B1[i]*B1[i] ;
beta2 += K1[i]*K1[i] ;
}
GetEquationOfMotion()->EvaluateRhsReturnB(tTemp,yderiv,B) ; // Calculates yderive & returns B too!
// GetFieldValue(tTemp,B) ;
for(i=0;i<3;i++)
{
K2[i] = Step * yderiv[i+3];
tTemp[i+3] = tIn[i+3] + 0.5*K2[i] ;
alpha2 += 2*B[i]*B[i] ;
beta2 += K2[i]*K2[i] ;
}
// Given B, calculate yderiv !
GetEquationOfMotion()->EvaluateRhsGivenB(tTemp,B,yderiv) ;
for(i=0;i<3;i++)
{
K3[i] = Step * yderiv[i+3];
tTemp[i] = tIn[i] + Step*(tIn[i+3] + 0.5*K3[i]) ;
tTemp[i+3] = tIn[i+3] + K3[i] ;
beta2 += K3[i]*K3[i] ;
}
// Calculates y-deriv(atives) & returns B too!
GetEquationOfMotion()->EvaluateRhsReturnB(tTemp,yderiv,B2) ;
G4double drds2 = 0 ;
for(i=0;i<3;i++) // Output trajectory vector
{
K4[i] = Step * yderiv[i+3];
tOut[i] = tIn[i] + Step*(tIn[i+3] + (K1[i] + K2[i] + K3[i])/6.0) ;
tOut[i+3] = tIn[i+3] + (K1[i] + 2*K2[i] + 2*K3[i] +K4[i])/6.0 ;
alpha2 += B2[i]*B2[i] ;
beta2 += K4[i]*K4[i] ;
// drds2 += tOut[i+3]*tOut[i+3] ;
}
alpha2 *= sqr(GetEquationOfMotion()->FCof()*Step) * 0.25 ;
beta2 *= 0.25 ;
// drds2 = sqrt(drds2) ;
// for(i=0;i<3;i++) {tOut[i+3] /= drds2 ; } // Unit vector along momentum
// NormaliseTangentVector( tOut ); // Deleted
#endif
return ;
}
// -----------------------------------------------------------------
// Integrator RK Stepper from G3 with only two field evaluation per Step.
// It is used in propagation initial Step by small substeps after solution
// error and delta geometry considerations. B[3] is magnetic field which
// is passed from substep to substep.
void G4RKG3_Stepper::StepNoErr(const G4double tIn[7],
const G4double dydx[7],
const G4double Step,
G4double tOut[7],
G4double B[3] ) // const
{
// Copy and edit the routine above, to delete alpha2, beta2, ...
G4double K1[7],K2[7],K3[7],K4[7] ;
G4double tTemp[7], yderiv[6] ;
G4int i ;
G4Exception(" G4ClassicalRK4::StepNoErr ERROR: this Method should no longer be used.");
#if 0
// GetEquationOfMotion()->EvaluateRhsReturnB(tIn,dydx,B1) ;
for(i=0;i<3;i++)
{
K1[i] = Step * dydx[i+3];
tTemp[i] = tIn[i] + Step*(0.5*tIn[i+3] + 0.125*K1[i]) ;
tTemp[i+3] = tIn[i+3] + 0.5*K1[i] ;
}
GetEquationOfMotion()->EvaluateRhsReturnB(tTemp,yderiv,B) ; // Calculates yderive
// & returns B too!
for(i=0;i<3;i++)
{
K2[i] = Step * yderiv[i+3];
tTemp[i+3] = tIn[i+3] + 0.5*K2[i] ;
}
// Given B, calculate yderiv !
GetEquationOfMotion()->EvaluateRhsGivenB(tTemp,B,yderiv) ;
for(i=0;i<3;i++)
{
K3[i] = Step * yderiv[i+3];
tTemp[i] = tIn[i] + Step*(tIn[i+3] + 0.5*K3[i]) ;
tTemp[i+3] = tIn[i+3] + K3[i] ;
}
// Calculates y-deriv(atives) & returns B too!
GetEquationOfMotion()->EvaluateRhsReturnB(tTemp,yderiv,B) ;
G4double drds2 = 0 ;
for(i=0;i<3;i++) // Output trajectory vector
{
K4[i] = Step * yderiv[i+3];
tOut[i] = tIn[i] + Step*(tIn[i+3] + (K1[i] + K2[i] + K3[i])/6.0) ;
tOut[i+3] = tIn[i+3] + (K1[i] + 2*K2[i] + 2*K3[i] +K4[i])/6.0 ;
}
// NormaliseTangentVector( tOut );
#endif
return ;
}
// ---------------------------------------------------------------------------
G4double G4RKG3_Stepper::DistChord() const
{
// Soon: must check whether h/R > 2 pi !!
// Method below is good only for < 2 pi
return G4LineSection::Distline( fyMidPoint, fyInitial, fyFinal );
// This is a class method that gives distance of Mid
// from the Chord between the Initial and Final points.
}
@@ -0,0 +1,90 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4SimpleHeum.cc,v 2.6 1998/11/17 18:20:11 japost Exp $
// GEANT4 tag $Name: geant4-00 $
//
// Simple Heum:
// x_1 = x_0 + h *
// 1/4 * dx(t0,x0) +
// 3/4 * dx(t0+2/3*h, x0+2/3*h*(dx(t0+h/3,x0+h/3*dx(t0,x0))))
//
// third order solver
//
// W.Wander <wwc@mit.edu> 12/09/97
// 6.11.98. V.Grichine new data member fNumberOfVariables
#include "G4SimpleHeum.hh"
#include "G4ThreeVector.hh"
///////////////////////////////////////////////////////////////////////////
//
// Constructor
G4SimpleHeum::G4SimpleHeum(G4Mag_EqRhs *EqRhs, G4int num_variables):
G4MagErrorStepper(EqRhs, num_variables),
fNumberOfVariables(num_variables)
{
dydxTemp = new G4double[fNumberOfVariables] ;
dydxTemp2 = new G4double[fNumberOfVariables] ;
yTemp = new G4double[fNumberOfVariables] ;
yTemp2 = new G4double[fNumberOfVariables] ;
}
//////////////////////////////////////////////////////////////////////////
//
// Destructor
G4SimpleHeum::~G4SimpleHeum()
{
delete dydxTemp;
delete dydxTemp2;
delete yTemp;
delete yTemp2;
}
//////////////////////////////////////////////////////////////////////
//
//
void
G4SimpleHeum::DumbStepper( const G4double yIn[],
const G4double dydx[],
const G4double h,
G4double yOut[])
{
// const G4int nvar = 6 ;
G4int i;
for( i = 0; i < fNumberOfVariables; i++ )
{
yTemp[i] = yIn[i] + (1.0/3.0) * h * dydx[i] ;
}
RightHandSide(yTemp,dydxTemp);
for( i = 0; i < fNumberOfVariables; i++ )
{
yTemp2[i] = yIn[i] + (2.0/3.0) * h * dydxTemp[i] ;
}
RightHandSide(yTemp2,dydxTemp2);
for( i = 0; i < fNumberOfVariables; i++ )
{
yOut[i] = yIn[i] + h * ( 0.25 * dydx[i] +
0.75 * dydxTemp2[i]);
}
// NormaliseTangentVector( yOut );
return ;
}
@@ -0,0 +1,79 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4SimpleRunge.cc,v 2.8 1998/11/19 20:54:58 japost Exp $
// GEANT4 tag $Name: geant4-00 $
//
// Simple Runge:
//
// x_1 = x_0 + h * ( dx( t_0+h/2, x_0 + h/2 * dx( t_0, x_0) ) )
//
// second order solver
// take the derivative at a position to be assumed at the middle of the
// Step and add it to the current position.
//
//
// W.Wander <wwc@mit.edu> 12/09/97
// 6.11.98 V.Grichine new data member fNumberOfVariables
//
#include "G4SimpleRunge.hh"
#include "G4ThreeVector.hh"
////////////////////////////////////////////////////////////////
//
// Constructor
G4SimpleRunge::G4SimpleRunge(G4Mag_EqRhs *EqRhs, G4int numberOfVariables):
G4MagErrorStepper(EqRhs, numberOfVariables),
fNumberOfVariables(numberOfVariables)
{
dydxTemp = new G4double[fNumberOfVariables] ;
yTemp = new G4double[fNumberOfVariables] ;
}
/////////////////////////////////////////////////////////////////
//
// Destructor
G4SimpleRunge::~G4SimpleRunge()
{
;
}
//////////////////////////////////////////////////////////////////
//
//
void
G4SimpleRunge::DumbStepper( const G4double yIn[],
const G4double dydx[],
const G4double h,
G4double yOut[])
{
// const G4int nvar = 6 ;
G4int i;
for( i = 0; i < fNumberOfVariables; i++ )
{
yTemp[i] = yIn[i] + 0.5 * h*dydx[i] ;
}
RightHandSide(yTemp,dydxTemp);
for( i = 0; i < fNumberOfVariables; i++ )
{
yOut[i] = yIn[i] + h * ( dydxTemp[i] );
}
// NormaliseTangentVector( yOut );
return ;
}
@@ -0,0 +1,75 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4UniformElectricField.cc,v 2.2 1998/11/19 20:45:22 japost Exp $
// GEANT4 tag $Name: geant4-00 $
//
//
//
// Class for creation of uniform Electric Field
//
// 30.1.97 V.Grichine
//
#include "G4UniformElectricField.hh"
#include "globals.hh"
#include "geomdefs.hh"
G4UniformElectricField::G4UniformElectricField(const G4ThreeVector FieldVector )
{
fFieldComponents[3] = FieldVector.x();
fFieldComponents[4] = FieldVector.y();
fFieldComponents[5] = FieldVector.z();
}
G4UniformElectricField::G4UniformElectricField(G4double vField,
G4double vTheta,
G4double vPhi )
{
if(vField >= 0 &&
vTheta >= 0 && vTheta <= pi &&
vPhi >= 0 && vPhi <= twopi)
{
fFieldComponents[3] = vField*sin(vTheta)*cos(vPhi) ;
fFieldComponents[4] = vField*sin(vTheta)*sin(vPhi) ;
fFieldComponents[5] = vField*cos(vTheta) ;
}
else
{
G4Exception("Invalid parameters in G4UniformElectricField::G4UniformElectricField") ;
}
}
G4UniformElectricField::~G4UniformElectricField()
{
;
}
G4UniformElectricField::G4UniformElectricField (const G4UniformElectricField &p)
{
for (G4int i=3; i<6; i++)
fFieldComponents[i] = p.fFieldComponents[i];
}
G4UniformElectricField& G4UniformElectricField::operator = (const G4UniformElectricField &p)
{
for (G4int i=3; i<6; i++)
fFieldComponents[i] = p.fFieldComponents[i];
return *this;
}
// ------------------------------------------------------------------------
void G4UniformElectricField::GetFieldValue (const G4double [3],
G4double E[3] ) const
{
E[0]= fFieldComponents[3] ;
E[1]= fFieldComponents[4] ;
E[2]= fFieldComponents[5] ;
return ;
}
@@ -0,0 +1,83 @@
// This code implementation is the intellectual property of
// the RD44 GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4UniformMagField.cc,v 2.4 1998/11/27 16:15:53 japost Exp $
// GEANT4 tag $Name: geant4-00 $
//
//
//
// Class for creation of uniform Magnetic Field
//
// 30.1.97 V.Grichine
//
#include "G4UniformMagField.hh"
#include "globals.hh"
#include "geomdefs.hh"
G4UniformMagField::G4UniformMagField(const G4ThreeVector& FieldVector )
{
fFieldComponents[0] = FieldVector.x();
fFieldComponents[1] = FieldVector.y();
fFieldComponents[2] = FieldVector.z();
}
void
G4UniformMagField::SetFieldValue(const G4ThreeVector& newFieldVector )
{
fFieldComponents[0] = newFieldVector.x();
fFieldComponents[1] = newFieldVector.y();
fFieldComponents[2] = newFieldVector.z();
}
G4UniformMagField::G4UniformMagField(G4double vField,
G4double vTheta,
G4double vPhi )
{
if(vField >= 0 &&
vTheta >= 0 && vTheta <= pi &&
vPhi >= 0 && vPhi <= twopi)
{
fFieldComponents[0] = vField*sin(vTheta)*cos(vPhi) ;
fFieldComponents[1] = vField*sin(vTheta)*sin(vPhi) ;
fFieldComponents[2] = vField*cos(vTheta) ;
}
else
{
G4Exception("Invalid parameters in G4UniformMagField::G4UniformMagField") ;
}
}
G4UniformMagField::~G4UniformMagField()
{
;
}
G4UniformMagField::G4UniformMagField (const G4UniformMagField &p)
{
for (G4int i=0; i<3; i++)
fFieldComponents[i] = p.fFieldComponents[i];
}
G4UniformMagField& G4UniformMagField::operator = (const G4UniformMagField &p)
{
for (G4int i=0; i<3; i++)
fFieldComponents[i] = p.fFieldComponents[i];
return *this;
}
// ------------------------------------------------------------------------
void G4UniformMagField::GetFieldValue (const G4double [3],
G4double *B ) const
{
B[0]= fFieldComponents[0] ;
B[1]= fFieldComponents[1] ;
B[2]= fFieldComponents[2] ;
return ;
}