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
+78
View File
@@ -15,6 +15,84 @@ committal in the CVS repository !
----------------------------------------------------------
* Reverse chronological order (last date on top), please *
----------------------------------------------------------
November 26, 2020 J.Apostolakis - field-V10-06-09
-------------------------------
- Fix to enable G4TDormandPrince45 to be used with G4InterpolationDriver.
This fix was needed because G4Interpolation driver creates additional
copies of the stepper class. Due to this it must obtain the equation
with the type of the templated stepper.
For a stepper to be used with 'G4InterpolationDriver', it must
implement the method
Equation_type GetSpecificEquation()
Templated steppers must ensure that the return type 'Equation_type'
is the specific equation type of the template.
This method was added to G4DormandPrince745 and G4TDormandPrince745.
October 12, 2020 J.Apostolakis - field-V10-06-08
------------------------------
- Fixes & refinements - mostly in templated classes, tests.
Compilation fixes, e.g. missing include <cassert>.
Refinements, e.g. int -> unsigned int in templates
October 9, 2020 J.Apostolakis - field-V10-06-07
-----------------------------
- Configure G4ChordFinder to use templated G4TDormandPrince45 as the
default stepper for magnetic fields (when one is not chosen
explicitly by the application.)
October 9, 2020 J.Apostolakis & J. Xie - field-V10-06-06
--------------------------------------
- Adapted classes that avoid virtual calls for field, equation, stepper
created by Josh Xie (Google Summer of Code 2014), supervised by
S. Wenzel & J.A.
The revised design and implementations include:
* equation of motion templated on the field type;
* steppers templated on the type of equation and the number of integration
variables.
In addition the key methods are marked as 'inline' to enable compilers, where
they judge possible, to embed them and avoid any function calls.
These classes can be combined also with the templated drivers
(G4IntegrationStepper, G4FSALIntegrationStepper and/or G4InterpolationDriver
to avoid virtual calls in all the levels up to the chord finder's call to
the integration driver. ]
The types of stepper currently available are
i) the originally developed intermediate order stepper:
- Name (templated) - original -- Order/ - Comments
/ Embdedded
==============================================================================
G4TClassicalRK4: G4ClassicalRK4 4th / no robust, old default
G4TCashKarpRKF45: G4CashKarpRKF45 5th / yes first embedded RK in G4
ii) the original low order steppers (for specialised uses)
G4TSimpleHeum: G4SimpleHeum 3rd / no lower order alternative
G4TSimpleRunge: G4SimpleRunge 2nd / no very low order
G4TExplicitEuler: G4ExplicitEuler 1st / no lowest order - for checks only
and
iii) some newly adapted stepper(s) / ( J.A. Oct 2020 )
G4TDormandPrince45 G4DormandPrince745 5th/ yes default / preferred
==============================================================================
Note: Additional lower-order steppers are not yet available.
'Vector' steppers (using blaze) are not supported.
Experimental versions of fields with inline methods:
G4TUniformMagField, G4TQuadrupoleMagField
are included to show how the field evaluation GetFieldValue can also be inlined.
Note 2:
Steppers which are not embedded obtain their error estimates by
breaking the step into two halves, then comparing with the whole step.
As a result many more field / derivative evaluations are needed than
embedded steppers of the same order, but the reliability of their error
estimation has different properties; so it may be more robust in some cases. )
June 15, 2020 G.Cosmo - field-V10-06-05
---------------------
@@ -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
@@ -98,6 +98,17 @@ geant4_define_module(NAME G4magneticfield
G4RKIntegrationDriver.icc
G4SimpleHeum.hh
G4SimpleRunge.hh
G4TExplicitEuler.hh
G4TSimpleHeum.hh
G4TSimpleRunge.hh
G4TCashKarpRKF45.hh
G4TClassicalRK4.hh
G4TDormandPrince45.hh
G4TMagFieldEquation.hh
G4TMagErrorStepper.hh
G4TQuadrupoleMagField.hh
G4TUniformMagneticField.hh
G4TCachedMagneticField.hh
G4TrialsCounter.hh
G4TrialsCounter.icc
G4TsitourasRK45.hh
@@ -37,35 +37,46 @@
#include "G4MagIntegratorDriver.hh"
// #include "G4ClassicalRK4.hh"
// #include "G4CashKarpRKF45.hh"
// #include "G4NystromRK4.hh"
// #include "G4BogackiShampine23.hh"
// #include "G4BogackiShampine45.hh"
#include "G4DormandPrince745.hh"
// New FSAL type driver / steppers -----
// New templated stepper(s) -- avoid virtual calls to equation rhs
#include "G4TDormandPrince45.hh"
// FSAL type driver / steppers -----
#include "G4FSALIntegrationDriver.hh"
#include "G4VFSALIntegrationStepper.hh"
#include "G4RK547FEq1.hh"
// #include "G4RK547FEq2.hh"
// #include "G4RK547FEq3.hh"
#include "G4NystromRK4.hh"
// New FSAL type driver / steppers -----
#include "G4IntegrationDriver.hh"
#include "G4InterpolationDriver.hh"
// #include "G4FSALBogackiShampine45.hh"
// #include "G4FSALDormandPrince745.hh"
// Templated type drivers -----
#include "G4IntegrationDriver.hh"
#include "G4InterpolationDriver.hh"
#include "G4HelixHeum.hh"
#include "G4BFieldIntegrationDriver.hh"
#include "G4CachedMagneticField.hh"
#include <cassert>
static G4bool gVerboseCtor = false; // true;
// ..........................................................................
G4ChordFinder::G4ChordFinder(G4VIntegrationDriver* pIntegrationDriver)
: fDefaultDeltaChord(0.25 * mm), fIntgrDriver(pIntegrationDriver)
{
// Simple constructor -- it does not create equation
if( gVerboseCtor )
G4cout << "G4ChordFinder: Simple constructor -- it uses pre-existing driver." << G4endl;
fDeltaChord = fDefaultDeltaChord; // Parameters
}
@@ -75,45 +86,71 @@ G4ChordFinder::G4ChordFinder(G4VIntegrationDriver* pIntegrationDriver)
G4ChordFinder::G4ChordFinder( G4MagneticField* theMagField,
G4double stepMinimum,
G4MagIntegratorStepper* pItsStepper,
G4bool useFSALstepper )
G4int stepperDriverId )
: fDefaultDeltaChord(0.25 * mm)
{
// Construct the Chord Finder
// by creating in inverse order the Driver, the Stepper and EqRhs ...
constexpr G4int nVar6 = 6; // Components integrated in Usual Equation of motion
fDeltaChord = fDefaultDeltaChord; // Parameters
using NewFsalStepperType = G4RK547FEq1; // or 2 or 3
const char* NewFSALStepperName =
"G4RK574FEq1> FSAL 4th/5th order 7-stage 'Equilibrium-type' #1.";
// stepperDriverId = 2;
G4bool useFSALstepper= (stepperDriverId == 1);
G4bool useTemplatedStepper= (stepperDriverId == 2);
G4bool useRegularStepper = (stepperDriverId == 3);
// G4bool useBFieldDriver = !useRegularStepper && !useFSALstepper && !useTemplatedStepper;
// G4bool useRegularStepper = !stepperDriverId != 3) && !useFSALStepper && !useTemplatedStepper;
// If it's not 0, 1 or 2 then 'BFieldDriver' which combines DoPri5 (short) and helix is used.
using EquationType = G4Mag_UsualEqRhs;
using TemplatedStepperType =
G4TDormandPrince45<EquationType,nVar6>; // 5th order embedded method. High efficiency.
const char* TemplatedStepperName =
"G4TDormandPrince745 (templated Dormand-Prince45, aka DoPri5): 5th/4th Order 7-stage embedded";
using RegularStepperType =
G4DormandPrince745; // 5th order embedded method. High efficiency.
G4DormandPrince745; // 5th order embedded method. High efficiency.
// G4ClassicalRK4; // The old default
// G4CashKarpRKF45; // First embedded method in G4
// G4BogackiShampine45; // High efficiency 5th order embedded method
// G4NystromRK4; // Nystrom stepper 4th order
// G4RK547FEq1; // or 2 or 3
const char* RegularStepperName =
"G4DormandPrince745 (aka DOPRI5): 5th/4th Order 7-stage embedded stepper";
"G4DormandPrince745 (aka DOPRI5): 5th/4th Order 7-stage embedded";
// "BogackiShampine 45 (Embedded 5th/4th Order, 7-stage)";
// "Nystrom stepper 4th order";
// Configurable
G4bool forceFSALstepper = false; // Choice - true to enable !!
G4bool recallFSALflag = useFSALstepper;
useFSALstepper = forceFSALstepper || useFSALstepper;
using NewFsalStepperType = G4DormandPrince745; // Now works -- 2020.10.08
// Was G4RK547FEq1; // or 2 or 3
const char* NewFSALStepperName =
"G4RK574FEq1> FSAL 4th/5th order 7-stage 'Equilibrium-type' #1.";
#ifdef G4DEBUG_FIELD
static G4bool verboseDebug = true;
if( verboseDebug )
{
G4cout << "G4ChordFinder 2nd Constructor called. " << G4endl;
G4cout << " Parameters: " << G4endl;
G4cout << " useFSAL stepper= " << useFSALstepper
<< " (request = " << recallFSALflag
<< " force FSAL = " << forceFSALstepper << " )" << G4endl;
G4cout << " Arguments: " << G4endl
<< " - min step = " << stepMinimum << G4endl
<< " - stepper ptr provided : "
<< ( pItsStepper==nullptr ? " no " : " yes " ) << G4endl;
if( pItsStepper==nullptr )
G4cout << " - stepper/driver Id = " << stepperDriverId << " i.e. "
<< " useFSAL = " << useFSALstepper
<< " , useTemplated = " << useTemplatedStepper
<< " , useRegular = " << useRegularStepper
<< " , useFSAL = " << useFSALstepper
<< G4endl;
}
#endif
// useHigherStepper = forceHigherEffiencyStepper || useHigherStepper;
G4Mag_EqRhs* pEquation = new G4Mag_UsualEqRhs(theMagField);
EquationType* pEquation = new G4Mag_UsualEqRhs(theMagField);
fEquation = pEquation;
// G4MagIntegratorStepper* regularStepper = nullptr;
@@ -126,41 +163,87 @@ G4ChordFinder::G4ChordFinder( G4MagneticField* theMagField,
if( pItsStepper != nullptr )
{
#if 0
// G4cout << " G4ChordFinder: Creating G4IntegrationDriver<G4MagIntegratorStepper> with "
// << " stepMinimum = " << stepMinimum
// << " numVar= " << pItsStepper->GetNumberOfVariables() << G4endl;
// Type is not known - so must use old class
if( gVerboseCtor )
G4cout << " G4ChordFinder: Creating G4IntegrationDriver<G4MagIntegratorStepper> with "
<< " stepMinimum = " << stepMinimum
<< " numVar= " << pItsStepper->GetNumberOfVariables() << G4endl;
// Stepper type is not known - so must use base class G4MagIntegratorStepper
fIntgrDriver = new G4IntegrationDriver<G4MagIntegratorStepper>(
stepMinimum, pItsStepper, pItsStepper->GetNumberOfVariables());
#else
G4cout << " G4ChordFinder: Creating G4MagInt_Driver with "
<< " stepMinimum = " << stepMinimum
<< " numVar= " << pItsStepper->GetNumberOfVariables() << G4endl;
fIntgrDriver = new G4MagInt_Driver( stepMinimum, pItsStepper,
pItsStepper->GetNumberOfVariables());
#endif
// -- Older:
// G4cout << " G4ChordFinder: Creating G4MagInt_Driver with " ...
// Type is not known - so must use old class
// fIntgrDriver = new G4MagInt_Driver( stepMinimum, pItsStepper,
// pItsStepper->GetNumberOfVariables());
}
else if ( !useFSALstepper )
else if ( useTemplatedStepper )
{
if( gVerboseCtor )
G4cout << " G4ChordFinder: Creating Templated Stepper of type> "
<< TemplatedStepperName << G4endl;
// RegularStepperType* regularStepper = nullptr; // To check the exception
auto regularStepper = new RegularStepperType(pEquation);
auto templatedStepper = new TemplatedStepperType(pEquation);
// *** ******************
//
// Alternative - for G4NystromRK4:
// = new G4NystromRK4(pEquation, 0.1*mm );
fRegularStepperOwned = regularStepper;
if( regularStepper == nullptr )
fRegularStepperOwned = templatedStepper;
if( templatedStepper == nullptr )
{
message << "Stepper instantiation FAILED." << G4endl;
message << "Templated Stepper instantiation FAILED." << G4endl;
message << "G4ChordFinder: Attempted to instantiate "
<< RegularStepperName << " type stepper " << G4endl;
G4Exception("G4ChordFinder::G4ChordFinder()",
"GeomField1001", JustWarning, message);
<< TemplatedStepperName << " type stepper " << G4endl;
errorInStepperCreation = true;
}
else
{
fIntgrDriver = new G4IntegrationDriver<TemplatedStepperType>(
stepMinimum, templatedStepper, nVar6 );
if( gVerboseCtor )
G4cout << " G4ChordFinder: Using G4IntegrationDriver. " << G4endl;
}
}
else if ( useRegularStepper ) // Plain stepper -- not double ...
{
auto regularStepper = new RegularStepperType(pEquation);
// *** ******************
fRegularStepperOwned = regularStepper;
if( gVerboseCtor )
G4cout << " G4ChordFinder: Creating Driver for regular stepper.";
if( regularStepper == nullptr )
{
message << "Regular Stepper instantiation FAILED." << G4endl;
message << "G4ChordFinder: Attempted to instantiate "
<< RegularStepperName << " type stepper " << G4endl;
errorInStepperCreation = true;
}
else
{
auto dp5= dynamic_cast<G4DormandPrince745*>(regularStepper);
if( dp5 ) {
fIntgrDriver = new G4InterpolationDriver<G4DormandPrince745>(
stepMinimum, dp5, nVar6 );
if( gVerboseCtor )
G4cout << " Using InterpolationDriver<DoPri5> " << G4endl;
} else {
fIntgrDriver = new G4IntegrationDriver<RegularStepperType>(
stepMinimum, regularStepper, nVar6 );
if( gVerboseCtor )
G4cout << " Using IntegrationDriver<DoPri5> " << G4endl;
}
}
}
else if ( !useFSALstepper )
{
auto regularStepper = new G4DormandPrince745(pEquation);
// *** ******************
//
fRegularStepperOwned = regularStepper;
{
using SmallStepDriver = G4InterpolationDriver<G4DormandPrince745>;
using LargeStepDriver = G4IntegrationDriver<G4HelixHeum>;
@@ -245,9 +328,13 @@ G4ChordFinder::G4ChordFinder( G4MagneticField* theMagField,
const std::string BoolName[2]= { "False", "True" };
errmsg << " Configuration: (constructor arguments) " << G4endl
<< " provided Stepper = " << pItsStepper << G4endl
<< " use FSAL stepper = " << BoolName[useFSALstepper]
<< " (request = " << BoolName[recallFSALflag]
<< " force FSAL = " << BoolName[forceFSALstepper] << " )"
<< " stepper/driver Id = " << stepperDriverId << " i.e. "
<< " useTemplated = " << BoolName[useTemplatedStepper]
<< " useRegular = " << BoolName[useRegularStepper]
<< " useFSAL = " << BoolName[useFSALstepper]
<< " using combo BField Driver = " <<
BoolName[ ! (useFSALstepper||useTemplatedStepper
|| useRegularStepper ) ]
<< G4endl;
errmsg << message.str();
errmsg << "Aborting.";
@@ -57,6 +57,13 @@
using namespace field_utils;
const G4String G4DormandPrince745::gStepperType =
G4String("G4DormandPrince745: 5th order");
const G4String G4DormandPrince745::gStepperDescription= G4String(
"Embedeed 5th order Runge-Kutta stepper - 7 stages, FSAL, Interpolating.");
G4DormandPrince745::G4DormandPrince745(G4EquationOfMotion* equation,
G4int noIntegrationVariables)
: G4MagIntegratorStepper(equation, noIntegrationVariables)
@@ -71,7 +78,7 @@ void G4DormandPrince745::Stepper(const G4double yInput[],
G4double dydxOutput[])
{
Stepper(yInput, dydx, hstep, yOutput, yError);
copy(dydxOutput, ak7);
field_utils::copy(dydxOutput, ak7);
}
// Stepper
@@ -28,6 +28,7 @@
// Author: J.Apostolakis, CERN - 15.01.1997
// --------------------------------------------------------------------
#include <cassert>
#include "G4MagIntegratorStepper.hh"
// Constructor for stepper abstract base class.
@@ -43,4 +44,9 @@ G4MagIntegratorStepper( G4EquationOfMotion* Equation,
fNoStateVariables(std::max(num_state_vars,8)),
fIsFSAL(isFSAL)
{
if( Equation == nullptr ) {
G4Exception( "G4MagIntegratorStepper::G4MagIntegratorStepper", "GeomField0003",
FatalErrorInArgument, "Must have non-null equation." );
}
assert( Equation != nullptr );
}