Import Geant4 10.7.0 source tree

This commit is contained in:
Gabriele Cosmo
2020-12-04 12:30:43 +01:00
parent 67ba86d073
commit dab42d2018
3770 changed files with 226369 additions and 286486 deletions
@@ -29,6 +29,8 @@
// Supervision: John Apostolakis, CERN
// --------------------------------------------------------------------
#include <cassert>
#include "G4LineSection.hh"
#include "G4FieldUtils.hh"
@@ -59,7 +59,7 @@ class G4ChordFinder
G4double stepMinimum = 1.0e-2, // * mm
G4MagIntegratorStepper* pItsStepper = nullptr,
// G4bool useHigherEfficiencyStepper = true,
G4bool useFSALstepper = false );
G4int stepperDriverChoice = 2 );
// A constructor that creates defaults for all "children" classes.
//
// The type of equation of motion is fixed.
@@ -75,6 +75,9 @@ class G4DormandPrince745 : public G4MagIntegratorStepper
virtual G4int IntegratorOrder() const override { return 4; }
const G4String& StepperType() const { return gStepperType; }
const G4String& StepperDescription() const { return gStepperDescription; }
const field_utils::State& GetYOut() const { return fyOut; }
void Interpolate4thOrder(G4double yOut[], G4double tau) const;
@@ -82,12 +85,17 @@ class G4DormandPrince745 : public G4MagIntegratorStepper
void SetupInterpolation5thOrder();
void Interpolate5thOrder(G4double yOut[], G4double tau) const;
G4EquationOfMotion* GetSpecificEquation() { return GetEquationOfMotion(); }
private:
// Name and description of this steppers - plus details of its implementation
static const G4String gStepperType;
static const G4String gStepperDescription;
// const unsigned int fIntegratorOrder = 4; // Should it not be 5 ?
field_utils::State ak2, ak3, ak4, ak5, ak6, ak7, ak8, ak9;
field_utils::State fyIn, fyOut, fdydxIn;
G4double fLastStepLength = -1.0;
};
#endif
@@ -44,6 +44,9 @@ namespace field_utils
using State = G4double[G4FieldTrack::ncompSVEC];
template <unsigned int N>
using ShortState = G4double[N];
enum class Value3D
{
Position = 0,
@@ -57,7 +57,7 @@ G4InterpolationDriver ( G4double hminimum, T* pStepper,
for (G4int i = 0; i < Base::GetMaxNoSteps(); ++i)
{
fSteppers.push_back({
std::unique_ptr<T>(new T(pStepper->GetEquationOfMotion(),
std::unique_ptr<T>(new T(pStepper->GetSpecificEquation(), // Interpolating stepper must have this!
pStepper->GetNumberOfVariables()) ),
DBL_MAX, -DBL_MAX, 0.0
});
@@ -0,0 +1,151 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
#ifndef TCACHED_MAGNETIC_FIELD_DEF
#define TCACHED_MAGNETIC_FIELD_DEF
#include "G4Types.hh"
#include "G4ThreeVector.hh"
#include "G4MagneticField.hh"
template <class T_Field>
class G4TCachedMagneticField : public G4MagneticField
{
public: // with description
G4TCachedMagneticField(T_Field* pTField, G4double distance)
: G4MagneticField()
, fLastLocation(DBL_MAX, DBL_MAX, DBL_MAX)
, fLastValue(DBL_MAX, DBL_MAX, DBL_MAX)
, fCountCalls(0)
, fCountEvaluations(0)
{
fpMagneticField = pTField;
fDistanceConst = distance;
// G4cout << " Cached-B-Field constructor> Distance = " << distance <<
// G4endl;
this->ClearCounts();
}
G4TCachedMagneticField(const G4TCachedMagneticField<T_Field>& rightCMF)
{
fpMagneticField = rightCMF.fpMagneticField;
fDistanceConst = rightCMF.fDistanceConst;
fLastLocation = rightCMF.fLastLocation;
fLastValue = rightCMF.fLastValue;
this->ClearCounts();
}
G4TCachedMagneticField* Clone() const
{
G4cout << "Clone is called" << G4endl;
// Cannot use copy constructor: I need to clone the associated magnetif
// field
T_Field* aF = this->fpMagneticField->T_Field::Clone();
G4TCachedMagneticField* cloned =
new G4TCachedMagneticField(aF, this->fDistanceConst);
cloned->fLastLocation = this->fLastLocation;
cloned->fLastValue = this->fLastValue;
return cloned;
}
virtual ~G4TCachedMagneticField() { ; }
// Constructor and destructor. No actions.
void ReportStatistics()
{
G4cout << " Cached field: " << G4endl
<< " Number of calls: " << fCountCalls << G4endl
<< " Number of evaluations : " << fCountEvaluations << G4endl;
}
virtual void GetFieldValue(const G4double Point[4], G4double* Bfield) const
{
G4ThreeVector newLocation(Point[0], Point[1], Point[2]);
G4double distSq = (newLocation - fLastLocation).mag2();
fCountCalls++;
if(distSq < fDistanceConst * fDistanceConst)
{
Bfield[0] = fLastValue.x();
Bfield[1] = fLastValue.y();
Bfield[2] = fLastValue.z();
}
else
{
// G4CachedMagneticField* thisNonC=
// const_cast<G4CachedMagneticField*>(this);
fpMagneticField->T_Field::GetFieldValue(Point, Bfield);
// G4cout << " Evaluating. " << G4endl;
fCountEvaluations++;
// thisNonC->
fLastLocation = G4ThreeVector(Point[0], Point[1], Point[2]);
// thisNonC->
fLastValue = G4ThreeVector(Bfield[0], Bfield[1], Bfield[2]);
}
}
G4double GetConstDistance() const { return fDistanceConst; }
void SetConstDistance(G4double dist) { fDistanceConst = dist; }
G4int GetCountCalls() const { return fCountCalls; }
G4int GetCountEvaluations() const { return fCountEvaluations; }
void ClearCounts()
{
fCountCalls = 0;
fCountEvaluations = 0;
}
G4TCachedMagneticField& operator=(const G4TCachedMagneticField& right)
{
if(&right == this)
return *this;
fpMagneticField = right.fpMagneticField;
fDistanceConst= right.fDistanceConst;
fLastLocation = right.fLastLocation;
fLastValue = right.fLastValue;
fCountCalls = 0;
fCountEvaluations = 0;
return *this;
}
private:
T_Field* fpMagneticField;
// When the field is evaluated within this distance it will not change
G4double fDistanceConst;
// Caching state
mutable G4ThreeVector fLastLocation;
mutable G4ThreeVector fLastValue;
protected:
mutable G4int fCountCalls, fCountEvaluations;
};
#endif /* TCACHED_MAGNETIC_FIELD_DEF */
@@ -0,0 +1,321 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// G4TCashKarpRKF45
//
// Class description:
//
// Templated version of Cash-Karp 4th/5th order embedded stepper
//
// Knowing the type (class) of the equation of motion enables a non-
// virtual call of its methods.
// As an embedded 5th order method, it requires fewer field evaluations
// (1 initial + 5 others per step = 6 per step) than ClassicalRK4 and
// also non-embedded methods of the same order.
//
// Can be used to enable use of non-virtual calls for field, equation,
// and stepper - potentially with inlined methods.
//
// Created: Josh Xie June 2014 (supported by Google Summer of Code 2014 )
// Supervisors: Sandro Wenzel, John Apostolakis (CERN)
//
// Adapted from G4CashKarpRKF45 class
// --------------------------------------------------------------------
// Original description (G4CashKarpRKF45):
// 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. [ref. Numerical Recipes in C, 2nd Edition]
// Used to integrate the equations of motion of a particle in a field.
// Original Authors: J.Apostolakis, V.Grichine - 30.01.1997
#ifndef G4T_CASH_KARP_RKF45_HH
#define G4T_CASH_KARP_RKF45_HH
#include <cassert>
#include "G4LineSection.hh"
#include "G4MagIntegratorStepper.hh"
template <class T_Equation, unsigned int N = 6 >
class G4TCashKarpRKF45 : public G4MagIntegratorStepper
{
public:
G4TCashKarpRKF45(T_Equation* EqRhs, // G4int noIntegrationVariables = 6,
G4bool primary = true);
virtual ~G4TCashKarpRKF45();
inline void
StepWithError(const G4double yInput[], // * __restrict__ yInput,
const G4double dydx[], // * __restrict__ dydx,
G4double Step,
G4double yOut[], // * __restrict__ yOut,
G4double yErr[] ); // * __restrict__ yErr);
virtual void Stepper(const G4double yInput[],
const G4double dydx[],
G4double hstep,
G4double yOutput[],
G4double yError[]) override final;
// __attribute__((always_inline))
void RightHandSideInl( const G4double y[], // * __restrict__ y,
G4double dydx[] ) // * __restrict__ dydx )
{
fEquation_Rhs->T_Equation::RightHandSide(y, dydx);
}
inline G4double DistChord() const override;
inline G4int IntegratorOrder() const override { return 4; }
private:
G4TCashKarpRKF45(const G4TCashKarpRKF45&);
G4TCashKarpRKF45& operator=(const G4TCashKarpRKF45&);
// private copy constructor and assignment operator.
private:
G4double ak2[N], ak3[N], ak4[N], ak5[N], ak6[N], ak7[N], yTemp[N], yIn[N];
// scratch space
G4double fLastStepLength= 0.0;
G4double* fLastInitialVector;
G4double* fLastFinalVector;
G4double* fLastDyDx;
G4double* fMidVector;
G4double* fMidError;
// for DistChord calculations
G4TCashKarpRKF45* fAuxStepper = nullptr;
// ... or G4TCashKarpRKF45<T_Equation, N>* fAuxStepper;
T_Equation* fEquation_Rhs;
};
/////////////////////////////////////////////////////////////////////
//
// Constructor
//
template <class T_Equation, unsigned int N >
G4TCashKarpRKF45<T_Equation,N>::G4TCashKarpRKF45(T_Equation* EqRhs,
G4bool primary)
: G4MagIntegratorStepper(dynamic_cast<G4EquationOfMotion*>(EqRhs), N )
, fEquation_Rhs(EqRhs)
{
if( dynamic_cast<G4EquationOfMotion*>(EqRhs) == nullptr )
{
G4Exception("G4TCashKarpRKF45: constructor", "GeomField0001",
FatalException, "Equation is not an G4EquationOfMotion.");
}
fLastInitialVector = new G4double[N];
fLastFinalVector = new G4double[N];
fLastDyDx = new G4double[N];
fMidVector = new G4double[N];
fMidError = new G4double[N];
if(primary)
{
fAuxStepper = new G4TCashKarpRKF45<T_Equation, N> (EqRhs, !primary);
}
}
template <class T_Equation, unsigned int N >
G4TCashKarpRKF45<T_Equation,N>::~G4TCashKarpRKF45()
{
delete[] fLastInitialVector;
delete[] fLastFinalVector;
delete[] fLastDyDx;
delete[] fMidVector;
delete[] fMidError;
delete fAuxStepper;
}
//////////////////////////////////////////////////////////////////////
//
// 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 equation's method is called (inline)
// via RightHandSideInl(y,dydx), which returns derivatives dydx for y .
//
template <class T_Equation, unsigned int N >
inline void
G4TCashKarpRKF45<T_Equation,N>::StepWithError(const G4double* yInput,
const G4double* dydx,
G4double Step,
G4double * yOut,
G4double * yErr)
{
// const G4double a2 = 0.2 , a3 = 0.3 , a4 = 0.6 , a5 = 1.0 , a6 = 0.875;
const G4double 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;
// Initialise time to t0, needed when it is not updated by the integration.
// [ Note: Only for time dependent fields (usually electric)
// is it neccessary to integrate the time.]
// yOut[7] = yTemp[7] = yIn[7];
// Saving yInput because yInput and yOut can be aliases for same array
for(unsigned int i = 0; i < N; ++i)
{
yIn[i] = yInput[i];
}
// RightHandSideInl(yIn, dydx) ; // 1st Step
for(unsigned int i = 0; i < N; ++i)
{
yTemp[i] = yIn[i] + b21 * Step * dydx[i];
}
this->RightHandSideInl(yTemp, ak2); // 2nd Step
for(unsigned int i = 0; i < N; ++i)
{
yTemp[i] = yIn[i] + Step * (b31 * dydx[i] + b32 * ak2[i]);
}
this->RightHandSideInl(yTemp, ak3); // 3rd Step
for(unsigned int i = 0; i < N; ++i)
{
yTemp[i] = yIn[i] + Step * (b41 * dydx[i] + b42 * ak2[i] + b43 * ak3[i]);
}
this->RightHandSideInl(yTemp, ak4); // 4th Step
for(unsigned int i = 0; i < N; ++i)
{
yTemp[i] = yIn[i] + Step * (b51 * dydx[i] + b52 * ak2[i] + b53 * ak3[i] +
b54 * ak4[i]);
}
this->RightHandSideInl(yTemp, ak5); // 5th Step
for(unsigned int i = 0; i < N; ++i)
{
yTemp[i] = yIn[i] + Step * (b61 * dydx[i] + b62 * ak2[i] + b63 * ak3[i] +
b64 * ak4[i] + b65 * ak5[i]);
}
this->RightHandSideInl(yTemp, ak6); // 6th Step
for(unsigned int i = 0; i < N; ++i)
{
// Accumulate increments with proper weights
yOut[i] = yIn[i] +
Step * (c1 * dydx[i] + c3 * ak3[i] + c4 * ak4[i] + c6 * ak6[i]);
}
for(unsigned int i = 0; i < N; ++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]);
}
for(unsigned int i = 0; i < N; ++i)
{
// Store Input and Final values, for possible use in calculating chord
fLastInitialVector[i] = yIn[i];
fLastFinalVector[i] = yOut[i];
fLastDyDx[i] = dydx[i];
}
// NormaliseTangentVector( yOut ); // Not wanted
fLastStepLength = Step;
return;
}
template <class T_Equation, unsigned int N >
inline G4double
G4TCashKarpRKF45<T_Equation,N>::DistChord() const
{
G4double distLine, distChord;
G4ThreeVector initialPoint, finalPoint, midPoint;
// Store last initial and final points (they will be overwritten in
// self-Stepper call!)
initialPoint = G4ThreeVector(fLastInitialVector[0], fLastInitialVector[1],
fLastInitialVector[2]);
finalPoint = G4ThreeVector(fLastFinalVector[0], fLastFinalVector[1],
fLastFinalVector[2]);
// Do half a step using StepNoErr
fAuxStepper->G4TCashKarpRKF45::Stepper(fLastInitialVector, fLastDyDx,
0.5 * fLastStepLength, fMidVector,
fMidError);
midPoint = G4ThreeVector(fMidVector[0], fMidVector[1], fMidVector[2]);
// Use stored values of Initial and Endpoint + new Midpoint to evaluate
// distance of Chord
if(initialPoint != finalPoint)
{
distLine = G4LineSection::Distline(midPoint, initialPoint, finalPoint);
distChord = distLine;
}
else
{
distChord = (midPoint - initialPoint).mag();
}
return distChord;
}
template <class T_Equation, unsigned int N >
inline void
G4TCashKarpRKF45<T_Equation,N>::Stepper(const G4double yInput[],
const G4double dydx[],
G4double Step,
G4double yOutput[],
G4double yError[])
{
assert( yOutput != yInput );
assert( yError != yInput );
StepWithError( yInput, dydx, Step, yOutput, yError);
}
#endif /* G4TCashKARP_RKF45_hh */
@@ -0,0 +1,154 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// G4TClassicalRK4
//
// Class description:
//
// Templated version of G4ClassicalRK4
//
//
// Created: Josh Xie (supported by Google Summer of Code 2014 )
// Supervisors: Sandro Wenzel, John Apostolakis (CERN)
// Adapted from G4G4TClassicalRK4 class
// --------------------------------------------------------------------
#include "G4ThreeVector.hh"
#include "G4MagIntegratorStepper.hh"
#include "G4TMagErrorStepper.hh"
template <class T_Equation, unsigned int N>
class G4TClassicalRK4
: public G4TMagErrorStepper<G4TClassicalRK4<T_Equation, N>, T_Equation, N>
{
public: // with description
static constexpr G4double IntegratorCorrection = 1. / ((1 << 4) - 1);
G4TClassicalRK4(T_Equation* EqRhs, G4int numberOfVariables = 8);
virtual ~G4TClassicalRK4() { ; }
void RightHandSideInl(G4double y[],
G4double dydx[])
{
fEquation_Rhs->T_Equation::RightHandSide(y, dydx);
}
// A stepper that does not know about errors.
// It is used by the MagErrorStepper stepper.
inline // __attribute__((always_inline))
void DumbStepper(const G4double yIn[],
const G4double dydx[],
G4double h,
G4double yOut[]);
public: // without description
G4int IntegratorOrder() const { return 4; }
G4TClassicalRK4(const G4TClassicalRK4&) = delete;
G4TClassicalRK4& operator=(const G4TClassicalRK4&) = delete;
// No copy constructor and assignment operator.
private:
// G4int fNumberOfVariables ; // is set default to 6 in constructor
G4double dydxm[N < 8 ? 8 : N];
G4double dydxt[N < 8 ? 8 : N];
G4double yt[N < 8 ? 8 : N];
// scratch space - not state
T_Equation* fEquation_Rhs;
};
template <class T_Equation, unsigned int N >
G4TClassicalRK4<T_Equation,N>::
G4TClassicalRK4(T_Equation* EqRhs, G4int numberOfVariables)
: G4TMagErrorStepper<G4TClassicalRK4<T_Equation, N>, T_Equation, N>(
EqRhs, numberOfVariables > 8 ? numberOfVariables : 8 )
, fEquation_Rhs(EqRhs)
{
// unsigned int noVariables = std::max(numberOfVariables, 8); // For Time .. 7+1
if( dynamic_cast<G4EquationOfMotion*>(EqRhs) == nullptr )
{
G4Exception("G4TClassicalRK4: constructor", "GeomField0001",
FatalException, "Equation is not an G4EquationOfMotion.");
}
}
template <class T_Equation, unsigned int N >
void
G4TClassicalRK4<T_Equation,N>::DumbStepper(const G4double yIn[],
const G4double dydx[],
G4double h,
G4double yOut[])
// 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 .
{
G4double hh = h * 0.5, h6 = h / 6.0;
// Initialise time to t0, needed when it is not updated by the integration.
// [ Note: Only for time dependent fields (usually electric)
// is it neccessary to integrate the time.]
yt[7] = yIn[7];
yOut[7] = yIn[7];
for(unsigned int i = 0; i < N; ++i)
{
yt[i] = yIn[i] + hh * dydx[i]; // 1st Step K1=h*dydx
}
this->RightHandSideInl(yt, dydxt); // 2nd Step K2=h*dydxt
for(unsigned int i = 0; i < N; ++i)
{
yt[i] = yIn[i] + hh * dydxt[i];
}
this->RightHandSideInl(yt, dydxm); // 3rd Step K3=h*dydxm
for(unsigned int i = 0; i < N; ++i)
{
yt[i] = yIn[i] + h * dydxm[i];
dydxm[i] += dydxt[i]; // now dydxm=(K2+K3)/h
}
this->RightHandSideInl(yt, dydxt); // 4th Step K4=h*dydxt
for(unsigned int i = 0; i < N; ++i) // Final RK4 output
{
yOut[i] = yIn[i] + h6 * (dydx[i] + dydxt[i] +
2.0 * dydxm[i]); //+K1/6+K4/6+(K2+K3)/3
}
if(N == 12)
{
this->NormalisePolarizationVector(yOut);
}
} // end of DumbStepper ....................................................
// template <class T_Equation, unsigned int N >
// G4TClassicalRK4<T_Equation,N>::
@@ -0,0 +1,593 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// G4TDormandPrince45
//
// Class desription:
//
// An implementation of the 5th order embedded RK method from the paper:
// J. R. Dormand and P. J. Prince, "A family of embedded Runge-Kutta formulae"
// Journal of computational and applied Math., vol.6, no.1, pp.19-26, 1980.
//
// DormandPrince7 - 5(4) embedded RK method
//
// Created: Somnath Banerjee, Google Summer of Code 2015, 25 May 2015
// Supervision: John Apostolakis, CERN
// --------------------------------------------------------------------
#ifndef G4TDORMAND_PRINCE_45_HH
#define G4TDORMAND_PRINCE_45_HH
#include <cassert>
#include "G4MagIntegratorStepper.hh"
#include "G4FieldUtils.hh"
template <class T_Equation, unsigned int N = 6 >
class G4TDormandPrince45 : public G4MagIntegratorStepper
{
public:
G4TDormandPrince45(T_Equation* equation );
G4TDormandPrince45(T_Equation* equation, G4int numVar ); // must have numVar == N
inline void
StepWithError(const G4double yInput[],
const G4double dydx[],
G4double hstep,
G4double yOutput[],
G4double yError[] ) ;
virtual void Stepper(const G4double yInput[],
const G4double dydx[],
G4double hstep,
G4double yOutput[],
G4double yError[]) override final;
inline
void StepWithFinalDerivate(const G4double yInput[],
const G4double dydx[],
G4double hstep,
G4double yOutput[],
G4double yError[],
G4double dydxOutput[]);
inline void SetupInterpolation() {}
void Interpolate(G4double tau, G4double yOut[]) const
{
Interpolate4thOrder(yOut, tau);
}
// For calculating the output at the tau fraction of Step
virtual G4double DistChord() const override final;
virtual G4int IntegratorOrder() const override { return 4; }
const field_utils::ShortState<N>& GetYOut() const { return fyOut; }
void Interpolate4thOrder(G4double yOut[], G4double tau) const;
void SetupInterpolation5thOrder();
void Interpolate5thOrder(G4double yOut[], G4double tau) const;
// __attribute__((always_inline))
void RightHandSideInl( const G4double y[],
G4double dydx[] )
{
fEquation_Rhs->T_Equation::RightHandSide(y, dydx);
}
inline
void Stepper(const G4double yInput[], const G4double dydx[],
G4double hstep, G4double yOutput[],
G4double yError[], G4double dydxOutput[])
{
StepWithFinalDerivate(yInput, dydx, hstep,
yOutput, yError, dydxOutput);
}
T_Equation* GetSpecificEquation() { return fEquation_Rhs; }
static constexpr int N8= N > 8 ? N : 8; // y[
private:
field_utils::ShortState<N> ak2, ak3, ak4, ak5, ak6, ak7, ak8, ak9;
field_utils::ShortState<N8> fyIn;
field_utils::ShortState<N> fyOut, fdydxIn;
// - Simpler :
// field_utils::State ak2, ak3, ak4, ak5, ak6, ak7, ak8, ak9;
// field_utils::State fyIn, fyOut, fdydxIn;
G4double fLastStepLength = -1.0;
T_Equation* fEquation_Rhs;
};
// G4TDormandPrince745 implementation -- borrowed from G4DormandPrince745
//
// DormandPrince7 - 5(4) non-FSAL
// definition of the stepper() method that evaluates one step in
// field propagation.
// The coefficients and the algorithm have been adapted from
//
// J. R. Dormand and P. J. Prince, "A family of embedded Runge-Kutta formulae"
// Journal of computational and applied Math., vol.6, no.1, pp.19-26, 1980.
//
// The Butcher table of the Dormand-Prince-7-4-5 method is as follows :
//
// 0 |
// 1/5 | 1/5
// 3/10| 3/40 9/40
// 4/5 | 44/45 56/15 32/9
// 8/9 | 19372/6561 25360/2187 64448/6561 212/729
// 1 | 9017/3168 355/33 46732/5247 49/176 5103/18656
// 1 | 35/384 0 500/1113 125/192 2187/6784 11/84
// ------------------------------------------------------------------------
// 35/384 0 500/1113 125/192 2187/6784 11/84 0
// 5179/57600 0 7571/16695 393/640 92097/339200 187/2100 1/40
//
// Created: Somnath Banerjee, Google Summer of Code 2015, 25 May 2015
// Supervision: John Apostolakis, CERN
// --------------------------------------------------------------------
#include "G4LineSection.hh"
#include <cstring>
// using namespace field_utils;
/////////////////////////////////////////////////////////////////////
// Constructor
//
template <class T_Equation, unsigned int N>
G4TDormandPrince45<T_Equation,N>::G4TDormandPrince45(T_Equation* equation )
: G4MagIntegratorStepper(dynamic_cast<G4EquationOfMotion*>(equation), N )
, fEquation_Rhs(equation)
{
// assert( dynamic_cast<G4EquationOfMotion*>(equation) != nullptr );
if( dynamic_cast<G4EquationOfMotion*>(equation) == nullptr )
{
G4Exception("G4TDormandPrince745: constructor", "GeomField0001",
FatalException, "T_Equation is not an G4EquationOfMotion.");
}
/***
assert( equation->GetNumberOfVariables == N );
if( equation->GetNumberOfVariables != N ){
G4ExceptionDescription msg;
msg << "Equation has an incompatible number of variables." ;
msg << " template N = " << N << " equation-Nvar= "
<< equation->GetNumberOfVariables;
G4Exception("G4TCashKarpRKF45: constructor", "GeomField0001",
FatalException, msg );
} ****/
}
template <class T_Equation, unsigned int N>
G4TDormandPrince45<T_Equation,N>::G4TDormandPrince45(T_Equation* equation, G4int numVar )
: G4TDormandPrince45<T_Equation,N>(equation )
{
if( numVar != G4int(N)){
G4ExceptionDescription msg;
msg << "Equation has an incompatible number of variables." ;
msg << " template N = " << N
<< " argument numVar = " << numVar ;
// << " equation-Nvar= " << equation->GetNumberOfVariables(); // --> Expected later
G4Exception("G4TCashKarpRKF45: constructor", "GeomField0001",
FatalErrorInArgument, msg );
}
assert( numVar == N );
}
template <class T_Equation, unsigned int N>
inline void G4TDormandPrince45<T_Equation,N>::
StepWithFinalDerivate(const G4double yInput[],
const G4double dydx[],
G4double hstep,
G4double yOutput[],
G4double yError[],
G4double dydxOutput[])
{
StepWithError(yInput, dydx, hstep, yOutput, yError);
field_utils::copy(dydxOutput, ak7, N);
}
// Stepper
//
// Passing in the value of yInput[],the first time dydx[] and Step length
// Giving back yOut and yErr arrays for output and error respectively
//
template <class T_Equation, unsigned int N>
inline void
G4TDormandPrince45<T_Equation,N>::StepWithError(const G4double yInput[],
const G4double dydx[],
G4double hstep,
G4double yOut[],
G4double yErr[] )
{
// The parameters of the Butcher tableu
//
constexpr G4double b21 = 0.2,
b31 = 3.0 / 40.0, b32 = 9.0 / 40.0,
b41 = 44.0 / 45.0, b42 = -56.0 / 15.0, b43 = 32.0/9.0,
b51 = 19372.0 / 6561.0, b52 = -25360.0 / 2187.0, b53 = 64448.0 / 6561.0,
b54 = -212.0 / 729.0,
b61 = 9017.0 / 3168.0 , b62 = -355.0 / 33.0,
b63 = 46732.0 / 5247.0, b64 = 49.0 / 176.0,
b65 = -5103.0 / 18656.0,
b71 = 35.0 / 384.0, b72 = 0.,
b73 = 500.0 / 1113.0, b74 = 125.0 / 192.0,
b75 = -2187.0 / 6784.0, b76 = 11.0 / 84.0,
//Sum of columns, sum(bij) = ei
// e1 = 0. ,
// e2 = 1.0/5.0 ,
// e3 = 3.0/10.0 ,
// e4 = 4.0/5.0 ,
// e5 = 8.0/9.0 ,
// e6 = 1.0 ,
// e7 = 1.0 ,
// Difference between the higher and the lower order method coeff. :
// b7j are the coefficients of higher order
dc1 = -(b71 - 5179.0 / 57600.0),
dc2 = -(b72 - .0),
dc3 = -(b73 - 7571.0 / 16695.0),
dc4 = -(b74 - 393.0 / 640.0),
dc5 = -(b75 + 92097.0 / 339200.0),
dc6 = -(b76 - 187.0 / 2100.0),
dc7 = -(- 1.0 / 40.0);
// const G4int numberOfVariables = GetNumberOfVariables();
// The number of variables to be integrated over
field_utils::ShortState<N8> yTemp;
yOut[7] = yTemp[7] = fyIn[7] = yInput[7]; // Pass along the time - used in RightHandSide
// Saving yInput because yInput and yOut can be aliases for same array
//
for(unsigned int i = 0; i < N; ++i)
{
fyIn[i] = yInput[i];
yTemp[i] = yInput[i] + b21 * hstep * dydx[i];
}
RightHandSideInl(yTemp, ak2); // 2nd stage
for(unsigned int i = 0; i < N; ++i)
{
yTemp[i] = fyIn[i] + hstep * (b31 * dydx[i] + b32 * ak2[i]);
}
RightHandSideInl(yTemp, ak3); // 3rd stage
for(unsigned int i = 0; i < N; ++i)
{
yTemp[i] = fyIn[i] + hstep * (
b41 * dydx[i] + b42 * ak2[i] + b43 * ak3[i]);
}
RightHandSideInl(yTemp, ak4); // 4th stage
for(unsigned int i = 0; i < N; ++i)
{
yTemp[i] = fyIn[i] + hstep * (
b51 * dydx[i] + b52 * ak2[i] + b53 * ak3[i] + b54 * ak4[i]);
}
RightHandSideInl(yTemp, ak5); // 5th stage
for(unsigned int i = 0; i < N; ++i)
{
yTemp[i] = fyIn[i] + hstep * (
b61 * dydx[i] + b62 * ak2[i] +
b63 * ak3[i] + b64 * ak4[i] + b65 * ak5[i]);
}
RightHandSideInl(yTemp, ak6); // 6th stage
for(unsigned int i = 0; i < N; ++i)
{
yOut[i] = fyIn[i] + hstep * (
b71 * dydx[i] + b72 * ak2[i] + b73 * ak3[i] +
b74 * ak4[i] + b75 * ak5[i] + b76 * ak6[i]);
}
RightHandSideInl(yOut, ak7); // 7th and Final stage
for(unsigned int i = 0; i < N; ++i)
{
yErr[i] = hstep * (
dc1 * dydx[i] + dc2 * ak2[i] +
dc3 * ak3[i] + dc4 * ak4[i] +
dc5 * ak5[i] + dc6 * ak6[i] + dc7 * ak7[i]
) + 1.5e-18;
// Store Input and Final values, for possible use in calculating chord
//
fyOut[i] = yOut[i];
fdydxIn[i] = dydx[i];
}
fLastStepLength = hstep;
}
template <class T_Equation, unsigned int N >
inline void
G4TDormandPrince45<T_Equation,N>::Stepper(const G4double yInput[],
const G4double dydx[],
G4double Step,
G4double yOutput[],
G4double yError[])
{
assert( yOutput != yInput );
assert( yError != yInput );
StepWithError( yInput, dydx, Step, yOutput, yError);
}
template <class T_Equation, unsigned int N>
G4double
G4TDormandPrince45<T_Equation,N>::DistChord() const
{
// Coefficients were taken from Some Practical Runge-Kutta Formulas
// by Lawrence F. Shampine, page 149, c*
//
const G4double hf1 = 6025192743.0 / 30085553152.0,
hf3 = 51252292925.0 / 65400821598.0,
hf4 = - 2691868925.0 / 45128329728.0,
hf5 = 187940372067.0 / 1594534317056.0,
hf6 = - 1776094331.0 / 19743644256.0,
hf7 = 11237099.0 / 235043384.0;
G4ThreeVector mid;
for(unsigned int i = 0; i < 3; ++i)
{
mid[i] = fyIn[i] + 0.5 * fLastStepLength * (
hf1 * fdydxIn[i] + hf3 * ak3[i] +
hf4 * ak4[i] + hf5 * ak5[i] + hf6 * ak6[i] + hf7 * ak7[i]);
}
const G4ThreeVector begin = makeVector(fyIn, field_utils::Value3D::Position);
const G4ThreeVector end = makeVector(fyOut, field_utils::Value3D::Position);
return G4LineSection::Distline(mid, begin, end);
}
// The lower (4th) order interpolant given by Dormand and Prince:
// J. R. Dormand and P. J. Prince, "Runge-Kutta triples"
// Computers & Mathematics with Applications, vol. 12, no. 9,
// pp. 1007-1017, 1986.
//
template <class T_Equation, unsigned int N>
void
G4TDormandPrince45<T_Equation,N>::
Interpolate4thOrder(G4double yOut[], G4double tau) const
{
// const G4int numberOfVariables = GetNumberOfVariables();
const G4double tau2 = tau * tau,
tau3 = tau * tau2,
tau4 = tau2 * tau2;
const G4double bf1 = 1.0 / 11282082432.0 * (
157015080.0 * tau4 - 13107642775.0 * tau3 + 34969693132.0 * tau2 -
32272833064.0 * tau + 11282082432.0);
const G4double bf3 = - 100.0 / 32700410799.0 * tau * (
15701508.0 * tau3 - 914128567.0 * tau2 + 2074956840.0 * tau -
1323431896.0);
const G4double bf4 = 25.0 / 5641041216.0 * tau * (
94209048.0 * tau3 - 1518414297.0 * tau2 + 2460397220.0 * tau -
889289856.0);
const G4double bf5 = - 2187.0 / 199316789632.0 * tau * (
52338360.0 * tau3 - 451824525.0 * tau2 + 687873124.0 * tau -
259006536.0);
const G4double bf6 = 11.0 / 2467955532.0 * tau * (
106151040.0 * tau3 - 661884105.0 * tau2 +
946554244.0 * tau - 361440756.0);
const G4double bf7 = 1.0 / 29380423.0 * tau * (1.0 - tau) * (
8293050.0 * tau2 - 82437520.0 * tau + 44764047.0);
for(unsigned int i = 0; i < N; ++i)
{
yOut[i] = fyIn[i] + fLastStepLength * tau * (
bf1 * fdydxIn[i] + bf3 * ak3[i] + bf4 * ak4[i] +
bf5 * ak5[i] + bf6 * ak6[i] + bf7 * ak7[i]);
}
}
// Following interpolant of order 5 was given by Baker,Dormand,Gilmore, Prince :
// T. S. Baker, J. R. Dormand, J. P. Gilmore, and P. J. Prince,
// "Continuous approximation with embedded Runge-Kutta methods"
// Applied Numerical Mathematics, vol. 22, no. 1, pp. 51-62, 1996.
//
// Calculating the extra stages for the interpolant
//
template <class T_Equation, unsigned int N>
void G4TDormandPrince45<T_Equation,N>::SetupInterpolation5thOrder()
{
// Coefficients for the additional stages
//
const G4double b81 = 6245.0 / 62208.0,
b82 = 0.0,
b83 = 8875.0 / 103032.0,
b84 = -125.0 / 1728.0,
b85 = 801.0 / 13568.0,
b86 = -13519.0 / 368064.0,
b87 = 11105.0 / 368064.0,
b91 = 632855.0 / 4478976.0,
b92 = 0.0,
b93 = 4146875.0 / 6491016.0,
b94 = 5490625.0 /14183424.0,
b95 = -15975.0 / 108544.0,
b96 = 8295925.0 / 220286304.0,
b97 = -1779595.0 / 62938944.0,
b98 = -805.0 / 4104.0;
// const G4int numberOfVariables = GetNumberOfVariables();
field_utils::ShortState<N> yTemp;
// Evaluate the extra stages
//
for(unsigned int i = 0; i < N; ++i)
{
yTemp[i] = fyIn[i] + fLastStepLength * (
b81 * fdydxIn[i] + b82 * ak2[i] + b83 * ak3[i] +
b84 * ak4[i] + b85 * ak5[i] + b86 * ak6[i] +
b87 * ak7[i]
);
}
RightHandSideInl(yTemp, ak8); // 8th Stage
for(unsigned int i = 0; i < N; ++i)
{
yTemp[i] = fyIn[i] + fLastStepLength * (
b91 * fdydxIn[i] + b92 * ak2[i] + b93 * ak3[i] +
b94 * ak4[i] + b95 * ak5[i] + b96 * ak6[i] +
b97 * ak7[i] + b98 * ak8[i]
);
}
RightHandSideInl(yTemp, ak9); // 9th Stage
}
// Calculating the interpolated result yOut with the coefficients
//
template <class T_Equation, unsigned int N>
void G4TDormandPrince45<T_Equation,N>::
Interpolate5thOrder(G4double yOut[], G4double tau) const
{
// Define the coefficients for the polynomials
//
G4double bi[10][5];
// COEFFICIENTS OF bi[1]
bi[1][0] = 1.0,
bi[1][1] = -38039.0 / 7040.0,
bi[1][2] = 125923.0 / 10560.0,
bi[1][3] = -19683.0 / 1760.0,
bi[1][4] = 3303.0 / 880.0,
// --------------------------------------------------------
//
// COEFFICIENTS OF bi[2]
bi[2][0] = 0.0,
bi[2][1] = 0.0,
bi[2][2] = 0.0,
bi[2][3] = 0.0,
bi[2][4] = 0.0,
// --------------------------------------------------------
//
// COEFFICIENTS OF bi[3]
bi[3][0] = 0.0,
bi[3][1] = -12500.0 / 4081.0,
bi[3][2] = 205000.0 / 12243.0,
bi[3][3] = -90000.0 / 4081.0,
bi[3][4] = 36000.0 / 4081.0,
// --------------------------------------------------------
//
// COEFFICIENTS OF bi[4]
bi[4][0] = 0.0,
bi[4][1] = -3125.0 / 704.0,
bi[4][2] = 25625.0 / 1056.0,
bi[4][3] = -5625.0 / 176.0,
bi[4][4] = 1125.0 / 88.0,
// --------------------------------------------------------
//
// COEFFICIENTS OF bi[5]
bi[5][0] = 0.0,
bi[5][1] = 164025.0 / 74624.0,
bi[5][2] = -448335.0 / 37312.0,
bi[5][3] = 295245.0 / 18656.0,
bi[5][4] = -59049.0 / 9328.0,
// --------------------------------------------------------
//
// COEFFICIENTS OF bi[6]
bi[6][0] = 0.0,
bi[6][1] = -25.0 / 28.0,
bi[6][2] = 205.0 / 42.0,
bi[6][3] = -45.0 / 7.0,
bi[6][4] = 18.0 / 7.0,
// --------------------------------------------------------
//
// COEFFICIENTS OF bi[7]
bi[7][0] = 0.0,
bi[7][1] = -2.0 / 11.0,
bi[7][2] = 73.0 / 55.0,
bi[7][3] = -171.0 / 55.0,
bi[7][4] = 108.0 / 55.0,
// --------------------------------------------------------
//
// COEFFICIENTS OF bi[8]
bi[8][0] = 0.0,
bi[8][1] = 189.0 / 22.0,
bi[8][2] = -1593.0 / 55.0,
bi[8][3] = 3537.0 / 110.0,
bi[8][4] = -648.0 / 55.0,
// --------------------------------------------------------
//
// COEFFICIENTS OF bi[9]
bi[9][0] = 0.0,
bi[9][1] = 351.0 / 110.0,
bi[9][2] = -999.0 / 55.0,
bi[9][3] = 2943.0 / 110.0,
bi[9][4] = -648.0 / 55.0;
// --------------------------------------------------------
// Calculating the polynomials
G4double b[10];
std::memset(b, 0.0, sizeof(b));
G4double tauPower = 1.0;
for(G4int j = 0; j <= 4; ++j)
{
for(G4int iStage = 1; iStage <= 9; ++iStage)
{
b[iStage] += bi[iStage][j] * tauPower;
}
tauPower *= tau;
}
// const G4int numberOfVariables = GetNumberOfVariables();
const G4double stepLen = fLastStepLength * tau;
for(G4int i = 0; i < N; ++i)
{
yOut[i] = fyIn[i] + stepLen * (
b[1] * fdydxIn[i] + b[2] * ak2[i] + b[3] * ak3[i] +
b[4] * ak4[i] + b[5] * ak5[i] + b[6] * ak6[i] +
b[7] * ak7[i] + b[8] * ak8[i] + b[9] * ak9[i]
);
}
}
#endif
@@ -0,0 +1,101 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// G4TExplicitEuler
//
// Class description:
//
// Templated version of G4ExplicitEuler
//
//
// Created: Josh Xie, June 2014 (supported by Google Summer of Code 2014 )
//
// Supervisors: Sandro Wenzel, John Apostolakis (CERN)
// Adapted from G4G4TExplicitEuler class
// -------------------------------------------------------------------
//
// Information from G4Explicit Euler:
// ----------------------------------
// Explicit Euler stepper for magnetic field: x_1 = x_0 + h * dx_0.
// The simplistic approach to solving linear differential equations.
// Take the current derivative and add it to the current position.
//
// Created: W.Wander <wwc@mit.edu>, 12.09.1997
// -------------------------------------------------------------------
// --------------------------------------------------------------------
#ifndef G4TExplicitEuler_HH
#define G4TExplicitEuler_HH
#include "G4TMagErrorStepper.hh"
#include "G4ThreeVector.hh"
template <class T_Equation, int N>
class G4TExplicitEuler
: public G4TMagErrorStepper<G4TExplicitEuler<T_Equation, N>, T_Equation, N>
{
public: // with description
static constexpr double IntegratorCorrection = 1.;
G4TExplicitEuler(T_Equation* EqRhs, G4int numberOfVariables = N)
: G4TMagErrorStepper<G4TExplicitEuler<T_Equation, N>, T_Equation, N>(
EqRhs, numberOfVariables)
, fEquation_Rhs(EqRhs)
{
if( numberOfVariables != N ){
G4ExceptionDescription msg;
msg << "Equation has an incompatible number of variables." ;
msg << " template N = " << N << " equation-Nvar= "
<< numberOfVariables;
G4Exception("G4TExplicitEuler: constructor", "GeomField0003",
FatalErrorInArgument, msg );
}
}
~G4TExplicitEuler() { ; }
inline void DumbStepper(const G4double yIn[],
const G4double dydx[],
G4double h, G4double yOut[]) // override final
{
// Initialise time to t0, needed when it is not updated by the integration.
// yOut[7] = yIn[7]; // Better to set it to NaN; // TODO
for(G4int i = 0; i < N; ++i)
{
yOut[i] = yIn[i] + h * dydx[i]; // 1st and only Step
}
return;
}
public: // without description
G4int IntegratorOrder() const { return 1; }
private:
T_Equation* fEquation_Rhs;
};
#endif /* G4TExplicitEuler_HH */
@@ -0,0 +1,181 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// G4TMagErrorStepper
//
// Class description:
//
// Templated version of G4MagErrorStepper
//
//
// Created: Josh Xie (supported by Google Summer of Code 2014 )
// Supervisors: Sandro Wenzel, John Apostolakis (CERN)
// Adapted from G4G4TMagErrorStepper class
// --------------------------------------------------------------------
#ifndef G4TMAG_ERROR_STEPPER_HH
#define G4TMAG_ERROR_STEPPER_HH
#include "G4Types.hh"
#include "G4MagIntegratorStepper.hh"
#include "G4ThreeVector.hh"
#include "G4LineSection.hh"
template <class T_Stepper, class T_Equation, unsigned int N>
class G4TMagErrorStepper : public G4MagIntegratorStepper
{
public: // with description
G4TMagErrorStepper(T_Equation* EqRhs, G4int numberOfVariables,
G4int numStateVariables = 12)
: G4MagIntegratorStepper(EqRhs, numberOfVariables, numStateVariables)
, fEquation_Rhs(EqRhs)
{
// G4int nvar = std::max(this->GetNumberOfVariables(), 8);
}
virtual ~G4TMagErrorStepper() { ; }
inline void RightHandSide(G4double y[], G4double dydx[])
{
fEquation_Rhs->T_Equation::RightHandSide(y, dydx);
}
inline void Stepper(const G4double yInput[], const G4double dydx[],
G4double hstep, G4double yOutput[], G4double yError[]) override final;
inline G4double DistChord() const override final;
private:
G4TMagErrorStepper(const G4TMagErrorStepper&);
G4TMagErrorStepper& operator=(const G4TMagErrorStepper&);
// Private copy constructor and assignment operator.
private:
// STATE
G4ThreeVector fInitialPoint, fMidPoint, fFinalPoint;
// Data stored in order to find the chord
// Dependent Objects, owned --- part of the STATE
G4double yInitial[N < 8 ? 8 : N];
G4double yMiddle[N < 8 ? 8 : N];
G4double dydxMid[N < 8 ? 8 : N];
G4double yOneStep[N < 8 ? 8 : N];
// The following arrays are used only for temporary storage
// they are allocated at the class level only for efficiency -
// so that calls to new and delete are not made in Stepper().
T_Equation* fEquation_Rhs;
};
// ------------ Implementation -----------------------
template <class T_Stepper, class T_Equation, unsigned int N >
void G4TMagErrorStepper<T_Stepper,T_Equation,N>::
Stepper(const G4double yInput[],
const G4double dydx[],
G4double hstep,
G4double yOutput[],
G4double yError[])
// The stepper for the Runge Kutta integration. The stepsize
// is fixed, with the Step size given by hstep.
// Integrates ODE starting values y[0 to N].
// Outputs yout[] and its estimated error yerr[].
{
const unsigned int maxvar = GetNumberOfStateVariables();
// Saving yInput because yInput and yOutput can be aliases for same array
for(unsigned int i = 0; i < N; ++i)
yInitial[i] = yInput[i];
yInitial[7] =
yInput[7]; // Copy the time in case ... even if not really needed
yMiddle[7] = yInput[7]; // Copy the time from initial value
yOneStep[7] = yInput[7]; // As it contributes to final value of yOutput ?
// yOutput[7] = yInput[7]; // -> dumb stepper does it too for RK4
for(unsigned int i = N; i < maxvar; ++i)
yOutput[i] = yInput[i];
G4double halfStep = hstep * 0.5;
// Do two half steps
static_cast<T_Stepper*>(this)->DumbStepper(yInitial, dydx, halfStep,
yMiddle);
this->RightHandSide(yMiddle, dydxMid);
static_cast<T_Stepper*>(this)->DumbStepper(yMiddle, dydxMid, halfStep,
yOutput);
// Store midpoint, chord calculation
fMidPoint = G4ThreeVector(yMiddle[0], yMiddle[1], yMiddle[2]);
// Do a full Step
static_cast<T_Stepper*>(this)->DumbStepper(yInitial, dydx, hstep, yOneStep);
for(unsigned int i = 0; i < N; ++i)
{
yError[i] = yOutput[i] - yOneStep[i];
yOutput[i] +=
yError[i] *
T_Stepper::IntegratorCorrection; // Provides accuracy increased
// by 1 order via the
// Richardson Extrapolation
}
fInitialPoint = G4ThreeVector(yInitial[0], yInitial[1], yInitial[2]);
fFinalPoint = G4ThreeVector(yOutput[0], yOutput[1], yOutput[2]);
return;
}
template <class T_Stepper, class T_Equation, unsigned int N >
inline G4double
G4TMagErrorStepper<T_Stepper,T_Equation,N>::DistChord() const
{
// Estimate the maximum distance from the curve to the chord
//
// We estimate this using the distance of the midpoint to
// chord (the line between
//
// Method below is good only for angle deviations < 2 pi,
// This restriction should not a problem for the Runge cutta methods,
// which generally cannot integrate accurately for large angle deviations.
G4double distLine, distChord;
if(fInitialPoint != fFinalPoint)
{
distLine = G4LineSection::Distline(fMidPoint, fInitialPoint, fFinalPoint);
// This is a class method that gives distance of Mid
// from the Chord between the Initial and Final points.
distChord = distLine;
}
else
{
distChord = (fMidPoint - fInitialPoint).mag();
}
return distChord;
}
#endif /* G4TMagErrorStepper_HH */
@@ -0,0 +1,101 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// G4TMagFieldEquation
//
// Class description:
//
// Templated version of equation of motion of a particle in a pure magnetic field.
// Enables use of inlined code for field, equation, stepper, driver,
// avoiding all virtual calls.
//
// Adapted from G4Mag_UsualEqRhs.hh
// --------------------------------------------------------------------
// Created: Josh Xie (Google Summer of Code 2014 )
// Adapted from G4Mag_UsualEqRhs
//
// #include "G4ChargeState.hh"
#include "G4Mag_UsualEqRhs.hh"
template
<class T_Field>
class G4TMagFieldEquation : public G4Mag_UsualEqRhs
{
public:
G4TMagFieldEquation(T_Field* f)
: G4Mag_UsualEqRhs(f)
{
itsField = f;
}
virtual ~G4TMagFieldEquation(){;}
inline void GetFieldValue(const G4double Point[4],
G4double Field[]) const
{
itsField->T_Field::GetFieldValue(Point, Field);
}
inline void TEvaluateRhsGivenB( const G4double y[],
const G4double B[3],
G4double dydx[] ) const
{
G4double momentum_mag_square = y[3]*y[3] + y[4]*y[4] + y[5]*y[5];
G4double inv_momentum_magnitude = 1.0 / std::sqrt( momentum_mag_square );
G4double cof = FCof()*inv_momentum_magnitude;
dydx[0] = y[3]*inv_momentum_magnitude; // (d/ds)x = Vx/V
dydx[1] = y[4]*inv_momentum_magnitude; // (d/ds)y = Vy/V
dydx[2] = y[5]*inv_momentum_magnitude; // (d/ds)z = Vz/V
dydx[3] = cof*(y[4]*B[2] - y[5]*B[1]) ; // Ax = a*(Vy*Bz - Vz*By)
dydx[4] = cof*(y[5]*B[0] - y[3]*B[2]) ; // Ay = a*(Vz*Bx - Vx*Bz)
dydx[5] = cof*(y[3]*B[1] - y[4]*B[0]) ; // Az = a*(Vx*By - Vy*Bx)
return ;
}
__attribute__((always_inline))
void RightHandSide(const G4double y[], G4double dydx[] )
// const
{
G4double Field[G4maximum_number_of_field_components];
G4double PositionAndTime[4];
PositionAndTime[0] = y[0];
PositionAndTime[1] = y[1];
PositionAndTime[2] = y[2];
PositionAndTime[3] = y[7];
GetFieldValue(PositionAndTime, Field) ;
TEvaluateRhsGivenB(y, Field, dydx);
}
private:
enum { G4maximum_number_of_field_components = 24 };
// Dependent objects
T_Field *itsField;
};
@@ -0,0 +1,113 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// G4TMagFieldEquation
//
// Class description:
//
// Templated version of motion of quadrupole magnetic field.
// Enables testing of inlined code for field, equation, stepper, driver,
// avoiding all virtual calls.
//
// --------------------------------------------------------------------
// Created: Josh Xie (Google Summer of Code 2014 )
// Adapted from G4QuadrupoleMagField ( of June 2014 .... )
//
#ifndef G4T_QUADRUPOLE_MAGFIELD_HH
#define G4T_QUADRUPOLE_MAGFIELD_HH
#include "G4ThreeVector.hh"
#include "G4RotationMatrix.hh"
#include "G4MagneticField.hh"
static G4RotationMatrix IdentityMatrix;
class G4TQuadrupoleMagField : public G4MagneticField
{
public: // with description
G4TQuadrupoleMagField(G4double pGradient)
{
fGradient = pGradient ;
fOrigin = G4ThreeVector( 0.0, 0.0, 0.0) ;
fpMatrix = &IdentityMatrix;
}
G4TQuadrupoleMagField(G4double pGradient,
G4ThreeVector pOrigin,
G4RotationMatrix* pMatrix)
{
fGradient = pGradient ;
fOrigin = pOrigin ;
fpMatrix = pMatrix ;
}
virtual ~G4TQuadrupoleMagField() {;}
inline void GetFieldValue(const G4double y[7],
G4double B[3] ) const
{
G4ThreeVector r_global = G4ThreeVector(
y[0] - fOrigin.x(),
y[1] - fOrigin.y(),
y[2] - fOrigin.z());
G4ThreeVector r_local = G4ThreeVector(
fpMatrix->colX() * r_global,
fpMatrix->colY() * r_global,
fpMatrix->colZ() * r_global);
G4ThreeVector B_local = G4ThreeVector(
fGradient * r_local.y(),
fGradient * r_local.x(),
0);
G4ThreeVector B_global = G4ThreeVector(
fpMatrix->inverse().rowX() * B_local,
fpMatrix->inverse().rowY() * B_local,
fpMatrix->inverse().rowZ() * B_local);
B[0] = B_global.x() ;
B[1] = B_global.y() ;
B[2] = B_global.z() ;
}
G4TQuadrupoleMagField* Clone() const
{
//TODO: Can the fpMatrix be shared??
return new G4TQuadrupoleMagField(this->fGradient,
this->fOrigin,
this->fpMatrix);
}
private:
G4double fGradient;
G4ThreeVector fOrigin;
G4RotationMatrix* fpMatrix;
};
#endif
@@ -0,0 +1,140 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// G4TSimpleHeum
//
// Class description:
//
// Templated version of G4SimpleHeum
//
// Created: Josh Xie (supported by Google Summer of Code 2014 )
// Supervisors: Sandro Wenzel, John Apostolakis (CERN)
// --------------------------------------------------------------------
// Adapted from G4G4TSimpleHeum class
// Original desription:
//
// Simple Heum stepper for magnetic field:
// 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.
// Created: W.Wander <wwc@mit.edu>, 12/09/1997
// --------------------------------------------------------------------
#ifndef TSIMPLEHEUM_HH
#define TSIMPLEHEUM_HH
#include <cassert>
#include "G4TMagErrorStepper.hh"
#include "G4ThreeVector.hh"
template <class T_Equation, unsigned int N>
class G4TSimpleHeum
: public G4TMagErrorStepper<G4TSimpleHeum<T_Equation, N>, T_Equation, N>
{
public: // with description
constexpr static unsigned int gIntegratorOrder = 3;
static constexpr double IntegratorCorrection= 1.0 /
((1<<gIntegratorOrder) - 1);
G4TSimpleHeum(T_Equation* EqRhs, unsigned int numberOfVariables = 6);
~G4TSimpleHeum() { ; }
// Constructor and destructor.
inline void RightHandSide(G4double y[],
G4double dydx[])
{
fEquation_Rhs->T_Equation::RightHandSide(y, dydx);
}
inline void DumbStepper(const G4double yIn[],
const G4double dydx[],
G4double h, G4double yOut[]); // override final
public: // without description
G4int IntegratorOrder() const { return gIntegratorOrder; }
private:
G4int fNumberOfVariables;
G4double dydxTemp[N];
G4double dydxTemp2[N];
G4double yTemp[N];
G4double yTemp2[N];
// scratch space
T_Equation* fEquation_Rhs;
};
template <class T_Equation, unsigned int N >
G4TSimpleHeum<T_Equation,N>::G4TSimpleHeum(T_Equation* EqRhs,
unsigned int numberOfVariables )
: G4TMagErrorStepper<G4TSimpleHeum<T_Equation, N>, T_Equation, N>(
EqRhs, numberOfVariables)
, fNumberOfVariables(numberOfVariables)
, fEquation_Rhs(EqRhs)
{
assert(fNumberOfVariables == N);
if( dynamic_cast<G4EquationOfMotion*>(EqRhs) == nullptr )
{
G4Exception("G4TSimpleHeum: constructor", "GeomField0001",
FatalException, "Equation is not an G4EquationOfMotion.");
}
}
template <class T_Equation, unsigned int N >
inline void
G4TSimpleHeum<T_Equation,N>::DumbStepper(const G4double yIn[],
const G4double dydx[],
G4double h, G4double yOut[])
{
for(unsigned int i = 0; i < N; ++i)
{
yTemp[i] = yIn[i] + (1.0 / 3.0) * h * dydx[i];
}
this->RightHandSide(yTemp, dydxTemp);
for(unsigned int i = 0; i < N; ++i)
{
yTemp2[i] = yIn[i] + (2.0 / 3.0) * h * dydxTemp[i];
}
this->RightHandSide(yTemp2, dydxTemp2);
for(unsigned int i = 0; i < N; ++i)
{
yOut[i] = yIn[i] + h * (0.25 * dydx[i] + 0.75 * dydxTemp2[i]);
}
if(fNumberOfVariables == 12)
{
this->NormalisePolarizationVector(yOut);
}
}
#endif /* TSIMPLEHEUM_HH */
@@ -0,0 +1,102 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// G4TSimpleRunge
//
// Class description:
//
// Templated version of G4SimpleRunge
//
//
// Created: Josh Xie (supported by Google Summer of Code 2014 )
// Supervisors: Sandro Wenzel, John Apostolakis (CERN)
// Adapted from G4G4TSimpleRunge class
// --------------------------------------------------------------------
#ifndef G4TSimpleRunge_HH
#define G4TSimpleRunge_HH
#include <cassert>
#include "G4TMagErrorStepper.hh"
#include "G4ThreeVector.hh"
template <class T_Equation, int N>
class G4TSimpleRunge
: public G4TMagErrorStepper<G4TSimpleRunge<T_Equation, N>, T_Equation, N>
{
public: // with description
static constexpr double IntegratorCorrection = 1. / ((1 << 2) - 1);
G4TSimpleRunge(T_Equation* EqRhs, G4int numberOfVariables = 6)
: G4TMagErrorStepper<G4TSimpleRunge<T_Equation, N>, T_Equation, N>(
EqRhs, numberOfVariables)
, fNumberOfVariables(numberOfVariables)
, fEquation_Rhs(EqRhs)
{
// default GetNumberOfStateVariables() == 12
assert(this->GetNumberOfStateVariables() <= 12);
}
~G4TSimpleRunge() { ; }
inline void RightHandSide(G4double y[],
G4double dydx[])
{
fEquation_Rhs->T_Equation::RightHandSide(y, dydx);
}
inline void DumbStepper(const G4double yIn[],
const G4double dydx[],
G4double h, G4double yOut[]) // override final
{
// Initialise time to t0, needed when it is not updated by the integration.
yTemp[7] = yOut[7] = yIn[7]; // Better to set it to NaN; // TODO
for(G4int i = 0; i < N; ++i)
{
yTemp[i] = yIn[i] + 0.5 * h * dydx[i];
}
this->RightHandSide(yTemp, dydxTemp);
for(G4int i = 0; i < N; ++i)
{
yOut[i] = yIn[i] + h * (dydxTemp[i]);
}
}
public: // without description
inline G4int IntegratorOrder() const { return 2; }
private:
G4int fNumberOfVariables;
G4double dydxTemp[N > 12 ? N : 12];
G4double yTemp[N > 12 ? N : 12];
T_Equation* fEquation_Rhs;
// scratch space
};
#endif /* G4TSimpleRunge_HH */
@@ -0,0 +1,114 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
#ifndef G4UniformMagneticField_HH
#define G4UniformMagneticField_HH
#include "G4Types.hh"
#include "G4ThreeVector.hh"
#include "G4MagneticField.hh"
class G4TUniformMagneticField : public G4MagneticField
{
public: // with description
G4TUniformMagneticField(const G4ThreeVector& FieldVector )
// A field with value equal to FieldVector.
{
fFieldComponents[0] = FieldVector.x();
fFieldComponents[1] = FieldVector.y();
fFieldComponents[2] = FieldVector.z();
}
G4TUniformMagneticField(G4double vField,
G4double vTheta,
G4double vPhi )
{
if ( (vField<0) || (vTheta<0) || (vTheta>pi) || (vPhi<0) || (vPhi>twopi) )
{
G4Exception("G4TUniformMagneticField::G4TUniformMagneticField()",
"GeomField0002", FatalException, "Invalid parameters.") ;
}
fFieldComponents[0] = vField*std::sin(vTheta)*std::cos(vPhi) ;
fFieldComponents[1] = vField*std::sin(vTheta)*std::sin(vPhi) ;
fFieldComponents[2] = vField*std::cos(vTheta) ;
}
virtual ~G4TUniformMagneticField() {;}
G4TUniformMagneticField(const G4TUniformMagneticField &p)
: G4MagneticField(p)
{
for (G4int i=0; i<3; ++i)
fFieldComponents[i] = p.fFieldComponents[i];
}
G4TUniformMagneticField& operator = (const G4TUniformMagneticField &p)
// Copy constructor and assignment operator.
{
if (&p == this) return *this;
for (G4int i=0; i<3; ++i)
fFieldComponents[i] = p.fFieldComponents[i];
return *this;
}
inline void GetFieldValue(const G4double yTrack[4],
G4double *B) const
{
B[0]= fFieldComponents[0] ;
B[1]= fFieldComponents[1] ;
B[2]= fFieldComponents[2] ;
}
void SetFieldValue(const G4ThreeVector& newFieldVector)
{
fFieldComponents[0] = newFieldVector.x();
fFieldComponents[1] = newFieldVector.y();
fFieldComponents[2] = newFieldVector.z();
}
G4ThreeVector GetConstantFieldValue() const
{
G4ThreeVector B(fFieldComponents[0],
fFieldComponents[1],
fFieldComponents[2]);
return B;
}
// Return the field value
virtual G4TUniformMagneticField* Clone() const
{
return new G4TUniformMagneticField( G4ThreeVector(this->fFieldComponents[0],
this->fFieldComponents[1],
this->fFieldComponents[2]) );
}
private:
G4double fFieldComponents[3] ;
};
#endif