Import Geant4 11.4.0 source tree

This commit is contained in:
Gabriele Cosmo
2025-12-05 08:54:02 +01:00
parent a499fb82e9
commit b4a16de652
6484 changed files with 232674 additions and 221097 deletions
+59 -2
View File
@@ -6,6 +6,65 @@ It must **not** be used as a substitute for writing good git commit messages!
-------------------------------------------------------------------------------
## 2025-11-03 Vladimir Ivanchenko (field-V11-03-09)
- G4TClassicalRK4 - fixed typo identified by CMS
## 2025-10-21 Gabriele Cosmo (field-V11-03-08)
- Reorganised and enriched comments in headers to follow Doxygen style.
- Moved inline implementations to .icc file for G4ChargeState and for
G4FieldParameters.
- Removed not implemented methods in G4ChordFinder, G4DoLoMcPriRK34 and
G4FieldSetup.
## 2025-09-09 Gabriele Cosmo (field-V11-03-07)
- Applied clang-tidy fixes: basic, modernize-use-default-member-init,
readability-redundant-member-init, modernize-use-emplace,
readability-container-size-empty, readability-implicit-bool-conversion,
performance-unnecessary-value-param, readability-else-after-return,
modernize-return-braced-init-list.
- Minor code cleanup and formatting.
## 2025-09-08 Gabriele Cosmo (field-V11-03-06)
- Disabled use of QSS as default stepper in G4ChordFinder.
## 2025-08-19 John Apostolakis (field-V11-03-05)
- Fixed big bug in method compare_time_and_update, from conversion of macro
- Enabled use of QSS3 (now a choice in G4ChordFinder).
- Addressed Coverity issues (memory leak, initialisation) in G4QSStepper
and G4QSSubstepStruct.
- G4QSSMessenger: added QSS3 as option, made data private, added access methods
- G4QSStepper: cleanup of constructors, made qssOrder const data member.
- testQssDriver.cc : corrected and improved this unit test, a critical check.
## 2025-08-11 Ivana Hrivnacova (field-V11-03-04)
- Added default implementation to pure virtual functions introduced in the
previous tag for backward compatibility:
G4MagIntegratorStepper.hh:
virtual G4StepperType StepperType() const { return kUserStepper; }
G4Field.hh
virtual G4FieldType GetFieldType() const { return kUserFieldType; }
## 2025-06-23 Ivana Hrivnacova (field-V11-03-03)
- Consistent use of the parameters introduced in G4FieldParameters
in field classes:
- Extracted default parameters values as constexpr in new namespace 'G4FieldDefaults',
so that they can be used in other classes as default parameters in functions
declarations
- Replaced defalut values in 'G4FieldManager' and 'G4ChordFinder' with
'G4FieldDefaults' constants
- Added functions for accessing the field, stepper and equation types
using the enum types defined in 'G4FieldParameters':
G4MagIntegratorStepper.hh:
virtual G4StepperType StepperType() const = 0;
G4Field.hh
virtual G4FieldType GetFieldType() const = 0;
G4EquationOfMotion.hh:
virtual G4EquationType GetEquationType() const { return kUserEquation; }
and their implementation in all derived classes defined in the magneticfield category
- Updated enums 'G4EquationType' and 'G4StepperType' with missing constants
with a comment that these equations/templated steppers are not built by G4FieldBuilder
- Renamed 'const G4String& G4DormandPrince745::StepperType() const;' in 'StepperTypeName'
## 2025-06-13 Gabriele Cosmo (field-V11-03-02)
- Fixed compilation warning in G4QSStepper and minor code formatting.
@@ -123,7 +182,6 @@ It must **not** be used as a substitute for writing good git commit messages!
- Fixed compilation warnings for implicit type conversions on macOS/XCode 14.1.
## 2022-11-05 Divyansh Tiwari, John Apostolakis (field-V11-00-02)
- Introduced G4BorisScheme and G4BorisDriver, a 2nd order symplectic
integration method, created as part of GSoC 2022.
@@ -243,7 +301,6 @@ March 13, 2020 J.Apostolakis - field-V10-06-03
( Done to enable comparisons with new G4IntegrationDriver<> implementation.)
- G4OldMagIntDriver maintains all old behaviour of G4MagInt_Driver.
January 22, 2020 G.Cosmo - field-V10-06-02
------------------------
- Fixed compilation errors and configuration for field07 unit test.
@@ -27,9 +27,10 @@
//
// Class description:
//
// Specialized integration driver for pure magnetic field
// Specialised integration driver for pure magnetic field.
// Author: D.Sorokin
// Author: Dmitry Sorokin (CERN, Google Summer of Code 2017), 12.09.2018
// Supervision: John Apostolakis (CERN)
// --------------------------------------------------------------------
#ifndef G4BFIELD_INTEGRATION_DRIVER_HH
#define G4BFIELD_INTEGRATION_DRIVER_HH
@@ -39,115 +40,143 @@
#include <memory>
/**
* @brief G4BFieldIntegrationDriver is specialised integration driver
* for pure magnetic field.
*/
class G4BFieldIntegrationDriver : public G4VIntegrationDriver
{
public:
/**
* Constructor for the integrator driver.
* @param[in] smallStepDriver Pointer to driver for small steps.
* @param[in] largeStepDriver Pointer to driver for large steps.
*/
G4BFieldIntegrationDriver(
std::unique_ptr<G4VIntegrationDriver> smallStepDriver,
std::unique_ptr<G4VIntegrationDriver> largeStepDriver);
/**
* Default Destructor.
*/
~G4BFieldIntegrationDriver() override = default;
/**
* Copy constructor and assignment operator not allowed.
*/
G4BFieldIntegrationDriver(const G4BFieldIntegrationDriver &) = delete;
const G4BFieldIntegrationDriver& operator =(const G4BFieldIntegrationDriver &) = delete;
/**
* Computes the step to take, based on chord limits.
* @param[in,out] track The current track in field.
* @param[in] hstep Proposed step length.
* @param[in] eps Requested accuracy, y_err/hstep.
* @param[in] chordDistance Maximum sagitta distance.
* @returns The length of step taken.
*/
G4double AdvanceChordLimited(G4FieldTrack& track,
G4double hstep,
G4double eps,
G4double chordDistance) override;
G4bool AccurateAdvance(G4FieldTrack& track,
G4double hstep,
G4double eps,
G4double hinitial = 0) override
{
return fCurrDriver->AccurateAdvance(track, hstep, eps, hinitial);
}
/**
* Integrates ODE from current s (s=s0) to s=s0+h with accuracy eps.
* @param[in,out] track The current track in field.
* @param[in] hstep Proposed step length.
* @param[in] eps Requested accuracy, y_err/hstep.
* @param[in] hinitial Initial minimum integration step.
* @returns true if integration succeeds.
*/
inline G4bool AccurateAdvance(G4FieldTrack& track,
G4double hstep,
G4double eps,
G4double hinitial = 0) override;
G4bool DoesReIntegrate() const override
{
return fCurrDriver->DoesReIntegrate();
}
/**
* Checks whether the driver implements re-integration.
* @returns true if driver *Recalculates* when AccurateAdvance() is called.
*/
inline G4bool DoesReIntegrate() const override;
//[[deprecated("will be removed")]]
void GetDerivatives(const G4FieldTrack& track,
G4double dydx[]) const override
{
fCurrDriver->GetDerivatives(track, dydx);
}
//[[deprecated("will be removed")]]
void GetDerivatives(const G4FieldTrack& track,
G4double dydx[],
G4double field[]) const override
{
fCurrDriver->GetDerivatives(track, dydx, field);
}
/**
* Setter and getter for the equation of motion.
*/
void SetEquationOfMotion(G4EquationOfMotion* equation) override;
inline G4EquationOfMotion* GetEquationOfMotion() override;
G4EquationOfMotion* GetEquationOfMotion() override
{
return fCurrDriver->GetEquationOfMotion();
}
/**
* Returns a pointer to the integrator stepper.
*/
inline G4MagIntegratorStepper* GetStepper() override;
//[[deprecated("use GetEquationOfMotion() instead of GetStepper()->GetEquationOfMotion()")]]
const G4MagIntegratorStepper* GetStepper() const override
{
return fCurrDriver->GetStepper();
}
/**
* Computes a step size for the next step, taking the last step's
* normalised error 'errMaxNorm'.
* @param[in] errMaxNorm The normalised error on last step.
* @param[in] hstepCurrent The current proposed step.
* @returns The step size for the next step.
*/
inline G4double ComputeNewStepSize(G4double errMaxNorm,
G4double hstepCurrent) override;
G4MagIntegratorStepper* GetStepper() override
{
return fCurrDriver->GetStepper();
}
/**
* Setter and getter for verbosity.
*/
inline void SetVerboseLevel(G4int level) override;
inline G4int GetVerboseLevel() const override;
G4double ComputeNewStepSize(G4double errMaxNorm,
G4double hstepCurrent) override
{
return fCurrDriver->ComputeNewStepSize(errMaxNorm, hstepCurrent);
}
/**
* Dispatch interface method for computing step.
*/
inline void OnComputeStep(const G4FieldTrack* track) override;
void SetVerboseLevel(G4int level) override
{
fSmallStepDriver->SetVerboseLevel(level);
fLargeStepDriver->SetVerboseLevel(level);
}
/**
* Dispatch interface method for initialisation/reset of driver.
*/
inline void OnStartTracking() override;
G4int GetVerboseLevel() const override
{
return fCurrDriver->GetVerboseLevel();
}
void OnComputeStep(const G4FieldTrack* track) override
{
fSmallStepDriver->OnComputeStep(track);
fLargeStepDriver->OnComputeStep(track);
}
void OnStartTracking() override
{
fSmallStepDriver->OnStartTracking();
fLargeStepDriver->OnStartTracking();
}
void StreamInfo( std::ostream& os ) const override
{
os << "Small Step Driver Info: " << std::endl;
fSmallStepDriver->StreamInfo(os);
os << "Large Step Driver Info: " << std::endl;
fLargeStepDriver->StreamInfo(os);
}
// Write out the parameters / state of the driver
/**
* Writes out to stream the parameters/state of the driver.
*/
inline void StreamInfo( std::ostream& os ) const override;
/**
* Prints out statistics of the integrator driver.
*/
void PrintStatistics() const;
/** [[deprecated("will be removed")]] */
inline void GetDerivatives(const G4FieldTrack& track,
G4double dydx[]) const override;
/** [[deprecated("will be removed")]] */
inline void GetDerivatives(const G4FieldTrack& track,
G4double dydx[],
G4double field[]) const override;
/** [[deprecated("use GetEquationOfMotion() instead of GetStepper()->GetEquationOfMotion()")]] */
inline const G4MagIntegratorStepper* GetStepper() const override;
private:
/**
* Given the field track, computes the radius of the curvature in field.
*/
G4double CurvatureRadius(const G4FieldTrack& track) const;
/**
* Returns the value of the field in the 'Field' array, give the track.
* @param[in] track The current field track.
* @param[in,out] Field The array with field values.
*/
void GetFieldValue(const G4FieldTrack& track,
G4double Field[] ) const;
G4double Field[] ) const;
private:
std::unique_ptr<G4VIntegrationDriver> fSmallStepDriver;
std::unique_ptr<G4VIntegrationDriver> fLargeStepDriver;
G4VIntegrationDriver* fCurrDriver = nullptr;
@@ -157,4 +186,6 @@ class G4BFieldIntegrationDriver : public G4VIntegrationDriver
G4int fLargeDriverSteps = 0;
};
#include "G4BFieldIntegrationDriver.icc"
#endif
@@ -23,99 +23,103 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// class G4BFieldIntegrationDriver
// G4BFieldIntegrationDriver inline methods
//
// Class description:
//
// Specialized integration driver for pure magnetic field
// Author: D.Sorokin, CERN
// Author: Dmitry Sorokin (CERN, Google Summer of Code), 12.09.2018
// Supervision: John Apostolakis (CERN)
// --------------------------------------------------------------------
#include "globals.hh"
#include "G4GeometryTolerance.hh"
#include "G4FieldTrack.hh"
#include "G4FieldUtils.hh"
namespace internal
{
G4Mag_EqRhs* toMagneticEquation(G4EquationOfMotion* equation)
{
auto e = dynamic_cast<G4Mag_EqRhs*>(equation);
if (!e)
{
G4Exception("G4BFieldIntegrationDriver::G4BFieldIntegrationDriver",
"GeomField0003", FatalErrorInArgument,
"Works only with G4Mag_EqRhs");
}
return e;
}
} // internal
template <class T>
G4BFieldIntegrationDriver<T>::G4BFieldIntegrationDriver(G4double hminimum,
T* pStepper,
G4int numComponents,
G4int statisticsVerbose)
: G4IntegrationDriver<T>(hminimum, pStepper, numComponents, statisticsVerbose),
fallbackThreshold(pi / 3.),
fequation(internal::toMagneticEquation(pStepper->GetEquationOfMotion())),
fallbackStepper(fequation)
inline
G4bool G4BFieldIntegrationDriver::AccurateAdvance(G4FieldTrack& track,
G4double hstep,
G4double eps,
G4double hinitial)
{
return fCurrDriver->AccurateAdvance(track, hstep, eps, hinitial);
}
template <class T>
bool G4BFieldIntegrationDriver<T>::QuickAdvance(G4FieldTrack& fieldTrack,
const G4double dydx[],
G4double hstep,
G4double inverseCurvatureRadius,
G4double& dchord_step,
G4double& dyerr)
inline
G4bool G4BFieldIntegrationDriver::DoesReIntegrate() const
{
if (hstep * inverseCurvatureRadius < fallbackThreshold)
{
return G4IntegrationDriver<T>::QuickAdvance(
fieldTrack, dydx, hstep, inverseCurvatureRadius, dchord_step, dyerr);
}
G4IntegrationDriver<T>::IncrementQuickAdvanceCalls();
G4double yError[G4FieldTrack::ncompSVEC],
yIn[G4FieldTrack::ncompSVEC],
yOut[G4FieldTrack::ncompSVEC];
fieldTrack.DumpToArray(yIn);
fallbackStepper.Stepper(yIn, dydx, hstep, yOut, yError);
dchord_step = fallbackStepper.DistChord();
dyerr = field_utils::absoluteError(yOut, yError, hstep);
fieldTrack.LoadFromArray(yOut, fallbackStepper.GetNumberOfVariables());
fieldTrack.SetCurveLength(fieldTrack.GetCurveLength() + hstep);
return true;
return fCurrDriver->DoesReIntegrate();
}
inline
G4EquationOfMotion* G4BFieldIntegrationDriver::GetEquationOfMotion()
{
return fCurrDriver->GetEquationOfMotion();
}
template <class T>
void G4BFieldIntegrationDriver<T>::
SetEquationOfMotion(G4EquationOfMotion* equation)
inline
G4MagIntegratorStepper* G4BFieldIntegrationDriver::GetStepper()
{
G4IntegrationDriver<T>::SetEquationOfMotion(equation);
fequation = internal::toMagneticEquation(equation);
return fCurrDriver->GetStepper();
}
template <class T>
G4double G4BFieldIntegrationDriver<T>::
GetInverseCurvatureRadius(const G4FieldTrack& track,
G4double field[]) const
inline
G4double G4BFieldIntegrationDriver::ComputeNewStepSize(G4double errMaxNorm,
G4double hstepCurrent)
{
const G4double Bmag = std::sqrt(field[0] * field[0]
+ field[1] * field[1] + field[2] * field[2]);
const G4double momentum = track.GetMomentum().mag();
const G4double particleCharge = fequation->FCof()
/ (CLHEP::eplus * CLHEP::c_light);
return std::abs(field_utils::inverseCurvatureRadius(particleCharge,
momentum, Bmag));
return fCurrDriver->ComputeNewStepSize(errMaxNorm, hstepCurrent);
}
inline
void G4BFieldIntegrationDriver::SetVerboseLevel(G4int level)
{
fSmallStepDriver->SetVerboseLevel(level);
fLargeStepDriver->SetVerboseLevel(level);
}
inline
G4int G4BFieldIntegrationDriver::GetVerboseLevel() const
{
return fCurrDriver->GetVerboseLevel();
}
inline
void G4BFieldIntegrationDriver::OnComputeStep(const G4FieldTrack* track)
{
fSmallStepDriver->OnComputeStep(track);
fLargeStepDriver->OnComputeStep(track);
}
inline
void G4BFieldIntegrationDriver::OnStartTracking()
{
fSmallStepDriver->OnStartTracking();
fLargeStepDriver->OnStartTracking();
}
inline
void G4BFieldIntegrationDriver::StreamInfo( std::ostream& os ) const
{
os << "Small Step Driver Info: " << std::endl;
fSmallStepDriver->StreamInfo(os);
os << "Large Step Driver Info: " << std::endl;
fLargeStepDriver->StreamInfo(os);
}
/** ----------------- Deprecated methods ----------------------------------- **/
inline
void G4BFieldIntegrationDriver::GetDerivatives(const G4FieldTrack& track,
G4double dydx[]) const
{
fCurrDriver->GetDerivatives(track, dydx);
}
inline
void G4BFieldIntegrationDriver::GetDerivatives(const G4FieldTrack& track,
G4double dydx[],
G4double field[]) const
{
fCurrDriver->GetDerivatives(track, dydx, field);
}
inline
const G4MagIntegratorStepper* G4BFieldIntegrationDriver::GetStepper() const
{
return fCurrDriver->GetStepper();
}
/** ------------------------------------------------------------------------ **/
@@ -27,19 +27,19 @@
//
// Class description:
//
// Bogacki-Shampine - 4 - 3(2) non-FSAL implementation
// Bogacki-Shampine - 4 - 3(2) non-FSAL implementation
//
// An implementation of the embedded RK method from the paper
// An implementation of the embedded RK method from the paper
// [1] P. Bogacki and L. F. Shampine,
// "A 3(2) pair of Runge - Kutta formulas"
// Appl. Math. Lett., vol. 2, no. 4, pp. 321-325, Jan. 1989.
//
// This version does not utilise the FSAL property of the method,
// which would allow the reuse of the last derivative in the next step.
// (Alternative FSAL implementation created with revised interface)
// This version does not utilise the FSAL property of the method,
// which would allow the reuse of the last derivative in the next step.
// (Alternative FSAL implementation created with revised interface)
// Created: Somnath Banerjee, Google Summer of Code 2015, 20 May 2015
// Supervision: John Apostolakis, CERN
// Author: Somnath Banerjee (CERN, Google Summer of Code 2015), 20.05.2015
// Supervision: John Apostolakis (CERN)
// --------------------------------------------------------------------
#ifndef G4BOGACKI_SHAMPINE23_HH
#define G4BOGACKI_SHAMPINE23_HH
@@ -47,19 +47,60 @@
#include "G4MagIntegratorStepper.hh"
#include "G4FieldTrack.hh"
/**
* @brief G4BogackiShampine23 is an integrator of particle's equation of
* motion based on the Bogacki-Shampine non-FSAL implementation.
*/
class G4BogackiShampine23 : public G4MagIntegratorStepper
{
public:
/**
* Constructor for G4BogackiShampine23.
* @param[in] EqRhs Pointer to the provided equation of motion.
* @param[in] numberOfVariables The number of integration variables.
*/
G4BogackiShampine23(G4EquationOfMotion* EqRhs,
G4int numberOfVariables = 6);
/**
* Default Destructor.
*/
~G4BogackiShampine23() override = default;
/**
* Copy constructor and assignment operator not allowed.
*/
G4BogackiShampine23(const G4BogackiShampine23&) = delete;
G4BogackiShampine23& operator = (const G4BogackiShampine23&) = delete;
/**
* The stepper for the Runge Kutta integration.
* The stepsize is fixed, with the step size given by 'hstep'.
* Integrates ODE starting values yInput[0 to 6].
* Outputs yOutput[] and its estimated error yError[].
* @param[in] yInput Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[in] hstep The given step size.
* @param[out] yOutput Integration output.
* @param[out] yError The estimated error.
*/
void Stepper(const G4double yInput[],
const G4double dydx[],
G4double hstep,
G4double yOutput[],
G4double yError[]) override;
/**
* Same as the Stepper() function above, with dydx also in ouput.
* @param[in] yInput Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[in] hstep The given step size.
* @param[out] yOutput Integration output.
* @param[out] yError The estimated error.
* @param[out] dydxOutput dydx in output.
*/
void Stepper(const G4double yInput[],
const G4double dydx[],
G4double hstep,
@@ -67,14 +108,26 @@ class G4BogackiShampine23 : public G4MagIntegratorStepper
G4double yError[],
G4double dydxOutput[]);
G4BogackiShampine23(const G4BogackiShampine23&) = delete;
G4BogackiShampine23& operator = (const G4BogackiShampine23&) = delete;
/**
* Returns the distance from chord line.
*/
G4double DistChord() const override;
G4int IntegratorOrder() const override { return 3; }
/**
* Returns the order, 3, of integration.
*/
inline G4int IntegratorOrder() const override { return 3; }
/**
* Returns the stepper type-ID, "kBogackiShampine23".
*/
inline G4StepperType StepperType() const override { return kBogackiShampine23; }
private:
/**
* Utility method used in Stepper() for computing the actual step.
*/
void makeStep(const G4double yInput[],
const G4double dydx[],
const G4double hstep,
@@ -82,6 +135,8 @@ class G4BogackiShampine23 : public G4MagIntegratorStepper
G4double* dydxOutput = nullptr,
G4double* yError = nullptr) const;
private:
G4double fyIn[G4FieldTrack::ncompSVEC],
fdydx[G4FieldTrack::ncompSVEC],
fyOut[G4FieldTrack::ncompSVEC],
@@ -27,78 +27,118 @@
//
// Class description:
//
// An implementation of the embedded RK method from the following paper
// by P. Bogacki and L. F. Shampine:
// "An efficient Runge-Kutta (4,5) pair"
// Comput. Math. with Appl., vol. 32, no. 6, pp. 15-28, Sep. 1996.
// An implementation of the embedded RK method from the following paper
// by P. Bogacki and L. F. Shampine:
// "An efficient Runge-Kutta (4,5) pair"
// Comput. Math. with Appl., vol. 32, no. 6, pp. 15-28, Sep. 1996.
//
// An interpolation method provides the value of an intermediate
// point in a step -- if a step was sucessful.
// An interpolation method provides the value of an intermediate
// point in a step -- if a step was sucessful.
//
// This version can provide the FSAL property of the method,
// which allows the reuse of the last derivative in the next step,
// but only by using the additional method GetLastDyDx() (an alternative
// interface for simpler use of FSAL is under development).
// This version can provide the FSAL property of the method,
// which allows the reuse of the last derivative in the next step,
// but only by using the additional method GetLastDyDx() (an alternative
// interface for simpler use of FSAL is under development).
// Created: Somnath Banerjee, Google Summer of Code 2015, 25 May 2015
// Supervision: John Apostolakis, CERN
// Author: Somnath Banerjee (CERN, Google Summer of Code 2015), 25.05.2015
// Supervision: John Apostolakis (CERN)
// --------------------------------------------------------------------
#ifndef BOGACKI_SHAMPINE_45_HH
#define BOGACKI_SHAMPINE_45_HH
#include "G4MagIntegratorStepper.hh"
/**
* @brief G4BogackiShampine45 is an integrator of particle's equation of
* motion based on the Bogacki-Shampine method with FSAL property, allowing
* the reuse of the last derivative in the next step.
* This Stepper provides 'dense output'. After a successful step, it is
* possible to obtain an estimate of the value of the function at an
* intermediate point of the interval. This requires only two additional
* evaluations of the derivative (and thus the field).
*/
class G4BogackiShampine45 : public G4MagIntegratorStepper
{
public:
/**
* Constructor for G4BogackiShampine45.
* @param[in] EqRhs Pointer to the provided equation of motion.
* @param[in] numberOfVariables The number of integration variables.
* @param[in] primary Flag for initialisation of the auxiliary stepper.
*/
G4BogackiShampine45(G4EquationOfMotion* EqRhs,
G4int numberOfVariables = 6,
G4bool primary = true);
/**
* Destructor.
*/
~G4BogackiShampine45() override;
/**
* Copy constructor and assignment operator not allowed.
*/
G4BogackiShampine45(const G4BogackiShampine45&) = delete;
G4BogackiShampine45& operator=(const G4BogackiShampine45&) = delete;
/**
* The stepper for the Runge Kutta integration.
* The stepsize is fixed, with the step size given by 'h'.
* Integrates ODE starting values y[0 to 6].
* Outputs yout[] and its estimated error yerr[].
* @param[in] y Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[in] h The given step size.
* @param[out] yout Integration output.
* @param[out] yerr The estimated error.
*/
void Stepper( const G4double y[],
const G4double dydx[],
G4double h,
G4double yout[],
G4double yerr[] ) override ;
G4double yerr[] ) override;
// This Stepper provides 'dense output'. After a successful
// step, it is possible to obtain an estimate of the value
// of the function at an intermediate point of the interval.
// This requires only two additional evaluations of the
// derivative (and thus the field).
inline void SetupInterpolation()
{
SetupInterpolationHigh(); // ( yInput, dydx, Step);
}
/**
* Setup all coefficients for interpolation.
*/
void SetupInterpolationHigh(); // ( yInput, dydx, Step);
inline void SetupInterpolation() { SetupInterpolationHigh(); }
// For calculating the output at the tau fraction of Step
//
/**
* Calculates the output at the tau fraction of step.
* @param[in] tau The tau fraction of the step.
* @param[out] yOut Interpolation output.
*/
void InterpolateHigh( G4double tau, G4double yOut[] ) const;
inline void Interpolate( G4double tau,
G4double yOut[] ) // Output value
{
InterpolateHigh( tau, yOut);
// InterpolateHigh( yInput, dydx, Step, yOut, tau);
}
void SetupInterpolationHigh();
// For calculating the output at the tau fraction of Step
//
void InterpolateHigh( G4double tau,
G4double yOut[] ) const;
G4double DistChord() const override;
G4int IntegratorOrder() const override { return 4; }
G4double yOut[] ) { InterpolateHigh( tau, yOut); }
/**
* Returns the distance from chord line.
*/
G4double DistChord() const override;
/**
* Returns the order, 4, of integration.
*/
inline G4int IntegratorOrder() const override { return 4; }
/**
* Returns the stepper type-ID, "kBogackiShampine45".
*/
inline G4StepperType StepperType() const override { return kBogackiShampine45; }
/**
* Acccessor for dydx array.
*/
void GetLastDydx( G4double dyDxLast[] );
void PrepareConstants(); // Initialise the values of the bi[][] array
/**
* Initialises the values of the bi[][] array.
*/
void PrepareConstants();
private:
@@ -108,15 +148,17 @@ class G4BogackiShampine45 : public G4MagIntegratorStepper
G4double *p[6];
G4double fLastStepLength = -1.0;
/** For DistChord() calculations. */
G4double *fLastInitialVector, *fLastFinalVector, *fLastDyDx,
*fMidVector, *fMidError;
// For DistChord calculations
G4BogackiShampine45* fAuxStepper = nullptr;
// For chord - until interpolation is proven
/** For chord - until interpolation is proven. */
G4bool fPreparedInterpolation = false;
// Class constants
/** Class constants. */
static G4bool fPreparedConstants;
static G4double bi[12][7];
};
@@ -26,12 +26,11 @@
//
// Class description:
//
// G4BorisDriver is a driver class using the second order Boris
// G4BorisDriver is a driver class using the second order Boris
// method to integrate the equation of motion.
//
//
// Author: Divyansh Tiwari, Google Summer of Code 2022
// Supervision: John Apostolakis,Renee Fatemi, Soon Yung Jun
// Author: Divyansh Tiwari (CERN, Google Summer of Code 2022), 05.11.2022
// Supervision: John Apostolakis (CERN), Renee Fatemi, Soon Yung Jun (FNAL)
// --------------------------------------------------------------------
#ifndef G4BORIS_DRIVER_HH
#define G4BORIS_DRIVER_HH
@@ -40,102 +39,180 @@
#include "G4BorisScheme.hh"
#include "G4ChordFinderDelegate.hh"
/**
* @brief G4BorisDriver is a driver class using the second order Boris
* method to integrate the equation of motion.
*/
class G4BorisDriver : public G4VIntegrationDriver,
public G4ChordFinderDelegate<G4BorisDriver>
{
public:
/**
* Constructor for G4BorisDriver.
* @param[in] hminimum The minumum allowed step.
* @param[in] Boris Pointer to the Boris motion algorithm.
* @param[in] numberOfComponents The number of integration variables.
* @param[in] verbosity Flag for verbosity.
*/
G4BorisDriver( G4double hminimum,
G4BorisScheme* Boris,
G4int numberOfComponents = 6,
G4bool verbosity = false);
inline ~G4BorisDriver() override = default;
/**
* Default Destructor.
*/
~G4BorisDriver() override = default;
inline G4BorisDriver(const G4BorisDriver&) = delete;
inline G4BorisDriver& operator=(const G4BorisDriver&) = delete;
/**
* Copy constructor and assignment operator not allowed.
*/
G4BorisDriver(const G4BorisDriver&) = delete;
G4BorisDriver& operator=(const G4BorisDriver&) = delete;
// 1. Core methods that advance the integration
G4bool AccurateAdvance( G4FieldTrack& track,
G4double stepLen,
G4double epsilon,
G4double beginStep = 0) override;
// Advance integration accurately
// - by relative accuracy better than 'epsilon'
/**
* Advances integration accurately by relative accuracy better than 'eps'.
* @param[in,out] track The current track in field.
* @param[in] stepLen Proposed step length.
* @param[in] epsilon Requested accuracy, y_err/hstep.
* @param[in] beginStep Initial minimum integration step.
* @returns true if integration succeeds.
*/
G4bool AccurateAdvance(G4FieldTrack& track,
G4double stepLen,
G4double eps,
G4double beginStep = 0) override;
G4bool QuickAdvance( G4FieldTrack& y_val, // In/Out
const G4double dydx[],
G4double hstep,
G4double& missDist, // Out: estimated sagitta
G4double& dyerr ) override;
// Attempt one integration step, and return estimated error 'dyerr'
void OneGoodStep(G4double yCurrentState[], // In/Out: state ('y')
G4double& curveLength, // In/Out: 'x'
G4double htry, // step to attempt
G4double epsilon_rel, // relative accuracy
G4double restMass,
G4double charge,
G4double& hdid, // Out: step achieved
G4double& hnext); // Out: proposed next step
// Method to implement Accurate Advance
/**
* Attempts one integration step, and returns estimated error 'dyerr'.
* It does not ensure accuracy.
* @param[in,out] y_val The current track in field.
* @param[in] dydx dydx array.
* @param[in] hstep Proposed step length.
* @param[out] missDist Estimated sagitta distance.
* @param[out] dyerr Estimated error.
* @returns true if integration succeeds.
*/
G4bool QuickAdvance(G4FieldTrack& y_val, // In/Out
const G4double dydx[],
G4double hstep,
G4double& missDist, // Out: estimated sagitta
G4double& dyerr) override;
/**
* Takes one Step that is as large as possible while satisfying the
* accuracy criterion.
* @param[in,out] yCurrentState The current track state, y.
* @param[in,out] curveLength Step start, x.
* @param[in] htry Step to attempt.
* @param[in] epsilon_rel The relative accuracy.
* @param[in] restMass Mass value for computing velocity.
* @param[in] charge Charge value for computing momentum.
* @param[out] hdid Step achieved.
* @param[out] hnext Proposed next step.
* @returns true if integration succeeds.
*/
void OneGoodStep(G4double yCurrentState[], // In/Out: state ('y')
G4double& curveLength, // In/Out: 'x'
G4double htry, // step to attempt
G4double epsilon_rel, // relative accuracy
G4double restMass,
G4double charge,
G4double& hdid, // Out: step achieved
G4double& hnext); // Out: proposed next step
// 2. Methods needed to co-work with G4ChordFinder
G4double AdvanceChordLimited(G4FieldTrack& track,
G4double hstep,
G4double eps,
G4double chordDistance) override
{
return ChordFinderDelegate::
AdvanceChordLimitedImpl(track, hstep, eps, chordDistance);
}
/**
* Computes the step to take, based on chord limits.
* @param[in,out] track The current track in field.
* @param[in] hstep Proposed step length.
* @param[in] eps Requested accuracy, y_err/hstep.
* @param[in] chordDistance Maximum sagitta distance.
* @returns The length of step taken.
*/
inline G4double AdvanceChordLimited(G4FieldTrack& track,
G4double hstep,
G4double eps,
G4double chordDistance) override;
/**
* Dispatch interface method for initialisation/reset of driver.
*/
inline void OnStartTracking() override;
void OnStartTracking() override
{
ChordFinderDelegate::ResetStepEstimate();
}
void OnComputeStep(const G4FieldTrack*) override {}
/**
* Dispatch interface method for computing step. Does nothing here.
*/
inline void OnComputeStep(const G4FieldTrack*) override;
// 3. Does the method redo integrations when called to obtain values for
// internal, smaller intervals? (when needed to identify an intersection)
G4bool DoesReIntegrate() const override { return true; }
// It would be no if it just used interpolation to provide a result.
/**
* The driver implements re-integration. Returns true.
* It would be false if it just used interpolation to provide a result.
*/
inline G4bool DoesReIntegrate() const override;
// 4. Relevant for calculating a new step size to achieve required accuracy
inline G4double ComputeNewStepSize(G4double errMaxNorm, // normalised error
G4double hstepCurrent) override; // current step size
/**
* Computes a step size for the next step, taking the last step's
* normalised error 'errMaxNorm'.
* @param[in] errMaxNorm The normalised error on last step.
* @param[in] hstepCurrent The current proposed step.
* @returns The step size for the next step.
*/
inline G4double ComputeNewStepSize(G4double errMaxNorm,
G4double hstepCurrent) override;
/**
* Methods to calculate the next step size given the square of the
* relative error.
*/
G4double ShrinkStepSize2(G4double h, G4double error2) const;
G4double GrowStepSize2(G4double h, G4double error2) const;
// Calculate the next step size given the square of the relative error
// 5. Auxiliary Methods ...
/**
* Getters for derivatives.
*/
void GetDerivatives( const G4FieldTrack& track,
G4double dydx[] ) const override;
void GetDerivatives( const G4FieldTrack& track,
G4double dydx[],
G4double field[] ) const override;
/**
* Setter and getter for verbosity.
*/
inline void SetVerboseLevel(G4int level) override;
inline G4int GetVerboseLevel() const override;
/**
* Getters for the equation of motion.
*/
inline G4EquationOfMotion* GetEquationOfMotion() override;
inline const G4EquationOfMotion* GetEquationOfMotion() const;
/**
* Setter for the equation of motion. Issues an exception, as not
* foreseen to change equation of motion for the Boris stepper.
*/
void SetEquationOfMotion(G4EquationOfMotion* equation) override;
void StreamInfo( std::ostream& os ) const override;
// Write out the parameters / state of the driver
/**
* Writes out to stream the parameters/state of the driver.
*/
void StreamInfo( std::ostream& os ) const override;
// 6. Not relevant for Boris and other non-RK methods
/**
* Accessors for stepper. Not relevant for Boris and other non-RK methods.
*/
inline const G4MagIntegratorStepper* GetStepper() const override;
inline G4MagIntegratorStepper* GetStepper() override;
@@ -24,94 +24,118 @@
// ********************************************************************
//
// G4BorisDriver inline methods implementation
// Author: Divyansh Tiwari, Google Summer of Code 2022
// Supervision: John Apostolakis,Renee Fatemi, Soon Yung Jun
//
// Author: Divyansh Tiwari (CERN, Google Summer of Code 2022), 05.11.2022
// Supervision: John Apostolakis (CERN), Renee Fatemi, Soon Yung Jun (FNAL)
// --------------------------------------------------------------------
inline
G4double G4BorisDriver::AdvanceChordLimited(G4FieldTrack& track,
G4double hstep,
G4double eps,
G4double chordDistance)
{
return ChordFinderDelegate::
AdvanceChordLimitedImpl(track, hstep, eps, chordDistance);
}
inline
void G4BorisDriver::OnStartTracking()
{
ChordFinderDelegate::ResetStepEstimate();
}
inline
void G4BorisDriver::OnComputeStep(const G4FieldTrack*)
{
}
inline
G4bool G4BorisDriver::DoesReIntegrate() const
{
return true;
}
inline
G4double G4BorisDriver::ComputeNewStepSize( G4double /* errMaxNorm*/,
G4double hstepCurrent)
{
return hstepCurrent;
}
inline
void G4BorisDriver::SetVerboseLevel(G4int level)
{
fVerbosity = (level != 0);
fVerbosity = (level != 0);
}
inline
G4int G4BorisDriver::GetVerboseLevel() const
{
return static_cast<G4int>(fVerbosity);
}
G4double G4BorisDriver::ComputeNewStepSize( G4double /* errMaxNorm*/, G4double hstepCurrent)
{
return hstepCurrent;
return static_cast<G4int>(fVerbosity);
}
inline
const G4EquationOfMotion* G4BorisDriver::GetEquationOfMotion() const
{
auto eq = boris->GetEquationOfMotion();
return eq;
auto eq = boris->GetEquationOfMotion();
return eq;
}
inline
G4EquationOfMotion* G4BorisDriver::GetEquationOfMotion()
{
auto eq = boris->GetEquationOfMotion();
return eq;
auto eq = boris->GetEquationOfMotion();
return eq;
}
#if 0
// #ifdef G4USE_SET_EQUATION_OF_MOTION
void G4BorisDriver::
SetEquationOfMotion( G4EquationOfMotion* equation )
{
boris->SetEquationOfMotion(equation);
}
#endif
inline
G4int G4BorisDriver::GetNumberOfVariables() const
{
return boris->GetNumberOfVariables();
return boris->GetNumberOfVariables();
}
const G4MagIntegratorStepper*
G4BorisDriver::GetStepper() const
inline
const G4MagIntegratorStepper* G4BorisDriver::GetStepper() const
{
return nullptr;
return nullptr;
}
G4MagIntegratorStepper*
G4BorisDriver::GetStepper()
inline
G4MagIntegratorStepper* G4BorisDriver::GetStepper()
{
return nullptr;
return nullptr;
}
inline
void G4BorisDriver::CheckStep(const G4ThreeVector& posIn,
const G4ThreeVector& posOut,
G4double hdid) const
{
const G4double endPointDist = (posOut - posIn).mag();
if (endPointDist >= hdid * (1. + CLHEP::perMillion))
{
// ++fNoAccurateAdvanceBadSteps;
const G4double endPointDist = (posOut - posIn).mag();
if (endPointDist >= hdid * (1. + CLHEP::perMillion))
{
// ++fNoAccurateAdvanceBadSteps;
// #ifdef G4DEBUG_FIELD
// Issue a warning only for gross differences -
// we understand how small difference occur.
if (endPointDist >= hdid * (1. + CLHEP::perThousand))
{
G4Exception("G4BorisDriver::CheckStep()",
"GeomField1002", JustWarning,
"endPointDist >= hdid!");
}
else
{
G4cerr << "G4BorisDriver::CheckStep: moved further than curve distance! "
<< " curve hdid= " << hdid << " endpoint dist= " << endPointDist
<< " ratio - 1 = " << (endPointDist - hdid) / hdid
<< " ( > 1.0e-6 threshold to report ) "
<< G4endl;
}
// Issue a warning only for gross differences -
// we understand how small difference occur.
if (endPointDist >= hdid * (1. + CLHEP::perThousand))
{
G4Exception("G4BorisDriver::CheckStep()", "GeomField1002", JustWarning,
"endPointDist >= hdid!");
}
else
{
G4cerr << "G4BorisDriver::CheckStep: moved further than curve distance! "
<< " curve hdid= " << hdid << " endpoint dist= " << endPointDist
<< " ratio - 1 = " << (endPointDist - hdid) / hdid
<< " ( > 1.0e-6 threshold to report ) "
<< G4endl;
}
// #endif
}
else
{
// ++fNoAccurateAdvanceGoodSteps;
}
}
else
{
// ++fNoAccurateAdvanceGoodSteps;
}
}
@@ -29,62 +29,106 @@
// Implementation of the Boris algorithm for advancing
// charged particles in an electromagnetic field.
// Author: Divyansh Tiwari, Google Summer of Code 2022
// Supervision: John Apostolakis,Renee Fatemi, Soon Yung Jun
// Author: Divyansh Tiwari (CERN, Google Summer of Code 2022), 05.11.2022
// Supervision: John Apostolakis (CERN), Renee Fatemi, Soon Yung Jun (FNAL)
// --------------------------------------------------------------------
#ifndef G4BORIS_SCHEME_HH
#define G4BORIS_SCHEME_HH
class G4EquationOfMotion;
#include "G4Types.hh"
// class G4EqMagElectricField;
// #include "G4FieldTrack.hh"
#include <CLHEP/Units/PhysicalConstants.h>
class G4EquationOfMotion;
/**
* @brief The G4BorisScheme class implements of the Boris algorithm for
* advancing charged particles in an electromagnetic field.
*/
class G4BorisScheme
{
public:
/**
* Default Constructor.
*/
G4BorisScheme() = default;
G4BorisScheme( // G4EqMagElectricField
G4EquationOfMotion* equation,
G4int nvar = 6);
~G4BorisScheme() = default;
void DoStep( G4double restMass, G4double charge, const G4double yIn[],
G4double yOut[], G4double hstep) const;
/**
* Constructor for the equation of motion.
* @param[in] equation Pointer to the equation of motion algorithm.
* @param[in] nvar The number of integration variables.
*/
G4BorisScheme( G4EquationOfMotion* equation, G4int nvar = 6 );
protected:
// Used to implement the 'DoStep' method above
void UpdatePosition(const G4double restMass, const G4double charge, const G4double yIn[],
G4double yOut[], G4double hstep) const;
/**
* Default Destructor.
*/
~G4BorisScheme() = default;
void UpdateVelocity(const G4double restMass, const G4double charge, const G4double yIn[],
G4double yOut[], G4double hstep) const;
/**
* Does one step, updating velocity and position.
* @param[in] restMass Particle mass.
* @param[in] charge Particle charge.
* @param[in] yIn Initial position.
* @param[out] yOut Updated position.
* @param[in] hstep Proposed step.
*/
void DoStep(G4double restMass, G4double charge, const G4double yIn[],
G4double yOut[], G4double hstep) const;
public:
// - Methods using the Boris Scheme Stepping to estimate integration error
void StepWithErrorEstimate(const G4double yIn[], G4double restMass, G4double charge, G4double hstep,
/**
* Adopts the Boris Scheme Stepping to estimate the integration error.
* Uses two half-steps (comparing to a full step) to obtain output and
* error estimate.
* @param[in] yIn Initial position.
* @param[in] restMass Particle mass.
* @param[in] charge Particle charge.
* @param[in] hstep Proposed step.
* @param[out] yOut Updated position.
* @param[out] yErr The estimated error.
*/
void StepWithErrorEstimate(const G4double yIn[], G4double restMass,
G4double charge, G4double hstep,
G4double yOut[], G4double yErr[]) const;
// Use two half-steps (comparing to a full step) to obtain output and error estimate
void StepWithMidAndErrorEstimate(const G4double yIn[], G4double restMass, G4double charge, G4double hstep,
G4double yMid[], G4double yOut[], G4double yErr[]) const;
// Same, and also return mid-point evaluation
// Auxiliary method
inline G4EquationOfMotion* GetEquationOfMotion();
// inline void SetEquationOfMotion(G4EquationOfMotion* equation); // Un-needed, dangerous
/**
* Adopts the Boris Scheme Stepping to estimate the integration error.
* Uses two half-steps (comparing to a full step) to obtain output and
* error estimate. Same as above, but also returns the mid-point evaluation.
* @param[in] yIn Initial position.
* @param[in] restMass Particle mass.
* @param[in] charge Particle charge.
* @param[in] hstep Proposed step.
* @param[out] yMid tThe mid-point evaluation.
* @param[out] yOut Updated position.
* @param[out] yErr The estimated error.
*/
void StepWithMidAndErrorEstimate(const G4double yIn[], G4double restMass,
G4double charge, G4double hstep,
G4double yMid[], G4double yOut[], G4double yErr[]) const;
/**
* Auxiliary methods returning a pointer to the equation of motion
* and the number of integration variables.
*/
inline G4EquationOfMotion* GetEquationOfMotion() const;
inline G4int GetNumberOfVariables() const;
private:
/**
* Internal methods for updating position and velocity, used in DoStep().
*/
void UpdatePosition(const G4double restMass, const G4double charge,
const G4double yIn[], G4double yOut[], G4double hstep) const;
void UpdateVelocity(const G4double restMass, const G4double charge,
const G4double yIn[], G4double yOut[], G4double hstep) const;
/**
* Utility to mem-copy 'src' array data to 'dst'.
*/
void copy(G4double dst[], const G4double src[]) const;
private:
@@ -95,4 +139,5 @@ class G4BorisScheme
};
#include "G4BorisScheme.icc"
#endif
@@ -29,19 +29,12 @@
// Supervision: John Apostolakis,Renee Fatemi, Soon Yung Jun
// --------------------------------------------------------------------
#if 0
inline void G4BorisScheme::SetEquationOfMotion(G4EquationOfMotion* eq)
inline G4EquationOfMotion* G4BorisScheme::GetEquationOfMotion() const
{
fEquation = eq;
}
#endif
inline G4EquationOfMotion* G4BorisScheme::GetEquationOfMotion()
{
return fEquation;
return fEquation;
}
inline G4int G4BorisScheme::GetNumberOfVariables() const
{
return fnvar;
return fnvar;
}
@@ -30,8 +30,8 @@
// and order of the method. The algorithm uses the modified midpoint and
// a polynomial extrapolation computes the solution.
// Author: Dmitry Sorokin, Google Summer of Code 2016
// Supervision: John Apostolakis, CERN
// Author: Dmitry Sorokin (CERN, Google Summer of Code 2016), 13.02.2018
// Supervision: John Apostolakis (CERN)
// --------------------------------------------------------------------
#ifndef G4BULIRSCH_STOER_HH
#define G4BULIRSCH_STOER_HH
@@ -40,87 +40,136 @@
#include "G4FieldTrack.hh"
/**
* @brief G4BulirschStoer is a controlled driver that adjusts both step size
* and order of the method. The algorithm uses the modified midpoint and
* a polynomial extrapolation computes the solution.
*/
class G4BulirschStoer
{
public:
enum class step_result
{
success,
fail
};
enum class step_result { success, fail };
G4BulirschStoer( G4EquationOfMotion* equation, G4int nvar,
G4double eps_rel, G4double max_dt = DBL_MAX);
/**
* Constructor for G4BulirschStoer.
* @param[in] equation Pointer to the provided equation of motion.
* @param[in] nvar The number of integration variables.
* @param[in] eps_rel Relative tolerance.
* @param[in] max_dt Maximum allowed time step.
*/
G4BulirschStoer(G4EquationOfMotion* equation, G4int nvar,
G4double eps_rel, G4double max_dt = DBL_MAX);
/**
* Default Destructor.
*/
~G4BulirschStoer() = default;
/**
* Modifiers.
*/
inline void set_max_dt(G4double max_dt);
inline void set_max_relative_error(G4double eps_rel);
// Stepper method
//
/**
* Stepper method.
* @param[in] in Initial position.
* @param[in] dxdt dxdt for mid-point calculation.
* @param[out] t The updated step.
* @param[out] out Updated position.
* @param[in,out] dt Step size.
* @returns success if step is not rejected.
*/
step_result try_step(const G4double in[], const G4double dxdt[],
G4double& t, G4double out[], G4double& dt);
// Reset the internal state of the stepper
//
/**
* Resets the internal state of the stepper.
*/
void reset();
/**
* Setter and getter for the equation of motion.
*/
inline void SetEquationOfMotion(G4EquationOfMotion* equation);
inline G4EquationOfMotion* GetEquationOfMotion();
inline G4EquationOfMotion* GetEquationOfMotion() const;
/**
* Returns the number of integration variables.
*/
inline G4int GetNumberOfVariables() const;
private:
const static G4int m_k_max = 8;
/**
* Polynomial extrapolation.
*/
void extrapolate(std::size_t k, G4double xest[]);
/**
* Calculates the optimal step size for a given error and stage number.
*/
G4double calc_h_opt(G4double h, G4double error, std::size_t k) const;
/**
* Calculates the optimal stage number.
*/
G4bool set_k_opt(std::size_t k, G4double& dt);
/**
* Utilities.
*/
G4bool in_convergence_window(G4int k) const;
G4bool should_reject(G4double error, G4int k) const;
// Number of vars to be integrated
private:
/** Maximum number of stages. */
const static G4int m_k_max = 8;
/** Number of vars to be integrated. */
G4int fnvar;
// Relative tolerance
/** Relative tolerance. */
G4double m_eps_rel;
// Modified midpoint algorithm
/** Modified midpoint algorithm. */
G4ModifiedMidpoint m_midpoint;
/** Flags for step. */
G4bool m_last_step_rejected{false};
G4bool m_first{true};
/** Last step size. */
G4double m_dt_last{0.0};
// G4double m_t_last;
// Max allowed time step
/** Max allowed time step. */
G4double m_max_dt;
/** Crude estimate of optimal order. */
G4int m_current_k_opt;
// G4double m_xnew[G4FieldTrack::ncompSVEC];
/** Error estimate. */
G4double m_err[G4FieldTrack::ncompSVEC];
// G4double m_dxdt[G4FieldTrack::ncompSVEC];
// Stores the successive interval counts
/** Stores the successive interval counts. */
G4int m_interval_sequence[m_k_max+1];
// Extrapolation coeffs (Nevilles algorithm)
/** Extrapolation coeffs (Neville's algorithm). */
G4double m_coeff[m_k_max+1][m_k_max];
// Costs for interval count
/** Costs for interval count. */
G4int m_cost[m_k_max+1];
// Sequence of states for extrapolation
/** Sequence of states for extrapolation. */
G4double m_table[m_k_max][G4FieldTrack::ncompSVEC];
// Optimal step size
/** Optimal step size. */
G4double h_opt[m_k_max+1];
// Work per unit step
/** Work per unit step. */
G4double work[m_k_max+1];
};
@@ -25,30 +25,31 @@
//
// G4BulirschStoer inline methods implementation
//
// Author: Dmitry Sorokin, Google Summer of Code 2016
// Author: Dmitry Sorokin (CERN, Google Summer of Code 2016), 13.02.2018
// Supervision: John Apostolakis (CERN)
// --------------------------------------------------------------------
inline void G4BulirschStoer::set_max_dt(G4double max_dt)
{
m_max_dt = max_dt;
m_max_dt = max_dt;
}
inline void G4BulirschStoer::set_max_relative_error(G4double eps_rel)
{
m_eps_rel = eps_rel;
m_eps_rel = eps_rel;
}
inline void G4BulirschStoer::SetEquationOfMotion(G4EquationOfMotion* equation)
{
m_midpoint.SetEquationOfMotion(equation);
m_midpoint.SetEquationOfMotion(equation);
}
inline G4EquationOfMotion* G4BulirschStoer::GetEquationOfMotion()
inline G4EquationOfMotion* G4BulirschStoer::GetEquationOfMotion() const
{
return m_midpoint.GetEquationOfMotion();
return m_midpoint.GetEquationOfMotion();
}
inline G4int G4BulirschStoer::GetNumberOfVariables() const
{
return fnvar;
return fnvar;
}
@@ -26,11 +26,11 @@
//
// Class description:
//
// G4IntegrationDriver<G4BulirschStoer> is a driver class using
// G4IntegrationDriver<G4BulirschStoer> is a concrete driver class using
// Bulirsch-Stoer method to integrate the equation of motion.
// Author: Dmitry Sorokin, Google Summer of Code 2016
// Supervision: John Apostolakis, CERN
// Author: Dmitry Sorokin (CERN, Google Summer of Code 2016), 13.02.2018
// Supervision: John Apostolakis (CERN)
// --------------------------------------------------------------------
#ifndef G4BULIRSCH_STOER_DRIVER_HH
#define G4BULIRSCH_STOER_DRIVER_HH
@@ -39,6 +39,11 @@
#include "G4BulirschStoer.hh"
#include "G4ChordFinderDelegate.hh"
/**
* @brief G4IntegrationDriver<G4BulirschStoer> is a concrete driver class
* using the Bulirsch-Stoer method to integrate the equation of motion.
*/
template <>
class G4IntegrationDriver<G4BulirschStoer>:
public G4VIntegrationDriver,
@@ -46,45 +51,97 @@ class G4IntegrationDriver<G4BulirschStoer>:
{
public:
/**
* Constructor for the concrete G4IntegrationDriver.
* @param[in] hminimum The minumum allowed step..
* @param[in] Boris Pointer to the Bulirsch-Stoer motion algorithm.
* @param[in] numberOfComponents The number of integration variables.
* @param[in] verbosity Flag for verbosity.
*/
G4IntegrationDriver( G4double hminimum,
G4BulirschStoer* stepper,
G4int numberOfComponents = 6,
G4int statisticsVerbosity = 1);
/**
* Default Destructor.
*/
~G4IntegrationDriver() = default;
/**
* Copy constructor and assignment operator not allowed.
*/
G4IntegrationDriver(const G4IntegrationDriver&) = delete;
G4IntegrationDriver& operator=(const G4IntegrationDriver&) = delete;
virtual G4double AdvanceChordLimited(G4FieldTrack& track,
G4double hstep,
G4double eps,
G4double chordDistance) override
{
return ChordFinderDelegate::
AdvanceChordLimitedImpl(track, hstep, eps, chordDistance);
}
virtual void OnStartTracking() override
{
ChordFinderDelegate::ResetStepEstimate();
}
virtual void OnComputeStep(const G4FieldTrack* /*track*/ = nullptr) override {};
virtual G4bool DoesReIntegrate() const override { return false; } /// ????
virtual G4bool AccurateAdvance( G4FieldTrack& track,
G4double stepLen,
G4double eps,
G4double beginStep = 0) override;
virtual G4bool QuickAdvance( G4FieldTrack& y_val,
const G4double dydx[],
/**
* Computes the step to take, based on chord limits.
* @param[in,out] track The current track in field.
* @param[in] hstep Proposed step length.
* @param[in] eps Requested accuracy, y_err/hstep.
* @param[in] chordDistance Maximum sagitta distance.
* @returns The length of step taken.
*/
G4double AdvanceChordLimited(G4FieldTrack& track,
G4double hstep,
G4double& missDist,
G4double& dyerr) override;
G4double eps,
G4double chordDistance) override;
/**
* Dispatch interface method for initialisation/reset of driver.
*/
void OnStartTracking() override;
/**
* Dispatch interface method for computing step. Does nothing here.
*/
void OnComputeStep(const G4FieldTrack* track = nullptr) override;
/**
* The driver does not implement re-integration. Returns false.
*/
G4bool DoesReIntegrate() const override;
/**
* Advances integration accurately by relative accuracy better than 'eps'.
* @param[in,out] track The current track in field.
* @param[in] stepLen Proposed step length.
* @param[in] eps Requested accuracy, y_err/hstep.
* @param[in] beginStep Initial minimum integration step.
* @returns true if integration succeeds.
*/
G4bool AccurateAdvance( G4FieldTrack& track,
G4double stepLen,
G4double eps,
G4double beginStep = 0) override;
/**
* Attempts one integration step, and returns estimated error 'dyerr'.
* It does not ensure accuracy.
* @param[in,out] y_val The current track in field.
* @param[in] dydx dydx array.
* @param[in] hstep Proposed step length.
* @param[out] missDist Estimated sagitta distance.
* @param[out] dyerr Estimated error.
* @returns true if integration succeeds.
*/
G4bool QuickAdvance( G4FieldTrack& y_val,
const G4double dydx[],
G4double hstep,
G4double& missDist,
G4double& dyerr) override;
/**
* Takes one Step that is as large as possible while satisfying the
* accuracy criterion.
* @param[in,out] y The current track state, y.
* @param[in] dydx dydx array.
* @param[in,out] curveLength Step start, x.
* @param[in] htry Step to attempt.
* @param[in] eps The relative accuracy.
* @param[out] hdid Step achieved.
* @param[out] hnext Proposed next step.
*/
void OneGoodStep( G4double y[],
const G4double dydx[],
G4double& curveLength,
@@ -93,29 +150,47 @@ class G4IntegrationDriver<G4BulirschStoer>:
G4double& hdid,
G4double& hnext);
virtual void GetDerivatives( const G4FieldTrack& track,
G4double dydx[]) const override;
/**
* Getters for derivatives.
*/
void GetDerivatives( const G4FieldTrack& track,
G4double dydx[]) const override;
void GetDerivatives( const G4FieldTrack& track,
G4double dydx[],
G4double field[]) const override;
virtual void GetDerivatives( const G4FieldTrack& track,
G4double dydx[],
G4double field[]) const override;
/**
* Setter and getter for verbosity.
*/
void SetVerboseLevel(G4int level) override;
G4int GetVerboseLevel() const override;
virtual void SetVerboseLevel(G4int level) override;
virtual G4int GetVerboseLevel() const override;
/**
* Computes the new step size .
* @param[in] errMaxNorm The normalised error.
* @param[in] hstepCurrent The current step size.
* @returns The new step size.
*/
G4double ComputeNewStepSize(G4double errMaxNorm,
G4double hstepCurrent) override;
virtual G4double ComputeNewStepSize(
G4double errMaxNorm, // normalised error
G4double hstepCurrent) override; // current step size
virtual G4EquationOfMotion* GetEquationOfMotion() override;
/**
* Getters and setter for the equation of motion.
*/
G4EquationOfMotion* GetEquationOfMotion() override;
const G4EquationOfMotion* GetEquationOfMotion() const;
virtual void SetEquationOfMotion(G4EquationOfMotion* equation) override;
void SetEquationOfMotion(G4EquationOfMotion* equation) override;
virtual const G4MagIntegratorStepper* GetStepper() const override;
virtual G4MagIntegratorStepper* GetStepper() override;
/**
* Getters for the stepper.
*/
const G4MagIntegratorStepper* GetStepper() const override;
G4MagIntegratorStepper* GetStepper() override;
virtual void StreamInfo( std::ostream& os ) const override;
// Write out the parameters / state of the driver
/**
* Writes out to stream the parameters/state of the driver.
*/
void StreamInfo( std::ostream& os ) const override;
private:
@@ -25,8 +25,8 @@
//
// G4BulirschStoer driver inline methods implementation
// Author: Dmitry Sorokin, Google Summer of Code 2016
// Supervision: John Apostolakis, CERN
// Author: Dmitry Sorokin (CERN, Google Summer of Code 2016), 13.02.2018
// Supervision: John Apostolakis (CERN)
// --------------------------------------------------------------------
#include <cassert>
@@ -61,9 +61,9 @@ G4bool G4IntegrationDriver<G4BulirschStoer>::
AccurateAdvance( G4FieldTrack& track, G4double hstep,
G4double eps, G4double hinitial)
{
G4int fNoTotalSteps = 0;
// G4int fNoTotalSteps = 0;
G4int fMaxNoSteps = 10000;
G4double fNoBadSteps = 0.0;
// G4double fNoBadSteps = 0.0;
G4double fSmallestFraction = 1.0e-12;
// Driver with adaptive stepsize control. Integrate starting
@@ -124,13 +124,13 @@ AccurateAdvance( G4FieldTrack& track, G4double hstep,
// loop variables
//
G4int nstp = 1, no_warnings = 0;
G4int nstp = 1; //, no_warnings = 0;
G4double hnext, hdid;
G4bool succeeded = true, lastStepSucceeded;
G4int noFullIntegr = 0, noSmallIntegr = 0 ;
static G4ThreadLocal G4int noGoodSteps = 0 ; // Bad = chord > curve-len
// static G4ThreadLocal G4int noGoodSteps = 0 ; // Bad = chord > curve-len
G4bool lastStep = false;
@@ -142,7 +142,7 @@ AccurateAdvance( G4FieldTrack& track, G4double hstep,
{
G4ThreeVector StartPos(yCurrent[0], yCurrent[1], yCurrent[2]);
GetEquationOfMotion()->RightHandSide(yCurrent, dydxCurrent);
fNoTotalSteps++;
// fNoTotalSteps++;
// Perform the Integration
//
@@ -185,7 +185,7 @@ AccurateAdvance( G4FieldTrack& track, G4double hstep,
lastStepSucceeded ? ++noFullIntegr : ++noSmallIntegr;
G4ThreeVector EndPos(yCurrent[0], yCurrent[1], yCurrent[2]);
/*
// Check the endpoint
//
G4double endPointDist = (EndPos - StartPos).mag();
@@ -205,7 +205,7 @@ AccurateAdvance( G4FieldTrack& track, G4double hstep,
{
++noGoodSteps;
}
*/
// Avoid numerous small last steps
//
if((h < eps * hstep) || (h < fSmallestFraction * startCurveLength))
@@ -262,7 +262,7 @@ AccurateAdvance( G4FieldTrack& track, G4double hstep,
if(nstp > fMaxNoSteps)
{
++no_warnings;
// ++no_warnings;
succeeded = false;
}
@@ -329,6 +329,14 @@ QuickAdvance( G4FieldTrack& track, const G4double dydx[],
return true;
}
G4double G4IntegrationDriver<G4BulirschStoer>::
AdvanceChordLimited(G4FieldTrack& track, G4double hstep, G4double eps,
G4double chordDistance)
{
return ChordFinderDelegate::
AdvanceChordLimitedImpl(track, hstep, eps, chordDistance);
}
void G4IntegrationDriver<G4BulirschStoer>::
OneGoodStep( G4double y[], const G4double dydx[], G4double& curveLength,
G4double htry, G4double eps, G4double& hdid, G4double& hnext)
@@ -353,6 +361,23 @@ OneGoodStep( G4double y[], const G4double dydx[], G4double& curveLength,
hdid = curveLength - curveLengthBegin;
}
void G4IntegrationDriver<G4BulirschStoer>::
OnStartTracking()
{
ChordFinderDelegate::ResetStepEstimate();
}
void G4IntegrationDriver<G4BulirschStoer>::
OnComputeStep(const G4FieldTrack* /*track*/)
{
}
G4bool G4IntegrationDriver<G4BulirschStoer>::
DoesReIntegrate() const
{
return false;
}
void G4IntegrationDriver<G4BulirschStoer>::
GetDerivatives( const G4FieldTrack& track, G4double dydx[]) const
{
@@ -29,7 +29,7 @@
//
// Caches Magnetic Field value, for field whose evaluation is expensive.
// Author: J.Apostolakis, 20 July 2009.
// Author: John Apostolakis (CERN), 20.07.2009.
// --------------------------------------------------------------------
#ifndef G4CACHED_MAGNETIC_FIELD_HH
#define G4CACHED_MAGNETIC_FIELD_HH
@@ -38,29 +38,68 @@
#include "G4ThreeVector.hh"
#include "G4MagneticField.hh"
/**
* @brief G4CachedMagneticField is a specialisation of G4MagneticField and
* is used to cache the Magnetic Field value, for fields whose evaluation is
* expensive.
*/
class G4CachedMagneticField : public G4MagneticField
{
public:
G4CachedMagneticField(G4MagneticField*, G4double distanceConst);
~G4CachedMagneticField() override;
// Constructor and destructor. No actions.
/**
* Constructor for G4CachedMagneticField.
* @param[in] pMagField Pointer to the original magnetic field.
* @param[in] distance Distance for field evaluation, within
* which the field does not change.
*/
G4CachedMagneticField(G4MagneticField* pMagField, G4double distance);
/**
* Default Destructor.
*/
~G4CachedMagneticField() override = default;
/**
* Copy constructor and assignment operator.
*/
G4CachedMagneticField(const G4CachedMagneticField& r);
G4CachedMagneticField& operator = (const G4CachedMagneticField& p);
// Copy constructor & assignment operator.
/**
* Returns the value of the field at the give 'Point'.
* @param[in] Point The given position time vector (x,y,z,t).
* @param[out] Bfield The returned field array.
*/
void GetFieldValue( const G4double Point[4],
G4double* Bfield ) const override;
G4double GetConstDistance() const { return fDistanceConst; }
void SetConstDistance( G4double dist ) { fDistanceConst= dist;}
/**
* Getter and setter for the distance within which field is constant.
*/
inline G4double GetConstDistance() const { return fDistanceConst; }
inline void SetConstDistance( G4double dist ) { fDistanceConst = dist;}
G4int GetCountCalls() const { return fCountCalls; }
G4int GetCountEvaluations() const { return fCountEvaluations; }
void ClearCounts() { fCountCalls = 0; fCountEvaluations=0; }
/**
* Accessors.
*/
inline G4int GetCountCalls() const { return fCountCalls; }
inline G4int GetCountEvaluations() const { return fCountEvaluations; }
/**
* Resets counters.
*/
inline void ClearCounts() { fCountCalls = 0; fCountEvaluations=0; }
/**
* Streams on standard output the values of counters.
*/
void ReportStatistics();
/**
* Returns a pointer of an allocated clone of the field.
*/
G4Field* Clone() const override;
protected:
@@ -70,13 +109,13 @@ class G4CachedMagneticField : public G4MagneticField
private:
G4MagneticField* fpMagneticField = nullptr;
G4double fDistanceConst;
// When the field is evaluated within this distance it will not change
// Caching state
//
/** When the field is evaluated within this distance it will not change. */
G4double fDistanceConst;
/** Caching state. */
mutable G4ThreeVector fLastLocation;
mutable G4ThreeVector fLastValue;
};
#endif /* G4CACHED_MAGNETIC_FIELD_DEF */
#endif
@@ -34,56 +34,89 @@
// It is used to integrate the equations of the motion of a particle
// in a magnetic field.
// Authors: J.Apostolakis, V.Grichine - 30.01.1997
// Authors: J.Apostolakis, V.Grichine (CERN), 30.01.1997
// -------------------------------------------------------------------
#ifndef G4CASHKARP_RKF45_HH
#define G4CASHKARP_RKF45_HH
#include "G4MagIntegratorStepper.hh"
/**
* @brief G4CashKarpRKF45 implements the Cash-Karp Runge-Kutta-Fehlberg
* 4/5 method, 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.
* It is used to integrate the equations of the motion of a particle
* in a magnetic field.
*/
class G4CashKarpRKF45 : public G4MagIntegratorStepper
{
public:
/**
* Constructor for G4CashKarpRKF45.
* @param[in] EqRhs Pointer to the provided equation of motion.
* @param[in] numberOfVariables The number of integration variables.
* @param[in] primary Flag for initialisation of the auxiliary stepper.
*/
G4CashKarpRKF45( G4EquationOfMotion* EqRhs,
G4int numberOfVariables = 6,
G4bool primary = true ) ;
~G4CashKarpRKF45() override ;
G4bool primary = true );
/**
* Destructor.
*/
~G4CashKarpRKF45() override;
/**
* Copy constructor and assignment operator not allowed.
*/
G4CashKarpRKF45(const G4CashKarpRKF45&) = delete;
G4CashKarpRKF45& operator=(const G4CashKarpRKF45&) = delete;
// Deleted copy constructor and assignment operator.
/**
* The stepper for the Runge Kutta integration.
* The stepsize is fixed, with the step size given by 'h'.
* Integrates ODE starting values y[0 to 6].
* Outputs yout[] and its estimated error yerr[].
* @param[in] y Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[in] h The given step size.
* @param[out] yout Integration output.
* @param[out] yerr The estimated error.
*/
void Stepper( const G4double y[],
const G4double dydx[],
G4double h,
G4double yout[],
G4double yerr[] ) override ;
G4double yerr[] ) override;
G4double DistChord() const override;
G4int IntegratorOrder() const override { return 4; }
/**
* Returns the distance from chord line.
*/
G4double DistChord() const override;
/**
* Returns the order, 4, of integration.
*/
inline G4int IntegratorOrder() const override { return 4; }
/**
* Returns the stepper type-ID, "kCashKarpRKF45".
*/
inline G4StepperType StepperType() const override { return kCashKarpRKF45; }
private:
void StepWithEst( const G4double yIn[],
const G4double dydx[],
G4double Step,
G4double yOut[],
G4double& alpha2,
G4double& beta2,
const G4double B1[],
G4double B2[] );
// No longer used. Obsolete.
private:
G4double *ak2, *ak3, *ak4, *ak5, *ak6, *yTemp, *yIn; // *ak7
// scratch space
/** Scratch space. */
G4double *ak2, *ak3, *ak4, *ak5, *ak6, *yTemp, *yIn;
G4double fLastStepLength = 0.0;
/** For DistChord calculations. */
G4double *fLastInitialVector, *fLastFinalVector,
*fLastDyDx, *fMidVector, *fMidError;
// for DistChord calculations
G4CashKarpRKF45* fAuxStepper = nullptr;
};
@@ -29,80 +29,92 @@
//
// Container for magnetic charge and moments.
// Authors: J.Apostolakis, P.Gumplinger - 10 April 2013
// Authors: J.Apostolakis (CERN), P.Gumplinger (TRIUMF), 10.04.2013
// -------------------------------------------------------------------
#ifndef G4CHARGESTATE_HH
#define G4CHARGESTATE_HH
#include "globals.hh"
/**
* @brief G4ChargeState is a container for magnetic charge and moments.
*/
class G4ChargeState
{
public:
public:
inline G4ChargeState(G4double charge,
G4double magnetic_dipole_moment,
G4double pdgSpin,
G4double electric_dipole_moment = 0.0,
G4double magnetic_charge = 0.0);
/**
* Constructor for G4ChargeState.
* @param[in] charge Particle charge.
* @param[in] magnetic_dipole_moment Magnetic dipole moment.
* @param[in] pdgSpin Spin.
* @param[in] electric_dipole_moment Electric dipole moment.
* @param[in] magnetic_charge Magnetic charge for monopoles.
*/
inline G4ChargeState(G4double charge,
G4double magnetic_dipole_moment,
G4double pdgSpin,
G4double electric_dipole_moment = 0.0,
G4double magnetic_charge = 0.0);
inline G4ChargeState( const G4ChargeState& right );
inline G4ChargeState& operator = ( const G4ChargeState& right );
/**
* Copy constructor and assignment operator.
*/
inline G4ChargeState( const G4ChargeState& right );
inline G4ChargeState& operator = ( const G4ChargeState& right );
void SetChargeSpinMoments(G4double charge,
G4double pdgSpin,
G4double magnetic_dipole_moment= DBL_MAX,
G4double electric_dipole_moment= DBL_MAX,
G4double magnetic_charge= DBL_MAX );
// Revise the charge, pdgSpin, and optionally both moments
// and magnetic charge
/**
* Default Destructor.
*/
~G4ChargeState() = default;
void SetCharge(G4double charge){ fCharge = charge; }
G4double GetCharge() const { return fCharge; }
// Revise the charge (in units of the positron charge)
/**
* Revises the charge, pdgSpin, and optionally both moments and
* magnetic charge.
*/
void SetChargeSpinMoments(G4double charge,
G4double pdgSpin,
G4double magnetic_dipole_moment= DBL_MAX,
G4double electric_dipole_moment= DBL_MAX,
G4double magnetic_charge= DBL_MAX );
/**
* Revises the charge (in units of the positron charge).
*/
inline void SetCharge(G4double charge);
inline G4double GetCharge() const;
// Basic Get / Set methods
/**
* Modifiers and accessors.
*/
inline void SetPDGSpin(G4double spin);
inline G4double GetPDGSpin() const;
inline void SetSpin(G4double spin);
inline G4double GetSpin() const;
inline void SetMagneticDipoleMoment(G4double moment);
inline G4double GetMagneticDipoleMoment() const;
inline void SetElectricDipoleMoment(G4double moment);
inline G4double ElectricDipoleMoment() const;
inline void SetMagneticCharge(G4double charge);
inline G4double MagneticCharge() const;
void SetPDGSpin(G4double spin){ fSpin = spin; }
G4double GetPDGSpin() const { return fSpin; }
void SetMagneticDipoleMoment(G4double moment){ fMagn_dipole = moment; }
G4double GetMagneticDipoleMoment() const { return fMagn_dipole; }
void SetElectricDipoleMoment(G4double moment){ fElec_dipole = moment; }
G4double ElectricDipoleMoment() const { return fElec_dipole; }
void SetMagneticCharge(G4double charge){ fMagneticCharge=charge; }
G4double MagneticCharge() const { return fMagneticCharge; }
// Auxiliary methods to set several properties at once
inline void SetChargeMdm(G4double charge, G4double mag_dipole_moment);
// SetCharge and Magnetic Dipole Moment
inline void SetChargeMdmSpin(G4double charge,
G4double magnetic_dipole_moment,
G4double pdgSpin);
inline void SetChargeSpin(G4double charge,
G4double pdgSpin);
// Revise the charge, spin and all both moments
inline void SetChargeDipoleMoments(G4double charge,
/**
* Auxiliary methods to set several properties at once.
*/
inline void SetChargeMdm(G4double charge, G4double mag_dipole_moment);
inline void SetChargeMdmSpin(G4double charge,
G4double magnetic_dipole_moment,
G4double electric_dipole_moment);
inline void SetChargesAndMoments(G4double charge,
G4double magnetic_dipole_moment,
G4double electric_dipole_moment,
G4double magnetic_charge );
// Obsolete
//
inline void SetSpin(G4double spin){ SetPDGSpin( spin); }
inline G4double GetSpin() const { return GetPDGSpin(); }
G4double pdgSpin);
inline void SetChargeSpin(G4double charge,
G4double pdgSpin);
inline void SetChargeDipoleMoments(G4double charge,
G4double magnetic_dipole_moment,
G4double electric_dipole_moment);
inline void SetChargesAndMoments(G4double charge,
G4double magnetic_dipole_moment,
G4double electric_dipole_moment,
G4double magnetic_charge );
private:
@@ -115,78 +127,6 @@ class G4ChargeState
// Inline methods implementation
inline G4ChargeState::G4ChargeState(G4double charge,
G4double magnetic_dipole_moment,
G4double spin,
G4double electric_dipole_moment,
G4double magnetic_charge)
{
fCharge = charge;
fSpin = spin;
fMagn_dipole = magnetic_dipole_moment;
fElec_dipole = electric_dipole_moment;
fMagneticCharge = magnetic_charge;
}
#include "G4ChargeState.icc"
inline G4ChargeState::G4ChargeState( const G4ChargeState& right )
{
fCharge = right.fCharge;
fSpin = right.fSpin;
fMagn_dipole = right.fMagn_dipole;
fElec_dipole = right.fElec_dipole;
fMagneticCharge = right.fMagneticCharge;
}
inline G4ChargeState& G4ChargeState::operator = ( const G4ChargeState& right )
{
if (&right == this) { return *this; }
fCharge = right.fCharge;
fSpin = right.fSpin;
fMagn_dipole = right.fMagn_dipole;
fElec_dipole = right.fElec_dipole;
fMagneticCharge = right.fMagneticCharge;
return *this;
}
inline void G4ChargeState::SetChargeMdm(G4double charge, G4double mdipole_mom)
{
SetCharge( charge );
SetMagneticDipoleMoment( mdipole_mom );
}
inline void G4ChargeState::SetChargeMdmSpin(G4double charge,
G4double magDipoleMoment,
G4double pdgSpin)
{
SetChargeMdm( charge, magDipoleMoment );
SetPDGSpin( pdgSpin );
}
inline void G4ChargeState::SetChargeSpin(G4double charge,
G4double pdgSpin)
{
SetCharge( charge );
SetPDGSpin( pdgSpin );
}
inline void
G4ChargeState::SetChargeDipoleMoments(G4double charge,
G4double magneticDM,
G4double electricDM)
{
SetChargeMdm( charge, magneticDM );
SetElectricDipoleMoment( electricDM );
}
inline void
G4ChargeState::SetChargesAndMoments(G4double charge,
G4double magneticDM,
G4double electricDM,
G4double magnetic_charge )
{
SetChargeDipoleMoments( charge, magneticDM, electricDM);
SetMagneticCharge( magnetic_charge );
}
#endif
@@ -0,0 +1,164 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// G4ChargeState inline methods implementation
// Authors: J.Apostolakis (CERN), P.Gumplinger (TRIUMF), 10.04.2013
// --------------------------------------------------------------------
inline G4ChargeState::G4ChargeState(G4double charge,
G4double magnetic_dipole_moment,
G4double spin,
G4double electric_dipole_moment,
G4double magnetic_charge)
{
fCharge = charge;
fSpin = spin;
fMagn_dipole = magnetic_dipole_moment;
fElec_dipole = electric_dipole_moment;
fMagneticCharge = magnetic_charge;
}
inline G4ChargeState::G4ChargeState( const G4ChargeState& right )
{
fCharge = right.fCharge;
fSpin = right.fSpin;
fMagn_dipole = right.fMagn_dipole;
fElec_dipole = right.fElec_dipole;
fMagneticCharge = right.fMagneticCharge;
}
inline G4ChargeState& G4ChargeState::operator = ( const G4ChargeState& right )
{
if (&right == this) { return *this; }
fCharge = right.fCharge;
fSpin = right.fSpin;
fMagn_dipole = right.fMagn_dipole;
fElec_dipole = right.fElec_dipole;
fMagneticCharge = right.fMagneticCharge;
return *this;
}
inline void G4ChargeState::SetCharge(G4double charge)
{
fCharge = charge;
}
inline G4double G4ChargeState::GetCharge() const
{
return fCharge;
}
inline void G4ChargeState::SetPDGSpin(G4double spin)
{
fSpin = spin;
}
inline G4double G4ChargeState::GetPDGSpin() const
{
return fSpin;
}
inline void G4ChargeState::SetSpin(G4double spin)
{
SetPDGSpin( spin);
}
inline G4double G4ChargeState::GetSpin() const
{
return GetPDGSpin();
}
inline void G4ChargeState::SetMagneticDipoleMoment(G4double moment)
{
fMagn_dipole = moment;
}
inline G4double G4ChargeState::GetMagneticDipoleMoment() const
{
return fMagn_dipole;
}
inline void G4ChargeState::SetElectricDipoleMoment(G4double moment)
{
fElec_dipole = moment;
}
inline G4double G4ChargeState::ElectricDipoleMoment() const
{
return fElec_dipole;
}
inline void G4ChargeState::SetMagneticCharge(G4double charge)
{
fMagneticCharge=charge;
}
inline G4double G4ChargeState::MagneticCharge() const
{
return fMagneticCharge;
}
inline void G4ChargeState::SetChargeMdm(G4double charge, G4double mdipole_mom)
{
SetCharge( charge );
SetMagneticDipoleMoment( mdipole_mom );
}
inline void G4ChargeState::SetChargeMdmSpin(G4double charge,
G4double magDipoleMoment,
G4double pdgSpin)
{
SetChargeMdm( charge, magDipoleMoment );
SetPDGSpin( pdgSpin );
}
inline void G4ChargeState::SetChargeSpin(G4double charge,
G4double pdgSpin)
{
SetCharge( charge );
SetPDGSpin( pdgSpin );
}
inline void
G4ChargeState::SetChargeDipoleMoments(G4double charge,
G4double magneticDM,
G4double electricDM)
{
SetChargeMdm( charge, magneticDM );
SetElectricDipoleMoment( electricDM );
}
inline void
G4ChargeState::SetChargesAndMoments(G4double charge,
G4double magneticDM,
G4double electricDM,
G4double magnetic_charge )
{
SetChargeDipoleMoments( charge, magneticDM, electricDM);
SetMagneticCharge( magnetic_charge );
}
@@ -31,12 +31,13 @@
// and also has a method that returns an Approximate point on the curve
// near to a (chord) point.
// Author: J.Apostolakis - Design and implementation - 25.02.1997
// Author: John Apostolakis (CERN), 25.02.1997 - Design and implementation
// -------------------------------------------------------------------
#ifndef G4CHORDFINDER_HH
#define G4CHORDFINDER_HH
#include "G4VIntegrationDriver.hh"
#include "G4FieldParameters.hh"
#include "G4MagIntegratorStepper.hh"
#include <memory>
@@ -48,116 +49,166 @@ class G4CachedMagneticField;
class G4HelixHeum;
class G4QSStepper;
/**
* @brief G4ChordFinder is a class that provides Runge-Kutta integration of
* motion ODE and also has a method that returns an approximate point on the
* curve near to a (chord) point.
*/
class G4ChordFinder
{
public: // with description
public:
explicit G4ChordFinder( G4VIntegrationDriver* pIntegrationDriver );
// The most flexible constructor, which allows the user to specify
// any type of field, equation, stepper and integration driver.
enum kIntegrationType {kDefaultDriverType=0, kFSALStepperType=1,
kTemplatedStepperType, kRegularStepperType,
kBfieldDriverType, kQss2DriverType, kQss3DriverType};
enum kIntegrationType { kDefaultDriverType=0, kFSALStepperType=1,
kTemplatedStepperType, kRegularStepperType, kBfieldDriverType, kQss2DriverType, kQss3DriverType };
/**
* The most flexible constructor, which allows the user to specify
* any type of field, equation, stepper and integration driver.
* @param[in] pIntegrationDriver Pointer to the integrator driver to use.
*/
explicit G4ChordFinder( G4VIntegrationDriver* pIntegrationDriver );
G4ChordFinder( G4MagneticField* itsMagField,
G4double stepMinimum = 1.0e-2, // * mm
G4MagIntegratorStepper* pItsStepper = nullptr,
// G4bool useHigherEfficiencyStepper = true,
G4int stepperDriverChoice = kTemplatedStepperType );
// A constructor that creates defaults for all "children" classes.
//
// The type of equation of motion is fixed.
// A default type of stepper (Dormand Prince since release 10.4) is used,
// and the corresponding integration driver.
// Except if 'useFSAL' is set (true), which provides a FSAL stepper
// and its corresponding specialised (templated) driver.
/**
* Constructor that creates defaults for all "children" classes.
* The type of equation of motion is fixed.
* A default type of stepper (Dormand Prince since release 10.4) is used,
* and the corresponding integration driver.
* @param[in] itsMagField Pointer to the magnetic field.
* @param[in] stepMinimum Pointer to the magnetic field.
* @param[in] pItsStepper Optional pointer to the stepper algorithm.
* @param[in] stepperDriverChoice Type of stepper driver.
*/
G4ChordFinder( G4MagneticField* itsMagField,
G4double stepMinimum = G4FieldDefaults::kMinimumStep,
G4MagIntegratorStepper* pItsStepper = nullptr,
G4int stepperDriverChoice = kTemplatedStepperType );
virtual ~G4ChordFinder();
/**
* Destructor.
*/
~G4ChordFinder();
G4ChordFinder(const G4ChordFinder&) = delete;
G4ChordFinder& operator=(const G4ChordFinder&) = delete;
// Copy constructor and assignment operator not allowed.
/**
* Copy constructor and assignment operator not allowed.
*/
G4ChordFinder(const G4ChordFinder&) = delete;
G4ChordFinder& operator=(const G4ChordFinder&) = delete;
inline G4double AdvanceChordLimited( G4FieldTrack& yCurrent,
G4double stepInitial,
G4double epsStep_Relative,
const G4ThreeVector& latestSafetyOrigin,
G4double lasestSafetyRadius);
// Uses ODE solver's driver to find the endpoint that satisfies
// the chord criterion: that d_chord < delta_chord
// -> Returns Length of Step taken.
/**
* Computes the step to take, based on chord limits.
* Uses ODE solver's driver to find the endpoint that satisfies
* the chord criterion that: d_chord < delta_chord.
* @param[in,out] yCurrent The current track in field.
* @param[in] stepInitial Proposed initial step length.
* @param[in] epsStep_Relative Requested accuracy.
* @param[in] latestSafetyOrigin Last safety origin point. Unused.
* @param[in] lasestSafetyRadius Last safety distance. Unused.
* @returns The length of step taken.
*/
inline G4double AdvanceChordLimited( G4FieldTrack& yCurrent,
G4double stepInitial,
G4double epsStep_Relative,
const G4ThreeVector& latestSafetyOrigin,
G4double lasestSafetyRadius );
G4FieldTrack ApproxCurvePointS( const G4FieldTrack& curveAPointVelocity,
const G4FieldTrack& curveBPointVelocity,
const G4FieldTrack& ApproxCurveV,
const G4ThreeVector& currentEPoint,
const G4ThreeVector& currentFPoint,
const G4ThreeVector& PointG,
G4bool first, G4double epsStep);
/**
* Uses the Brent algorithm when possible, to determine the closest point
* on the curve. Given a starting curve point A (CurveA_PointVelocity),
* curve point B (CurveB_PointVelocity), a point E which is (generally)
* not on the curve and a point F which is on the curve (first
* approximation), find new point S on the curve closer to point E.
* While advancing towards S utilise 'eps_step' as a measure of the
* relative accuracy of each Step.
* @returns The end point on the curve closer to the given point E.
*/
G4FieldTrack ApproxCurvePointS( const G4FieldTrack& curveAPointVelocity,
const G4FieldTrack& curveBPointVelocity,
const G4FieldTrack& ApproxCurveV,
const G4ThreeVector& currentEPoint,
const G4ThreeVector& currentFPoint,
const G4ThreeVector& PointG,
G4bool first, G4double epsStep );
G4FieldTrack ApproxCurvePointV( const G4FieldTrack& curveAPointVelocity,
const G4FieldTrack& curveBPointVelocity,
const G4ThreeVector& currentEPoint,
G4double epsStep);
/**
* If r=|AE|/|AB|, and s=true path lenght (AB)
* returns the point that is r*s along the curve.
*/
G4FieldTrack ApproxCurvePointV( const G4FieldTrack& curveAPointVelocity,
const G4FieldTrack& curveBPointVelocity,
const G4ThreeVector& currentEPoint,
G4double epsStep);
inline G4double InvParabolic( const G4double xa, const G4double ya,
const G4double xb, const G4double yb,
const G4double xc, const G4double yc );
/**
* Calculates the inverse parabolic through the three points (x,y) and
* returns the value x that, for the inverse parabolic, corresponds to y=0.
*/
inline G4double InvParabolic( const G4double xa, const G4double ya,
const G4double xb, const G4double yb,
const G4double xc, const G4double yc );
inline G4double GetDeltaChord() const;
inline void SetDeltaChord(G4double newval);
/**
* Accessors and modifiers.
*/
inline G4double GetDeltaChord() const;
inline void SetDeltaChord(G4double newval);
inline void SetIntegrationDriver(G4VIntegrationDriver* IntegrationDriver);
inline G4VIntegrationDriver* GetIntegrationDriver();
inline void SetIntegrationDriver(G4VIntegrationDriver* IntegrationDriver);
inline G4VIntegrationDriver* GetIntegrationDriver();
// Access and set Driver.
/**
* Clears the internal state (last step estimate).
*/
inline void ResetStepEstimate();
inline void ResetStepEstimate();
// Clear internal state (last step estimate)
/**
* Sets the verbosity.
* @returns The old verbosity value.
*/
inline G4int SetVerbose( G4int newvalue=1 );
inline G4int SetVerbose( G4int newvalue=1);
// Set verbosity and return old value
/**
* Dispatch interface method for computing step.
*/
inline void OnComputeStep(const G4FieldTrack* track);
void OnComputeStep(const G4FieldTrack* track);
/**
* Writes out to stream the parameters/state of the driver.
*/
friend std::ostream& operator<<( std::ostream& os, const G4ChordFinder& cf);
friend std::ostream&
operator<<( std::ostream& os, const G4ChordFinder& cf);
/**
* Sets verbosity for constructor.
*/
static void SetVerboseConstruction(G4bool v = true);
static void SetVerboseConstruction(G4bool v=true) { gVerboseCtor=v;}
// Verbosity for contructor
protected: // .........................................................
private: // ............................................................
void PrintDchordTrial(G4int noTrials,
G4double stepTrial,
G4double oldStepTrial,
G4double dChordStep);
static G4bool gVerboseCtor; // Verbosity for contructor
static G4bool gVerboseCtor; // Verbosity for contructor
// Constants
// ---------------------
const G4double fDefaultDeltaChord = G4FieldDefaults::kDeltaChord;
private: // ............................................................
// PARAMETERS
// ---------------------
G4double fDeltaChord; // Maximum miss distance
// Constants
// ---------------------
const G4double fDefaultDeltaChord; // SET in G4ChordFinder.cc = 0.25 mm
G4int fStatsVerbose = 0; // if > 0, print Statistics in destructor
// PARAMETERS
// ---------------------
G4double fDeltaChord; // Maximum miss distance
G4int fStatsVerbose = 0; // if > 0, print Statistics in destructor
// DEPENDENT Objects
// ---------------------
G4VIntegrationDriver* fIntgrDriver = nullptr;
G4MagIntegratorStepper* fRegularStepperOwned = nullptr;
G4MagIntegratorStepper* fNewFSALStepperOwned = nullptr;
std::unique_ptr<G4HelixHeum> fLongStepper;
G4CachedMagneticField* fCachedField = nullptr;
G4QSStepper* fQssStepperOwned = nullptr;
G4EquationOfMotion* fEquation = nullptr;
// DEPENDENT Objects
// ---------------------
G4VIntegrationDriver* fIntgrDriver = nullptr;
G4MagIntegratorStepper* fRegularStepperOwned = nullptr;
G4MagIntegratorStepper* fNewFSALStepperOwned = nullptr;
std::unique_ptr<G4HelixHeum> fLongStepper;
G4CachedMagneticField* fCachedField = nullptr;
G4QSStepper* fQssStepperOwned = nullptr;
G4EquationOfMotion* fEquation = nullptr;
};
// Inline function implementation:
#include "G4ChordFinder.icc"
#endif // G4CHORDFINDER_HH
#endif
@@ -25,7 +25,7 @@
//
// G4ChordFinder inline implementations
//
// Author: J.Apostolakis - Design and implementation - 25.02.1997
// Author: John Apostolakis (CERN), 25.02.1997 - Design and implementation
// --------------------------------------------------------------------
inline
@@ -28,55 +28,89 @@
// Class description:
//
// Implementation of common algorithm of finding step size
// with distance to chord less then provided value.
// with distance to chord less than provided value.
// Created: D.Sorokin
// Author: Dmitry Sorokin (CERN, Google Summer of Code 2017), 12.09.2018
// --------------------------------------------------------------------
#ifndef G4CHORD_FINDER_DELEGATE_HH
#define G4CHORD_FINDER_DELEGATE_HH
#include <iomanip>
#include "G4VIntegrationDriver.hh"
/**
* @brief G4ChordFinderDelegate is a templated class for a common algorithm
* of finding step size with distance to the chord less than the provided value.
*/
template <class Driver>
class G4ChordFinderDelegate
{
public:
/**
* Virtual Destructor.
*/
virtual ~G4ChordFinderDelegate();
/**
* Computes the step to take, based on chord limits.
* @param[in,out] track The current track in field.
* @param[in] hstep Proposed step length.
* @param[in] eps Requested accuracy, y_err/hstep.
* @param[in] chordDistance Maximum sagitta distance.
* @returns The length of step taken.
*/
G4double AdvanceChordLimitedImpl(G4FieldTrack& track,
G4double hstep,
G4double eps,
G4double chordDistance);
/**
* Resets last step estimate to DBL_MAX.
*/
void ResetStepEstimate();
/**
* Getter and setter for step estimate.
*/
G4double GetLastStepEstimateUnc();
void SetLastStepEstimateUnc(G4double stepEst);
/**
* Gets statistics about number of calls & trials in FindNextChord().
*/
G4int GetNoCalls();
G4int GetNoTrials(); // Total number of trials
G4int GetNoMaxTrials(); // Maximum # of trials for one call
/**
* Setters of performance parameters... change with great care!
*/
void SetFractions_Last_Next(G4double fractLast = 0.90,
G4double fractNext = 0.95);
void SetFirstFraction(G4double fractFirst);
/**
* Printing for monitoring ...
*/
G4double GetFirstFraction(); // Originally 0.999
G4double GetFractionLast(); // Originally 1.000
G4double GetFractionNextEstimate(); // Originally 0.980
/**
* Writes out to stream the parameters/state of the driver.
*/
void StreamDelegateInfo( std::ostream& os ) const;
/**
* statistics printout for testing.
*/
void TestChordPrint(G4int noTrials,
G4int lastStepTrial,
G4double dChordStep,
G4double fDeltaChord,
G4double nextStepTrial);
// Get statistics about number of calls & trials in FindNextChord
G4int GetNoCalls();
G4int GetNoTrials(); // Total number of trials
G4int GetNoMaxTrials(); // Maximum # of trials for one call
// Parameters for performance ... change with great care
void SetFractions_Last_Next(G4double fractLast = 0.90,
G4double fractNext = 0.95);
void SetFirstFraction(G4double fractFirst);
// Printing for monitoring ...
G4double GetFirstFraction(); // Originally 0.999
G4double GetFractionLast(); // Originally 1.000
G4double GetFractionNextEstimate(); // Originally 0.980
G4double GetLastStepEstimateUnc();
void SetLastStepEstimateUnc(G4double stepEst);
void StreamDelegateInfo( std::ostream& os ) const;
// Write out the parameters / state of the driver
private:
Driver& GetDriver();
@@ -98,6 +132,8 @@ class G4ChordFinderDelegate
void PrintStatistics();
private:
G4double fFirstFraction = 0.999;
G4double fFractionLast = 1.0;
G4double fFractionNextEstimate = 0.98;
@@ -25,11 +25,9 @@
//
// G4ChordFinderDelegate inline methods implementation
//
// Created: D.Sorokin
// Author: Dmitry Sorokin (CERN, Google Summer of Code 2017), 12.09.2018
// --------------------------------------------------------------------
#include <iomanip>
template <class Driver>
G4ChordFinderDelegate<Driver>::~G4ChordFinderDelegate()
{
@@ -30,54 +30,70 @@
// Integrate the equations of the motion of a particle in a magnetic field
// using the classical 4th Runge-Kutta method.
// Created: J.Apostolakis, V.Grichine - 30.01.1997
// Authors: J.Apostolakis, V.Grichine (CERN), 30.01.1997
// -------------------------------------------------------------------
#ifndef G4CLASSICALRK4_HH
#define G4CLASSICALRK4_HH
#include "G4MagErrorStepper.hh"
/**
* @brief G4ClassicalRK4 integrates the equations of the motion of a particle
* in a magnetic field using the classical 4th Runge-Kutta method.
*/
class G4ClassicalRK4 : public G4MagErrorStepper
{
public:
/**
* Constructor for G4ClassicalRK4.
* @param[in] EquationMotion Pointer to the provided equation of motion.
* @param[in] numberOfVariables The number of integration variables.
*/
G4ClassicalRK4(G4EquationOfMotion* EquationMotion,
G4int numberOfVariables = 6) ;
/**
* Destructor.
*/
~G4ClassicalRK4() override ;
/**
* Copy constructor and assignment operator not allowed.
*/
G4ClassicalRK4(const G4ClassicalRK4&) = delete;
G4ClassicalRK4& operator=(const G4ClassicalRK4&) = delete;
// Copy constructor and assignment operator not allowed.
// A stepper that does not know about errors.
// It is used by the MagErrorStepper stepper.
/**
* Given values for the variables y[0,..,n-1] and their derivatives
* dydx[0,...,n-1] known at x, uses the classical 4th Runge-Kutta
* method to advance the solution over an interval h and returns the
* incremented variables as yout[0,...,n-1]. The user supplies the
* function RightHandSide(x,y,dydx), which returns derivatives dydx at x.
* The source is routine rk4 from NRC p.712-713.
* @param[in] yIn Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[in] h The given step size.
* @param[out] yOut Integration output.
*/
void DumbStepper( const G4double yIn[],
const G4double dydx[],
G4double h,
G4double yOut[] ) override ;
// 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 .
/**
* Returns the order, 4, of integration.
*/
G4int IntegratorOrder() const override { return 4; }
private:
void StepWithEst( const G4double yIn[],
const G4double dydx[],
G4double h,
G4double yOut[],
G4double& alpha2,
G4double& beta2,
const G4double B1[],
G4double B2[] );
// No longer used. Obsolete.
/**
* Returns the stepper type-ID, "kClassicalRK4".
*/
G4StepperType StepperType() const override { return kClassicalRK4; }
private:
@@ -25,7 +25,7 @@
//
// G4ConstRK4
//
// class description:
// Class description:
//
// G4ConstRK4 performs the integration of one step with error calculation
// in constant magnetic field. The integration method is the same as in
@@ -33,7 +33,7 @@
// This field evaluation is called only once per step.
// G4ConstRK4 can be used only for magnetic fields.
// Created: J.Apostolakis, T.Nikitina - 18.09.2008
// Authors: J.Apostolakis, T.Nikitina (CERN), 18.09.2008
// -------------------------------------------------------------------
#ifndef G4CONSTRK4_HH
#define G4CONSTRK4_HH
@@ -42,34 +42,99 @@
#include "G4EquationOfMotion.hh"
#include "G4Mag_EqRhs.hh"
/**
* @brief G4ConstRK4 performs the integration of one step with error
* calculation in constant magnetic field. The integration method is the
* same as in ClassicalRK4. The field value is assumed constant for the step.
* This field evaluation is called only once per step.
* G4ConstRK4 can be used only for magnetic fields.
*/
class G4ConstRK4 : public G4MagErrorStepper
{
public:
G4ConstRK4(G4Mag_EqRhs* EquationMotion, G4int numberOfStateVariables=8);
~G4ConstRK4() override;
/**
* Constructor for G4ConstRK4.
* @param[in] EqRhs Pointer to the provided equation of motion.
* @param[in] numberOfVariables The number of integration variables.
*/
G4ConstRK4(G4Mag_EqRhs* EquationMotion,
G4int numberOfStateVariables=8);
/**
* Destructor.
*/
~G4ConstRK4() override;
/**
* Copy constructor and assignment operator not allowed.
*/
G4ConstRK4(const G4ConstRK4&) = delete;
G4ConstRK4& operator=(const G4ConstRK4&) = delete;
// Copy constructor and assignment operator not allowed
/**
* The stepper for the Runge Kutta integration.
* The stepsize is fixed, with the step size given by 'h'.
* Integrates ODE starting values y[0 to 6].
* Outputs yout[] and its estimated error yerr[].
* @param[in] y Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[in] h The given step size.
* @param[out] yout Integration output.
* @param[out] yerr The estimated error.
*/
void Stepper( const G4double y[],
const G4double dydx[],
G4double h,
G4double yout[],
G4double yerr[] ) override;
/**
* Given values for the variables y[0,..,n-1] and their derivatives
* dydx[0,...,n-1] known at x, uses the classical 4th Runge-Kutta
* method to advance the solution over an interval h and returns the
* incremented variables as yout[0,...,n-1]. The user supplies the
* function RightHandSide(x,y,dydx), which returns derivatives dydx at x.
* The source is routine rk4 from NRC p.712-713.
* @param[in] y Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[in] h The given step size.
* @param[out] yout Integration output.
*/
void DumbStepper( const G4double yIn[],
const G4double dydx[],
G4double h,
G4double yOut[] ) override ;
/**
* Returns the distance from chord line.
*/
G4double DistChord() const override;
inline void RightHandSideConst(const G4double y[],
G4double dydx[] ) const;
/**
* Returns the derivatives value, at position and time 'y'.
* @param[in] y The position vector plus time (x,y,z,t).
* @param[out] dydx The derivatives array.
*/
inline void RightHandSideConst(const G4double y[], G4double dydx[] ) const;
inline void GetConstField(const G4double y[], G4double Field[]);
/**
* Returns the field values, at position and time 'y'.
* @param[in] y The position vector plus time (x,y,z,t).
* @param[out] Field The field value in output.
*/
inline void GetConstField(const G4double y[], G4double Field[]);
G4int IntegratorOrder() const override { return 4; }
/**
* Returns the order, 4, of integration.
*/
inline G4int IntegratorOrder() const override { return 4; }
/**
* Returns the stepper type-ID, "kConstRK4".
*/
inline G4StepperType StepperType() const override { return kConstRK4; }
private:
@@ -27,29 +27,47 @@
//
// Class description:
//
// Class describing the DELPHI magnetic field. This axial symmetry
// field mainly directed along Z axis. The function MagneticField(yTrack,B)
// Class describing the DELPHI magnetic field. The axial symmetry
// field is mainly directed along Z axis. The function MagneticField(yTrack,B)
// calculates the magnetic induction vector B in point corresponding to
// yTrack according to parametrization given in:
// P.Billoir, Precise tracking in a quasi-honogeneous magnetic field,
// P.Billoir, Precise tracking in a quasi-homogeneous magnetic field,
// DELPHI 87-6 PROG 65, 1987.
// Created: V.Grichine - 03.02.1997
// Author: Vladimir Grichine (CERN), 03.02.1997
// -------------------------------------------------------------------
#ifndef G4DELPHIMAGFIELD_HH
#define G4DELPHIMAGFIELD_HH
#include "G4MagneticField.hh"
/**
* @brief describes the DELPHI magnetic field. The axial symmetry field is
* mainly directed along Z axis. The function MagneticField(yTrack,B)
* calculates the magnetic induction vector B in given point corresponding
* according to parameterisation given in: P.Billoir, DELPHI 87-6 PROG 65, 1987.
*/
class G4DELPHIMagField : public G4MagneticField
{
public:
G4DELPHIMagField();
~G4DELPHIMagField() override;
/**
* Default Constructor and Destructor.
*/
G4DELPHIMagField() = default;
~G4DELPHIMagField() override = default;
void GetFieldValue(const G4double yTrack[],
G4double B[] ) const override;
/**
* Returns the field value on the given position 'yTrack'.
* @param[in] yTrack Time position array.
* @param[out] B The returned field array.
*/
void GetFieldValue(const G4double yTrack[], G4double B[]) const override;
/**
* Returns a pointer to a new allocated clone of this object.
*/
G4Field* Clone() const override;
};
@@ -27,71 +27,110 @@
//
// Class description:
//
// Dormand-Lockyer-McGorrigan-Prince-6-3-4 non-FSAL method
// ( 6 stage, 3rd & 4th order embedded RK method )
// Dormand-Lockyer-McGorrigan-Prince-6-3-4 non-FSAL method
// ( 6 stage, 3rd & 4th order embedded RK method )
// Created: Somnath Banerjee, Google Summer of Code 2015, 7 July 2015
// Supervision: John Apostolakis, CERN
// Author: Somnath Banerjee (CERN, Google Summer of Code 2015), 07.07.2015
// Supervision: John Apostolakis (CERN)
// --------------------------------------------------------------------
#ifndef DOLO_MCPRI_RK34_HH
#define DOLO_MCPRI_RK34_HH
#include "G4MagIntegratorStepper.hh"
/**
* @brief G4DoLoMcPriRK34 implements the Dormand-Lockyer-McGorrigan-Prince-6-3-4
* non-FSAL method ( 6 stage, 3rd & 4th order embedded Runge-Kutta method ).
*/
class G4DoLoMcPriRK34 : public G4MagIntegratorStepper
{
public:
/**
* Constructor for G4DoLoMcPriRK34.
* @param[in] EqRhs Pointer to the provided equation of motion.
* @param[in] numberOfVariables The number of integration variables.
* @param[in] primary Flag for initialisation of the auxiliary stepper.
*/
G4DoLoMcPriRK34( G4EquationOfMotion* EqRhs,
G4int numberOfVariables = 6,
G4bool primary = true );
// Constructor using Equation
/**
* Destructor.
*/
~G4DoLoMcPriRK34() override;
/**
* Copy constructor and assignment operator not allowed.
*/
G4DoLoMcPriRK34(const G4DoLoMcPriRK34&) = delete;
G4DoLoMcPriRK34& operator=(const G4DoLoMcPriRK34&) = delete;
// Copy constructor and assignment operator not allowed
/**
* The stepper for the Runge Kutta integration.
* The stepsize is fixed, with the step size given by 'h'.
* Integrates ODE starting values y[0 to 6].
* Outputs yout[] and its estimated error yerr[].
* @param[in] y Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[in] h The given step size.
* @param[out] yout Integration output.
* @param[out] yerr The estimated error.
*/
void Stepper( const G4double y[],
const G4double dydx[],
G4double h,
G4double yout[],
G4double yerr[] ) override ;
void SetupInterpolation();
void SetupInterpolate( const G4double yInput[],
const G4double dydx[],
const G4double Step );
// For Preparing the interpolation and calculating the extra stages
/**
* Interface method for interpolation setup. Does nothing here.
*/
inline void SetupInterpolation() {}
/**
* Calculates the output at the tau fraction of Step.
* @param[in] yInput Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[in] Step The given step size.
* @param[out] yOut Interpolation output.
* @param[out] tau Fraction of step.
*/
void Interpolate( const G4double yInput[],
const G4double dydx[],
const G4double Step,
G4double yOut[],
G4double tau );
// For calculating the output at the tau fraction of Step
void Interpolate( G4double tau,
G4double yOut[]);
void interpolate(const G4double yInput[],
const G4double dydx[],
G4double yOut[],
G4double Step,
G4double tau ) ;
/**
* Returns the distance from chord line.
*/
G4double DistChord() const override;
G4int IntegratorOrder() const override { return 3; }
/**
* Returns the order, 3, of integration.
*/
inline G4int IntegratorOrder() const override { return 3; }
/**
* Returns the stepper type-ID, "kDoLoMcPriRK34".
*/
inline G4StepperType StepperType() const override { return kDoLoMcPriRK34; }
private :
G4double *ak2, *ak3, *ak4, *ak5, *ak6, *yTemp, *yIn;
G4double fLastStepLength = -1.0;
/** For DistChord calculations. */
G4double *fLastInitialVector, *fLastFinalVector,
*fLastDyDx, *fMidVector, *fMidError;
// for DistChord calculations
G4DoLoMcPriRK34* fAuxStepper = nullptr;
};
@@ -27,15 +27,14 @@
//
// 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
// 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
// Author: Somnath Banerjee (CERN, Google Summer of Code 2015), 25.05.2015
// Supervision: John Apostolakis (CERN)
// --------------------------------------------------------------------
#ifndef G4DORMAND_PRINCE_745_HH
#define G4DORMAND_PRINCE_745_HH
@@ -43,19 +42,61 @@
#include "G4MagIntegratorStepper.hh"
#include "G4FieldUtils.hh"
/**
* @brief G4DormandPrince745 implements the 5th order embedded Runge-Kutta
* method, non-FSAL definition of the stepper() method that evaluates one step
* in field propagation.
*/
class G4DormandPrince745 : public G4MagIntegratorStepper
{
public:
/**
* Constructor for G4DormandPrince745.
* @param[in] equation Pointer to the provided equation of motion.
* @param[in] numberOfVariables The number of integration variables.
*/
G4DormandPrince745(G4EquationOfMotion* equation,
G4int numberOfVariables = 6);
/**
* Default Destructor.
*/
~G4DormandPrince745() override = default;
/**
* Copy constructor and assignment operator not allowed.
*/
G4DormandPrince745(const G4DormandPrince745&) = delete;
G4DormandPrince745& operator=(const G4DormandPrince745&) = delete;
/**
* The stepper for the Runge Kutta integration.
* The stepsize is fixed, with the step size given by 'hstep'.
* Integrates ODE starting values yInput[0 to 6].
* Outputs yOutput[] and its estimated error yError[].
* @param[in] yInput Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[in] hstep The given step size.
* @param[out] yOutput Integration output.
* @param[out] yError The estimated error.
*/
void Stepper(const G4double yInput[],
const G4double dydx[],
G4double hstep,
G4double yOutput[],
G4double yError[]) override;
/**
* Same as the Stepper() function above, with dydx also in ouput.
* @param[in] yInput Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[in] hstep The given step size.
* @param[out] yOutput Integration output.
* @param[out] yError The estimated error.
* @param[out] dydxOutput dysx in output.
*/
void Stepper(const G4double yInput[],
const G4double dydx[],
G4double hstep,
@@ -63,29 +104,67 @@ class G4DormandPrince745 : public G4MagIntegratorStepper
G4double yError[],
G4double dydxOutput[]);
/**
* Interface method for interpolation setup. Does nothing here.
*/
inline void SetupInterpolation() {}
/**
* Calculates the output at the tau fraction of Step.
* Lower (4th) order interpolant given by Dormand and Prince.
*/
void Interpolate4thOrder(G4double yOut[], G4double tau) const;
/**
* Wrapper for Interpolate4thOrder() function above.
*/
inline void Interpolate(G4double tau, G4double yOut[]) const
{
Interpolate4thOrder(yOut, tau);
}
// For calculating the output at the tau fraction of Step
G4double DistChord() const override;
G4int IntegratorOrder() const override { return 4; }
const G4String& StepperType() const;
const G4String& StepperDescription() const;
const field_utils::State& GetYOut() const { return fyOut; }
void Interpolate4thOrder(G4double yOut[], G4double tau) const;
/**
* Sets up the extra stages for the 5th order interpolant.
*/
void SetupInterpolation5thOrder();
/**
* Calculates the interpolated result 'yOut' with the coefficients.
* Interpolant of 5th order given by Baker, Dormand, Gilmore and Prince.
*/
void Interpolate5thOrder(G4double yOut[], G4double tau) const;
G4EquationOfMotion* GetSpecificEquation() { return GetEquationOfMotion(); }
/**
* Returns the distance from chord line.
*/
G4double DistChord() const override;
/**
* Returns the order, 4, of integration.
*/
inline G4int IntegratorOrder() const override { return 4; }
/**
* Returns the stepper type-ID, "kDormandPrince745".
*/
inline G4StepperType StepperType() const override { return kDormandPrince745; }
/**
* Methods to return the stepper name and description.
*/
const G4String& StepperTypeName() const;
const G4String& StepperDescription() const;
/**
* Returns the field state in output.
*/
inline const field_utils::State& GetYOut() const { return fyOut; }
/**
* Returns a pointer to the equation of motion.
*/
inline G4EquationOfMotion* GetSpecificEquation() { return GetEquationOfMotion(); }
private:
@@ -29,60 +29,110 @@
//
// Dormand-Prince RK 6(5) non-FSAL method
// Created: Somnath Banerjee, Google Summer of Code 2015, 26 June 2015
// Supervision: John Apostolakis, CERN
// Author: Somnath Banerjee (CERN, Google Summer of Code 2015), 26.06.2015
// Supervision: John Apostolakis (CERN)
// --------------------------------------------------------------------
#ifndef G4DORMAND_PRINCE_RK56_HH
#define G4DORMAND_PRINCE_RK56_HH
#include "G4MagIntegratorStepper.hh"
/**
* @brief G4DormandPrinceRK56 implements the 6(5) embedded Runge-Kutta
* non-FSAL method.
*/
class G4DormandPrinceRK56 : public G4MagIntegratorStepper
{
public:
/**
* Constructor for G4DormandPrinceRK56.
* @param[in] EqRhs Pointer to the provided equation of motion.
* @param[in] numberOfVariables The number of integration variables.
* @param[in] primary Flag for initialisation of the auxiliary stepper.
*/
G4DormandPrinceRK56( G4EquationOfMotion* EqRhs,
G4int numberOfVariables = 6,
G4bool primary = true ) ;
/**
* Destructor.
*/
~G4DormandPrinceRK56() override ;
/**
* Copy constructor and assignment operator not allowed.
*/
G4DormandPrinceRK56(const G4DormandPrinceRK56&) = delete;
G4DormandPrinceRK56& operator=(const G4DormandPrinceRK56&) = delete;
/**
* The stepper for the Runge Kutta integration.
* The stepsize is fixed, with the step size given by 'h'.
* Integrates ODE starting values y[0 to 6].
* Outputs yout[] and its estimated error yerr[].
* @param[in] y Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[in] h The given step size.
* @param[out] yout Integration output.
* @param[out] yerr The estimated error.
*/
void Stepper( const G4double y[],
const G4double dydx[],
G4double h,
G4double yout[],
G4double yerr[] ) override ;
G4double DistChord() const override;
G4int IntegratorOrder() const override { return 5; }
/**
* Returns the distance from chord line.
*/
G4double DistChord() const override;
/**
* Returns the order, 5, of integration.
*/
inline G4int IntegratorOrder() const override { return 5; }
/**
* Returns the stepper type-ID, "kDormandPrinceRK56".
*/
inline G4StepperType StepperType() const override { return kDormandPrinceRK56; }
/**
* Prepares the interpolant and calculates the extra stages.
* Fifth order interpolant with one extra function evaluation per step.
*/
void SetupInterpolate_low( const G4double yInput[],
const G4double dydx[],
const G4double Step );
// For preparing the Interpolant and calculating the extra stages
void Interpolate_low( const G4double yInput[],
const G4double dydx[],
const G4double Step,
G4double yOut[],
G4double tau );
// For calculating the output at the tau fraction of Step
inline void SetupInterpolation()
{
SetupInterpolate( fLastInitialVector, fLastDyDx, fLastStepLength);
}
/**
* Wrappers for SetupInterpolate_low() above.
*/
inline void SetupInterpolate( const G4double yInput[],
const G4double dydx[],
const G4double Step )
{
SetupInterpolate_low( yInput, dydx, Step);
}
inline void SetupInterpolation()
{
SetupInterpolate( fLastInitialVector, fLastDyDx, fLastStepLength);
}
/**
* Calculates the output at the tau fraction of Step.
*/
void Interpolate_low( const G4double yInput[],
const G4double dydx[],
const G4double Step,
G4double yOut[],
G4double tau );
/**
* Wrappers for Interpolate_low() above.
*/
inline void Interpolate( const G4double yInput[],
const G4double dydx[],
const G4double Step,
@@ -91,38 +141,46 @@ class G4DormandPrinceRK56 : public G4MagIntegratorStepper
{
Interpolate_low( yInput, dydx, Step, yOut, tau);
}
// For calculating the output at the tau fraction of Step
inline void Interpolate( G4double tau, G4double yOut[])
{
Interpolate( fLastInitialVector, fLastDyDx, fLastStepLength, yOut, tau );
}
/**
* Prepares the interpolant and calculates the extra stages.
* Sixth order interpolant with 3 additional stages per step.
*/
void SetupInterpolate_high( const G4double yInput[],
const G4double dydx[],
const G4double Step );
/**
* Calculates the output at the tau fraction of Step, using
* the polynomial coefficients and the respective stages.
*/
void Interpolate_high( const G4double yInput[],
const G4double dydx[],
const G4double Step,
G4double yOut[],
G4double tau );
// For calculating the output at the tau fraction of Step
private:
/** For storing intermediate 'k' values in stepper. */
G4double *ak2, *ak3, *ak4, *ak5, *ak6, *ak7, *ak8, *ak9;
// For storing intermediate 'k' values in stepper
/** For the additional stages of Interpolant. */
G4double *ak10_low, *ak10, *ak11, * ak12;
// For the additional stages of Interpolant
G4double *yTemp, *yIn;
G4double fLastStepLength = -1.0;
/** For DistChord() calculations. */
G4double *fLastInitialVector, *fLastFinalVector,
*fLastDyDx, *fMidVector, *fMidError;
// For DistChord calculations
G4DormandPrinceRK56* fAuxStepper = nullptr;
};
#endif /* G4DormandPrinceRK56 */
#endif
@@ -35,45 +35,88 @@
// Journal of Computational and Applied Mathematics, Volume 7, Issue 1, 1981,
// Pages 67-75, ISSN 0377-0427, DOI: 10.1016/0771-050X(81)90010-3
// Created: Somnath Banerjee, Google Summer of Code 2015, 28 June 2015
// Supervision: John Apostolakis, CERN
// Author: Somnath Banerjee (CERN, Google Summer of Code 2015), 28.06.2015
// Supervision: John Apostolakis (CERN)
// --------------------------------------------------------------------
#ifndef G4DORMAND_PRINCE_RK78_HH
#define G4DORMAND_PRINCE_RK78_HH
#include "G4MagIntegratorStepper.hh"
/**
* @brief G4DormandPrinceRK78 implements the Dormand-Prince 8(7)13M non-FSAL
* Runge-Kutta method, a 13 stage embedded explicit Runge-Kutta method, using
* a pair of 7th and 8th order formulae.
*/
class G4DormandPrinceRK78 : public G4MagIntegratorStepper
{
public:
/**
* Constructor for G4DormandPrince745.
* @param[in] EqRhs Pointer to the provided equation of motion.
* @param[in] numberOfVariables The number of integration variables.
* @param[in] primary Flag for initialisation of the auxiliary stepper.
*/
G4DormandPrinceRK78(G4EquationOfMotion* EqRhs,
G4int numberOfVariables = 6,
G4bool primary = true);
/**
* Destructor.
*/
~G4DormandPrinceRK78() override;
/**
* Copy constructor and assignment operator not allowed.
*/
G4DormandPrinceRK78(const G4DormandPrinceRK78&) = delete;
G4DormandPrinceRK78& operator=(const G4DormandPrinceRK78&) = delete;
/**
* The stepper for the Runge Kutta integration.
* The stepsize is fixed, with the step size given by 'h'.
* Integrates ODE starting values y[0 to 6].
* Outputs yout[] and its estimated error yerr[].
* @param[in] y Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[in] h The given step size.
* @param[out] yout Integration output.
* @param[out] yerr The estimated error.
*/
void Stepper( const G4double y[],
const G4double dydx[],
G4double h,
G4double yout[],
G4double yerr[]) override ;
/**
* Returns the distance from chord line.
*/
G4double DistChord() const override;
/**
* Returns the order, 7, of integration.
*/
inline G4int IntegratorOrder() const override { return 7; }
/**
* Returns the stepper type-ID, "kDormandPrinceRK78".
*/
inline G4StepperType StepperType() const override { return kDormandPrinceRK78; }
private :
private :
G4double *ak2, *ak3, *ak4, *ak5, *ak6, *ak7, *ak8,
*ak9, *ak10, *ak11, *ak12, *ak13,
*yTemp, *yIn;
G4double fLastStepLength = -1.0;
/** For DistChord() calculations. */
G4double *fLastInitialVector, *fLastFinalVector,
*fLastDyDx, *fMidVector, *fMidError;
// For DistChord calculations
G4DormandPrinceRK78* fAuxStepper = nullptr;
};
@@ -27,32 +27,37 @@
//
// Class description:
//
// Auxiliary class to print information from integration drivers
// Can be used by different types of drivers.
// Auxiliary class to print information from integration drivers.
// Can be used by different types of drivers.
// Authors: J.Apostolakis - January/March 2020
// Author: John Apostolakis (CERN), January/March 2020
// -------------------------------------------------------------------
#ifndef G4DRIVERREPORTER_HH
#define G4DRIVERREPORTER_HH
#include "G4FieldTrack.hh"
/**
* @brief G4DriverReporter is an auxiliary utility class to print information
* from integration drivers. It can be used by different types of drivers.
*/
class G4DriverReporter
{
public:
static void PrintStatus(const G4double* StartArr,
G4double xstart,
G4double xstart,
const G4double* CurrentArr,
G4double xcurrent,
G4double requestStep,
unsigned int subStepNo,
unsigned int noIntegrationVariables);
G4double xcurrent,
G4double requestStep,
unsigned int subStepNo,
unsigned int noIntegrationVariables);
static void PrintStatus(const G4FieldTrack& StartFT,
const G4FieldTrack& CurrentFT,
G4double requestStep,
unsigned int subStepNo);
G4double requestStep,
unsigned int subStepNo);
static void PrintStat_Aux(const G4FieldTrack& aFieldTrack,
G4double requestStep,
@@ -60,9 +65,5 @@ class G4DriverReporter
G4int subStepNo,
G4double subStepSize,
G4double dotVelocities);
private:
// G4int fVerboseLevel; // Verbose output for debugging
// unsigned int fNoIntegrationVariables);
};
#endif
@@ -29,7 +29,7 @@
//
// Electric field abstract class, implements inquiry function interface.
// Created: J.Apostolakis - 04.11.2003
// Author: John Apostolakis (CERN), 04.11.2003
// --------------------------------------------------------------------
#ifndef G4ELECTRIC_FIELD_HH
#define G4ELECTRIC_FIELD_HH
@@ -37,23 +37,37 @@
#include "G4Types.hh"
#include "G4ElectroMagneticField.hh"
/**
* @brief G4ElectricField is an abstract class for electric field.
* It implements inquiry function interface.
*/
class G4ElectricField : public G4ElectroMagneticField
{
public:
G4ElectricField();
~G4ElectricField() override;
// Constructor and destructor. No actions.
/**
* Default Constructor and Destructor.
*/
G4ElectricField() = default;
~G4ElectricField() override = default;
G4ElectricField(const G4ElectricField& r);
/**
* Copy constructor and assignment operator.
*/
G4ElectricField(const G4ElectricField& r) = default;
G4ElectricField& operator = (const G4ElectricField& p);
// Copy constructor & assignment operator.
G4bool DoesFieldChangeEnergy() const override { return true; }
// Since an electric field can change track energy
/**
* Returns true, since an electric field can change track energy.
*/
inline G4bool DoesFieldChangeEnergy() const override { return true; }
void GetFieldValue( const G4double Point[4],
G4double* Bfield ) const override = 0;
/**
* Interface for returning the field value 'Bfield' on given time 'Point'.
*/
void GetFieldValue( const G4double Point[4],
G4double* Bfield ) const override = 0;
};
#endif /* G4ELECTRIC_FIELD_DEF */
#endif
@@ -41,8 +41,8 @@
// Note 2: such a convention is required between any field and its
// corresponding equation of motion.
// Created: J.Apostolakis, 12.11.1998
// Modified: V.Grichine, 08.11.2001: Extended "Point" to add time
// Author: John Apostolakis (CERN), 12.11.1998 - Created
// Vladimir Grichine(CERN), 08.11.2001 - Extended "Point" to add time
// -------------------------------------------------------------------
#ifndef G4ELECTROMAGNETIC_FIELD_HH
#define G4ELECTROMAGNETIC_FIELD_HH
@@ -53,22 +53,37 @@ class G4ElectroMagneticField : public G4Field
{
public:
/**
* Constructor and default Destructor.
*/
G4ElectroMagneticField();
~G4ElectroMagneticField() override;
~G4ElectroMagneticField() override = default;
G4ElectroMagneticField(const G4ElectroMagneticField& r);
/**
* Copy constructor and assignment operator.
*/
G4ElectroMagneticField(const G4ElectroMagneticField& r) = default;
G4ElectroMagneticField& operator = (const G4ElectroMagneticField& p);
// Copy constructor & assignment operators.
void GetFieldValue(const G4double Point[4],
G4double *Bfield ) const override = 0;
// Return as Bfield[0], [1], [2] the magnetic field x, y & z components
// and as Bfield[3], [4], [5] the electric field x, y & z components
/**
* Interface for returning the field value 'Bfield' on given time 'Point'.
* Returns as Bfield[0], [1], [2] the magnetic field x, y & z components
* and as Bfield[3], [4], [5] the electric field x, y & z components.
*/
void GetFieldValue(const G4double Point[4],
G4double* Bfield ) const override = 0;
/**
* For field with an electric component it should return true.
* For pure magnetic field it should return false.
* Alternative: default safe implementation is to return true.
*/
G4bool DoesFieldChangeEnergy() const override = 0;
// For field with an electric component this should be true
// For pure magnetic field this should be false
// Alternative: default safe implementation { return true; }
/**
* Returns the field type-ID, "kElectroMagnetic".
*/
inline G4FieldType GetFieldType() const override { return kElectroMagnetic; }
};
#endif
@@ -31,7 +31,7 @@
// electric and magnetic field, with spin tracking for both MDM and
// EDM terms.
// Created: Kevin Lynch, 19.02.2009 - Based on G4EqEMFieldWithSpin
// Author: Kevin Lynch (Boston Univ.), 19.02.2009 - Based on G4EqEMFieldWithSpin
// -------------------------------------------------------------------
#ifndef G4EQEMFIELDWITHEDM_HH
#define G4EQEMFIELDWITHEDM_HH
@@ -41,31 +41,65 @@
class G4ElectroMagneticField;
/**
* @brief G4EqEMFieldWithEDM implements the right-hand side of equation of
* motion in a combined electric and magnetic field, with spin tracking for
* both MDM and EDM terms.
*/
class G4EqEMFieldWithEDM : public G4EquationOfMotion
{
public:
G4EqEMFieldWithEDM(G4ElectroMagneticField* emField );
/**
* Constructor for G4EqEMFieldWithEDM.
* @param[in] emField Pointer to the electromagnetic field.
*/
G4EqEMFieldWithEDM(G4ElectroMagneticField* emField);
~G4EqEMFieldWithEDM() override;
/**
* Default Destructor.
*/
~G4EqEMFieldWithEDM() override = default;
void SetChargeMomentumMass(G4ChargeState particleCharge, // in e+ units
G4double MomentumXc,
G4double mass) override;
/**
* Sets the charge, momentum and mass of the current particle.
* Used to set the equation's coefficients.
* @param[in] particleCharge Magnetic charge and moments in e+ units.
* @param[in] MomentumXc Particle momentum.
* @param[in] mass Particle mass.
*/
void SetChargeMomentumMass(G4ChargeState particleCharge, // in e+ units
G4double MomentumXc,
G4double mass) override;
/**
* Calculates the value of the derivative, given the value of the
* electromagnetic field.
* @param[in] y Coefficients array.
* @param[in] Field Field value.
* @param[out] dydx Derivatives array.
*/
void EvaluateRhsGivenB(const G4double y[],
const G4double Field[],
G4double dydx[] ) const override;
// Given the value of the electromagnetic field, this function
// calculates the value of the derivative dydx.
/**
* Setter and getter for magnetic anomaly.
*/
inline void SetAnomaly(G4double a) { anomaly = a; }
inline G4double GetAnomaly() const { return anomaly; }
// set/get magnetic anomaly
/**
* Setter and getter for EDM eta parameter.
*/
inline void SetEta(G4double n) { eta = n; }
inline G4double GetEta() const { return eta; }
// set/get EDM eta parameter
/**
* Returns the equation type-ID, "kEqEMfieldWithEDM".
*/
inline G4EquationType GetEquationType() const override { return kEqEMfieldWithEDM; }
private:
@@ -30,7 +30,7 @@
// This is the right-hand side of equation of motion in a combined
// electric and magnetic field.
// Created: Chris Gong & Peter Gumplinger, 30.08.2007
// Authors: Chris Gong & Peter Gumplinger (TRIUMF), 30.08.2007
// -------------------------------------------------------------------
#ifndef G4EQEMFIELDWITHSPIN_HH
#define G4EQEMFIELDWITHSPIN_HH
@@ -40,26 +40,58 @@
class G4ElectroMagneticField;
/**
* @brief G4EqEMFieldWithSpin implements the right-hand side of equation
* of motion in a combined electric and magnetic field.
*/
class G4EqEMFieldWithSpin : public G4EquationOfMotion
{
public:
/**
* Constructor for G4EqEMFieldWithSpin.
* @param[in] emField Pointer to the electromagnetic field.
*/
G4EqEMFieldWithSpin(G4ElectroMagneticField* emField );
~G4EqEMFieldWithSpin() override;
/**
* Default Destructor.
*/
~G4EqEMFieldWithSpin() override = default;
/**
* Sets the charge, momentum and mass of the current particle.
* Used to set the equation's coefficients.
* @param[in] particleCharge Magnetic charge and moments in e+ units.
* @param[in] MomentumXc Particle momentum.
* @param[in] mass Particle mass.
*/
void SetChargeMomentumMass(G4ChargeState particleCharge, // in e+ units
G4double MomentumXc,
G4double mass) override;
/**
* Calculates the value of the derivative, given the value of the
* electromagnetic field.
* @param[in] y Coefficients array.
* @param[in] Field Field value.
* @param[out] dydx Derivatives array.
*/
void EvaluateRhsGivenB(const G4double y[],
const G4double Field[],
G4double dydx[] ) const override;
// Given the value of the electromagnetic field, this function
// calculates the value of the derivative dydx.
/**
* Setter and getter for magnetic anomaly.
*/
inline void SetAnomaly(G4double a) { anomaly = a; }
inline G4double GetAnomaly() const { return anomaly; }
// set/get magnetic anomaly
/**
* Returns the equation type-ID, "kEqEMfieldWithSpin".
*/
inline G4EquationType GetEquationType() const override { return kEqEMfieldWithSpin; }
private:
@@ -29,8 +29,8 @@
//
// This is the right-hand side of equation of motion in a gravity field.
// Created: P.Gumplinger, 14.06.11 - Adopted from G4EqMagElectricField
// Thanks to P.Fierlinger (PSI) and A.Capra and A.Fontana (INFN Pavia)
// Author: Peter Gumplinger (TRIUMF), 14.06.11 - Adopted from G4EqMagElectricField
// Thanks to P.Fierlinger (PSI) and A.Capra and A.Fontana (INFN Pavia)
// -------------------------------------------------------------------
#ifndef G4EQGRAVITYFIELD_HH
#define G4EQGRAVITYFIELD_HH
@@ -39,22 +39,52 @@
#include "G4EquationOfMotion.hh"
#include "G4UniformGravityField.hh"
/**
* @brief G4EqGravityField implements the right-hand side of equation
* of motion in a gravity field.
*/
class G4EqGravityField : public G4EquationOfMotion
{
public:
/**
* Constructor for G4EqGravityField.
* @param[in] gField Pointer to the uniform gravity field.
*/
G4EqGravityField(G4UniformGravityField* gField);
~G4EqGravityField() override;
/**
* Default Destructor.
*/
~G4EqGravityField() override = default;
/**
* Sets the charge, momentum and mass of the current particle.
* Used to set the equation's coefficients.
* @param[in] particleCharge Magnetic charge and moments in e+ units.
* @param[in] MomentumXc Particle momentum.
* @param[in] mass Particle mass.
*/
void SetChargeMomentumMass(G4ChargeState particleCharge, // in e+ units
G4double MomentumXc,
G4double mass) override;
/**
* Calculates the value of the derivative, given the value of the
* electromagnetic field.
* @param[in] y Coefficients array.
* @param[in] Field Field value.
* @param[out] dydx Derivatives array.
*/
void EvaluateRhsGivenB( const G4double y[],
const G4double Field[],
G4double dydx[] ) const override;
// Given the value of the gravitational field, this function
// calculates the value of the derivative dydx.
/**
* Returns the equation type-ID, "kEqGravity".
*/
inline G4EquationType GetEquationType() const override { return kEqGravity; }
private:
@@ -30,7 +30,7 @@
// This is the right-hand side of equation of motion in a combined
// electric and magnetic field.
// Created: V.Grichine, 10.11.1998
// Author: Vladimir Grichine (CERN), 10.11.1998
// -------------------------------------------------------------------
#ifndef G4EQMAGELECTRICFIELD_HH
#define G4EQMAGELECTRICFIELD_HH
@@ -39,22 +39,52 @@
#include "G4EquationOfMotion.hh"
#include "G4ElectroMagneticField.hh"
/**
* @brief G4EqMagElectricField implements the right-hand side of equation of
* motion in a combined electric and magnetic field.
*/
class G4EqMagElectricField : public G4EquationOfMotion
{
public:
/**
* Constructor for G4EqMagElectricField.
* @param[in] emField Pointer to the electromagnetic field.
*/
G4EqMagElectricField(G4ElectroMagneticField* emField );
~G4EqMagElectricField() override;
/**
* Default Destructor.
*/
~G4EqMagElectricField() override = default;
/**
* Sets the charge, momentum and mass of the current particle.
* Used to set the equation's coefficients.
* @param[in] particleCharge Magnetic charge and moments in e+ units.
* @param[in] MomentumXc Particle momentum.
* @param[in] mass Particle mass.
*/
void SetChargeMomentumMass(G4ChargeState particleCharge, // in e+ units
G4double MomentumXc,
G4double mass) override;
/**
* Calculates the value of the derivative, given the value of the
* electromagnetic field.
* @param[in] y Coefficients array.
* @param[in] Field Field value.
* @param[out] dydx Derivatives array.
*/
void EvaluateRhsGivenB(const G4double y[],
const G4double Field[],
G4double dydx[] ) const override;
// Given the value of the electromagnetic field, this function
// calculates the value of the derivative dydx.
/**
* Returns the equation type-ID, "kEqElectroMagnetic".
*/
inline G4EquationType GetEquationType() const override { return kEqElectroMagnetic; }
private:
@@ -30,64 +30,101 @@
// Abstract Base Class for the right hand size of the equation of
// motion of a particle in a field.
// Created: J.Apostolakis, 1998
// Author: John Apostolakis (CERN), 1998
// -------------------------------------------------------------------
#ifndef G4EQUATIONOFMOTION_HH
#define G4EQUATIONOFMOTION_HH
#include "G4Types.hh"
#include "G4Field.hh" // required in inline method implementations
#include "G4FieldParameters.hh"
#include "G4ChargeState.hh"
/**
* @brief G4EquationOfMotion is the abstract base class for the right
* hand size of the equation of motion of a particle in a field.
*/
class G4EquationOfMotion
{
public: // with description
public:
G4EquationOfMotion( G4Field* Field );
virtual ~G4EquationOfMotion();
// Constructor and virtual destructor. No operations.
/**
* Constructor for G4EquationOfMotion.
* @param[in] Field Pointer to the field.
*/
G4EquationOfMotion( G4Field* Field );
virtual void EvaluateRhsGivenB( const G4double y[],
const G4double B[3],
G4double dydx[] ) const = 0;
// Given the value of the field "B", this function
// calculates the value of the derivative dydx.
// --------------------------------------------------------
// This is the _only_ function a subclass must define.
// The other two functions use Rhs_givenB.
/**
* Default virtual Destructor.
*/
virtual ~G4EquationOfMotion() = default;
virtual void SetChargeMomentumMass(G4ChargeState particleCharge,
G4double MomentumXc,
G4double MassXc2) = 0;
// Set the charge, momentum and mass of the current particle
// --> used to set the equation's coefficients ...
/**
* Calculates the value of the derivative, given the value of the field.
* @param[in] y Coefficients array.
* @param[in] Field Field value.
* @param[out] dydx Derivatives array.
*/
virtual void EvaluateRhsGivenB( const G4double y[],
const G4double B[3],
G4double dydx[] ) const = 0;
inline void RightHandSide( const G4double y[],
G4double dydx[] ) const;
// This calculates the value of the derivative dydx at y.
// It is the usual enquiry function.
// ---------------------------
// (It is not virtual, but calls the virtual function above.)
/**
* Sets the charge, momentum and mass of the current particle.
* Used to set the equation's coefficients.
* @param[in] particleCharge Magnetic charge and moments in e+ units.
* @param[in] MomentumXc Particle momentum.
* @param[in] mass Particle mass.
*/
virtual void SetChargeMomentumMass(G4ChargeState particleCharge,
G4double MomentumXc,
G4double MassXc2) = 0;
inline void EvaluateRhsReturnB( const G4double y[],
G4double dydx[],
G4double Field[] ) const;
// Same as RHS above, but also returns the value of B.
// Should be made the new default ? after putting dydx & B in a class.
/**
* Returns the equation type-ID, "kUserEquation".
*/
virtual G4EquationType GetEquationType() const { return kUserEquation; }
inline void GetFieldValue( const G4double Point[4],
G4double Field[] ) const;
// Obtain only the field - the stepper assumes it is pure Magnetic.
// Not protected, because G4RKG3_Stepper uses it directly.
/**
* Calculates the value of the derivative 'dydx' at 'y'.
* Calls the virtual function above.
* @param[in] y Coefficients array.
* @param[out] dydx Derivatives array.
*/
inline void RightHandSide( const G4double y[],
G4double dydx[] ) const;
inline const G4Field* GetFieldObj() const;
inline G4Field* GetFieldObj();
inline void SetFieldObj(G4Field* pField);
/**
* Calculates the value of the derivative 'dydx' at 'y' as above,
* but also returns the value of B.
* @param[in] y Coefficients array.
* @param[out] dydx Derivatives array.
* @param[out] Field Field value.
*/
inline void EvaluateRhsReturnB( const G4double y[],
G4double dydx[],
G4double Field[] ) const;
/**
* Returns the 'Field' value at the given time 'Point'.
* @param[in] Point The time point (x,y,z,t).
* @param[out] Field The returned field value.
*/
inline void GetFieldValue( const G4double Point[4],
G4double Field[] ) const;
/**
* Accessors and modifier for the field.
*/
inline const G4Field* GetFieldObj() const;
inline G4Field* GetFieldObj();
inline void SetFieldObj(G4Field* pField);
private:
G4Field* itsField = nullptr;
G4Field* itsField = nullptr;
};
#include "G4EquationOfMotion.icc"
@@ -25,7 +25,7 @@
//
// G4EquationOfMotion inline methods implementation
//
// Created: J.Apostolakis, 1998
// Author: John Apostolakis (CERN), 1998
// -------------------------------------------------------------------
inline
@@ -30,7 +30,7 @@
// Serves to reverse the magnetic field when propagation is backwards
// for error propagation.
// Created: P.Arce, September 2004.
// Author: Pedro Arce (CIEMAT), September 2004.
// --------------------------------------------------------------------
#ifndef G4ERRORMAG_USUALEQRHS_HH
#define G4ERRORMAG_USUALEQRHS_HH
@@ -38,17 +38,36 @@
#include "G4Mag_UsualEqRhs.hh"
#include "G4MagneticField.hh"
/**
* @brief G4ErrorMag_UsualEqRhs serves to reverse the magnetic field when
* propagation is backwards. It is used for error propagation.
*/
class G4ErrorMag_UsualEqRhs : public G4Mag_UsualEqRhs
{
public:
public:
G4ErrorMag_UsualEqRhs( G4MagneticField* MagField );
~G4ErrorMag_UsualEqRhs() override;
/**
* Constructor for G4ErrorMag_UsualEqRhs.
* @param[in] MagField Pointer to the magnetic field.
*/
G4ErrorMag_UsualEqRhs( G4MagneticField* MagField );
void EvaluateRhsGivenB( const G4double y[],
const G4double B[3],
G4double dydx[] ) const override;
// Reverses dedx if propagation is backwards
/**
* Default Destructor.
*/
~G4ErrorMag_UsualEqRhs() override = default;
/**
* Calculates the value of the derivative, given the value of the
* magnetic field. Reverses dedx if propagation is backwards.
* @param[in] y Coefficients array.
* @param[in] B Field value.
* @param[out] dydx Derivatives array.
*/
void EvaluateRhsGivenB( const G4double y[],
const G4double B[3],
G4double dydx[] ) const override;
};
#endif
@@ -35,7 +35,7 @@
//
// As the field is assumed constant, an error is not calculated.
// Author: J.Apostolakis, 28.01.2005.
// Author: John Apostolakis (CERN), 28.01.2005.
// Implementation adapted from ExplicitEuler by W.Wander
// --------------------------------------------------------------------
#ifndef G4EXACTHELIXSTEPPER_HH
@@ -48,40 +48,81 @@
#include "G4MagHelicalStepper.hh"
#include "G4Mag_EqRhs.hh"
/**
* @brief G4ExactHelixStepper is a concrete class for particle motion in
* constant magnetic field. Helix a-la-Explicity Euler: x_1 = x_0 + helix(h)
* with helix(h) being a helix piece of length h.
* As the field is assumed constant, an error is not calculated.
*/
class G4ExactHelixStepper : public G4MagHelicalStepper
{
public:
/**
* Constructor for G4ExactHelixStepper.
* @param[in] EqRhs Pointer to the standard equation of motion.
*/
G4ExactHelixStepper(G4Mag_EqRhs* EqRhs);
~G4ExactHelixStepper() override;
/**
* Default Destructor.
*/
~G4ExactHelixStepper() override = default;
/**
* Copy constructor and assignment operator not allowed.
*/
G4ExactHelixStepper(const G4ExactHelixStepper&) = delete;
G4ExactHelixStepper& operator=(const G4ExactHelixStepper&) = delete;
/**
* The stepper for the Runge Kutta integration.
* The stepsize is fixed, with the step size given by 'h'.
* Provides helix starting values y[0 to 6].
* Outputs yout[] and ZERO estimated error yerr[]=0.
* @param[in] yInput Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[in] h The given step size.
* @param[out] yout Integration output.
* @param[out] yerr The estimated error.
*/
void Stepper( const G4double y[],
const G4double dydx[],
G4double h,
G4double yout[],
G4double yerr[] ) override;
// Step 'integration' for step size 'h'
// Provides helix starting at y[0 to 6]
// Outputs yout[] and ZERO estimated error yerr[]=0.
G4double yerr[] ) override;
/**
* Same as Stepper() function above, but should perform a 'dump' step
* without error calculation. Assuming a constant field, the solution is
* a helix. Should NOT be called; issues a fatal exception as the Stepper
* must do all the work.
*/
void DumbStepper( const G4double y[],
G4ThreeVector Bfld,
G4double h,
G4double yout[] ) override;
// Performs a 'dump' Step without error calculation.
/**
* Estimates the maximum distance of curved solution and chord.
*/
G4double DistChord() const override;
// Estimate maximum distance of curved solution and chord ...
G4int IntegratorOrder() const override;
/**
* Returns the order, 1, of integration.
*/
inline G4int IntegratorOrder() const override { return 1; }
/**
* Returns the stepper type-ID, "kExactHelixStepper".
*/
inline G4StepperType StepperType() const override { return kExactHelixStepper; }
private:
/** Initial value of field at last step. */
G4ThreeVector fBfieldValue;
// Initial value of field at last step
};
#endif
@@ -31,26 +31,58 @@
// The most simple approach for solving linear differential equations.
// Take the current derivative and add it to the current position.
// Created: W.Wander <wwc@mit.edu>, 12.09.1997
// Author: W.Wander (MIT), 12.09.1997
// -------------------------------------------------------------------
#ifndef G4EXPLICITEULER_HH
#define G4EXPLICITEULER_HH
#include "G4MagErrorStepper.hh"
/**
* @brief G4ExplicitEuler implements an Explicit Euler stepper for magnetic
* field: x_1 = x_0 + h * dx_0. The most simple approach for solving linear
* differential equations. Takes the current derivative and adds it to the
* current position.
*/
class G4ExplicitEuler : public G4MagErrorStepper
{
public:
G4ExplicitEuler(G4EquationOfMotion* EqRhs, G4int numberOfVariables = 6) ;
~G4ExplicitEuler() override;
/**
* Constructor for G4ExplicitEuler.
* @param[in] EqRhs Pointer to the provided equation of motion.
* @param[in] numberOfVariables The number of integration variables.
*/
G4ExplicitEuler(G4EquationOfMotion* EqRhs,
G4int numberOfVariables = 6) ;
void DumbStepper( const G4double y[],
/**
* Default Destructor.
*/
~G4ExplicitEuler() override = default;
/**
* The stepper function for the integration.
* @param[in] y Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[in] h The given step size.
* @param[out] yout Integration output.
*/
void DumbStepper( const G4double y[],
const G4double dydx[],
G4double h,
G4double yout[] ) override;
G4int IntegratorOrder() const override { return 1; }
/**
* Returns the order, 1, of integration.
*/
inline G4int IntegratorOrder() const override { return 1; }
/**
* Returns the stepper type-ID, "kExplicitEuler".
*/
inline G4StepperType StepperType() const override { return kExplicitEuler; }
};
#endif
@@ -29,26 +29,56 @@
//
// Bogacki-Shampine - 8 - 5(4) FSAL stepper
// Created: Somnath Banerjee, Google Summer of Code 2015, 26 May 2015
// Supervision: John Apostolakis, CERN
// Author: Somnath Banerjee (CERN, Google Summer of Code 2015), 26.05.2015
// Supervision: John Apostolakis (CERN)
// --------------------------------------------------------------------
#ifndef G4FSAL_BOGACKI_SHAMPINE_45_HH
#define G4FSAL_BOGACKI_SHAMPINE_45_HH
#include "G4VFSALIntegrationStepper.hh"
/**
* @brief G4FSALBogackiShampine45 is an integrator of particle's equation of
* motion based on the Bogacki-Shampine - 8 - 5(4) FSAL implementation.
*/
class G4FSALBogackiShampine45 : public G4VFSALIntegrationStepper
{
public:
/**
* Constructor for G4FSALBogackiShampine45.
* @param[in] EqRhs Pointer to the provided equation of motion.
* @param[in] numberOfVariables The number of integration variables.
* @param[in] primary Flag for initialisation of the auxiliary stepper.
*/
G4FSALBogackiShampine45(G4EquationOfMotion* EqRhs,
G4int numberOfVariables = 6,
G4bool primary = true);
~G4FSALBogackiShampine45() override;
/**
* Destructor.
*/
~G4FSALBogackiShampine45() override;
/**
* Copy constructor and assignment operator not allowed.
*/
G4FSALBogackiShampine45(const G4FSALBogackiShampine45&) = delete;
G4FSALBogackiShampine45& operator=(const G4FSALBogackiShampine45&) = delete;
/**
* The stepper for the Runge Kutta integration.
* The stepsize is fixed, with the step size given by 'h'.
* Integrates ODE starting values y[0 to 6].
* Outputs yout[] and its estimated error yerr[].
* @param[in] y Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[in] h The given step size.
* @param[out] yout Integration output.
* @param[out] yerr The estimated error.
* @param[out] nextDydx Last derivatives array for the next step.
*/
void Stepper( const G4double y[],
const G4double dydx[],
G4double h,
@@ -56,31 +86,48 @@ class G4FSALBogackiShampine45 : public G4VFSALIntegrationStepper
G4double yerr[],
G4double nextDydx[]) override ;
/**
* Calculates the output at the tau fraction of step.
* @param[in] yInput Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[out] yOut Interpolation output.
* @param[in] Step The given step size.
* @param[in] tau The tau fraction of the step.
*/
void interpolate( const G4double yInput[],
const G4double dydx[],
G4double yOut[],
G4double Step,
G4double tau ) ;
/**
* Returns the distance from chord line.
*/
G4double DistChord() const override;
/**
* Returns the order, 4, of integration.
*/
inline G4int IntegratorOrder() const override { return 4; }
private:
/**
* Init method used in constructor.
*/
void PrepareConstants();
// Working arrays -- used during stepping
//
/** Working arrays -- used during stepping. */
G4double *ak2, *ak3, *ak4, *ak5, *ak6, *ak7, *ak8, *ak9, *ak10, *ak11,
*DyDx, *yTemp, *yIn;
G4double *pseudoDydx_for_DistChord;
G4double fLastStepLength = -1.0;
G4double *fLastInitialVector, *fLastFinalVector,
*fLastDyDx, *fMidVector, *fMidError;
// for DistChord calculations
*fLastDyDx, *fMidVector, *fMidError; // for DistChord calculations
G4double b[12]; // Working array for interpolation
/** Working array for interpolation. */
G4double b[12];
G4FSALBogackiShampine45* fAuxStepper = nullptr;
@@ -29,68 +29,126 @@
//
// DormandPrince7 - 5(4) FSAL stepper
// Created: Somnath Banerjee, Google Summer of Code 2015, 25 May 2015
// Supervision: John Apostolakis, CERN
// Author: Somnath Banerjee (CERN, Google Summer of Code 2015), 25.05.2015
// Supervision: John Apostolakis (CERN)
// --------------------------------------------------------------------
#ifndef G4FSALDORMANDPRINCE745_HH
#define G4FSALDORMANDPRINCE745_HH
#include "G4VFSALIntegrationStepper.hh"
/**
* @brief G4FSALDormandPrince745 is an integrator of particle's equation of
* motion based on the DormandPrince7 - 5(4) FSAL implementation.
*/
class G4FSALDormandPrince745 : public G4VFSALIntegrationStepper
{
public:
/**
* Constructor for G4FSALDormandPrince745.
* @param[in] EqRhs Pointer to the provided equation of motion.
* @param[in] numberOfVariables The number of integration variables.
* @param[in] primary Flag for initialisation of the auxiliary stepper.
*/
G4FSALDormandPrince745(G4EquationOfMotion* EqRhs,
G4int numberOfVariables = 6,
G4bool primary = true);
~G4FSALDormandPrince745() override;
/**
* Destructor.
*/
~G4FSALDormandPrince745() override;
/**
* Copy constructor and assignment operator not allowed.
*/
G4FSALDormandPrince745(const G4FSALDormandPrince745&) = delete;
G4FSALDormandPrince745& operator=(const G4FSALDormandPrince745&) = delete;
/**
* The stepper for the Runge Kutta integration.
* The stepsize is fixed, with the step size given by 'h'.
* Integrates ODE starting values y[0 to 6].
* Outputs yout[] and its estimated error yerr[].
* @param[in] y Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[in] h The given step size.
* @param[out] yout Integration output.
* @param[out] yerr The estimated error.
* @param[out] nextDydx Last derivatives array for the next step.
*/
void Stepper( const G4double y[],
const G4double dydx[],
G4double h,
G4double yout[],
G4double yerr[],
G4double nextDydx[]) override ;
/**
* Calculates the output at the tau fraction of step.
* @param[in] yInput Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[out] yOut Interpolation output.
* @param[in] Step The given step size.
* @param[in] tau The tau fraction of the step.
*/
void interpolate( const G4double yInput[],
const G4double dydx[],
G4double yOut[],
G4double Step,
G4double tau ) ;
void SetupInterpolate( const G4double yInput[],
const G4double dydx[],
const G4double Step );
// For higher order Interpolant
/**
* Calculates the output at the tau fraction of step. Same as above
* for higher order interpolant.
*/
void Interpolate( const G4double yInput[],
const G4double dydx[],
const G4double Step,
G4double yOut[],
G4double tau );
// For calculating the output at the tau fraction of Step
/**
* Setup method for higher order interpolant.
* @param[in] yInput Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[in] Step The given step size.
*/
void SetupInterpolate( const G4double yInput[],
const G4double dydx[],
const G4double Step );
G4double DistChord() const override;
/**
* Returns the distance from chord line.
*/
G4double DistChord() const override;
/**
* Returns the order, 4, of integration.
*/
inline G4int IntegratorOrder() const override { return 4; }
/**
* Returns true as this is a FSAL integrator.
*/
inline G4bool isFSAL() const { return true; }
private:
/** Working arrays -- used during stepping. */
G4double *ak2, *ak3, *ak4, *ak5, *ak6, *ak7,
*ak8, *ak9, // For additional stages in the interpolant
*yTemp, *yIn;
/** Only for use with DistChord(). */
G4double* pseudoDydx_for_DistChord;
// Only for use with DistChord()
G4double fLastStepLength = -1.0;
G4double *fLastInitialVector, *fLastFinalVector,
*fInitialDyDx, *fLastDyDx, *fMidVector, *fMidError;
// For DistChord() calculations
*fInitialDyDx, *fLastDyDx,
*fMidVector, *fMidError; // For DistChord() calculations
G4FSALDormandPrince745* fAuxStepper = nullptr;
};
@@ -29,7 +29,7 @@
//
// Driver class which controls the integration error of a Runge-Kutta stepper
// Created: D.Sorokin, 2017
// Author: Dmitry Sorokin (CERN, Google Summer of Code 2017), 20.10.2017
// --------------------------------------------------------------------
#ifndef G4FSALINTEGRATIONDRIVER_HH
#define G4FSALINTEGRATIONDRIVER_HH
@@ -37,98 +37,170 @@
#include "G4RKIntegrationDriver.hh"
#include "G4ChordFinderDelegate.hh"
/**
* @brief G4FSALIntegrationDriver is a templated driver class which controls
* the integration error of a Runge-Kutta stepper.
*/
template <class T>
class G4FSALIntegrationDriver : public G4RKIntegrationDriver<T>,
public G4ChordFinderDelegate<G4FSALIntegrationDriver<T>>
public G4ChordFinderDelegate<G4FSALIntegrationDriver<T>>
{
public:
G4FSALIntegrationDriver(G4double hminimum,
T* stepper,
G4int numberOfComponents = 6,
G4int statisticsVerbosity = 1);
/**
* Constructor for G4FSALIntegrationDriver.
* @param[in] hminimum Minimum allowed step.
* @param[in] stepper Pointer to the stepper algorithm.
* @param[in] numberOfComponents The number of integration variables,
* if not matching stepper's number of variables, issue exception.
* @param[in] statisticsVerbosity Verbosity level.
*/
inline G4FSALIntegrationDriver(G4double hminimum,
T* stepper,
G4int numberOfComponents = 6,
G4int statisticsVerbosity = 1);
~G4FSALIntegrationDriver() override;
/**
* Destructor. Provides statistics if verbosity level is greater than zero.
*/
inline ~G4FSALIntegrationDriver() override;
/**
* Copy constructor and assignment operator not allowed.
*/
G4FSALIntegrationDriver(const G4FSALIntegrationDriver&) = delete;
G4FSALIntegrationDriver& operator=(const G4FSALIntegrationDriver&) = delete;
G4double AdvanceChordLimited(G4FieldTrack& track,
G4double hstep,
G4double eps,
G4double chordDistance) override;
/**
* Computes the step to take, based on chord limits.
* @param[in,out] track The current track in field.
* @param[in] hstep Proposed step length.
* @param[in] eps Requested accuracy, y_err/hstep.
* @param[in] chordDistance Maximum sagitta distance.
* @returns The length of step taken.
*/
inline G4double AdvanceChordLimited(G4FieldTrack& track,
G4double hstep,
G4double eps,
G4double chordDistance) override;
void OnStartTracking() override
{
ChordFinderDelegate::ResetStepEstimate();
}
/**
* Dispatch interface method for initialisation/reset of driver.
*/
inline void OnStartTracking() override;
void OnComputeStep(const G4FieldTrack* /*track*/ = nullptr) override {}
/**
* Dispatch interface method for computing step. Does nothing here.
*/
inline void OnComputeStep(const G4FieldTrack* /*track*/ = nullptr) override;
G4bool DoesReIntegrate() const override { return true; }
/**
* The driver does implement re-integration. Returns true.
*/
inline G4bool DoesReIntegrate() const override;
G4bool AccurateAdvance( G4FieldTrack& track,
G4double hstep,
G4double eps, // Requested y_err/hstep
G4double hinitial = 0.0) override;
// Integrates ODE from current s (s=s0) to s=s0+h with accuracy eps.
// On output track is replaced by value at end of interval.
// The concept is similar to the odeint routine from NRC p.721-722.
/**
* Advances integration accurately by relative accuracy better than 'eps'.
* On output the track is replaced by the value at the end of interval.
* @param[in,out] track The current track in field.
* @param[in] hstep Proposed step length.
* @param[in] eps Requested accuracy, y_err/hstep.
* @param[in] hinitial Initial minimum integration step.
* @returns true if integration succeeds.
*/
inline G4bool AccurateAdvance(G4FieldTrack& track,
G4double hstep,
G4double eps, // Requested y_err/hstep
G4double hinitial = 0.0) override;
G4bool QuickAdvance( G4FieldTrack& fieldTrack,
const G4double dydx[],
/**
* Attempts one integration step, and returns estimated error 'dyerr'.
* It does not ensure accuracy.
* @param[in,out] fieldTrack The current track in field.
* @param[in] dydx dydx array.
* @param[in] hstep Proposed step length.
* @param[out] dchord_step Estimated sagitta distance.
* @param[out] dyerr Estimated error.
* @returns true if integration succeeds.
*/
inline G4bool QuickAdvance(G4FieldTrack& fieldTrack,
const G4double dydx[],
G4double hstep,
G4double& dchord_step,
G4double& dyerr ) override;
// QuickAdvance just tries one Step - it does not ensure accuracy.
G4double& dyerr) override;
void SetVerboseLevel(G4int newLevel) override;
G4int GetVerboseLevel() const override;
/**
* Takes one Step that is as large as possible while satisfying the
* accuracy criterion.
* @param[in,out] y The current track state, y.
* @param[in] dydx dydx array.
* @param[in,out] curveLength Step start, x.
* @param[in] htry Step to attempt.
* @param[in] eps The relative accuracy.
* @param[out] hdid Step achieved.
* @param[out] hnext Proposed next step.
*/
inline void OneGoodStep(G4double y[], // InOut
G4double dydx[],
G4double& curveLength,
G4double htry,
G4double eps,
G4double& hdid,
G4double& hnext);
void StreamInfo( std::ostream& os ) const override;
// Write out the parameters / state of the driver
/**
* Setter and getter for verbosity.
*/
inline void SetVerboseLevel(G4int newLevel) override;
inline G4int GetVerboseLevel() const override;
/**
* Writes out to stream the parameters/state of the driver.
*/
inline void StreamInfo( std::ostream& os ) const override;
// Accessors
/**
* Getter and Setter for minimum allowed step.
*/
inline G4double GetMinimumStep() const;
inline void SetMinimumStep(G4double newval);
G4double GetMinimumStep() const;
void SetMinimumStep(G4double newval);
void OneGoodStep(G4double y[], // InOut
G4double dydx[],
G4double& curveLength,
G4double htry,
G4double eps,
G4double& hdid,
G4double& hnext);
// This takes one Step that is of size htry, or as large
// as possible while satisfying the accuracy criterion of:
// yerr < eps * |y_end-y_start|
G4double GetSmallestFraction() const;
void SetSmallestFraction(G4double val);
/**
* Getter and Setter for smallest fraction.
*/
inline G4double GetSmallestFraction() const;
inline void SetSmallestFraction(G4double val);
protected:
void IncrementQuickAdvanceCalls();
/**
* Increments the counter for the number of calls to QuickAdvance().
*/
inline void IncrementQuickAdvanceCalls();
private:
void CheckStep(const G4ThreeVector& posIn,
const G4ThreeVector& posOut,
G4double hdid);
/**
* Checks accuracy of step distance on the end point.
*/
inline void CheckStep(const G4ThreeVector& posIn,
const G4ThreeVector& posOut, G4double hdid);
private:
/** Minimum Step allowed in a Step (in absolute units). */
G4double fMinimumStep;
// Minimum Step allowed in a Step (in absolute units)
/** Smallest fraction of (existing) curve length in relative units.
* Below this fraction the current step will be the last.
* The expected range: smaller than 0.1 * epsilon and bigger than 5e-13
* (range not enforced). */
G4double fSmallestFraction{1e-12};
// Smallest fraction of (existing) curve length - in relative units
// below this fraction the current step will be the last
// Expected range: smaller than 0.1 * epsilon and bigger than 5e-13
// ( Note: this range is not enforced. )
/** Verbosity level for printing (debug, etc..)
* Could be varied during tracking to help identifying issues. */
G4int fVerboseLevel;
// Verbosity level for printing (debug, ..)
// Could be varied during tracking - to help identify issues
G4int fNoQuickAvanceCalls{0};
G4int fNoAccurateAdvanceCalls{0};
@@ -25,7 +25,7 @@
//
// G4FSALIntegrationDriver inline implementation
//
// Created: D.Sorokin, 2017
// Author: Dmitry Sorokin (CERN, Google Summer of Code 2017), 20.10.2017
// --------------------------------------------------------------------
#include "G4FieldUtils.hh"
@@ -34,34 +34,34 @@ template <class T>
G4FSALIntegrationDriver<T>::
G4FSALIntegrationDriver ( G4double hminimum, T* pStepper,
G4int numComponents, G4int statisticsVerbose )
: Base(pStepper),
fMinimumStep(hminimum),
fVerboseLevel(statisticsVerbose)
: Base(pStepper),
fMinimumStep(hminimum),
fVerboseLevel(statisticsVerbose)
{
if (numComponents != Base::GetStepper()->GetNumberOfVariables())
{
std::ostringstream message;
message << "Driver's number of integrated components "
<< numComponents
<< " != Stepper's number of components "
<< pStepper->GetNumberOfVariables();
G4Exception("G4FSALIntegrationDriver","GeomField0002",
FatalException, message);
}
if (numComponents != Base::GetStepper()->GetNumberOfVariables())
{
std::ostringstream message;
message << "Driver's number of integrated components "
<< numComponents
<< " != Stepper's number of components "
<< pStepper->GetNumberOfVariables();
G4Exception("G4FSALIntegrationDriver","GeomField0002",
FatalException, message);
}
}
template <class T>
G4FSALIntegrationDriver<T>::~G4FSALIntegrationDriver()
{
#ifdef G4VERBOSE
if( fVerboseLevel > 0 )
{
G4cout << "G4FSALIntegration Driver Stats: "
<< "#QuickAdvance " << fNoQuickAvanceCalls
<< " - #AccurateAdvance " << fNoAccurateAdvanceCalls << G4endl
<< "#good steps " << fNoAccurateAdvanceGoodSteps << " "
<< "#bad steps " << fNoAccurateAdvanceBadSteps << G4endl;
}
if( fVerboseLevel > 0 )
{
G4cout << "G4FSALIntegration Driver Stats: "
<< "#QuickAdvance " << fNoQuickAvanceCalls
<< " - #AccurateAdvance " << fNoAccurateAdvanceCalls << G4endl
<< "#good steps " << fNoAccurateAdvanceGoodSteps << " "
<< "#bad steps " << fNoAccurateAdvanceBadSteps << G4endl;
}
#endif
}
@@ -76,66 +76,65 @@ G4bool G4FSALIntegrationDriver<T>::
AccurateAdvance( G4FieldTrack& track, G4double hstep,
G4double eps, G4double hinitial )
{
++fNoAccurateAdvanceCalls;
++fNoAccurateAdvanceCalls;
if (hstep < GetMinimumStep())
if (hstep < GetMinimumStep())
{
G4double dchord_step = 0.0, dyerr = 0.0;
G4double dydx[G4FieldTrack::ncompSVEC];
Base::GetDerivatives(track, dydx);
return QuickAdvance(track, dydx, hstep, dchord_step, dyerr);
}
G4bool succeeded = false;
G4double hnext, hdid;
G4double y[G4FieldTrack::ncompSVEC], dydx[G4FieldTrack::ncompSVEC];
track.DumpToArray(y);
// hstep somtimes is too small. No need to add large curveLength.
G4double curveLength = 0.0;
G4double endCurveLength = hstep;
G4double h = hstep;
if (hinitial > CLHEP::perMillion * hstep && hinitial < hstep)
{
h = hinitial;
}
Base::GetStepper()->RightHandSide(y, dydx);
for (G4int iter = 0; iter < Base::GetMaxNoSteps(); ++iter)
{
const G4ThreeVector StartPos =
field_utils::makeVector(y, field_utils::Value3D::Position);
OneGoodStep(y, dydx, curveLength, h, eps, hdid, hnext);
const G4ThreeVector EndPos =
field_utils::makeVector(y, field_utils::Value3D::Position);
CheckStep(EndPos, StartPos, hdid);
G4double restCurveLength = endCurveLength - curveLength;
if (restCurveLength < GetSmallestFraction() * hstep)
{
G4double dchord_step = 0.0, dyerr = 0.0;
G4double dydx[G4FieldTrack::ncompSVEC];
Base::GetDerivatives(track, dydx);
return QuickAdvance(track, dydx, hstep, dchord_step, dyerr);
succeeded = true;
break;
}
G4bool succeeded = false;
G4double hnext, hdid;
G4double y[G4FieldTrack::ncompSVEC], dydx[G4FieldTrack::ncompSVEC];
track.DumpToArray(y);
// hstep somtimes is too small. No need to add large curveLength.
G4double curveLength = 0.0;
G4double endCurveLength = hstep;
h = std::min(hnext, restCurveLength);
}
G4double h = hstep;
if (hinitial > CLHEP::perMillion * hstep && hinitial < hstep)
{
h = hinitial;
}
if (succeeded)
{
track.LoadFromArray(y, Base::GetStepper()->GetNumberOfVariables());
track.SetCurveLength(track.GetCurveLength() + curveLength);
}
Base::GetStepper()->RightHandSide(y, dydx);
for (G4int iter = 0; iter < Base::GetMaxNoSteps(); ++iter)
{
const G4ThreeVector StartPos =
field_utils::makeVector(y, field_utils::Value3D::Position);
OneGoodStep(y, dydx, curveLength, h, eps, hdid, hnext);
const G4ThreeVector EndPos =
field_utils::makeVector(y, field_utils::Value3D::Position);
CheckStep(EndPos, StartPos, hdid);
G4double restCurveLength = endCurveLength - curveLength;
if (restCurveLength < GetSmallestFraction() * hstep)
{
succeeded = true;
break;
}
h = std::min(hnext, restCurveLength);
}
if (succeeded)
{
track.LoadFromArray(y, Base::GetStepper()->GetNumberOfVariables());
track.SetCurveLength(track.GetCurveLength() + curveLength);
}
return succeeded;
return succeeded;
}
// Driver for one Runge-Kutta Step with monitoring of local truncation error
@@ -161,36 +160,36 @@ OneGoodStep(G4double y[],
G4double& hdid, // Out
G4double& hnext) // Out
{
G4double error2 = DBL_MAX;
G4double error2 = DBL_MAX;
G4double yError[G4FieldTrack::ncompSVEC],
yOut[G4FieldTrack::ncompSVEC],
dydxOut[G4FieldTrack::ncompSVEC];
G4double yError[G4FieldTrack::ncompSVEC],
yOut[G4FieldTrack::ncompSVEC],
dydxOut[G4FieldTrack::ncompSVEC];
// Set stepsize to the initial trial value
G4double hstep = htry;
// Set stepsize to the initial trial value
G4double hstep = htry;
const G4int max_trials = 100;
const G4int max_trials = 100;
for (G4int iter = 0; iter < max_trials; ++iter)
{
Base::GetStepper()->Stepper(y, dydx, hstep, yOut, yError, dydxOut);
error2 = field_utils::relativeError2(y, yError, hstep, eps_rel_max);
for (G4int iter = 0; iter < max_trials; ++iter)
{
Base::GetStepper()->Stepper(y, dydx, hstep, yOut, yError, dydxOut);
error2 = field_utils::relativeError2(y, yError, hstep, eps_rel_max);
// Step succeeded.
if (error2 <= 1) { break; }
// Step succeeded.
if (error2 <= 1) { break; }
hstep = Base::ShrinkStepSize2(hstep, error2);
}
hstep = Base::ShrinkStepSize2(hstep, error2);
}
hnext = Base::GrowStepSize2(hstep, error2);
curveLength += (hdid = hstep);
hnext = Base::GrowStepSize2(hstep, error2);
curveLength += (hdid = hstep);
for(G4int k = 0; k < Base::GetStepper()->GetNumberOfVariables(); ++k)
{
y[k] = yOut[k];
dydx[k] = dydxOut[k];
}
for(G4int k = 0; k < Base::GetStepper()->GetNumberOfVariables(); ++k)
{
y[k] = yOut[k];
dydx[k] = dydxOut[k];
}
}
template <class T>
@@ -199,123 +198,122 @@ QuickAdvance( G4FieldTrack& fieldTrack, const G4double dydxIn[],
G4double hstep,
G4double& dchord_step, G4double& dyerr )
{
++fNoQuickAvanceCalls;
if (hstep == 0)
{
std::ostringstream message;
message << "Proposed step is zero; hstep = " << hstep << " !";
G4Exception("G4FSALIntegrationDriver ::QuickAdvance()",
"GeomField1001", JustWarning, message);
return true;
}
if (hstep < 0)
{
std::ostringstream message;
message << "Invalid run condition." << G4endl
<< "Proposed step is negative; hstep = "
<< hstep << "." << G4endl
<< "Requested step cannot be negative! Aborting event.";
G4Exception("G4FSALIntegrationDriver ::QuickAdvance()",
"GeomField0003", EventMustBeAborted, message);
return false;
}
G4double yError[G4FieldTrack::ncompSVEC],
yIn[G4FieldTrack::ncompSVEC],
yOut[G4FieldTrack::ncompSVEC],
dydxOut[G4FieldTrack::ncompSVEC];
fieldTrack.DumpToArray(yIn);
Base::GetStepper()->Stepper(yIn, dydxIn, hstep, yOut, yError, dydxOut);
dchord_step = Base::GetStepper()->DistChord();
fieldTrack.LoadFromArray(yOut, Base::GetStepper()->GetNumberOfVariables());
fieldTrack.SetCurveLength(fieldTrack.GetCurveLength() + hstep);
dyerr = field_utils::absoluteError(yOut, yError, hstep);
++fNoQuickAvanceCalls;
if (hstep == 0)
{
std::ostringstream message;
message << "Proposed step is zero; hstep = " << hstep << " !";
G4Exception("G4FSALIntegrationDriver ::QuickAdvance()",
"GeomField1001", JustWarning, message);
return true;
}
if (hstep < 0)
{
std::ostringstream message;
message << "Invalid run condition." << G4endl
<< "Proposed step is negative; hstep = "
<< hstep << "." << G4endl
<< "Requested step cannot be negative! Aborting event.";
G4Exception("G4FSALIntegrationDriver ::QuickAdvance()",
"GeomField0003", EventMustBeAborted, message);
return false;
}
G4double yError[G4FieldTrack::ncompSVEC],
yIn[G4FieldTrack::ncompSVEC],
yOut[G4FieldTrack::ncompSVEC],
dydxOut[G4FieldTrack::ncompSVEC];
fieldTrack.DumpToArray(yIn);
Base::GetStepper()->Stepper(yIn, dydxIn, hstep, yOut, yError, dydxOut);
dchord_step = Base::GetStepper()->DistChord();
fieldTrack.LoadFromArray(yOut, Base::GetStepper()->GetNumberOfVariables());
fieldTrack.SetCurveLength(fieldTrack.GetCurveLength() + hstep);
dyerr = field_utils::absoluteError(yOut, yError, hstep);
return true;
}
template <class T>
void G4FSALIntegrationDriver<T>::SetSmallestFraction(G4double newFraction)
{
if( newFraction > 1.e-16 && newFraction < 1e-8 )
{
fSmallestFraction = newFraction;
}
else
{
std::ostringstream message;
message << "Smallest Fraction not changed. " << G4endl
<< " Proposed value was " << newFraction << G4endl
<< " Value must be between 1.e-8 and 1.e-16";
G4Exception("G4FSALIntegrationDriver::SetSmallestFraction()",
"GeomField1001", JustWarning, message);
}
if( newFraction > 1.e-16 && newFraction < 1e-8 )
{
fSmallestFraction = newFraction;
}
else
{
std::ostringstream message;
message << "Smallest Fraction not changed. " << G4endl
<< " Proposed value was " << newFraction << G4endl
<< " Value must be between 1.e-8 and 1.e-16";
G4Exception("G4FSALIntegrationDriver::SetSmallestFraction()",
"GeomField1001", JustWarning, message);
}
}
template <class T>
void G4FSALIntegrationDriver<T>::CheckStep(
const G4ThreeVector& posIn, const G4ThreeVector& posOut, G4double hdid)
{
const G4double endPointDist = (posOut - posIn).mag();
if (endPointDist >= hdid * (1. + CLHEP::perMillion))
{
++fNoAccurateAdvanceBadSteps;
const G4double endPointDist = (posOut - posIn).mag();
if (endPointDist >= hdid * (1. + CLHEP::perMillion))
{
++fNoAccurateAdvanceBadSteps;
#ifdef G4DEBUG_FIELD
// Issue a warning only for gross differences -
// we understand how small difference occur.
if (endPointDist >= hdid * (1. + perThousand))
{
G4Exception("G4FSALIntegrationDriver::CheckStep()",
"GeomField1002", JustWarning,
"endPointDist >= hdid!");
}
#endif
}
else
// Issue a warning only for gross differences -
// we understand how small difference occur.
if (endPointDist >= hdid * (1. + perThousand))
{
++fNoAccurateAdvanceGoodSteps;
G4Exception("G4FSALIntegrationDriver::CheckStep()",
"GeomField1002", JustWarning, "endPointDist >= hdid!");
}
#endif
}
else
{
++fNoAccurateAdvanceGoodSteps;
}
}
template <class T>
inline G4double G4FSALIntegrationDriver<T>::GetMinimumStep() const
{
return fMinimumStep;
return fMinimumStep;
}
template <class T>
void G4FSALIntegrationDriver<T>::SetMinimumStep(G4double minimumStepLength)
{
fMinimumStep = minimumStepLength;
fMinimumStep = minimumStepLength;
}
template <class T>
G4int G4FSALIntegrationDriver<T>::GetVerboseLevel() const
{
return fVerboseLevel;
return fVerboseLevel;
}
template <class T>
void G4FSALIntegrationDriver<T>::SetVerboseLevel(G4int newLevel)
{
fVerboseLevel = newLevel;
fVerboseLevel = newLevel;
}
template <class T>
G4double G4FSALIntegrationDriver<T>::GetSmallestFraction() const
{
return fSmallestFraction;
return fSmallestFraction;
}
template <class T>
void G4FSALIntegrationDriver<T>::IncrementQuickAdvanceCalls()
{
++fNoQuickAvanceCalls;
++fNoQuickAvanceCalls;
}
template <class T>
@@ -325,14 +323,32 @@ G4FSALIntegrationDriver<T>::AdvanceChordLimited(G4FieldTrack& track,
G4double eps,
G4double chordDistance)
{
return ChordFinderDelegate::AdvanceChordLimitedImpl(track, hstep,
eps, chordDistance);
return ChordFinderDelegate::AdvanceChordLimitedImpl(track, hstep,
eps, chordDistance);
}
template <class T>
void G4FSALIntegrationDriver<T>::OnStartTracking()
{
ChordFinderDelegate::ResetStepEstimate();
}
template <class T>
void G4FSALIntegrationDriver<T>::OnComputeStep(const G4FieldTrack*)
{
}
template <class T>
G4bool G4FSALIntegrationDriver<T>::DoesReIntegrate() const
{
return true;
}
template <class T>
void G4FSALIntegrationDriver<T>::StreamInfo( std::ostream& os ) const
{
// Write out the parameters / state of the driver
// Write out the parameters / state of the driver
os << "State of G4IntegrationDriver: " << std::endl;
os << "--Base state (G4RKIntegrationDriver): " << std::endl;
Base::StreamInfo( os );
@@ -31,8 +31,8 @@
// It allows any kind of field (vector, scalar, tensor and any set of them)
// to be defined by implementing the inquiry function interface.
//
// The key method is GetFieldValue( const double Point[4],
// ************* double *fieldArr )
// The key method is GetFieldValue( const G4double Point[4],
// ************* G4double* fieldArr )
// Given an input position/time vector 'Point',
// this method must return the value of the field in "fieldArr".
//
@@ -44,68 +44,102 @@
// spin. For this a field and its equation of motion must follow the
// same convention for the order of field components in the array "fieldArr"
// Created: John Apostolakis, 10.03.1997
// Author: John Apostolakis (CERN), 10.03.1997
// -------------------------------------------------------------------
#ifndef G4FIELD_HH
#define G4FIELD_HH
#include "G4Types.hh"
#include "G4FieldParameters.hh"
#include "globals.hh"
/**
* @brief G4Field is the abstract class for any kind of field.
* It allows any kind of field (vector, scalar, tensor and any set of them)
* to be defined by implementing the inquiry function interface.
* A field must co-work with a corresponding Equation of Motion, to
* enable the integration of a particle's position, momentum and, optionally,
* spin. For this a field and its equation of motion must follow the same
* convention for the order of field components.
*/
class G4Field
{
public: // with description
public:
G4Field( G4bool gravityOn = false);
G4Field( const G4Field& );
virtual ~G4Field();
G4Field& operator = (const G4Field& p);
/**
* Constructor for G4Field.
* @param[in] gravityOn Flag to indicate if gravity is enabled or not.
*/
G4Field(G4bool gravityOn = false);
virtual void GetFieldValue( const G4double Point[4],
G4double* fieldArr ) const = 0;
// Given the position time vector 'Point',
// return the value of the field in the array fieldArr.
// Notes:
// 1) The 'Point' vector has the following structure:
// Point[0] is x ( position, in Geant4 units )
// Point[1] is y
// Point[2] is z
// Point[3] is t ( time, in Geant4 units )
// 2) The convention for the components of the field
// array 'fieldArr' are determined by the type of field.
// See for example the class G4ElectroMagneticField.
/**
* Default virtual Destructor.
*/
virtual ~G4Field() = default;
virtual G4bool DoesFieldChangeEnergy() const = 0;
// Each type/class of field should respond this accordingly
// For example:
// - an electric field should return "true"
// - a pure magnetic field should return "false"
/**
* Copy constructor and assignment operator.
*/
G4Field( const G4Field& p) = default;
G4Field& operator = (const G4Field& p);
inline G4bool IsGravityActive() const;
/**
* Given the position time vector 'Point', returns the value of the
* field in the array 'fieldArr'. Notes:
* 1) The 'Point' vector has the following structure:
* Point[0] is x ( position, in Geant4 units )
* Point[1] is y
* Point[2] is z
* Point[3] is t ( time, in Geant4 units )
* 2) The convention for the components of the field array 'fieldArr'
* are determined by the type of field.
* @param[in] Point The position time vector.
* @param[out] fieldArr The field array in output.
*/
virtual void GetFieldValue( const G4double Point[4],
G4double* fieldArr ) const = 0;
/**
* Each type/class of field should respond the field does change energy.
* For example:
* - an electric field should return "true"
* - a pure magnetic field should return "false"
*/
virtual G4bool DoesFieldChangeEnergy() const = 0;
/**
* Returns the field type-ID, "kUserFieldType".
* This should be overriden in derived classes.
*/
virtual G4FieldType GetFieldType() const { return kUserFieldType; }
/**
* Replies if the field includes gravity.
* @returns true if the field does include gravity.
*/
inline G4bool IsGravityActive() const { return fGravityActive; }
// Does this field include gravity?
inline void SetGravityActive( G4bool OnOffFlag );
/**
* Sets the gravity flag.
*/
inline void SetGravityActive(G4bool OnOffFlag) { fGravityActive = OnOffFlag; }
virtual G4Field* Clone() const;
// Implements cloning, needed by multi-threading
/**
* Interface method to implement cloning, needed by multi-threading.
* Here issuing a fatal exception, as expecting this to be implemented
* concretely in derived classes.
*/
virtual G4Field* Clone() const;
static constexpr G4int MAX_NUMBER_OF_COMPONENTS = 24;
public:
static constexpr G4int MAX_NUMBER_OF_COMPONENTS = 24;
private:
G4bool fGravityActive = false;
G4bool fGravityActive = false;
};
// Inline methods ...
inline G4bool G4Field::IsGravityActive() const
{
return fGravityActive;
}
inline void G4Field::SetGravityActive( G4bool OnOffFlag )
{
fGravityActive = OnOffFlag;
}
#endif
@@ -22,21 +22,35 @@
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//------------------------------------------------
// The Geant4 Virtual Monte Carlo package
// Copyright (C) 2007 - 2015 Ivana Hrivnacova
// All rights reserved.
//
// For the licensing terms see geant4_vmc/LICENSE.
// Contact: root-vmc@cern.ch
//-------------------------------------------------
/// \file G4FieldBuilder.h
/// \brief Definition of the G4FieldBuilder class
///
/// \author I. Hrivnacova; IJCLab, Orsay
// G4FieldBuilder
//
// Class description:
//
// The manager class for building magnetic or other fields
// using the configuration in field parameters.
//
// Purpose: Provide a single 'place' to configure field & integration
//
// - It can configure a global field, and field(s) local to a (logical) volume
// - The parameter values can be configured by the user (else use a default)
// - They can be set/changed via a messenger provided or in the code
// of the user detector construciton
// - It retains ownership of the following object(s):
// field parameters and field setups, field
//
// Note MT: an object of the builder class should be created on master only
// (in DetectorConstruction constructor)
// The functions SetGlobal/LocalField and ConstructFieldSetup should
// be called on workers (in DetectorConstruction::ConstructSDandField )
//
// This design/implementation covers the most common use cases.
// It cannot be used to create some complex setups such as
// - equations templated on the field type,
// - steppers/drivers templated on the equation and field types.
// Author: Ivana Hrivnacova (IJCLab, Orsay), 2024.
// --------------------------------------------------------------------
#ifndef G4FIELDBUILDER_HH
#define G4FIELDBUILDER_HH
@@ -46,187 +60,212 @@
#include <vector>
class G4Field;
class G4FieldBuilderMessenger;
class G4FieldSetup;
class G4LogicalVolume;
class G4EquationOfMotion;
class G4MagIntegratorStepper;
/// \brief The manger class for building magnetic or other field
/// using the configuration in field parameters.
///
/// Purpose: Provide a single 'place' to configure field & integration
///
/// - It can configure a global field, and field(s) local to a (logical) volume
/// - The parameter values can be configured by the user (else use a default)
/// - They can be set/changed via a messenger provided or in the code
/// of the user detector construciton
/// - It retains ownership of the following object(s):
/// field parameters and field setups, field
///
/// Note MT: an object of the builder class should be created on master only
/// (in DetectorConstruction constructor)
/// The functions SetGlobal/LocalField and ConstructFieldSetup should
/// be called on workers (in DetectorConstruction::ConstructSDandField )
///
/// This design/implementation covers the most common use cases.
/// It cannot be used to create some complex setups such as
/// - equations templated on the field type,
/// - steppers/drivers templated on the equation and field types.
///
/// \author I. Hrivnacova; IJCLab, Orsay
/**
* @brief G4FieldBuilder is a singleton manager class for building magnetic
* or other fields, using the configuration in G4FieldParameters.
*/
class G4FieldBuilder
{
public:
/// Destructor
~G4FieldBuilder();
public:
// Static access method
//
/**
* Destructor. Deletes associated messenger.
*/
~G4FieldBuilder();
/// Create the class instance, if it does not exist,
/// and return it on the next calls.
static G4FieldBuilder* Instance();
/**
* Copy constructor and assignment operator not allowed.
*/
G4FieldBuilder(const G4FieldBuilder& right) = delete;
G4FieldBuilder& operator=(const G4FieldBuilder& right) = delete;
/// Return the information if an instance exists
static G4bool IsInstance();
// Static access methods
// Functions for constructing field setup
//
/**
* Creates the class instance, if it does not exist; simply returns it
* on the next calls.
* @returns A pointer to the singleton instance.
*/
static G4FieldBuilder* Instance();
/// Create local magnetic field parameters (configuration) which can be then
/// configured by the user via UI commands.
/// The parameters are used in geometry only if a local magnetic field is
/// associated with the volumes with the given name
G4FieldParameters* CreateFieldParameters(const G4String& fieldVolName);
/**
* Tells if the singleton instance exists.
* @returns true if the singleton instance exists.
*/
static G4bool IsInstance();
/// Construct setups for all registered fields.
void ConstructFieldSetup();
// Functions for constructing field setup
/// Update magnetic field.
/// This function must be called if the field parameters were changed
/// in other than PreInit> phase.
void UpdateField();
/**
* Creates the local magnetic field parameters (configuration) which can
* be then configured by the user via UI commands.
* The parameters are used in geometry only if a local magnetic field is
* associated with the volumes with the given name.
* @param[in] fieldVolName Volume name.
* @returns A pointer to the field parameters.
*/
G4FieldParameters* CreateFieldParameters(const G4String& fieldVolName);
/// Reinitialize if geometry has been modified.
/// This function is called by G4RunManager during ReinitializeGeometry()
void Reinitialize();
/**
* Constructs the setup for all registered fields.
*/
void ConstructFieldSetup();
// Set methods
//
/**
* Updates the magnetic field. It must be called if the field parameters
* were changed in other than PreInit> phase.
*/
void UpdateField();
/// Default field type is set to kMagnetic;
/// this function should be called for other than magnetic field
/// in order to update the default equation and stepper types.
void SetFieldType(G4FieldType fieldType);
/**
* Reinitialises if geometry has been modified. This method is called
* by G4RunManager during ReinitializeGeometry().
*/
void Reinitialize();
// Set or reset the global field.
// Update field objects, if the field was already constructed.
// If warn, issue a warning if the previous field is deleted.
void SetGlobalField(G4Field* field, G4bool warn = false);
// Set methods
/// Register the local field in the map.
/// Update field objects, if the field was already constructed.
/// If warn, issue a warning if the previous field is deleted.
/// The field is propagated to all volume daughters regardless
/// if they have already assigned a field manager or not.
/// When multiple local fields are defined (by calling this function
/// multiple times), they will be applied in the order they were set.
void SetLocalField(G4Field* field, G4LogicalVolume* lv, G4bool warn = false);
/**
* The default field type is set to "kMagnetic". This method should be
* called for other than magnetic field, in order to update the default
* equation and stepper types.
* @param[in] fieldType The field type-ID.
*/
void SetFieldType(G4FieldType fieldType);
/// Set user equation of motion
void SetUserEquationOfMotion(
G4EquationOfMotion* equation, G4String volumeName = "");
/**
* Sets or resets the global field. It updates the field objects,
* if the field was already constructed.
* @param[in] field Pointer to the global field.
* @param[in] warn If flag is true, issues a warning if the previous
* field is deleted.
*/
void SetGlobalField(G4Field* field, G4bool warn=false);
/// Set user stepper
void SetUserStepper(
G4MagIntegratorStepper* stepper, G4String volumeName = "");
/**
* Registers the local field in the map. It updates the field objects,
* if the field was already constructed.
* The field is propagated to all volume daughters regardless if they
* have already assigned a field manager or not.
* When multiple local fields are defined (by calling this method multiple
* times), they will be applied in the order they were set.
* @param[in] field Pointer to the global field.
* @param[in] lv Pointer to the logical volume.
* @param[in] warn If flag is true, issues a warning if the previous
* field is deleted.
*/
void SetLocalField(G4Field* field, G4LogicalVolume* lv, G4bool warn=false);
/// Set verbose level
void SetVerboseLevel(G4int value);
/**
* Sets the user equation of motion.
* @param[in] equation Pointer to the equation of motion algorithm.
* @param[in] volumeName Optional volume name.
*/
void SetUserEquationOfMotion(G4EquationOfMotion* equation,
const G4String& volumeName = "");
// Get methods
//
/**
* Sets the user stepper.
* @param[in] stepper Pointer to the stepper algorithm.
* @param[in] volumeName Optional volume name.
*/
void SetUserStepper(G4MagIntegratorStepper* stepper,
const G4String& volumeName = "");
/// Get field parameters with the given volumeName.
/// Return global field parameters, if volume name is empty.
G4FieldParameters* GetFieldParameters(const G4String& volumeName = "") const;
/**
* Sets the verbosity level.
*/
void SetVerboseLevel(G4int value);
private:
/// Default constructor
G4FieldBuilder();
/// Not implemented
G4FieldBuilder(const G4FieldBuilder& right) = delete;
/// Not implemented
G4FieldBuilder& operator=(const G4FieldBuilder& right) = delete;
// Get methods
// Methods
/**
* Gets a pointer to the field parameters with the given 'volumeName'.
* Return global field parameters, if volume name is empty.
*/
G4FieldParameters* GetFieldParameters(const G4String& volumeName = "") const;
/// Get field parameters with the given volumeName or create them if they
/// do not exist yet
G4FieldParameters* GetOrCreateFieldParameters(const G4String& volumeName);
private:
/// Get field setup with the given logical volume
G4FieldSetup* GetFieldSetup(G4LogicalVolume* lv);
/**
* Private constructor.
*/
G4FieldBuilder();
/// Create magnetic, electromagnetic or gravity field setup
void CreateFieldSetup(G4Field* field,
G4FieldParameters* fieldParameters, G4LogicalVolume* lv);
/**
* Gets the pointer to field parameters with the given 'volumeName'
* or creates them if they do not exist yet.
*/
G4FieldParameters* GetOrCreateFieldParameters(const G4String& volumeName);
/// Construct Geant4 global magnetic field setup
void ConstructGlobalField();
/**
* Gets the pointer to the field setup with the given logical volume.
*/
G4FieldSetup* GetFieldSetup(G4LogicalVolume* lv);
/// Construct Geant4 local magnetic field setups from the local fields map
void ConstructLocalFields();
/**
* Creates magnetic, electromagnetic or gravity field setup.
*/
void CreateFieldSetup(G4Field* field, G4FieldParameters* fieldParameters,
G4LogicalVolume* lv);
/// Update all field setups
void UpdateFieldSetups();
/**
* Constructs global magnetic field setup.
*/
void ConstructGlobalField();
// helper methods
std::vector<G4FieldSetup*>& GetFieldSetups();
std::vector<std::pair<G4LogicalVolume*, G4Field*>>& GetLocalFields();
/**
* Constructs local magnetic field setups from the local fields map.
*/
void ConstructLocalFields();
// Data members
/**
* Updates all field setups.
*/
void UpdateFieldSetups();
/// Information if an instance exists
inline static G4ThreadLocal G4bool fgIsInstance { false };
/**
* Helper methods.
*/
inline std::vector<G4FieldSetup*>& GetFieldSetups();
inline std::vector<std::pair<G4LogicalVolume*, G4Field*>>& GetLocalFields();
/// Messenger for this class
G4FieldBuilderMessenger* fMessenger = nullptr;
private: // Data members
/// Field parameters
std::vector<G4FieldParameters*> fFieldParameters;
/** Information if an instance exists. */
inline static G4ThreadLocal G4bool fgIsInstance { false };
/// Field setups
G4Cache<std::vector<G4FieldSetup*>*> fFieldSetups;
/** Messenger for this class. */
G4FieldBuilderMessenger* fMessenger = nullptr;
/// Registered global field
static G4ThreadLocal G4Field* fGlobalField;
/** Field parameters. */
std::vector<G4FieldParameters*> fFieldParameters;
/// Registered local fields
G4Cache<std::vector<std::pair<G4LogicalVolume*, G4Field*>>*> fLocalFields;
/** Field setups. */
G4Cache<std::vector<G4FieldSetup*>*> fFieldSetups;
/// info if field objects were constructed
static G4ThreadLocal G4bool fIsConstructed;
/** Registered global field. */
static G4ThreadLocal G4Field* fGlobalField;
/// verbose level
G4int fVerboseLevel = 1;
/** Registered local fields. */
G4Cache<std::vector<std::pair<G4LogicalVolume*, G4Field*>>*> fLocalFields;
/** Info if field objects were constructed. */
static G4ThreadLocal G4bool fIsConstructed;
/** Verbose level. */
G4int fVerboseLevel = 1;
};
// inline methods
inline G4bool G4FieldBuilder::IsInstance()
{
// Return the information if an instance exists
return fgIsInstance;
}
inline void G4FieldBuilder::SetVerboseLevel(G4int value)
{
// Set verbose level
fVerboseLevel = value;
}
// Inline methods -------------------------------------------------------------
inline std::vector<G4FieldSetup*>& G4FieldBuilder::GetFieldSetups()
{
@@ -240,4 +279,4 @@ inline std::vector<std::pair<G4LogicalVolume*, G4Field*>>& G4FieldBuilder::GetLo
return *fLocalFields.Get();
}
#endif // G4FIELDBUILDER_HH
#endif
@@ -22,12 +22,15 @@
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// G4FieldBuilderMessenger
//
// Class description:
//
// Messenger class that defines commands for G4FieldBuilder.
/// \file G4FieldBuilderMessenger.h
/// \brief Definition of the G4FieldBuilderMessenger class
///
/// \author I. Hrivnacova; IJCLab, Orsay
// Author: Ivana Hrivnacova (IJCLab, Orsay), 2024
// --------------------------------------------------------------------
#ifndef G4FIELDBUILDERMESSENGER_HH
#define G4FIELDBUILDERMESSENGER_HH
@@ -41,44 +44,45 @@ class G4UIdirectory;
class G4UIcmdWithoutParameter;
class G4UIcmdWithAnInteger;
/// \ingroup geometry
/// \brief Messenger class that defines commands for G4FieldBuilder
///
/// Implements commands:
/// - /field/verboseLevel level
///
/// \author I. Hrivnacova; IJCLab, Orsay
/**
* @brief G4FieldBuilderMessenger is messenger class that defines
* commands for G4FieldBuilder.
*/
class G4FieldBuilderMessenger : public G4UImessenger
{
public:
/// Standard constructor
G4FieldBuilderMessenger(G4FieldBuilder* fieldBuilder);
/// Destructor
~G4FieldBuilderMessenger() override;
public:
// methods
/// Apply command to the associated object.
void SetNewValue(G4UIcommand* command, G4String newValues) override;
/**
* Standard Constructor and Destructor.
*/
G4FieldBuilderMessenger(G4FieldBuilder* fieldBuilder);
~G4FieldBuilderMessenger() override;
private:
/// Not implemented
G4FieldBuilderMessenger() = delete;
/// Not implemented
G4FieldBuilderMessenger(const G4FieldBuilderMessenger& right) = delete;
/// Not implemented
G4FieldBuilderMessenger& operator=(
const G4FieldBuilderMessenger& right) = delete;
/**
* Default constructor, copy constructor and assignment operator not allowed.
*/
G4FieldBuilderMessenger() = delete;
G4FieldBuilderMessenger(const G4FieldBuilderMessenger&) = delete;
G4FieldBuilderMessenger& operator=(const G4FieldBuilderMessenger&) = delete;
// \data members
G4FieldBuilder* fFieldBuilder = nullptr; ///< associated class
G4UIdirectory* fDirectory = nullptr; ///< command directory
/**
* Applies command to the associated object.
*/
void SetNewValue(G4UIcommand* command, G4String newValues) override;
//
// commands data members
private:
/// command: fieldType
G4UIcmdWithAnInteger* fVerboseLevelCmd = nullptr;
/** Associated class object. */
G4FieldBuilder* fFieldBuilder = nullptr;
/** Associated commands directory. */
G4UIdirectory* fDirectory = nullptr;
// Commands data members
/** Command: fieldType. */
G4UIcmdWithAnInteger* fVerboseLevelCmd = nullptr;
};
#endif // G4FIELDBUILDERMESSENGER_HH
#endif
@@ -50,8 +50,8 @@
// exists and what that object is.
//
// The Chord Finder must be created either by calling CreateChordFinder
// for a Magnetic Field or by the user creating a a Chord Finder object
// "manually" and setting this pointer.
// for a Magnetic Field or by the user creating a Chord Finder object
// "manually" and setting the pointer.
//
// A default FieldManager is created by the singleton class
// G4NavigatorForTracking and exists before main is called.
@@ -69,11 +69,12 @@
// Similarly it could be extended to treat other fields as additional
// components of a single field type.
// Author: John Apostolakis, 10.03.97 - design and implementation
// Author: John Apostolakis (CERN), 10.03.1997 - Design and implementation
// -------------------------------------------------------------------
#ifndef G4FIELDMANAGER_HH
#define G4FIELDMANAGER_HH 1
#define G4FIELDMANAGER_HH
#include "G4FieldParameters.hh"
#include "globals.hh"
class G4Field;
@@ -81,165 +82,243 @@ class G4MagneticField;
class G4ChordFinder;
class G4Track; // Forward reference for parameter configuration
/**
* @brief G4FieldManager is a manager (store) for a pointer to the Field
* subclass that describes the field of a detector (magnetic, electric or
* other). It also stores a reference to the chord finder.
* A field manager can be set to a logical volume (or to more than one),
* in order to vary its field from that of the world volume. In this manner
* a zero or constant field can override a global field, a more or less exact
* version can override the external approximation, lower or higher precision
* for tracking can be specified, a different stepper can be chosen for
* different volumes, etc...
* The Chord Finder must be created either by calling CreateChordFinder()
* for a Magnetic Field or by the user creating a Chord Finder object
* "manually" and setting the pointer.
* The current design envisions that one Field manager is valid for each
* detector region. It is expected that a particular geometrical region has
* a Field manager. By default a Field Manager is created for the world volume,
* and will be utilised for all volumes unless it is overridden by a 'local'
* field manager.
* Note also that a region with both electric E and magnetic B field will
* have these treated as one field. Similarly it could be extended to treat
* other fields as additional components of a single field type.
*/
class G4FieldManager
{
public: // with description
public:
/**
* General Constructor for any field. Must be set with field and chord finder
* for use.
* @param[in] detectorField Pointer to the field.
* @param[in] pChordFinder Pointer to the chord finder object.
* @param[in] b Flag to indicate if the field changes the energy; it is
* taken from the provided field, if specified.
*/
G4FieldManager(G4Field* detectorField = nullptr,
G4ChordFinder* pChordFinder = nullptr,
G4bool b = true ); // fieldChangesEnergy is taken from field
// General constructor for any field.
// -> Must be set with field and chordfinder for use.
G4FieldManager(G4MagneticField* detectorMagneticField);
// Creates ChordFinder
// -> Assumes pure magnetic field (so energy constant)
/**
* Constructor creating the chord finder. It assumes pure magnetic field,
* so energy constant.
* @param[in] detectorMagneticField Pointer to the magnetic field.
*/
G4FieldManager(G4MagneticField* detectorMagneticField);
/**
* Virtual Destructor.
*/
virtual ~G4FieldManager();
/**
* Copy constructor and assignment operator not allowed.
*/
G4FieldManager(const G4FieldManager&) = delete;
G4FieldManager& operator=(const G4FieldManager&) = delete;
/**
* Pushes the field to the equation. Failure to push the field (due to
* absence of a chord finder, driver, stepper or equation) is
* - '0' = quiet : Do not complain if chordFinder == 0
* (It will still warn for other error);
* - '1' = warn : a warning if anything is missing;
* - '2'/else = FATAL : a fatal error for all other values.
* @param[in] detectorField Pointer to the field.
* @param[in] failMode Flag (0/1/2) for selected failure mode.
* @returns Success (true) or failure (false).
*/
G4bool SetDetectorField(G4Field* detectorField, G4int failMode = 0);
// Pushes the field to the equation.
// Failure to push the field (due to absence of a chord finder, driver,
// stepper or equation) is
// - '0' = quiet : Do not complain if chordFinder == 0
// (It will still warn for other error.)
// - '1' = warn : a warning if anything is missing
// - '2'/else = FATAL : a fatal error for all other values.
// Returns success (true) or failure (false)
/**
* Pushes the field to this class only -- no further.
* Should be used to initialise this field, only *before* creating
* the chord finder and its dependent classes.
* User is then responsible to ensure that:
* i) an equation, stepper, driver and chord finder are created;
* ii) this field is used by the equation.
* @param[in] detectorField Pointer to the field.
*/
inline void ProposeDetectorField(G4Field* detectorField);
// Pushes the field to this class only -- no further.
// Should be used to initialise this field, only *before* creating
// the chord finder and its dependent classes.
// User is then responsible to ensure that:
// i) an equation, stepper, driver and chord finder are created
// ii) this field is used by the equation.
inline void ChangeDetectorField(G4Field* detectorField);
// Pushes the field to the equation ( & keeps its address )
// Can be used only once the equation, stepper, driver and chord finder
// have all been created. Else it is an error.
/**
* Pushes the field to the equation and keeps its address.
* Can be used only once the equation, stepper, driver and chord finder
* have all been created; else it is an error.
* @param[in] detectorField Pointer to the field.
*/
inline void ChangeDetectorField(G4Field* detectorField);
inline const G4Field* GetDetectorField() const;
inline G4bool DoesFieldExist() const;
// Set, get and check the field object
/**
* Methods to get and check (existance of) the field object.
*/
inline const G4Field* GetDetectorField() const;
inline G4bool DoesFieldExist() const;
/**
* Methods to create, set or get the associated Chord Finder.
*/
void CreateChordFinder(G4MagneticField* detectorMagField);
inline void SetChordFinder(G4ChordFinder* aChordFinder);
inline G4ChordFinder* GetChordFinder();
inline const G4ChordFinder* GetChordFinder() const;
// Create, set or get the associated Chord Finder
virtual void ConfigureForTrack( const G4Track * );
// Setup the choice of the configurable parameters
// relying on the current track's energy, particle identity, ..
// Note: in addition to the values of member variables,
// a user can use this to change the ChordFinder, the field, ...
/**
* Setups the choice of the configurable parameters, relying on the
* current track's energy, particle identity...
* Note: in addition to the values of member variables, a user can use
* this to change the ChordFinder, the field, etc.
* @param[in] pTrack Pointer to a track.
*/
virtual void ConfigureForTrack( const G4Track* pTrack );
// static functions to handle global field
/**
* Static methods to set/get the global field.
*/
static void SetGlobalFieldManager(G4FieldManager* fieldManager);
static G4FieldManager* GetGlobalFieldManager();
public: // with description
/**
* Returns the accuracy for boundary intersection.
*/
inline G4double GetDeltaIntersection() const;
// Accuracy for boundary intersection.
/**
* Returns the accuracy for one tracking/physics step.
*/
inline G4double GetDeltaOneStep() const;
// Accuracy for one tracking/physics step.
/**
* Sets both accuracies, maintaining a fixed ratio for accuracies
* of volume Intersection and Integration (in One Step).
*/
inline void SetAccuraciesWithDeltaOneStep(G4double valDeltaOneStep);
// Sets both accuracies, maintaining a fixed ratio for accuracies
// of volume Intersection and Integration (in One Step)
inline void SetDeltaOneStep(G4double valueD1step);
// Set accuracy for integration of one step. (only)
/**
* Sets the accuracy for integration of one step (only).
*/
inline void SetDeltaOneStep(G4double valueD1step);
/**
* Sets the accuracy of intersection of a volume (only).
*/
inline void SetDeltaIntersection(G4double valueDintersection);
// Set accuracy of intersection of a volume. (only)
inline G4double GetMinimumEpsilonStep() const;
G4bool SetMinimumEpsilonStep( G4double newEpsMin );
// Minimum for Relative accuracy of a Step
/**
* Methods to set/get the minimum for Relative accuracy of a Step.
*/
inline G4double GetMinimumEpsilonStep() const;
G4bool SetMinimumEpsilonStep( G4double newEpsMin );
inline G4double GetMaximumEpsilonStep() const;
G4bool SetMaximumEpsilonStep( G4double newEpsMax );
// Maximum for Relative accuracy of a Step
/**
* Methods to set/get the maximum for Relative accuracy of a Step.
*/
inline G4double GetMaximumEpsilonStep() const;
G4bool SetMaximumEpsilonStep( G4double newEpsMax );
inline G4bool DoesFieldChangeEnergy() const;
inline void SetFieldChangesEnergy(G4bool value);
// For electric field this should be true
// For magnetic field this should be false
/**
* Methods to set/get flag for field changing energy.
* For electric field this should be true; for magnetic field this
* should be false.
*/
inline G4bool DoesFieldChangeEnergy() const;
inline void SetFieldChangesEnergy(G4bool value);
/**
* Needed for multi-threading, create and returns an allocated clone
* of this object.
*/
virtual G4FieldManager* Clone() const;
// Needed for multi-threading, create a clone of this object
public:
/**
* Static methods to set/get the maximum accepted epsilon.
* If setting fails, with softFail=true it gives Warning, else
* a FatalException.
*/
static G4double GetMaxAcceptedEpsilon();
static G4bool SetMaxAcceptedEpsilon(G4double maxEps, G4bool softFail= false);
// Set value -- within limits.
// If it fails, with softFail=true it gives Warning, else FatalException
static G4bool SetMaxAcceptedEpsilon(G4double maxEps, G4bool softFail= false);
protected:
/**
* Logger for reporting on correctness of the proposed epsilon value.
*/
void ReportBadEpsilonValue(G4ExceptionDescription& erm, G4double value,
const G4String& name) const;
/** Epsilon_min/max values must be smaller than this for robust integration. */
static G4double fMaxAcceptedEpsilon;
static constexpr G4double fMinAcceptedEpsilon= 1000.0 * std::numeric_limits<G4double>::epsilon();
// Epsilon_min/max values must be smaller than this - for robust integration
static constexpr G4double fMinAcceptedEpsilon = 1000.0 * std::numeric_limits<G4double>::epsilon();
static constexpr G4double fMaxWarningEpsilon= 0.001; // Setting larger value will give warning.
static constexpr G4double fMaxFinalEpsilon= 0.02; // Will not accept larger values
/** Setting larger value will give warning. */
static constexpr G4double fMaxWarningEpsilon = 0.001;
/** Will not accept larger values. */
static constexpr G4double fMaxFinalEpsilon = 0.02;
static G4bool fVerboseConstruction;
// Control verbosity of constructors
/** Controls verbosity of constructors. */
static G4bool fVerboseConstruction;
private:
/**
* Checks whether the field/equation changes the energy and sets the data
* member accordingly. Does not handle special cases - this must be done
* separately (e.g. magnetic monopole in B field).
*/
void InitialiseFieldChangesEnergy();
// Check whether field/equation change the energy,
// and sets the data member accordingly
// Note: does not handle special cases - this must be done
// separately (e.g. magnetic monopole in B field )
protected:
void ReportBadEpsilonValue(G4ExceptionDescription& erm, G4double value,
G4String& name) const;
private:
/** Dependent objects -- with state that depends on tracking. */
G4Field* fDetectorField = nullptr;
G4ChordFinder* fChordFinder = nullptr;
// Dependent objects -- with state that depends on tracking
G4bool fAllocatedChordFinder = false; // Did we used "new" to
// create fChordFinder ?
// INVARIANTS of tracking ---------------------------------------
//
// 1. 'CONSTANTS' - default values for accuracy parameters
//
const G4double fEpsilonMinDefault= 5.0e-5; // Expected: 5.0e-5 to 1.0e-10 ...
const G4double fEpsilonMaxDefault= 1.0e-3; // Expected: 1.0e-3 to 1.0e-8 ...
/** Flag to indicate if "new" was used to create the Chord Finder. */
G4bool fAllocatedChordFinder = false; //
static G4double fDefault_Delta_One_Step_Value; // = 0.01 * millimeter;
static G4double fDefault_Delta_Intersection_Val; // = 0.001 * millimeter;
// Default values for accuracy parameters
// 1. CHARACTERISTIC of field
// 2. CHARACTERISTIC of field
//
G4bool fFieldChangesEnergy = false;
// 3. PARAMETERS that determine the accuracy of integration or intersection
//
G4double fDelta_One_Step_Value; // for one tracking/physics step
G4double fDelta_Intersection_Val; // for boundary intersection
// Values for the required accuracies
// 2. PARAMETERS that determine the accuracy of integration or intersection
G4double fEpsilonMin;
G4double fEpsilonMax;
// Values for the small possible relative accuracy of a step
// (corresponding to the greatest possible integration accuracy)
/** Value for the required accuracies for one tracking/physics step. */
G4double fDelta_One_Step_Value = G4FieldDefaults::kDeltaOneStep;
/** Value for the required accuracies for boundary intersection. */
G4double fDelta_Intersection_Val = G4FieldDefaults::kDeltaIntersection;
/** Values for the small possible relative accuracy of a step
(corresponding to the greatest possible integration accuracy). */
G4double fEpsilonMin = G4FieldDefaults::kMinimumEpsilonStep;
G4double fEpsilonMax = G4FieldDefaults::kMaximumEpsilonStep;
/** Global field manager set by G4TransportationManager to allow accessing
the global field without dependency on navigation. */
static G4ThreadLocal G4FieldManager* fGlobalFieldManager;
// Global field manager set by G4TransportationManager
// to allow accessing the global field without dependency
// on navigation
};
// Implementation of inline functions
@@ -25,7 +25,7 @@
//
// G4FieldManager inline implementation
//
// Author: John Apostolakis, 10.03.97 - design and implementation
// Author: John Apostolakis (CERN), 10.03.1997 - Design and implementation
// -------------------------------------------------------------------
inline
@@ -37,7 +37,7 @@
// Intended principally to enable resetting of 'state' at start of event.
// The underlying container initially has a capacity of 100.
// Author: J.Apostolakis, 07.12.2007 - Initial version
// Author: John Apostolakis (CERN), 07.12.2007 - Initial version
// --------------------------------------------------------------------
#ifndef G4FIELDMANAGERSTORE_HH
#define G4FIELDMANAGERSTORE_HH
@@ -46,29 +46,55 @@
#include "G4FieldManager.hh"
/**
* @brief G4FieldManagerStore is a container for all field managers, with
* functionality derived from std::vector<T>. The class is a singleton.
* All field managers should be registered with G4FieldManagerStore,
* and removed on their destruction. Intended principally to enable resetting
* of 'state' at start of an event.
*/
class G4FieldManagerStore : public std::vector<G4FieldManager*>
{
public: // with description
public:
static void Register(G4FieldManager* pVolume);
// Add the logical volume to the collection.
static void DeRegister(G4FieldManager* pVolume);
// Remove the logical volume from the collection.
/**
* Gets a pointer to the unique G4FieldManagerStore, creating it if
* necessary.
*/
static G4FieldManagerStore* GetInstance();
// Get a ptr to the unique G4FieldManagerStore, creating it if necessary.
static G4FieldManagerStore* GetInstanceIfExist();
// Get a ptr to the unique G4FieldManagerStore.
/**
* Adds the field manager to the collection.
*/
static void Register(G4FieldManager* pFieldMan);
/**
* Removes the field manager from the collection.
*/
static void DeRegister(G4FieldManager* pFieldMan);
/**
* Deletes all managers from the store.
*/
static void Clean();
// Delete all volumes from the store.
/**
* Loops over all field managers and calls each one to reset step estimate.
*/
void ClearAllChordFindersState();
// Looping over all field managers, call each one to reset step estimate
/**
* Destructor: takes care to delete the allocated field managers.
*/
~G4FieldManagerStore();
// Destructor: takes care to delete allocated field managers.
protected:
private:
/**
* Private constructor.
*/
G4FieldManagerStore();
private:
@@ -22,39 +22,47 @@
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// G4FieldParameters
//
// Class description:
//
// The class defines the type of equation of motion of a particle
// in a field and the integration method, as well as other accuracy
// parameters.
//
// The default values correspond to the defaults set in Geant4.
/// \file G4FieldParameters.hh
/// \brief Definition of the G4FieldParameters class
///
/// This code was initially developed in Geant4 VMC package
/// (https://github.com/vmc-project)
/// and adapted to Geant4.
///
/// \author I. Hrivnacova; IJCLab, Orsay
// Author: Ivana Hrivnacova (IJCLab, Orsay), 2024.
// -------------------------------------------------------------------
#ifndef G4FIELDPARAMETERS_HH
#define G4FIELDPARAMETERS_HH
#include "G4MagneticField.hh"
#include "globals.hh"
#include <CLHEP/Units/SystemOfUnits.h>
class G4FieldParametersMessenger;
class G4EquationOfMotion;
class G4MagIntegratorStepper;
/// The available fields in Geant4
/**
* @brief G4FieldType defines the available fields in Geant4.
*/
enum G4FieldType
{
kMagnetic, ///< magnetic field
kElectroMagnetic, ///< electromagnetic field
kGravity ///< gravity field
kMagnetic, ///< magnetic field
kElectroMagnetic, ///< electromagnetic field
kGravity, ///< gravity field
kUserFieldType ///< User defined field type
};
/// The available equations of motion of a particle in a field
/// in Geant4
/**
* @brief G4EquationType defines the types of equations of motion of a
* particle in a field in Geant4.
*/
enum G4EquationType
{
kEqMagnetic, ///< G4Mag_UsualEqRhs: the standard right-hand side for
@@ -70,11 +78,22 @@ enum G4EquationType
kEqEMfieldWithEDM, ///< G4EqEMFieldWithEDM: Equation of motion in a combined
///< electric and magnetic field, with spin tracking for
///< both MDM and EDM terms
kEqGravity, ///< G4EqGravityField: equation of motion in a gravity field
/// (not build by G4FieldBuilder)
kEqMonopole, ///< G4MonopoleEq: the right-hand side of equation of motion for monopole
/// in a combined electric and magnetic field
/// (not build by G4FieldBuilder)
kEqReplate, ///< G4RepleteEofM: equation of motion in a combined field, including:
/// magnetic, electric, gravity, and gradient B field, as well as spin tracking
/// (not build by G4FieldBuilder)
kUserEquation ///< User defined equation of motion
};
/// The available integrator of particle's equation of motion
/// in Geant4
/**
* @brief G4StepperType defines the available integrator of particle's
* equation of motion in Geant4.
*/
enum G4StepperType
{
// steppers with equation of motion of generic type (G4EquationOfMotion)
@@ -82,6 +101,7 @@ enum G4StepperType
kClassicalRK4, ///< G4ClassicalRK4
kBogackiShampine23, ///< G4BogackiShampine23
kBogackiShampine45, ///< G4BogackiShampine45
kDoLoMcPriRK34, ///< G4DoLoMcPriRK34
kDormandPrince745, ///< G4DormandPrince745
kDormandPrinceRK56, ///< G4DormandPrinceRK56
kDormandPrinceRK78, ///< G4DormandPrinceRK78
@@ -104,310 +124,281 @@ enum G4StepperType
kUserStepper, ///< User defined stepper
// FSAL steppers
kRK547FEq1, ///< G4RK547FEq1
kRK547FEq2, ///< G4RK547FEq2
kRK547FEq3 ///< G4RK547FEq3
kRK547FEq1, ///< G4RK547FEq1
kRK547FEq2, ///< G4RK547FEq2
kRK547FEq3, ///< G4RK547FEq3
// Templated steppers (not build by G4FieldBuilder)
kTCashKarpRKF45, ///< G4TCashKarpRKF45
kTDormandPrince45, ///< G4TDormandPrince45
kTMagErrorStepper, ///< G4TMagErrorStepper
kQSStepper ///< G4QSStepper
};
/// \brief The magnetic field parameters
///
/// The class defines the type of equation of motion of a particle
/// in a field and the integration method, as well as other accuracy
/// parameters.
///
/// The default values correspond to the defaults set in Geant4
/// (taken from Geant4 9.3 release.)
/// As Geant4 classes to not provide access methods for these defaults,
/// the defaults have to be checked with each new Geant4 release.
///
/// \author I. Hrivnacova; IJCLab, Orsay
/**
* @brief G4FieldDefaults defines the magnetic field parameters defaults.
* The namespace defines the default values of the field paraments as constexpr
* so that they can be used also as the default values in the magnetic field
* classes constructors and other member functions.
*/
namespace G4FieldDefaults
{
/// Default minimum step in G4ChordFinder
constexpr G4double kMinimumStep = 0.01 * CLHEP::mm;
/// Default delta chord in G4ChordFinder
constexpr G4double kDeltaChord = 0.25 * CLHEP::mm;
/// Default delta one step in global field manager
constexpr G4double kDeltaOneStep = 0.01 * CLHEP::mm;
/// Delta intersection in global field manager
constexpr G4double kDeltaIntersection = 0.001 * CLHEP::mm;
/// Default minimum epsilon step in global field manager
constexpr G4double kMinimumEpsilonStep = 5.0e-5; // Expected: 5.0e-5 to 1.0e-10 ...
/// Default maximum epsilon step in global field manager
constexpr G4double kMaximumEpsilonStep = 0.001; // Expected: 1.0e-3 to 1.0e-8 ...
}
/**
* @brief G4FieldParameters defines the type of equation of motion of a
* particle in a field and the integration method, as well as other accuracy
* parameters. The default values correspond to the defaults set in Geant4.
*/
class G4FieldParameters
{
public:
/// Standard and default constructor
G4FieldParameters(const G4String& volumeName = "");
/// Destructor
~G4FieldParameters();
public:
// Methods
//
/**
* Constructor for G4FieldParameters.
* @param[in] volumeName The volume name where field is applied.
*/
G4FieldParameters(const G4String& volumeName = "");
/// Return the field type as a string
static G4String FieldTypeName(G4FieldType field);
/// Return the equation type as a string
static G4String EquationTypeName(G4EquationType equation);
/// Return the stepper type as a string
static G4String StepperTypeName(G4StepperType stepper);
/// Return the field type for given field type name
static G4FieldType GetFieldType(const G4String& name);
/// Return the equation type for given equation type name
static G4EquationType GetEquationType(const G4String& name);
/// Return the stepper type for given stepper type name
static G4StepperType GetStepperType(const G4String& name);
/**
* Destructor.
*/
~G4FieldParameters();
/// Prints all customizable accuracy parameters
void PrintParameters() const;
/**
* Copy constructor and assignment operator not allowed.
*/
G4FieldParameters(const G4FieldParameters& right) = delete;
G4FieldParameters& operator=(const G4FieldParameters& right) = delete;
// Set methods
//
/**
* Returns the field type as a string.
*/
static G4String FieldTypeName(G4FieldType field);
/// Set type of field
void SetFieldType(G4FieldType field);
/// Set Type of equation of motion of a particle in a field
void SetEquationType(G4EquationType equation);
/// Type of integrator of particle's equation of motion
void SetStepperType(G4StepperType stepper);
/// Set user defined equation of motion
void SetUserEquationOfMotion(G4EquationOfMotion* equation);
/// Set user defined integrator of particle's equation of motion
void SetUserStepper(G4MagIntegratorStepper* stepper);
/**
* Returns the equation type as a string.
*/
static G4String EquationTypeName(G4EquationType equation);
/// Set minimum step in G4ChordFinder
void SetMinimumStep(G4double value);
/// Set delta chord in G4ChordFinder
void SetDeltaChord(G4double value);
/// Set delta one step in global field manager
void SetDeltaOneStep(G4double value);
/// Set delta intersection in global field manager
void SetDeltaIntersection(G4double value);
/// Set minimum epsilon step in global field manager
void SetMinimumEpsilonStep(G4double value);
/// Set maximum epsilon step in global field manager
void SetMaximumEpsilonStep(G4double value);
/// Set the distance within which the field is considered constant
void SetConstDistance(G4double value);
/**
* Returns the stepper type as a string.
*/
static G4String StepperTypeName(G4StepperType stepper);
// Get methods
//
/**
* Returns the field type for given field type name.
*/
static G4FieldType GetFieldType(const G4String& name);
// Get the name of associated volume, if local field
G4String GetVolumeName() const;
/**
* Returns the equation type for given equation type name.
*/
static G4EquationType GetEquationType(const G4String& name);
/// Get type of field
G4FieldType GetFieldType() const;
/// Get type of equation of motion of a particle in a field
G4EquationType GetEquationType() const;
/// Get rype of integrator of particle's equation of motion
G4StepperType GetStepperType() const;
/// Get user defined equation of motion
G4EquationOfMotion* GetUserEquationOfMotion() const;
/// Get user defined integrator of particle's equation of motion
G4MagIntegratorStepper* GetUserStepper() const;
/**
* Returns the stepper type for given stepper type name.
*/
static G4StepperType GetStepperType(const G4String& name);
/// Get minimum step in G4ChordFinder
G4double GetMinimumStep() const;
/// Get delta chord in G4ChordFinder
G4double GetDeltaChord() const;
/// Get delta one step in global field manager
G4double GetDeltaOneStep() const;
/// Get delta intersection in global field manager
G4double GetDeltaIntersection() const;
/// Get minimum epsilon step in global field manager
G4double GetMinimumEpsilonStep() const;
/// Get maximum epsilon step in global field manager
G4double GetMaximumEpsilonStep() const;
/// Get the distance within which the field is considered constant
G4double GetConstDistance() const;
/**
* Prints all customisable accuracy parameters.
*/
void PrintParameters() const;
private:
/// Not implemented
G4FieldParameters(const G4FieldParameters& right) = delete;
/// Not implemented
G4FieldParameters& operator=(const G4FieldParameters& right) = delete;
// Set methods ------------------------------------------------------------
// static data members
//
/// Default minimum step in G4ChordFinder
inline static const G4double fgkDefaultMinimumStep = 0.01 * CLHEP::mm;
/// Default delta chord in G4ChordFinder
inline static const G4double fgkDefaultDeltaChord = 0.25 * CLHEP::mm;
/// Default delta one step in global field manager
inline static const G4double fgkDefaultDeltaOneStep = 0.01 * CLHEP::mm;
/// Delta intersection in global field manager
inline static const G4double fgkDefaultDeltaIntersection = 0.001 * CLHEP::mm;
/// Default minimum epsilon step in global field manager
inline static const G4double fgkDefaultMinimumEpsilonStep = 5.0e-5;
/// Default maximum epsilon step in global field manager
inline static const G4double fgkDefaultMaximumEpsilonStep = 0.001;
/// Default constant distance
inline static const G4double fgkDefaultConstDistance = 0.;
/**
* Sets the type of field.
*/
void SetFieldType(G4FieldType field);
// data members
//
/// Messenger for this class
G4FieldParametersMessenger* fMessenger = nullptr;
/**
* Sets the type of equation of motion of a particle in a field.
*/
void SetEquationType(G4EquationType equation);
/// The name of associated volume, if local field
G4String fVolumeName;
/**
* Sets the type of integrator of particle's equation of motion.
*/
void SetStepperType(G4StepperType stepper);
/// Minimum step in G4ChordFinder
G4double fMinimumStep = fgkDefaultMinimumStep;
/// Delta chord in G4ChordFinder
G4double fDeltaChord = fgkDefaultDeltaChord;
/// Delta one step in global field manager
G4double fDeltaOneStep = fgkDefaultDeltaOneStep;
/// Delta intersection in global field manager
G4double fDeltaIntersection = fgkDefaultDeltaIntersection;
/// Minimum epsilon step in global field manager
G4double fMinimumEpsilonStep = fgkDefaultMinimumEpsilonStep;
/// Maximum epsilon step in global field manager
G4double fMaximumEpsilonStep = fgkDefaultMaximumEpsilonStep;
/**
* Sets the user defined equation of motion.
*/
void SetUserEquationOfMotion(G4EquationOfMotion* equation);
/// Type of field
G4FieldType fField = kMagnetic;
/**
* Sets the user defined integrator of particle's equation of motion.
*/
void SetUserStepper(G4MagIntegratorStepper* stepper);
/// Type of equation of motion of a particle in a field
G4EquationType fEquation = kEqMagnetic;
/**
* Sets the minimum step in G4ChordFinder.
*/
void SetMinimumStep(G4double value);
/// Type of integrator of particle's equation of motion
G4StepperType fStepper = kDormandPrince745;
/**
* Sets the delta chord in G4ChordFinder.
*/
void SetDeltaChord(G4double value);
/// User defined equation of motion
G4EquationOfMotion* fUserEquation = nullptr;
/**
* Sets the delta one step in global field manager.
*/
void SetDeltaOneStep(G4double value);
/// User defined integrator of particle's equation of motion
G4MagIntegratorStepper* fUserStepper = nullptr;
/**
* Sets the delta intersection in global field manager.
*/
void SetDeltaIntersection(G4double value);
/// The distance within which the field is considered constant
G4double fConstDistance = fgkDefaultConstDistance;
/**
* Sets the minimum epsilon step in global field manager.
*/
void SetMinimumEpsilonStep(G4double value);
/**
* Sets the maximum epsilon step in global field manager.
*/
void SetMaximumEpsilonStep(G4double value);
/**
* Sets the distance within which the field is considered constant.
*/
void SetConstDistance(G4double value);
// Get methods ------------------------------------------------------------
/**
* Gets the name of associated volume, if local field.
*/
const G4String& GetVolumeName() const;
/**
* Gets the type of field.
*/
const G4FieldType& GetFieldType() const;
/**
* Gets the type of equation of motion of a particle in a field.
*/
const G4EquationType& GetEquationType() const;
/**
* Gets the type of integrator of particle's equation of motion.
*/
const G4StepperType& GetStepperType() const;
/**
* Gets the user defined equation of motion.
*/
G4EquationOfMotion* GetUserEquationOfMotion() const;
/**
* Gets the user defined integrator of particle's equation of motion.
*/
G4MagIntegratorStepper* GetUserStepper() const;
/**
* Gets the minimum step in G4ChordFinder.
*/
G4double GetMinimumStep() const;
/**
* Gets the delta chord in G4ChordFinder.
*/
G4double GetDeltaChord() const;
/**
* Gets the delta one step in global field manager.
*/
G4double GetDeltaOneStep() const;
/**
* Gets the delta intersection in global field manager.
*/
G4double GetDeltaIntersection() const;
/**
* Gets the minimum epsilon step in global field manager.
*/
G4double GetMinimumEpsilonStep() const;
/**
* Gets the maximum epsilon step in global field manager.
*/
G4double GetMaximumEpsilonStep() const;
/**
* Gets the distance within which the field is considered constant.
*/
G4double GetConstDistance() const;
private:
/** Default constant distance. */
inline static const G4double fgkDefaultConstDistance = 0.;
/** Messenger for this class. */
G4FieldParametersMessenger* fMessenger = nullptr;
/** The name of the associated volume, if local field. */
G4String fVolumeName;
/** The minimum step in G4ChordFinder. */
G4double fMinimumStep = G4FieldDefaults::kMinimumStep;
/** The delta chord in G4ChordFinder. */
G4double fDeltaChord = G4FieldDefaults::kDeltaChord;
/** The delta one step in global field manager. */
G4double fDeltaOneStep = G4FieldDefaults::kDeltaOneStep;
/** The delta intersection in global field manager. */
G4double fDeltaIntersection = G4FieldDefaults::kDeltaIntersection;
/** The minimum epsilon step in global field manager. */
G4double fMinimumEpsilonStep = G4FieldDefaults::kMinimumEpsilonStep;
/** The maximum epsilon step in global field manager. */
G4double fMaximumEpsilonStep = G4FieldDefaults::kMaximumEpsilonStep;
/** The type of field. */
G4FieldType fField = kMagnetic;
/** Type of equation of motion of a particle in a field. */
G4EquationType fEquation = kEqMagnetic;
/** Type of integrator of particle's equation of motion. */
G4StepperType fStepper = kDormandPrince745;
/** User defined equation of motion. */
G4EquationOfMotion* fUserEquation = nullptr;
/// User defined integrator of particle's equation of motion. */
G4MagIntegratorStepper* fUserStepper = nullptr;
/** The distance within which the field is considered constant. */
G4double fConstDistance = fgkDefaultConstDistance;
};
// inline functions
// Inline functions
// Set type of field
inline void G4FieldParameters::SetFieldType(G4FieldType field)
{
fField = field;
}
#include "G4FieldParameters.icc"
// Set the type of equation of motion of a particle in a field
inline void G4FieldParameters::SetEquationType(G4EquationType equation)
{
fEquation = equation;
}
// Set the type of integrator of particle's equation of motion
inline void G4FieldParameters::SetStepperType(G4StepperType stepper)
{
fStepper = stepper;
}
// Set minimum step in G4ChordFinder
inline void G4FieldParameters::SetMinimumStep(G4double value)
{
fMinimumStep = value;
}
// Set delta chord in G4ChordFinder
inline void G4FieldParameters::SetDeltaChord(G4double value)
{
fDeltaChord = value;
}
// Set delta one step in global field manager
inline void G4FieldParameters::SetDeltaOneStep(G4double value)
{
fDeltaOneStep = value;
}
// Set delta intersection in global field manager
inline void G4FieldParameters::SetDeltaIntersection(G4double value)
{
fDeltaIntersection = value;
}
// Set minimum epsilon step in global field manager
inline void G4FieldParameters::SetMinimumEpsilonStep(G4double value)
{
fMinimumEpsilonStep = value;
}
// Set maximum epsilon step in global field manager
inline void G4FieldParameters::SetMaximumEpsilonStep(G4double value)
{
fMaximumEpsilonStep = value;
}
// Set the distance within which the field is considered constant
inline void G4FieldParameters::SetConstDistance(G4double value)
{
fConstDistance = value;
}
// Return the name of associated volume, if local field
inline G4String G4FieldParameters::GetVolumeName() const
{
return fVolumeName;
}
// Return the type of field
inline G4FieldType G4FieldParameters::GetFieldType() const { return fField; }
// Return the type of equation of motion of a particle in a field
inline G4EquationType G4FieldParameters::GetEquationType() const
{
return fEquation;
}
// Return the type of integrator of particle's equation of motion
inline G4StepperType G4FieldParameters::GetStepperType() const
{
return fStepper;
}
// Return the user defined equation of motion
inline G4EquationOfMotion* G4FieldParameters::GetUserEquationOfMotion() const
{
return fUserEquation;
}
// Return the user defined integrator of particle's equation of motion
inline G4MagIntegratorStepper* G4FieldParameters::GetUserStepper() const
{
return fUserStepper;
}
// Return minimum step in G4ChordFinder
inline G4double G4FieldParameters::GetMinimumStep() const
{
return fMinimumStep;
}
// Return delta chord in G4ChordFinder
inline G4double G4FieldParameters::GetDeltaChord() const
{
return fDeltaChord;
}
// Return delta one step in global field manager
inline G4double G4FieldParameters::GetDeltaOneStep() const
{
return fDeltaOneStep;
}
// Return delta intersection in global field manager
inline G4double G4FieldParameters::GetDeltaIntersection() const
{
return fDeltaIntersection;
}
// Return minimum epsilon step in global field manager
inline G4double G4FieldParameters::GetMinimumEpsilonStep() const
{
return fMinimumEpsilonStep;
}
// Return maximum epsilon step in global field manager
inline G4double G4FieldParameters::GetMaximumEpsilonStep() const
{
return fMaximumEpsilonStep;
}
// Return the distance within which the field is considered constant
inline G4double G4FieldParameters::GetConstDistance() const
{
return fConstDistance;
}
#endif // G4FIELDPARAMETERS_HH
#endif
@@ -0,0 +1,167 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// G4FieldParameters inline methods implementation
//
// Author: Ivana Hrivnacova (IJCLab, Orsay), 2024.
// -------------------------------------------------------------------
// Set type of field
inline void G4FieldParameters::SetFieldType(G4FieldType field)
{
fField = field;
}
// Set the type of equation of motion of a particle in a field
inline void G4FieldParameters::SetEquationType(G4EquationType equation)
{
fEquation = equation;
}
// Set the type of integrator of particle's equation of motion
inline void G4FieldParameters::SetStepperType(G4StepperType stepper)
{
fStepper = stepper;
}
// Set minimum step in G4ChordFinder
inline void G4FieldParameters::SetMinimumStep(G4double value)
{
fMinimumStep = value;
}
// Set delta chord in G4ChordFinder
inline void G4FieldParameters::SetDeltaChord(G4double value)
{
fDeltaChord = value;
}
// Set delta one step in global field manager
inline void G4FieldParameters::SetDeltaOneStep(G4double value)
{
fDeltaOneStep = value;
}
// Set delta intersection in global field manager
inline void G4FieldParameters::SetDeltaIntersection(G4double value)
{
fDeltaIntersection = value;
}
// Set minimum epsilon step in global field manager
inline void G4FieldParameters::SetMinimumEpsilonStep(G4double value)
{
fMinimumEpsilonStep = value;
}
// Set maximum epsilon step in global field manager
inline void G4FieldParameters::SetMaximumEpsilonStep(G4double value)
{
fMaximumEpsilonStep = value;
}
// Set the distance within which the field is considered constant
inline void G4FieldParameters::SetConstDistance(G4double value)
{
fConstDistance = value;
}
// Return the name of associated volume, if local field
inline const G4String& G4FieldParameters::GetVolumeName() const
{
return fVolumeName;
}
// Return the type of field
inline const G4FieldType& G4FieldParameters::GetFieldType() const
{
return fField;
}
// Return the type of equation of motion of a particle in a field
inline const G4EquationType& G4FieldParameters::GetEquationType() const
{
return fEquation;
}
// Return the type of integrator of particle's equation of motion
inline const G4StepperType& G4FieldParameters::GetStepperType() const
{
return fStepper;
}
// Return the user defined equation of motion
inline G4EquationOfMotion* G4FieldParameters::GetUserEquationOfMotion() const
{
return fUserEquation;
}
// Return the user defined integrator of particle's equation of motion
inline G4MagIntegratorStepper* G4FieldParameters::GetUserStepper() const
{
return fUserStepper;
}
// Return minimum step in G4ChordFinder
inline G4double G4FieldParameters::GetMinimumStep() const
{
return fMinimumStep;
}
// Return delta chord in G4ChordFinder
inline G4double G4FieldParameters::GetDeltaChord() const
{
return fDeltaChord;
}
// Return delta one step in global field manager
inline G4double G4FieldParameters::GetDeltaOneStep() const
{
return fDeltaOneStep;
}
// Return delta intersection in global field manager
inline G4double G4FieldParameters::GetDeltaIntersection() const
{
return fDeltaIntersection;
}
// Return minimum epsilon step in global field manager
inline G4double G4FieldParameters::GetMinimumEpsilonStep() const
{
return fMinimumEpsilonStep;
}
// Return maximum epsilon step in global field manager
inline G4double G4FieldParameters::GetMaximumEpsilonStep() const
{
return fMaximumEpsilonStep;
}
// Return the distance within which the field is considered constant
inline G4double G4FieldParameters::GetConstDistance() const
{
return fConstDistance;
}
@@ -22,16 +22,39 @@
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// G4FieldParametersMessenger
//
// Class description:
//
// Messenger class that defines commands for field configuration.
//
// Implements commands:
// - /field/fieldType fieldType
// fieldType = Magnetic | ElectroMagnetic | Gravity
// - /field/equationType eqType
// eqType = EqMagnetic | EqMagneticWithSpin | EqElectroMagnetic |
// EqEMfieldWithSpin | EqEMfieldWithEDM
// - /field/stepperType stepperType
// stepperType = CashKarpRKF45 | ClassicalRK4 | ExplicitEuler | ImplicitEuler |
// SimpleHeum | SimpleRunge | ConstRK4 | ExactHelixStepper
// | HelixExplicitEuler | HelixHeum | HelixImplicitEuler |
// HelixMixedStepper | HelixSimpleRunge | NystromRK4 |
// RKG3Stepper
// - /field/setMinimumStep value
// - /field/setDeltaChord value
// - /field/setDeltaOneStep value
// - /field/setDeltaIntersection value
// - /field/setMinimumEpsilonStep value
// - /field/setMaximumEpsilonStep value
// - /field/setConstDistance value
// - /field/printParameters
//
// Only equation type and stepper type values that are handled by G4FieldBuilder
// are accepted by the commands.
/// \file G4FieldParametersMessenger.h
/// \brief Definition of the G4FieldParametersMessenger class
///
/// This code was initially developed in Geant4 VMC package
/// (https://github.com/vmc-project)
/// and adapted to Geant4.
///
/// \author I. Hrivnacova; IJCLab, Orsay
// Author: Ivana Hrivnacova (IJClab, Orsay), 2024.
// -------------------------------------------------------------------
#ifndef G4FIELDPARAMETERSMESSENGER_HH
#define G4FIELDPARAMETERSMESSENGER_HH
@@ -48,92 +71,81 @@ class G4UIcmdWithADouble;
class G4UIcmdWithADoubleAndUnit;
class G4UIcmdWithABool;
/// \ingroup geometry
/// \brief Messenger class that defines commands for TG4DetConstruction.
///
/// Implements commands:
/// - /field/fieldType fieldType \n
/// fieldType = Magnetic | ElectroMagnetic | Gravity
/// - /field/equationType eqType \n
/// eqType = EqMagnetic | EqMagneticWithSpin | EqElectroMagnetic |
/// EqEMfieldWithSpin | EqEMfieldWithEDM
/// - /field/stepperType stepperType \n
/// stepperType = CashKarpRKF45 | ClassicalRK4 | ExplicitEuler | ImplicitEuler |
/// SimpleHeum | SimpleRunge | ConstRK4 | ExactHelixStepper
/// | HelixExplicitEuler | HelixHeum | HelixImplicitEuler |
/// HelixMixedStepper | HelixSimpleRunge | NystromRK4 |
/// RKG3Stepper
/// - /field/setMinimumStep value
/// - /field/setDeltaChord value
/// - /field/setDeltaOneStep value
/// - /field/setDeltaIntersection value
/// - /field/setMinimumEpsilonStep value
/// - /field/setMaximumEpsilonStep value
/// - /field/setConstDistance value
/// - /field/printParameters
///
/// \author I. Hrivnacova; IJClab, Orsay
/**
* @brief G4FieldParametersMessenger is a messenger class that defines
* commands for field configuration. Only equation type and stepper type
* values that are handled by G4FieldBuilder are accepted by the commands.
*/
class G4FieldParametersMessenger : public G4UImessenger
{
public:
/// Standard constructor
G4FieldParametersMessenger(G4FieldParameters* fieldParameters);
/// Destructor
~G4FieldParametersMessenger() override;
public:
// methods
/// Apply command to the associated object.
void SetNewValue(G4UIcommand* command, G4String newValues) override;
/**
* Standard constructor for G4FieldParametersMessenger.
* @param[in] fieldParameters Pointer to the field parameters object.
*/
G4FieldParametersMessenger(G4FieldParameters* fieldParameters);
private:
/// Not implemented
G4FieldParametersMessenger() = delete;
/// Not implemented
G4FieldParametersMessenger(const G4FieldParametersMessenger& right) = delete;
/// Not implemented
G4FieldParametersMessenger& operator=(
const G4FieldParametersMessenger& right) = delete;
/**
* Destructor.
*/
~G4FieldParametersMessenger() override;
// Data members
/**
* Default constructor, copy constructor and assignment operator not allowed.
*/
G4FieldParametersMessenger() = delete;
G4FieldParametersMessenger(const G4FieldParametersMessenger&) = delete;
G4FieldParametersMessenger& operator=(const G4FieldParametersMessenger&) = delete;
G4FieldParameters* fFieldParameters = nullptr; ///< associated class
G4UIdirectory* fDirectory = nullptr; ///< command directory
/**
* Applies command to the associated object.
*/
void SetNewValue(G4UIcommand* command, G4String newValues) override;
// Commands data members
private:
/// Command: fieldType
G4UIcmdWithAString* fFieldTypeCmd = nullptr;
/** Associated class object. */
G4FieldParameters* fFieldParameters = nullptr;
/// Command: equationType
G4UIcmdWithAString* fEquationTypeCmd = nullptr;
/** Commands directory. */
G4UIdirectory* fDirectory = nullptr;
/// Command: stepperType
G4UIcmdWithAString* fStepperTypeCmd = nullptr;
// Commands data members
/// Command: setMinimumStep
G4UIcmdWithADoubleAndUnit* fSetMinimumStepCmd = nullptr;
/** Command: fieldType. */
G4UIcmdWithAString* fFieldTypeCmd = nullptr;
/// Command: setDeltaChord
G4UIcmdWithADoubleAndUnit* fSetDeltaChordCmd = nullptr;
/** Command: equationType. */
G4UIcmdWithAString* fEquationTypeCmd = nullptr;
/// Command: setDeltaOneStep
G4UIcmdWithADoubleAndUnit* fSetDeltaOneStepCmd = nullptr;
/** Command: stepperType. */
G4UIcmdWithAString* fStepperTypeCmd = nullptr;
/// Command: setDeltaIntersection
G4UIcmdWithADoubleAndUnit* fSetDeltaIntersectionCmd = nullptr;
/** Command: setMinimumStep. */
G4UIcmdWithADoubleAndUnit* fSetMinimumStepCmd = nullptr;
/// Command: setMinimumEpsilon
G4UIcmdWithADouble* fSetMinimumEpsilonStepCmd = nullptr;
/** Command: setDeltaChord. */
G4UIcmdWithADoubleAndUnit* fSetDeltaChordCmd = nullptr;
/// Command: setMaximumEpsilon
G4UIcmdWithADouble* fSetMaximumEpsilonStepCmd = nullptr;
/** Command: setDeltaOneStep. */
G4UIcmdWithADoubleAndUnit* fSetDeltaOneStepCmd = nullptr;
/// Command: setConstDistance
G4UIcmdWithADoubleAndUnit* fSetConstDistanceCmd = nullptr;
/** Command: setDeltaIntersection. */
G4UIcmdWithADoubleAndUnit* fSetDeltaIntersectionCmd = nullptr;
/// Command: printParameters
G4UIcmdWithoutParameter* fPrintParametersCmd = nullptr;
/** Command: setMinimumEpsilon. */
G4UIcmdWithADouble* fSetMinimumEpsilonStepCmd = nullptr;
/** Command: setMaximumEpsilon. */
G4UIcmdWithADouble* fSetMaximumEpsilonStepCmd = nullptr;
/** Command: setConstDistance. */
G4UIcmdWithADoubleAndUnit* fSetConstDistanceCmd = nullptr;
/** Command: printParameters. */
G4UIcmdWithoutParameter* fPrintParametersCmd = nullptr;
};
#endif // G4FIELDPARAMETERSMESSENGER_HH
#endif
@@ -22,16 +22,22 @@
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// G4FieldSetup
//
// Class description:
//
// The class for constructing magnetic, electromagnetic and gravity
// fields which strength is defined via G4Field.
//
// The equation of motion of a particle in a field and the
// integration method are set according to the selection in
// G4FieldParameters, as well as other accuracy parameters.
// The default values in G4FieldParameters correspond to defaults
// set in Geant4.
/// \file G4FieldSetup.h
/// \brief Definition of the G4FieldSetup class
///
/// This code was initially developed in Geant4 VMC package
/// (https://github.com/vmc-project)
/// and adapted to Geant4.
///
/// \author I. Hrivnacova; IJCLab, Orsay
// Author: Ivana Hrivnacova (IJClab, Orsay), 2024.
// --------------------------------------------------------------------
#ifndef G4FIELDSETUP_HH
#define G4FIELDSETUP_HH
@@ -49,148 +55,160 @@ class G4MagIntegratorStepper;
class G4LogicalVolume;
class G4VIntegrationDriver;
class TVirtualMagField;
/// \ingroup geometry
/// \brief The class for constructing magnetic, electromagnetic and gravity
/// fields which strength is defined via G4Field.
///
/// The equation of motion of a particle in a field and the
/// integration method is set according to the selection in
/// G4FieldParameters, as well as other accuracy parameters.
/// The default values in G4FieldParameters correspond to defaults
/// set in Geant4 (taken from Geant4 9.3 release.)
/// As Geant4 classes to not provide access methods for these defaults,
/// the defaults have to be checked with each new Geant4 release.
/// TO DO: unify defaults in G4 classes and G4 parameters
///
/// \author I. Hrivnacova; IJClab, Orsay
/**
* @brief G4FieldSetup is a class for constructing magnetic, electromagnetic
* and gravity fields which strength is defined via G4Field.
* The equation of motion of a particle in a field and the integration method
* are set according to the selection in G4FieldParameters, as well as other
* accuracy parameters.
*/
class G4FieldSetup
{
public:
/// Standard constructor
G4FieldSetup(const G4FieldParameters& parameters, G4Field* field,
G4LogicalVolume* lv = nullptr);
/// Destructor
~G4FieldSetup();
public:
// Methods
/**
* Standard constructor for G4FieldSetup.
* @param[in] parameters The field parameters.
* @param[in] field Pointer to the field object.
* @param[in] lv Optional logical volume where field applies; if
* null, global field applies.
*/
G4FieldSetup(const G4FieldParameters& parameters,
G4Field* field,
G4LogicalVolume* lv = nullptr);
/// Clear previously created setup
void Clear();
/// Update field setup with new field parameters
void Update();
/// Print information
void PrintInfo(G4int verboseLevel, const G4String about = "created");
/**
* Default Destructor.
*/
~G4FieldSetup();
// Set methods
/**
* Default constructor, copy constructor and assignment operator not allowed.
*/
G4FieldSetup() = delete;
G4FieldSetup(const G4FieldSetup& right) = delete;
G4FieldSetup& operator=(const G4FieldSetup& right) = delete;
/// Set G4 field
void SetG4Field(G4Field* field);
/**
* Clears previously created setup.
*/
void Clear();
// Access to field setting
/**
* Updates the field setup with new field parameters.
*/
void Update();
/// Return the instantiated field
G4Field* GetG4Field() const;
/// Return the logical vol;ume
G4LogicalVolume* GetLogicalVolume() const;
/// Return the equation of motion
G4EquationOfMotion* GetEquation() const;
/// Return the magnetic integrator stepper
G4MagIntegratorStepper* GetStepper() const;
/// Return the magnetic integrator driver
G4VIntegrationDriver* GetIntegrationDriver() const;
/**
* Prints information.
* @param[in] verboseLevel Verbosity level; if greater than 1, parameters
* are also printed out to standard output.
* @param[in] about Optional string.
*/
void PrintInfo(G4int verboseLevel, const G4String& about = "created");
private:
/// Not implemented
G4FieldSetup() = delete;
/// Not implemented
G4FieldSetup(const G4FieldSetup& right) = delete;
/// Not implemented
G4FieldSetup& operator=(const G4FieldSetup& right) = delete;
/**
* Setter for the field object.
*/
inline void SetG4Field(G4Field* field) { fG4Field = field; }
// Methods
/**
* Accessors.
*/
inline G4Field* GetG4Field() const { return fG4Field; }
inline G4LogicalVolume* GetLogicalVolume() const { return fLogicalVolume; }
inline G4EquationOfMotion* GetEquation() const { return fEquation; }
inline G4MagIntegratorStepper* GetStepper() const { return fStepper; }
// Create cached magnetic field if const distance is set > 0.
// and field is of G4MagneticField.
// Return the input field otherwise.
G4Field* CreateCachedField(
const G4FieldParameters& parameters, G4Field* field);
private:
/// Set the equation of motion of a particle in a field
G4EquationOfMotion* CreateEquation(G4EquationType equation);
/**
* Creates cached magnetic field if const distance is set greater than zero.
* @param[in] parameters The field parameters.
* @param[in] field Pointer to the field in input.
* @returns The pointer to the cached field or the input field otherwise.
*/
G4Field* CreateCachedField( const G4FieldParameters& parameters,
G4Field* field);
/// Set the integrator of particle's equation of motion
G4MagIntegratorStepper* CreateStepper(
G4EquationOfMotion* equation, G4StepperType stepper);
/**
* Creates and sets the equation of motion of a particle in a field.
* @param[in] equation The equation type.
* @returns The pointer to the created equation of motion.
*/
G4EquationOfMotion* CreateEquation(G4EquationType equation);
/// Set the FSAL integrator of particle's equation of motion
G4VIntegrationDriver* CreateFSALStepperAndDriver(
G4EquationOfMotion* equation, G4StepperType stepper, G4double minStep);
/**
* Creates and sets the field integration stepper.
* @param[in] equation Pointer to the equation of motion.
* @param[in] stepper The stepper type.
* @returns The pointer to the created integration stepper.
*/
G4MagIntegratorStepper* CreateStepper(G4EquationOfMotion* equation,
G4StepperType stepper);
// methods to update field setup step by step
/// Create cached field (if ConstDistance is set)
void CreateCachedField();
/// Create cached field (if ConstDistance is set)
void CreateStepper();
/// Create chord finder
void CreateChordFinder();
/// Update field manager
void UpdateFieldManager();
/**
* Creates and sets the FSAL field integration driver.
* @param[in] equation Pointer to the equation of motion.
* @param[in] stepper The stepper type.
* @param[in] minStep The minimum allowed step.
* @returns The pointer to the created FSAL integration driver.
*/
G4VIntegrationDriver*
CreateFSALStepperAndDriver(G4EquationOfMotion* equation,
G4StepperType stepper, G4double minStep);
// Data members
// Methods to update field setup step by step
/// Messenger for this class
G4FieldSetupMessenger* fMessenger = nullptr;
/// Parameters
const G4FieldParameters& fParameters;
/// Geant4 field manager
G4FieldManager* fFieldManager = nullptr;
/// Geant4 field
G4Field* fG4Field = nullptr;
/// The associated ROOT volume (if local field)
G4LogicalVolume* fLogicalVolume = nullptr;
/// The equation of motion
G4EquationOfMotion* fEquation = nullptr;
/// The magnetic integrator stepper
G4MagIntegratorStepper* fStepper = nullptr;
/// The magnetic integrator driver
G4VIntegrationDriver* fDriver = nullptr;
/// Chord finder
G4ChordFinder* fChordFinder = nullptr;
/**
* Creates cached field (if ConstDistance is set).
*/
void CreateCachedField();
/**
* Creates the stepper.
*/
void CreateStepper();
/**
* Creates the chord finder.
*/
void CreateChordFinder();
/**
* Updates the field manager.
*/
void UpdateFieldManager();
private: // data members
/** Messenger for this class. */
G4FieldSetupMessenger* fMessenger = nullptr;
/** Field parameters. */
const G4FieldParameters& fParameters;
/** The field manager. */
G4FieldManager* fFieldManager = nullptr;
/** The field class object. */
G4Field* fG4Field = nullptr;
/** The associated volume (if local field). */
G4LogicalVolume* fLogicalVolume = nullptr;
/** The equation of motion. */
G4EquationOfMotion* fEquation = nullptr;
/** The magnetic integrator stepper. */
G4MagIntegratorStepper* fStepper = nullptr;
/** The magnetic integrator driver. */
G4VIntegrationDriver* fDriver = nullptr;
/** Chord finder. */
G4ChordFinder* fChordFinder = nullptr;
};
// inline functions
inline void G4FieldSetup::SetG4Field(G4Field* field)
{
// Set G4 field
fG4Field = field;
}
inline G4Field* G4FieldSetup::GetG4Field() const
{
// Return the instantiated field
return fG4Field;
}
inline G4LogicalVolume* G4FieldSetup::GetLogicalVolume() const
{
// Return the logical vol;ume
return fLogicalVolume;
}
inline G4EquationOfMotion* G4FieldSetup::GetEquation() const
{
// Return the equation of motion
return fEquation;
}
inline G4MagIntegratorStepper* G4FieldSetup::GetStepper() const
{
// Return the magnetic integrator stepper
return fStepper;
}
#endif // G4FIELDSETUP_HH
#endif
@@ -22,12 +22,18 @@
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// G4FieldSetupMessenger
//
// Class description:
//
// Messenger class that defines commands for G4FieldSetup.
//
// Implements commands:
// - /field/update
/// \file G4FieldSetupMessenger.h
/// \brief Definition of the G4FieldSetupMessenger class
///
/// \author I. Hrivnacova; IJCLab, Orsay
// Author: Ivana Hrivnacova (IJCLab, Orsay), 2024
// --------------------------------------------------------------------
#ifndef G4FIELDSETUPMESSENGER_HH
#define G4FIELDSETUPMESSENGER_HH
@@ -41,42 +47,42 @@ class G4UIdirectory;
class G4UIcmdWithoutParameter;
class G4UIcmdWithAnInteger;
/// \ingroup geometry
/// \brief Messenger class that defines commands for G4FieldSetup
///
/// Implements commands:
/// - /field/update
///
/// \author I. Hrivnacova; IJCLab, Orsay
/**
* @brief G4FieldSetupMessenger is a messenger class that defines
* commands for G4FieldSetup.
*/
class G4FieldSetupMessenger : public G4UImessenger
{
public:
/// Standard constructor
G4FieldSetupMessenger(G4FieldSetup* fieldSetup);
/// Destructor
~G4FieldSetupMessenger() override;
public:
// methods
/// Apply command to the associated object.
void SetNewValue(G4UIcommand* command, G4String newValues) override;
/**
* Standard Constructor and Destructor.
*/
G4FieldSetupMessenger(G4FieldSetup* fieldSetup);
~G4FieldSetupMessenger() override;
private:
/// Not implemented
G4FieldSetupMessenger() = delete;
/// Not implemented
G4FieldSetupMessenger(const G4FieldSetupMessenger& right) = delete;
/// Not implemented
G4FieldSetupMessenger& operator=(const G4FieldSetupMessenger& right) = delete;
/**
* Default constructor, copy constructor and assignment operator not allowed.
*/
G4FieldSetupMessenger() = delete;
G4FieldSetupMessenger(const G4FieldSetupMessenger&) = delete;
G4FieldSetupMessenger& operator=(const G4FieldSetupMessenger&) = delete;
// data members
G4FieldSetup* fFieldSetup = nullptr; ///< associated class
/**
* Applies command to the associated object.
*/
void SetNewValue(G4UIcommand* command, G4String newValues) override;
//
// commands data members
private:
/// Command: update
G4UIcmdWithoutParameter* fUpdateCmd = nullptr;
/** Associated class object. */
G4FieldSetup* fFieldSetup = nullptr;
// Commands data members
/** Command: update. */
G4UIcmdWithoutParameter* fUpdateCmd = nullptr;
};
#endif // G4FIELDBUILDERMESSENGER_HH
#endif
@@ -27,13 +27,13 @@
//
// Class description:
//
// Data structure bringing together a magnetic track's state.
// (position, momentum direction & modulus, energy, spin, ... )
// Data structure bringing together a magnetic track's state
// (position, momentum direction & modulus, energy, spin, ... ).
// Uses/abilities:
// - does not maintain any relationship between its data (eg energy/momentum).
// - for use in Runge-Kutta solver (in passing it the values right now).
// Author: John Apostolakis, CERN - First version, 14.10.1996
// Author: John Apostolakis (CERN), 14.10.1996 - First version
// -------------------------------------------------------------------
#ifndef G4FIELDTRACK_HH
#define G4FIELDTRACK_HH
@@ -41,140 +41,202 @@
#include "G4ThreeVector.hh"
#include "G4ChargeState.hh"
/**
* @brief G4FieldTrack defines a data structure bringing together a magnetic
* track's state (position, momentum direction & modulus, energy, spin, etc. ).
*/
class G4FieldTrack
{
public: // with description
public:
G4FieldTrack( const G4ThreeVector& pPosition,
G4double LaboratoryTimeOfFlight,
const G4ThreeVector& pMomentumDirection,
G4double kineticEnergy,
G4double restMass_c2,
G4double charge,
const G4ThreeVector& polarization,
G4double magnetic_dipole_moment = 0.0,
G4double curve_length = 0.0,
G4double PDGspin = -1.0 );
/**
* Constructor for G4FieldTrack.
* @param[in] pPosition Position in Cartesian coordinates.
* @param[in] LaboratoryTimeOfFlight Laboratory time of flight value.
* @param[in] pMomentumDirection Direction vector.
* @param[in] kineticEnergy Kinetic energy value.
* @param[in] restMass_c2 Mass at rest.
* @param[in] charge Charge.
* @param[in] polarization Polarisation vector.
* @param[in] magnetic_dipole_moment Magnetic dipole moment.
* @param[in] curve_length Length of curve.
* @param[in] PDGspin Spin.
*/
G4FieldTrack( const G4ThreeVector& pPosition,
G4double LaboratoryTimeOfFlight,
const G4ThreeVector& pMomentumDirection,
G4double kineticEnergy,
G4double restMass_c2,
G4double charge,
const G4ThreeVector& polarization,
G4double magnetic_dipole_moment = 0.0,
G4double curve_length = 0.0,
G4double PDGspin = -1.0 );
G4FieldTrack( char );
// Almost default constructor
/**
* Older constructor for G4FieldTrack, similar to above but missing charge.
* @param[in] pPosition Position in Cartesian coordinates.
* @param[in] pMomentumDirection Direction vector.
* @param[in] curve_length Length of curve.
* @param[in] kineticEnergy Kinetic energy value.
* @param[in] restMass_c2 Mass at rest.
* @param[in] velocity Velocity value - Not used.
* @param[in] LaboratoryTimeOfFlight Laboratory time of flight value.
* @param[in] ProperTimeOfFlight Proper time of flight value.
* @param[in] polarization Polarisation vector.
* @param[in] PDGspin Spin.
*/
G4FieldTrack( const G4ThreeVector& pPosition,
const G4ThreeVector& pMomentumDirection,
G4double curve_length,
G4double kineticEnergy,
const G4double restMass_c2,
G4double velocity,
G4double LaboratoryTimeOfFlight = 0.0,
G4double ProperTimeOfFlight = 0.0,
const G4ThreeVector* pPolarization = nullptr,
G4double PDGspin = -1.0 );
G4FieldTrack( const G4ThreeVector& pPosition,
const G4ThreeVector& pMomentumDirection,
G4double curve_length,
G4double kineticEnergy,
const G4double restMass_c2,
G4double velocity,
G4double LaboratoryTimeOfFlight = 0.0,
G4double ProperTimeOfFlight = 0.0,
const G4ThreeVector* pPolarization = nullptr,
G4double PDGspin = -1.0 );
// Older constructor
// ---> Misses charge !!!
/**
* Empty init constructor.
*/
G4FieldTrack( char );
~G4FieldTrack() = default;
// Destructor
/**
* Default Destructor.
*/
~G4FieldTrack() = default;
inline G4FieldTrack( const G4FieldTrack& pFieldTrack );
inline G4FieldTrack& operator= ( const G4FieldTrack& rStVec );
// Copy constructor & Assignment operator
/**
* Copy constructor and assignment operator.
*/
inline G4FieldTrack( const G4FieldTrack& pFieldTrack );
inline G4FieldTrack& operator= ( const G4FieldTrack& rStVec );
inline G4FieldTrack(G4FieldTrack&& from) noexcept ;
inline G4FieldTrack& operator=(G4FieldTrack&& from) noexcept ;
// Move constructor & operator
/**
* Move constructor and move assignment operator.
*/
inline G4FieldTrack(G4FieldTrack&& from) noexcept ;
inline G4FieldTrack& operator=(G4FieldTrack&& from) noexcept ;
inline void UpdateState( const G4ThreeVector& pPosition,
G4double LaboratoryTimeOfFlight,
const G4ThreeVector& pMomentumDirection,
G4double kineticEnergy);
// Update four-vectors for space/time and momentum/energy
// Also resets curve length.
/**
* Streaming operator.
*/
friend std::ostream& operator<<(std::ostream& os, const G4FieldTrack& SixVec);
inline void UpdateFourMomentum( G4double kineticEnergy,
const G4ThreeVector& momentumDirection );
// Update momentum (and direction), and kinetic energy
/**
* Updates four-vectors for space/time and momentum/energy, also
* resets the curve length.
* @param[in] pPosition Position in Cartesian coordinates.
* @param[in] LaboratoryTimeOfFlight Laboratory time of flight value.
* @param[in] pMomentumDirection Direction vector.
* @param[in] kineticEnergy Kinetic energy value.
*/
inline void UpdateState( const G4ThreeVector& pPosition,
G4double LaboratoryTimeOfFlight,
const G4ThreeVector& pMomentumDirection,
G4double kineticEnergy);
void SetChargeAndMoments(G4double charge,
G4double magnetic_dipole_moment = DBL_MAX,
G4double electric_dipole_moment = DBL_MAX,
G4double magnetic_charge = DBL_MAX );
// Set the charges and moments that are not given as DBL_MAX
/**
* Updates momentum, direction and kinetic energy.
* @param[in] kineticEnergy Kinetic energy value.
* @param[in] pMomentumDirection Direction vector.
*/
inline void UpdateFourMomentum( G4double kineticEnergy,
const G4ThreeVector& momentumDirection );
inline void SetPDGSpin(G4double pdgSpin);
inline G4double GetPDGSpin();
/**
* Sets the charges and moments that are not given as DBL_MAX.
* @param[in] charge Charge value.
* @param[in] magnetic_dipole_moment M agnetic dipole moment.
* @param[in] electric_dipole_moment Electric dipole moment.
* @param[in] magnetic_charge Magnetic charge.
*/
void SetChargeAndMoments(G4double charge,
G4double magnetic_dipole_moment = DBL_MAX,
G4double electric_dipole_moment = DBL_MAX,
G4double magnetic_charge = DBL_MAX );
inline G4ThreeVector GetMomentum() const;
inline G4ThreeVector GetPosition() const;
inline const G4ThreeVector& GetMomentumDir() const;
inline G4ThreeVector GetMomentumDirection() const;
inline G4double GetCurveLength() const;
// Distance along curve of point.
/**
* Setter and getter for PDG spin.
*/
inline void SetPDGSpin(G4double pdgSpin);
inline G4double GetPDGSpin();
inline G4ThreeVector GetPolarization() const;
inline void SetPolarization( const G4ThreeVector& vecPol );
/**
* Accessors.
*/
inline G4ThreeVector GetMomentum() const;
inline G4ThreeVector GetPosition() const;
inline const G4ThreeVector& GetMomentumDir() const;
inline G4ThreeVector GetMomentumDirection() const;
inline G4double GetCurveLength() const;
inline const G4ChargeState* GetChargeState() const;
inline G4double GetLabTimeOfFlight() const;
inline G4double GetProperTimeOfFlight() const;
inline G4double GetKineticEnergy() const;
inline G4double GetCharge() const;
inline G4double GetRestMass() const;
inline const G4ChargeState* GetChargeState() const;
inline G4double GetLabTimeOfFlight() const;
inline G4double GetProperTimeOfFlight() const;
inline G4double GetKineticEnergy() const;
inline G4double GetCharge() const;
inline G4double GetRestMass() const;
// Accessors.
/**
* Getter and setter for polarisation.
*/
inline G4ThreeVector GetPolarization() const;
inline void SetPolarization( const G4ThreeVector& vecPol );
inline void SetPosition(const G4ThreeVector& nPos);
inline void SetMomentum(const G4ThreeVector& nMomDir);
// Does change mom-dir too.
/**
* Setters for momentum. SetMomentumDir() does not change momentum
* or Velocity Vector.
*/
inline void SetMomentum(const G4ThreeVector& nMomDir);
inline void SetMomentumDir(const G4ThreeVector& nMomDir);
inline void SetMomentumDir(const G4ThreeVector& nMomDir);
// Does NOT change Momentum or Velocity Vector.
/**
* Modifiers.
*/
inline void SetPosition(const G4ThreeVector& nPos);
inline void SetRestMass(G4double Mass_c2);
inline void SetCurveLength(G4double nCurve_s); // Distance along curve.
inline void SetKineticEnergy(G4double nEnergy); // Does not modify momentum.
inline void SetLabTimeOfFlight(G4double tofLab);
inline void SetProperTimeOfFlight(G4double tofProper);
inline void SetRestMass(G4double Mass_c2);
inline void SetCurveLength(G4double nCurve_s);
// Distance along curve.
inline void SetKineticEnergy(G4double nEnergy);
// Does not modify momentum.
enum { ncompSVEC = 12 }; // Needed; should be used only for RK integration driver
inline void SetLabTimeOfFlight(G4double tofLab);
inline void SetProperTimeOfFlight(G4double tofProper);
// Modifiers
/**
* Dumps/loads values to/from a provided array 'valArray'.
*/
inline void DumpToArray(G4double valArr[ncompSVEC]) const;
void LoadFromArray(const G4double valArr[ncompSVEC],
G4int noVarsIntegrated);
public: // without description
/**
* More setters/getter foe spin, now obsolete.
*/
inline void InitialiseSpin( const G4ThreeVector& vecPolarization );
inline G4ThreeVector GetSpin() const;
inline void SetSpin(const G4ThreeVector& vSpin);
enum { ncompSVEC = 12 };
// Needed and should be used only for RK integration driver
private:
inline void DumpToArray(G4double valArr[ncompSVEC]) const;
void LoadFromArray(const G4double valArr[ncompSVEC],
G4int noVarsIntegrated);
friend std::ostream&
operator<<( std::ostream& os, const G4FieldTrack& SixVec);
/**
* Implementation method. Obsolete.
*/
inline G4FieldTrack& SetCurvePnt(const G4ThreeVector& pPosition,
const G4ThreeVector& pMomentum,
G4double s_curve );
private:
public: // Obsolete methods -- due to potential confusion with PDG spin
inline void InitialiseSpin( const G4ThreeVector& vecPolarization );
inline G4ThreeVector GetSpin() const;
inline void SetSpin(const G4ThreeVector& vSpin);
private: // Implementation method -- Obsolete
inline G4FieldTrack& SetCurvePnt(const G4ThreeVector& pPosition,
const G4ThreeVector& pMomentum,
G4double s_curve );
private:
G4double SixVector[6];
G4double fDistanceAlongCurve; // distance along curve of point
G4double fKineticEnergy;
G4double fRestMass_c2;
G4double fLabTimeOfFlight;
G4double fProperTimeOfFlight;
G4ThreeVector fPolarization;
G4ThreeVector fMomentumDir;
// G4double fInitialMomentumMag; // At 'track' creation.
// G4double fLastMomentumMag; // From last Update (for checking.)
G4ChargeState fChargeState;
G4double SixVector[6];
G4double fDistanceAlongCurve; // distance along curve of point
G4double fKineticEnergy;
G4double fRestMass_c2;
G4double fLabTimeOfFlight;
G4double fProperTimeOfFlight;
G4ThreeVector fPolarization;
G4ThreeVector fMomentumDir;
G4ChargeState fChargeState;
};
#include "G4FieldTrack.icc"
@@ -25,7 +25,7 @@
//
// G4FieldTrack inline methods implementation
//
// Author: John Apostolakis, CERN - First version, 14.10.1996
// Author: John Apostolakis (CERN), 14.10.1996 - First version
// -------------------------------------------------------------------
inline
@@ -35,7 +35,6 @@ G4FieldTrack::G4FieldTrack( const G4FieldTrack& rStVec )
fRestMass_c2( rStVec.fRestMass_c2),
fLabTimeOfFlight( rStVec.fLabTimeOfFlight ),
fProperTimeOfFlight( rStVec.fProperTimeOfFlight ),
// fMomentumModulus( rStVec.fMomentumModulus ),
fPolarization( rStVec.fPolarization ),
fMomentumDir( rStVec.fMomentumDir ),
fChargeState( rStVec.fChargeState )
@@ -101,8 +100,7 @@ G4FieldTrack::G4FieldTrack(G4FieldTrack&& from) noexcept
inline
G4FieldTrack& G4FieldTrack::operator=(G4FieldTrack&& from) noexcept
{
if (&from == this) { return *this;
}
if (&from == this) { return *this; }
SixVector[0]= from.SixVector[0];
SixVector[1]= from.SixVector[1];
@@ -175,8 +173,6 @@ void G4FieldTrack::SetPosition( const G4ThreeVector& pPosition)
inline
const G4ThreeVector& G4FieldTrack::GetMomentumDir() const
{
// G4ThreeVector myMomentum( SixVector[3], SixVector[4], SixVector[5] );
// return myVelocity;
return fMomentumDir;
}
@@ -337,8 +333,6 @@ void G4FieldTrack::UpdateFourMomentum( G4double kineticEnergy,
+2.0*fRestMass_c2*kineticEnergy);
G4ThreeVector momentumVector = momentum_mag * momentumDirection;
// SetMomentum( momentumVector );
// Set direction (from unit): used sqrt, div
SixVector[3] = momentumVector.x();
SixVector[4] = momentumVector.y();
SixVector[5] = momentumVector.z();
@@ -353,11 +347,9 @@ void G4FieldTrack::UpdateState( const G4ThreeVector& position,
const G4ThreeVector& momentumDirection,
G4double kineticEnergy )
{
// SetCurvePnt( position, momentumVector, s_curve=0.0);
SetPosition( position);
fLabTimeOfFlight = laboratoryTimeOfFlight;
fDistanceAlongCurve = 0.0;
UpdateFourMomentum( kineticEnergy, momentumDirection);
}
@@ -26,11 +26,11 @@
//
// Description:
//
// Simple methods to extract vectors from arrays in conventions of
// the magnetic field integration.
// Simple methods to extract vectors from arrays in conventions of
// the magnetic field integration.
// Author: Dmitry Sorokin, Google Summer of Code 2017
// Supervision: John Apostolakis, CERN
// Author: Dmitry Sorokin (CERN, Google Summer of Code 2017), 13.10.2017
// Supervision: John Apostolakis (CERN)
// --------------------------------------------------------------------
#ifndef G4FIELD_UTILS_HH
#define G4FIELD_UTILS_HH
@@ -39,9 +39,13 @@
#include "G4Types.hh"
#include "G4ThreeVector.hh"
/**
* @brief field_utils is a helper namespace, including simple methods to extract
* vectors from arrays in conventions of the magnetic field integration.
*/
namespace field_utils
{
using State = G4double[G4FieldTrack::ncompSVEC];
template <unsigned int N>
@@ -108,8 +112,7 @@ namespace field_utils
template <typename T>
T clamp(T value, T lo, T hi);
} // field_utils
}
#include "G4FieldUtils.icc"
@@ -24,8 +24,8 @@
//
// Helper namespace field_utils inline implementation
// Author: Dmitry Sorokin, Google Summer of Code 2017
// Supervision: John Apostolakis, CERN
// Author: Dmitry Sorokin (CERN, Google Summer of Code 2017), 13.10.2017
// Supervision: John Apostolakis (CERN)
// --------------------------------------------------------------------
namespace field_utils {
@@ -42,27 +42,27 @@ namespace internal
template <typename ArrayType>
inline G4double getValue(const ArrayType& array, Value1D value)
{
const auto begin = internal::getFirstIndex(value);
return array[begin];
const auto begin = internal::getFirstIndex(value);
return array[begin];
}
template <typename ArrayType>
G4double getValue2(const ArrayType& array, Value1D value)
{
return sqr(getValue(array, value));
return sqr(getValue(array, value));
}
template <typename ArrayType>
G4double getValue(const ArrayType& array, Value3D value)
{
return std::sqrt(getValue2(array, value));
return std::sqrt(getValue2(array, value));
}
template <typename ArrayType>
G4double getValue2(const ArrayType& array, const Value3D value)
{
const auto begin = internal::getFirstIndex(value);
return sqr(array[begin]) + sqr(array[begin+1]) + sqr(array[begin+2]);
const auto begin = internal::getFirstIndex(value);
return sqr(array[begin]) + sqr(array[begin+1]) + sqr(array[begin+2]);
}
template <typename ArrayType>
@@ -75,23 +75,23 @@ G4ThreeVector makeVector(const ArrayType& array, Value3D value)
template <typename SourceArray, typename TargetArray>
void setValue(const SourceArray& src, Value1D value, TargetArray& trg)
{
const auto begin = internal::getFirstIndex(value);
trg[begin] = src[begin];
const auto begin = internal::getFirstIndex(value);
trg[begin] = src[begin];
}
template <typename SourceArray, typename TargetArray, typename ...TargetArrays>
void setValue(const SourceArray& src, Value1D value,
TargetArray& trg, TargetArrays&... trgs)
{
const auto begin = internal::getFirstIndex(value);
trg[begin] = src[begin];
setValue(src, value, trgs...);
const auto begin = internal::getFirstIndex(value);
trg[begin] = src[begin];
setValue(src, value, trgs...);
}
template <typename T>
T clamp(T value, T lo, T hi)
{
return std::min(std::max(lo, value), hi);
return std::min(std::max(lo, value), hi);
}
} // field_utils
@@ -34,22 +34,38 @@
// M.Metcalf, Analysis of the SFM Field
// OM Development Note AP-10 (revised), 1974
// Author: V.Grichine, 03.02.1997
// Author: Vladimir Grichine (CERN), 03.02.1997
// --------------------------------------------------------------------
#ifndef G4HARMONICPOLMAGFIELD_HH
#define G4HARMONICPOLMAGFIELD_HH
#include "G4MagneticField.hh"
/**
* @brief G4HarmonicPolMagField describes a magnetic field parametrised
* by harmonic polynom up to 3rd order.
*/
class G4HarmonicPolMagField : public G4MagneticField
{
public:
G4HarmonicPolMagField();
~G4HarmonicPolMagField() override;
/**
* Default Constructor and Destructor.
*/
G4HarmonicPolMagField() = default;
~G4HarmonicPolMagField() override = default;
void GetFieldValue(const G4double yTrack[] ,
G4double B[] ) const override ;
/**
* Returns the field value on the given position 'yTrack'.
* @param[in] yTrack Time position array.
* @param[out] B The returned field array.
*/
void GetFieldValue(const G4double yTrack[], G4double B[]) const override;
/**
* Returns a pointer to a new allocated clone of this object.
*/
G4HarmonicPolMagField* Clone() const override;
};
@@ -32,34 +32,75 @@
// A simple approach for solving linear differential equations.
// Take the current derivative and add it to the current position.
// Author: W.Wander <wwc@mit.edu>, 12.09.1997
// Author: W.Wander (MIT), 12.09.1997
// -------------------------------------------------------------------
#ifndef G4HELIXEXPLICITEULER_HH
#define G4HELIXEXPLICITEULER_HH
#include "G4MagHelicalStepper.hh"
/**
* @brief G4HelixExplicitEuler implements an Explicit Euler stepper for
* magnetic field: x_1 = x_0 + helix(h), with helix(h) being a helix piece
* of length h. A simple approach for solving linear differential equations.
* Takes the current derivative and adds it to the current position.
*/
class G4HelixExplicitEuler : public G4MagHelicalStepper
{
public:
/**
* Constructor for G4HelixExplicitEuler.
* @param[in] EqRhs Pointer to the provided equation of motion.
*/
G4HelixExplicitEuler(G4Mag_EqRhs* EqRhs);
~G4HelixExplicitEuler() override;
/**
* Default Destructor.
*/
~G4HelixExplicitEuler() override = default;
/**
* The stepper function for the integration.
* @param[in] y Starting values array of integration variables.
* @param[in] na Not used.
* @param[in] h The given step size.
* @param[out] yout Integration output.
* @param[out] yerr Integration error.
*/
void Stepper( const G4double y[],
const G4double*,
const G4double* na,
G4double h,
G4double yout[],
G4double yerr[] ) override;
/**
* The stepper function for the integration.
* @param[in] y Starting values array of integration variables.
* @param[in] Bfld Derivatives array.
* @param[in] h The given step size.
* @param[out] yout Integration output.
*/
void DumbStepper( const G4double y[],
G4ThreeVector Bfld,
G4double h,
G4double yout[]) override;
G4ThreeVector Bfld,
G4double h,
G4double yout[]) override;
/**
* Returns the distance from chord line.
*/
G4double DistChord() const override;
/**
* Returns the order, 1, of integration.
*/
inline G4int IntegratorOrder() const override { return 1; }
/**
* Returns the stepper type-ID, "kHelixExplicitEuler".
*/
inline G4StepperType StepperType() const override { return kHelixExplicitEuler; }
};
#endif
@@ -33,26 +33,54 @@
// 3/4 * dx(t0+2/3*h, x0+2/3*h*(dx(t0+h/3,x0+h/3*dx(t0,x0))))
// Third order solver.
// Author: W.Wander <wwc@mit.edu>, 03/11/1998
// Author: W.Wander (MIT), 03.11.1998
// -------------------------------------------------------------------
#ifndef G4HELIXHEUM_HH
#define G4HELIXHEUM_HH
#include "G4MagHelicalStepper.hh"
/**
* @brief G4HelixHeum implements a simple Heum stepper for magnetic field
* with 3rd order solver.
*/
class G4HelixHeum : public G4MagHelicalStepper
{
public:
G4HelixHeum(G4Mag_EqRhs *EqRhs);
~G4HelixHeum() override;
/**
* Constructor for G4HelixHeum.
* @param[in] EqRhs Pointer to the provided equation of motion.
*/
G4HelixHeum(G4Mag_EqRhs* EqRhs);
/**
* Default Destructor.
*/
~G4HelixHeum() override = default;
/**
* The stepper function for the integration.
* @param[in] y Starting values array of integration variables.
* @param[in] Bfld The field vector.
* @param[in] h The given step size.
* @param[out] yout Integration output.
*/
void DumbStepper( const G4double y[],
G4ThreeVector Bfld,
G4double h,
G4double yout[] ) override;
G4double h,
G4double yout[] ) override;
/**
* Returns the order, 2, of integration.
*/
inline G4int IntegratorOrder() const override { return 2; }
/**
* Returns the stepper type-ID, "kHelixHeum".
*/
inline G4StepperType StepperType() const override { return kHelixHeum; }
};
#endif
@@ -35,26 +35,54 @@
// Take the output and its derivative. Add the mean of both derivatives
// to form the final output.
// Author: W.Wander <wwc@mit.edu>, 03/11/1998
// Author: W.Wander (MIT), 03.11.1998
// -------------------------------------------------------------------
#ifndef G4HELIXIMPLICITEULER_HH
#define G4HELIXIMPLICITEULER_HH
#include "G4MagHelicalStepper.hh"
/**
* @brief G4HelixImplicitEuler implements a helix implicit Euler
* stepper for magnetic field with 2nd order solver.
*/
class G4HelixImplicitEuler : public G4MagHelicalStepper
{
public:
G4HelixImplicitEuler(G4Mag_EqRhs *EqRhs);
~G4HelixImplicitEuler() override;
/**
* Constructor for G4HelixImplicitEuler.
* @param[in] EqRhs Pointer to the provided equation of motion.
*/
G4HelixImplicitEuler(G4Mag_EqRhs* EqRhs);
/**
* Default Destructor.
*/
~G4HelixImplicitEuler() override = default;
/**
* The stepper function for the integration.
* @param[in] y Starting values array of integration variables.
* @param[in] Bfld Derivatives array.
* @param[in] h The given step size.
* @param[out] yout Integration output.
*/
void DumbStepper( const G4double y[],
G4ThreeVector Bfld,
G4double h,
G4double yout[] ) override;
G4double h,
G4double yout[] ) override;
/**
* Returns the order, 2, of integration.
*/
inline G4int IntegratorOrder() const override { return 2; }
/**
* Returns the stepper type-ID, "kHelixImplicitEuler".
*/
inline G4StepperType StepperType() const override { return kHelixImplicitEuler; }
};
#endif
@@ -34,8 +34,8 @@
// Else use HelixExplicitEuler Stepper
//
// Stepper for the small step is G4ClassicalRK4 by default, but
// it possible to choose other stepper,like G4CashKarpRK45 or G4RKG3_Stepper,
// by setting StepperNumber : new HelixMixedStepper(EqRhs,N)
// it possible to choose other stepper,like G4CashKarpRK45 or G4RKG3_Stepper,
// by setting StepperNumber : new HelixMixedStepper(EqRhs,N)
//
// N=2 G4SimpleRunge; N=3 G4SimpleHeum;
// N=4 G4ClassicalRK4;
@@ -45,71 +45,134 @@
// N=23 BogackiShampine23 N=145 TsitourasRK45
// N=45 BogackiShampine45 N=745 DormandPrince745 (ie DoPri5)
//
// For completeness also available are:
// For completeness also available are:
// N=11 G4ExplicitEuler N=12 G4ImplicitEuler; -- Likely poor
// N=5 G4HelixExplicitEuler (testing only)
// For recommendations see comments in 'SetupStepper' method.
//
// Note: Like other helix steppers, only applicable in pure magnetic field
// Note: Like other helix steppers, only applicable in pure magnetic field.
// Created: T.Nikitina, CERN - 18.05.2007, derived from G4ExactHelicalStepper
// Author: Tatiana Nikitina (CERN), 18.05.2007
// -------------------------------------------------------------------
#ifndef G4HELIXMIXEDSTEPPER_HH
#define G4HELIXMIXEDSTEPPER_HH
#include "G4MagHelicalStepper.hh"
/**
* @brief G4HelixMixedStepper is a concrete class for particle motion in
* magnetic field which splits the method used for Integration in two:
* if the stepping angle ( h / R_curve) is less than pi/3, use a RK stepper
* for small step, else use G4HelixExplicitEuler stepper.
* Like other helix steppers, it is only applicable in pure magnetic field.
*/
class G4HelixMixedStepper : public G4MagHelicalStepper
{
public:
/**
* Constructor for G4ExactHelixStepper.
* @param[in] EqRhs Pointer to the standard equation of motion.
* @param[in] StepperNumber Identified for selecting the stepper type;
* default (-1) is DormandPrince745.
* @param[in] Angle_threshold The stepping angle threshold; default (-1)
* is (1/3)*pi.
*/
G4HelixMixedStepper(G4Mag_EqRhs* EqRhs,
G4int StepperNumber = -1,
G4double Angle_threshold = -1.0);
~G4HelixMixedStepper() override;
/**
* Default Destructor.
*/
~G4HelixMixedStepper() override;
/**
* The integration stepper. The stepsize is fixed, with the step size
* given by 'hstep'. Integrates ODE starting values yInput[0 to 6].
* Outputs yout[] and its estimated error yerr[].
* If SteppingAngle = h/R_curve < pi/3, uses default RK stepper else
* use Helix fast method.
* @param[in] y Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[in] h The given step size.
* @param[out] yout Integration output.
* @param[out] yerr The estimated error.
*/
void Stepper( const G4double y[],
const G4double dydx[],
G4double h,
G4double yout[],
G4double yerr[] ) override;
// Step 'integration' for step size 'h'
// If SteppingAngle= h/R_curve < pi/3 uses default RK stepper
// else use Helix Fast Method
/**
* Same as Stepper() function above, but should perform a 'dump' step
* without error calculation. Assuming a constant field, the solution is
* a helix.
* @param[in] y Starting values array of integration variables.
* @param[in] Bfld The field vector.
* @param[in] h The given step size.
* @param[out] yout Integration output.
*/
void DumbStepper( const G4double y[],
G4ThreeVector Bfld,
G4double h,
G4double yout[]) override;
G4ThreeVector Bfld,
G4double h,
G4double yout[] ) override;
/**
* Estimates the maximum distance of curved solution and chord.
*/
G4double DistChord() const override;
// Estimate maximum distance of curved solution and chord ...
/**
* Sets the verbosity level.
*/
inline void SetVerbose (G4int newvalue) { fVerbose = newvalue; }
void PrintCalls();
G4MagIntegratorStepper* SetupStepper(G4Mag_EqRhs* EqRhs, G4int StepperName);
/**
* Setter and getter for the stepping angle threshold.
*/
inline void SetAngleThreshold( G4double val ) { fAngle_threshold = val; }
inline G4double GetAngleThreshold() { return fAngle_threshold; }
/**
* Returns the order, 4, of integration.
*/
inline G4int IntegratorOrder() const override { return 4; }
/**
* Returns the stepper type-ID, "kHelixMixedStepper".
*/
inline G4StepperType StepperType() const override { return kHelixMixedStepper; }
/**
* Logger function for the number of calls.
*/
void PrintCalls();
/**
* Sets the chosen stepper and equation of motion.
*/
G4MagIntegratorStepper* SetupStepper(G4Mag_EqRhs* EqRhs, G4int StepperName);
private:
/** Mixed Integration RK4 for 'small' steps. */
G4MagIntegratorStepper* fRK4Stepper = nullptr;
// Mixed Integration RK4 for 'small' steps
/** Int ID of Runge-Kutta stepper. */
G4int fStepperNumber = -1;
// Int ID of RK stepper
/** Threshold angle (in radians ); above it, the Helical stepper is used. */
G4double fAngle_threshold = -1.0;
// Threshold angle (in radians ) - above it Helical stepper is used
private:
/** Verbosity level. */
G4int fVerbose = 0;
/** Used for statistic, i.e. how many calls to different steppers. */
G4int fNumCallsRK4 = 0;
G4int fNumCallsHelix = 0;
// Used for statistic = how many calls to different steppers
};
#endif
@@ -27,33 +27,61 @@
//
// Class description:
//
// Helix Simple Runge-Kutta stepper for magnetic field:
// x_1 = x_0 + h * ( dx( t_0+h/2, x_0 + h/2 * dx( t_0, x_0) ) )
// Helix Simple Runge-Kutta stepper for magnetic field:
// x_1 = x_0 + h * ( dx( t_0+h/2, x_0 + h/2 * dx( t_0, x_0) ) )
//
// Second order solver.
// Take the derivative at a position to be assumed at the middle of the
// Step and add it to the current position.
// Second order solver.
// Take the derivative at a position to be assumed at the middle of the
// Step and add it to the current position.
// Author: W. Wander <wwc@mit.edu>, 03.12.1998
// Author: W.Wander (MIT), 03.12.1998
// -------------------------------------------------------------------
#ifndef G4HELIXSIMPLERUNGE_HH
#define G4HELIXSIMPLERUNGE_HH
#include "G4MagHelicalStepper.hh"
/**
* @brief G4HelixSimpleRunge implements a simple Helix stepper for magnetic
* field with 2nd order solver.
*/
class G4HelixSimpleRunge : public G4MagHelicalStepper
{
public:
/**
* Constructor for G4HelixSimpleRunge.
* @param[in] EqRhs Pointer to the provided equation of motion.
*/
G4HelixSimpleRunge(G4Mag_EqRhs* EqRhs);
~G4HelixSimpleRunge() override;
/**
* Default Destructor.
*/
~G4HelixSimpleRunge() override = default;
/**
* The stepper function for the integration.
* @param[in] y Starting values array of integration variables.
* @param[in] Bfld The field vector.
* @param[in] h The given step size.
* @param[out] yout Integration output.
*/
void DumbStepper( const G4double y[],
G4ThreeVector Bfld,
G4double h,
G4double yout[] ) override;
G4double h,
G4double yout[] ) override;
/**
* Returns the order, 2, of integration.
*/
inline G4int IntegratorOrder() const override { return 2; }
/**
* Returns the stepper type-ID, "kHelixSimpleRunge".
*/
inline G4StepperType StepperType() const override { return kHelixSimpleRunge; }
};
#endif
@@ -35,32 +35,61 @@
// Takes the output and its derivative. Adds the mean of both
// derivatives to form the final output.
// Author: W. Wander <wwc@mit.edu>, 12.09.1997
// Author: W.Wander (MIT), 12.09.1997
// -------------------------------------------------------------------
#ifndef G4IMPLICITEULER_HH
#define G4IMPLICITEULER_HH
#include "G4MagErrorStepper.hh"
/**
* @brief G4ImplicitEuler implements a Euler stepper for magnetic field
* with 2nd order solver.
*/
class G4ImplicitEuler : public G4MagErrorStepper
{
public:
G4ImplicitEuler(G4EquationOfMotion* EqRhs, G4int numberOfVariables = 6);
~G4ImplicitEuler() override;
/**
* Constructor for G4HelixSimpleRunge.
* @param[in] EqRhs Pointer to the provided equation of motion.
* @param[in] numberOfVariables The number of integration variables.
*/
G4ImplicitEuler(G4EquationOfMotion* EqRhs,
G4int numberOfVariables = 6);
void DumbStepper( const G4double y[] ,
const G4double dydx[] ,
G4double h ,
G4double yout[] ) override;
/**
* Destructor.
*/
~G4ImplicitEuler() override;
/**
* The stepper function for the integration.
* @param[in] y Starting values array of integration variables.
* @param[in] dydx The derivates array.
* @param[in] h The given step size.
* @param[out] yout Integration output.
*/
void DumbStepper( const G4double y[] ,
const G4double dydx[] ,
G4double h ,
G4double yout[] ) override;
/**
* Returns the order, 2, of integration.
*/
inline G4int IntegratorOrder() const override { return 2; }
/**
* Returns the stepper type-ID, "kImplicitEuler".
*/
inline G4StepperType StepperType() const override { return kImplicitEuler; }
private:
/** Temporaries, created to avoid new/delete on every call. */
G4double* dydxTemp = nullptr;
G4double* yTemp = nullptr;
// Temporaries, created to avoid new/delete on every call
};
#endif
@@ -35,8 +35,8 @@
// have extra capabilities, in particular First Same As Last (FSAL)
// and/or interpolation.
// Author: Dmitry Sorokin, Google Summer of Code 2017
// Supervision: John Apostolakis, CERN
// Author: Dmitry Sorokin (CERN, Google Summer of Code 2017), 20.10.2017
// Supervision: John Apostolakis (CERN)
// --------------------------------------------------------------------
#ifndef G4INTEGRATIONDRIVER_HH
#define G4INTEGRATIONDRIVER_HH
@@ -44,92 +44,172 @@
#include "G4RKIntegrationDriver.hh"
#include "G4ChordFinderDelegate.hh"
/**
* @brief G4IntegrationDriver is a templated driver class which controls the
* integration error of a Runge-Kutta stepper.
* It serves as the driver of choice for steppers which do not have extra
* capabilities, in particular First Same As Last (FSAL) and/or interpolation.
*/
template <class T>
class G4IntegrationDriver : public G4RKIntegrationDriver<T>,
public G4ChordFinderDelegate<G4IntegrationDriver<T>>
{
public:
G4IntegrationDriver( G4double hminimum,
T* stepper,
G4int numberOfComponents = 6,
G4int statisticsVerbosity = 0 );
~G4IntegrationDriver() override;
/**
* Constructor for G4IntegrationDriver.
* @param[in] hminimum Minimum allowed step.
* @param[in] stepper Pointer to the stepper algorithm.
* @param[in] numberOfComponents The number of integration variables,
* if not matching stepper's number of variables, issue exception.
* @param[in] statisticsVerbosity Verbosity level.
*/
inline G4IntegrationDriver( G4double hminimum,
T* stepper,
G4int numberOfComponents = 6,
G4int statisticsVerbosity = 0 );
/**
* Destructor. Provides statistics if verbosity level is greater than zero.
*/
inline ~G4IntegrationDriver() override;
/**
* Copy constructor and assignment operator not allowed.
*/
G4IntegrationDriver(const G4IntegrationDriver &) = delete;
const G4IntegrationDriver& operator =(const G4IntegrationDriver &) = delete;
G4double AdvanceChordLimited(G4FieldTrack& track,
G4double stepMax,
G4double epsStep,
G4double chordDistance) override;
/**
* Computes the step to take, based on chord limits.
* @param[in,out] track The current track in field.
* @param[in] stepMax Proposed step length.
* @param[in] epsStep Requested accuracy, y_err/hstep.
* @param[in] chordDistance Maximum sagitta distance.
* @returns The length of step taken.
*/
inline G4double AdvanceChordLimited(G4FieldTrack& track,
G4double stepMax,
G4double epsStep,
G4double chordDistance) override;
void OnStartTracking() override;
void OnComputeStep(const G4FieldTrack* /*track*/ = nullptr) override {}
G4bool DoesReIntegrate() const override { return true; }
/**
* Dispatch interface method for initialisation/reset of driver.
*/
inline void OnStartTracking() override;
G4bool AccurateAdvance(G4FieldTrack& track,
G4double hstep,
G4double eps, // Requested y_err/hstep
G4double hinitial = 0 ) override;
// Integrates ODE from current s (s=s0) to s=s0+h with accuracy eps.
// On output track is replaced by value at end of interval.
// The concept is similar to the odeint routine from NRC p.721-722.
/**
* Dispatch interface method for computing step. Does nothing here.
*/
inline void OnComputeStep(const G4FieldTrack* /*track*/ = nullptr) override;
G4bool QuickAdvance( G4FieldTrack& fieldTrack,
const G4double dydx[],
G4double hstep,
G4double& dchord_step,
G4double& dyerr) override;
// QuickAdvance just tries one Step - it does not ensure accuracy.
/**
* The driver does implement re-integration. Returns true.
*/
inline G4bool DoesReIntegrate() const override;
void SetVerboseLevel(G4int newLevel) override;
G4int GetVerboseLevel() const override;
/**
* Advances integration accurately by relative accuracy better than 'eps'.
* On output the track is replaced by the value at the end of interval.
* @param[in,out] track The current track in field.
* @param[in] hstep Proposed step length.
* @param[in] eps Requested accuracy, y_err/hstep.
* @param[in] hinitial Initial minimum integration step.
* @returns true if integration succeeds.
*/
inline G4bool AccurateAdvance(G4FieldTrack& track,
G4double hstep,
G4double eps, // Requested y_err/hstep
G4double hinitial = 0 ) override;
void StreamInfo( std::ostream& os ) const override;
// Write out the parameters / state of the driver
/**
* Attempts one integration step, and returns estimated error 'dyerr'.
* It does not ensure accuracy.
* @param[in,out] fieldTrack The current track in field.
* @param[in] dydx dydx array.
* @param[in] hstep Proposed step length.
* @param[out] dchord_step Estimated sagitta distance.
* @param[out] dyerr Estimated error.
* @returns true if integration succeeds.
*/
inline G4bool QuickAdvance(G4FieldTrack& fieldTrack,
const G4double dydx[],
G4double hstep,
G4double& dchord_step,
G4double& dyerr) override;
/**
* Takes one Step that is as large as possible while satisfying the
* accuracy criterion.
* @param[in,out] yVar The current track state, y.
* @param[in] dydx dydx array.
* @param[in,out] curveLength Step start, x.
* @param[in] htry Step to attempt.
* @param[in] eps The relative accuracy.
* @param[out] hdid Step achieved.
* @param[out] hnext Proposed next step.
*/
inline void OneGoodStep(G4double yVar[], // InOut
const G4double dydx[],
G4double& curveLength,
G4double htry,
G4double eps,
G4double& hdid,
G4double& hnext);
/**
* Setter and getter for verbosity.
*/
inline void SetVerboseLevel(G4int newLevel) override;
inline G4int GetVerboseLevel() const override;
/**
* Writes out to stream the parameters/state of the driver.
*/
inline void StreamInfo( std::ostream& os ) const override;
// Accessors
//
G4double GetMinimumStep() const;
void SetMinimumStep(G4double newval);
/**
* Getter and Setter for minimum allowed step.
*/
inline G4double GetMinimumStep() const;
inline void SetMinimumStep(G4double newval);
void OneGoodStep( G4double yVar[], // InOut
const G4double dydx[],
G4double& curveLength,
G4double htry,
G4double eps,
G4double& hdid,
G4double& hnext);
// This takes one Step that is of size htry, or as large
// as possible while satisfying the accuracy criterion of:
// yerr < eps * |y_end-y_start|
G4double GetSmallestFraction() const;
void SetSmallestFraction(G4double val);
/**
* Getter and Setter for smallest fraction.
*/
inline G4double GetSmallestFraction() const;
inline void SetSmallestFraction(G4double val);
protected:
void IncrementQuickAdvanceCalls();
/**
* Increments the counter for the number of calls to QuickAdvance().
*/
inline void IncrementQuickAdvanceCalls();
private:
void CheckStep(const G4ThreeVector& posIn,
const G4ThreeVector& posOut,
G4double hdid);
/**
* Checks accuracy of step distance on the end point.
*/
inline void CheckStep(const G4ThreeVector& posIn,
const G4ThreeVector& posOut, G4double hdid);
private:
/** Minimum Step allowed in a Step (in absolute units). */
G4double fMinimumStep;
// Minimum Step allowed in a Step (in absolute units)
/** Smallest fraction of (existing) curve length in relative units.
* Below this fraction the current step will be the last.
* The expected range: smaller than 0.1 * epsilon and bigger than 5e-13
* (range not enforced). */
G4double fSmallestFraction{1e-12};
// Smallest fraction of (existing) curve length - in relative units
// below this fraction the current step will be the last
// Expected range: smaller than 0.1 * epsilon and bigger than 5e-13
// Note: this range is not enforced.
/** Verbosity level for printing (debug, etc..)
* Could be varied during tracking to help identifying issues. */
G4int fVerboseLevel;
// Verbosity level for printing (debug, ..)
// Could be varied during tracking - to help identify issues
G4int fNoQuickAvanceCalls{0};
G4int fNoAccurateAdvanceCalls{0};
@@ -25,8 +25,8 @@
//
// G4IntegrationDriver inline implementation
//
// Author: Dmitry Sorokin, Google Summer of Code 2017
// Supervision: John Apostolakis, CERN
// Author: Dmitry Sorokin (CERN, Google Summer of Code 2017), 20.10.2017
// Supervision: John Apostolakis (CERN)
// --------------------------------------------------------------------
#include "G4FieldUtils.hh"
@@ -41,30 +41,30 @@ G4IntegrationDriver ( G4double hminimum, T* pStepper,
fMinimumStep(hminimum),
fVerboseLevel(statisticsVerbose)
{
if (numComponents != Base::GetStepper()->GetNumberOfVariables())
{
std::ostringstream message;
message << "Driver's number of integrated components "
<< numComponents
<< " != Stepper's number of components "
<< pStepper->GetNumberOfVariables();
G4Exception("G4IntegrationDriver","GeomField0002",
FatalException, message);
}
if (numComponents != Base::GetStepper()->GetNumberOfVariables())
{
std::ostringstream message;
message << "Driver's number of integrated components "
<< numComponents
<< " != Stepper's number of components "
<< pStepper->GetNumberOfVariables();
G4Exception("G4IntegrationDriver","GeomField0002",
FatalException, message);
}
}
template <class T>
G4IntegrationDriver<T>::~G4IntegrationDriver()
{
#ifdef G4VERBOSE
if (fVerboseLevel > 0)
{
G4cout << "G4Integration Driver Stats: "
<< "#QuickAdvance " << fNoQuickAvanceCalls
<< " - #AccurateAdvance " << fNoAccurateAdvanceCalls << " "
<< "#good steps " << fNoAccurateAdvanceGoodSteps << " "
<< "#bad steps " << fNoAccurateAdvanceBadSteps << G4endl;
}
if (fVerboseLevel > 0)
{
G4cout << "G4Integration Driver Stats: "
<< "#QuickAdvance " << fNoQuickAvanceCalls
<< " - #AccurateAdvance " << fNoAccurateAdvanceCalls << " "
<< "#good steps " << fNoAccurateAdvanceGoodSteps << " "
<< "#bad steps " << fNoAccurateAdvanceBadSteps << G4endl;
}
#endif
}
@@ -74,14 +74,25 @@ G4double G4IntegrationDriver<T>::AdvanceChordLimited(G4FieldTrack& track,
G4double epsStep,
G4double chordDistance)
{
return ChordFinderDelegate::AdvanceChordLimitedImpl(track, stepMax, epsStep,
chordDistance);
return ChordFinderDelegate::AdvanceChordLimitedImpl(track, stepMax, epsStep,
chordDistance);
}
template <class T>
void G4IntegrationDriver<T>::OnStartTracking()
{
ChordFinderDelegate::ResetStepEstimate();
ChordFinderDelegate::ResetStepEstimate();
}
template <class T>
void G4IntegrationDriver<T>::OnComputeStep(const G4FieldTrack*)
{
}
template <class T>
G4bool G4IntegrationDriver<T>::DoesReIntegrate() const
{
return true;
}
// Runge-Kutta driver with adaptive stepsize control. Integrate starting
@@ -95,110 +106,110 @@ G4bool G4IntegrationDriver<T>::
AccurateAdvance(G4FieldTrack& track, G4double hstep,
G4double eps, G4double hinitial)
{
++fNoAccurateAdvanceCalls;
++fNoAccurateAdvanceCalls;
if (hstep == 0.0)
{
std::ostringstream message;
message << "Proposed step is zero; hstep = " << hstep << " !";
G4Exception("G4IntegrationDriver::AccurateAdvance()",
"GeomField1001", JustWarning, message);
return true;
}
if (hstep == 0.0)
{
std::ostringstream message;
message << "Proposed step is zero; hstep = " << hstep << " !";
G4Exception("G4IntegrationDriver::AccurateAdvance()",
"GeomField1001", JustWarning, message);
return true;
}
if (hstep < 0)
{
std::ostringstream message;
message << "Invalid run condition." << G4endl
<< "Proposed step is negative; hstep = " << hstep << "."
<< G4endl
<< "Requested step cannot be negative! Aborting event.";
G4Exception("G4IntegrationDriver::AccurateAdvance()",
"GeomField0003", EventMustBeAborted, message);
return false;
}
if (hstep < 0)
{
std::ostringstream message;
message << "Invalid run condition." << G4endl
<< "Proposed step is negative; hstep = " << hstep << "."
<< G4endl
<< "Requested step cannot be negative! Aborting event.";
G4Exception("G4IntegrationDriver::AccurateAdvance()",
"GeomField0003", EventMustBeAborted, message);
return false;
}
G4double hnext, hdid;
G4double hnext, hdid;
G4double dydx[G4FieldTrack::ncompSVEC];
G4bool succeeded = true;
G4double dydx[G4FieldTrack::ncompSVEC];
G4bool succeeded = true;
G4double y[G4FieldTrack::ncompSVEC];
track.DumpToArray(y);
G4double y[G4FieldTrack::ncompSVEC];
track.DumpToArray(y);
const G4double startCurveLength = track.GetCurveLength();
const G4double endCurveLength = startCurveLength + hstep;
const G4double hThreshold =
const G4double startCurveLength = track.GetCurveLength();
const G4double endCurveLength = startCurveLength + hstep;
const G4double hThreshold =
std::min(eps * hstep, fSmallestFraction * startCurveLength);
G4double h = hstep;
if (hinitial > CLHEP::perMillion * hstep && hinitial < hstep)
{
h = hinitial;
}
G4double h = hstep;
if (hinitial > CLHEP::perMillion * hstep && hinitial < hstep)
{
h = hinitial;
}
G4double curveLength = startCurveLength;
G4double curveLength = startCurveLength;
for (G4int nstp = 0; nstp < Base::GetMaxNoSteps(); ++nstp)
{
const G4ThreeVector StartPos =
field_utils::makeVector(y, field_utils::Value3D::Position);
for (G4int nstp = 0; nstp < Base::GetMaxNoSteps(); ++nstp)
{
const G4ThreeVector StartPos =
field_utils::makeVector(y, field_utils::Value3D::Position);
Base::GetStepper()->RightHandSide(y, dydx);
Base::GetStepper()->RightHandSide(y, dydx);
if (h > GetMinimumStep())
{
OneGoodStep(y, dydx, curveLength, h, eps, hdid, hnext);
}
else
{
G4FieldTrack yFldTrk('0');
G4double dchord_step, dyerr, dyerr_len;
yFldTrk.LoadFromArray(y, Base::GetStepper()->GetNumberOfVariables());
yFldTrk.SetCurveLength(curveLength);
QuickAdvance(yFldTrk, dydx, h, dchord_step, dyerr_len);
yFldTrk.DumpToArray(y);
if (h == 0.0)
{
G4Exception("G4IntegrationDriver::AccurateAdvance()",
"GeomField0003", FatalException,
"Integration Step became Zero!");
}
dyerr = dyerr_len / h;
hdid = h;
curveLength += hdid;
hnext = Base::ComputeNewStepSize(dyerr / eps, h);
}
const G4ThreeVector EndPos =
field_utils::makeVector(y, field_utils::Value3D::Position);
CheckStep(EndPos, StartPos, hdid);
// Avoid numerous small last steps
if (h < hThreshold || curveLength >= endCurveLength)
{
break;
}
h = std::max(hnext, GetMinimumStep());
if (curveLength + h > endCurveLength)
{
h = endCurveLength - curveLength;
}
if (h > GetMinimumStep())
{
OneGoodStep(y, dydx, curveLength, h, eps, hdid, hnext);
}
// Have we reached the end ?
// --> a better test might be x-endCurveLength > an_epsilon
succeeded = (curveLength >= endCurveLength);
// If it was a "forced" last step
else
{
G4FieldTrack yFldTrk('0');
G4double dchord_step, dyerr, dyerr_len;
yFldTrk.LoadFromArray(y, Base::GetStepper()->GetNumberOfVariables());
yFldTrk.SetCurveLength(curveLength);
track.LoadFromArray(y, Base::GetStepper()->GetNumberOfVariables());
track.SetCurveLength(curveLength);
QuickAdvance(yFldTrk, dydx, h, dchord_step, dyerr_len);
return succeeded;
yFldTrk.DumpToArray(y);
if (h == 0.0)
{
G4Exception("G4IntegrationDriver::AccurateAdvance()",
"GeomField0003", FatalException,
"Integration Step became Zero!");
}
dyerr = dyerr_len / h;
hdid = h;
curveLength += hdid;
hnext = Base::ComputeNewStepSize(dyerr / eps, h);
}
const G4ThreeVector EndPos =
field_utils::makeVector(y, field_utils::Value3D::Position);
CheckStep(EndPos, StartPos, hdid);
// Avoid numerous small last steps
if (h < hThreshold || curveLength >= endCurveLength)
{
break;
}
h = std::max(hnext, GetMinimumStep());
if (curveLength + h > endCurveLength)
{
h = endCurveLength - curveLength;
}
}
// Have we reached the end ?
// --> a better test might be x-endCurveLength > an_epsilon
succeeded = (curveLength >= endCurveLength);
// If it was a "forced" last step
track.LoadFromArray(y, Base::GetStepper()->GetNumberOfVariables());
track.SetCurveLength(curveLength);
return succeeded;
}
// Driver for one Runge-Kutta Step with monitoring of local truncation error
@@ -224,46 +235,46 @@ void G4IntegrationDriver<T>::OneGoodStep(G4double y[], // InOut
G4double& hnext) // Out
{
G4double error2 = DBL_MAX;
G4double error2 = DBL_MAX;
G4double yerr[G4FieldTrack::ncompSVEC], ytemp[G4FieldTrack::ncompSVEC];
G4double yerr[G4FieldTrack::ncompSVEC], ytemp[G4FieldTrack::ncompSVEC];
G4double h = htry;
G4double h = htry;
const G4int max_trials = 100;
const G4int max_trials = 100;
for (G4int iter = 0; iter < max_trials; ++iter)
{
Base::GetStepper()->Stepper(y, dydx, h, ytemp, yerr);
error2 = field_utils::relativeError2(y, yerr, std::max(h, fMinimumStep),
for (G4int iter = 0; iter < max_trials; ++iter)
{
Base::GetStepper()->Stepper(y, dydx, h, ytemp, yerr);
error2 = field_utils::relativeError2(y, yerr, std::max(h, fMinimumStep),
eps_rel_max);
if (error2 <= 1.0)
{
break;
}
h = Base::ShrinkStepSize2(h, error2);
G4double xnew = curveLength + h;
if(xnew == curveLength)
{
std::ostringstream message;
message << "Stepsize underflow in Stepper !" << G4endl
<< "- Step's start x=" << curveLength
<< " and end x= " << xnew
<< " are equal !! " << G4endl
<< " Due to step-size= " << h
<< ". Note that input step was " << htry;
G4Exception("G4IntegrationDriver::OneGoodStep()",
"GeomField1001", JustWarning, message);
break;
}
if (error2 <= 1.0)
{
break;
}
hnext = Base::GrowStepSize2(h, error2);
curveLength += (hdid = h);
h = Base::ShrinkStepSize2(h, error2);
field_utils::copy(y, ytemp, Base::GetStepper()->GetNumberOfVariables());
G4double xnew = curveLength + h;
if(xnew == curveLength)
{
std::ostringstream message;
message << "Stepsize underflow in Stepper !" << G4endl
<< "- Step's start x=" << curveLength
<< " and end x= " << xnew
<< " are equal !! " << G4endl
<< " Due to step-size= " << h
<< ". Note that input step was " << htry;
G4Exception("G4IntegrationDriver::OneGoodStep()",
"GeomField1001", JustWarning, message);
break;
}
}
hnext = Base::GrowStepSize2(h, error2);
curveLength += (hdid = h);
field_utils::copy(y, ytemp, Base::GetStepper()->GetNumberOfVariables());
}
template <class T>
@@ -273,40 +284,22 @@ G4bool G4IntegrationDriver<T>::QuickAdvance(G4FieldTrack& track, // INOUT
G4double& dchord_step,
G4double& dyerr)
{
++fNoQuickAvanceCalls;
++fNoQuickAvanceCalls;
G4double yIn[G4FieldTrack::ncompSVEC],
yOut[G4FieldTrack::ncompSVEC],
yError[G4FieldTrack::ncompSVEC];
G4double yIn[G4FieldTrack::ncompSVEC],
yOut[G4FieldTrack::ncompSVEC],
yError[G4FieldTrack::ncompSVEC];
track.DumpToArray(yIn);
track.DumpToArray(yIn);
Base::GetStepper()->Stepper(yIn, dydx, hstep, yOut, yError);
Base::GetStepper()->Stepper(yIn, dydx, hstep, yOut, yError);
dchord_step = Base::GetStepper()->DistChord();
dyerr = field_utils::absoluteError(yOut, yError, hstep);
track.LoadFromArray(yOut, Base::GetStepper()->GetNumberOfVariables());
track.SetCurveLength(track.GetCurveLength() + hstep);
dchord_step = Base::GetStepper()->DistChord();
dyerr = field_utils::absoluteError(yOut, yError, hstep);
track.LoadFromArray(yOut, Base::GetStepper()->GetNumberOfVariables());
track.SetCurveLength(track.GetCurveLength() + hstep);
return true;
}
template <class T>
void G4IntegrationDriver<T>::SetSmallestFraction(G4double newFraction)
{
if (newFraction > 1.e-16 && newFraction < 1e-8)
{
fSmallestFraction = newFraction;
}
else
{
std::ostringstream message;
message << "Smallest Fraction not changed. " << G4endl
<< " Proposed value was " << newFraction << G4endl
<< " Value must be between 1.e-8 and 1.e-16";
G4Exception("G4IntegrationDriver::SetSmallestFraction()",
"GeomField1001", JustWarning, message);
}
return true;
}
template <class T>
@@ -314,67 +307,86 @@ void G4IntegrationDriver<T>::CheckStep(const G4ThreeVector& posIn,
const G4ThreeVector& posOut,
G4double hdid)
{
const G4double endPointDist = (posOut - posIn).mag();
if (endPointDist >= hdid * (1. + CLHEP::perMillion))
{
++fNoAccurateAdvanceBadSteps;
const G4double endPointDist = (posOut - posIn).mag();
if (endPointDist >= hdid * (1. + CLHEP::perMillion))
{
++fNoAccurateAdvanceBadSteps;
#ifdef G4DEBUG_FIELD
// Issue a warning only for gross differences -
// we understand how small difference occur.
if (endPointDist >= hdid * (1. + perThousand))
{
G4Exception("G4IntegrationDriver::CheckStep()",
"GeomField1002", JustWarning,
"endPointDist >= hdid!");
}
#endif
}
else
// Issue a warning only for gross differences -
// we understand how small difference occur.
if (endPointDist >= hdid * (1. + perThousand))
{
++fNoAccurateAdvanceGoodSteps;
G4Exception("G4IntegrationDriver::CheckStep()",
"GeomField1002", JustWarning,
"endPointDist >= hdid!");
}
#endif
}
else
{
++fNoAccurateAdvanceGoodSteps;
}
}
template <class T>
inline G4double G4IntegrationDriver<T>::GetMinimumStep() const
{
return fMinimumStep;
return fMinimumStep;
}
template <class T>
void G4IntegrationDriver<T>::SetMinimumStep(G4double minimumStepLength)
{
fMinimumStep = minimumStepLength;
fMinimumStep = minimumStepLength;
}
template <class T>
G4int G4IntegrationDriver<T>::GetVerboseLevel() const
{
return fVerboseLevel;
return fVerboseLevel;
}
template <class T>
void G4IntegrationDriver<T>::SetVerboseLevel(G4int newLevel)
{
fVerboseLevel = newLevel;
fVerboseLevel = newLevel;
}
template <class T>
G4double G4IntegrationDriver<T>::GetSmallestFraction() const
{
return fSmallestFraction;
return fSmallestFraction;
}
template <class T>
void G4IntegrationDriver<T>::SetSmallestFraction(G4double newFraction)
{
if (newFraction > 1.e-16 && newFraction < 1e-8)
{
fSmallestFraction = newFraction;
}
else
{
std::ostringstream message;
message << "Smallest Fraction not changed. " << G4endl
<< " Proposed value was " << newFraction << G4endl
<< " Value must be between 1.e-8 and 1.e-16";
G4Exception("G4IntegrationDriver::SetSmallestFraction()",
"GeomField1001", JustWarning, message);
}
}
template <class T>
void G4IntegrationDriver<T>::IncrementQuickAdvanceCalls()
{
++fNoQuickAvanceCalls;
++fNoQuickAvanceCalls;
}
template <class T>
void G4IntegrationDriver<T>::StreamInfo( std::ostream& os ) const
{
// Write out the parameters / state of the driver
// Write out the parameters / state of the driver
os << "State of G4IntegrationDriver: " << std::endl;
os << "--Base state (G4RKIntegrationDriver): " << std::endl;
Base::StreamInfo( os );
@@ -1,443 +0,0 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// G4IntegrationDriver inline implementation
//
// Author: Dmitry Sorokin, Google Summer of Code 2017
// Supervision: John Apostolakis, CERN
// --------------------------------------------------------------------
#include "G4FieldUtils.hh"
#include "G4DriverReporter.hh"
template <class T>
G4IntegrationDriver<T>::
G4IntegrationDriver ( G4double hminimum, T* pStepper,
G4int numComponents, G4int statisticsVerbose )
: G4RKIntegrationDriver<T>(pStepper),
fMinimumStep(hminimum),
fSmallestFraction(1e-12),
fVerboseLevel(statisticsVerbose),
fNoQuickAvanceCalls(0),
fNoAccurateAdvanceCalls(0),
fNoAccurateAdvanceBadSteps(0),
fNoAccurateAdvanceGoodSteps(0)
{
if (numComponents != Base::GetStepper()->GetNumberOfVariables())
{
std::ostringstream message;
message << "Driver's number of integrated components "
<< numComponents
<< " != Stepper's number of components "
<< pStepper->GetNumberOfVariables();
G4Exception("G4IntegrationDriver","GeomField0002",
FatalException, message);
}
}
template <class T>
G4IntegrationDriver<T>::~G4IntegrationDriver()
{
#ifdef G4VERBOSE
if (fVerboseLevel > 0)
{
G4cout << "G4Integration Driver Stats: "
<< "#QuickAdvance " << fNoQuickAvanceCalls
<< " - #AccurateAdvance " << fNoAccurateAdvanceCalls << " "
<< "#good steps " << fNoAccurateAdvanceGoodSteps << " "
<< "#bad steps " << fNoAccurateAdvanceBadSteps << G4endl;
}
#endif
}
template <class T>
G4double G4IntegrationDriver<T>::AdvanceChordLimited(G4FieldTrack& track,
G4double stepMax,
G4double epsStep,
G4double chordDistance)
{
return ChordFinderDelegate::AdvanceChordLimitedImpl(track, stepMax, epsStep,
chordDistance);
}
template <class T>
void G4IntegrationDriver<T>::OnStartTracking()
{
ChordFinderDelegate::ResetStepEstimate();
}
// Runge-Kutta driver with adaptive stepsize control. Integrate starting
// values at y_current over hstep x2 with accuracy eps.
// On output ystart is replaced by values at the end of the integration
// interval. RightHandSide is the right-hand side of ODE system.
// The source is similar to odeint routine from NRC p.721-722 .
//
template <class T>
G4bool G4IntegrationDriver<T>::
AccurateAdvance(G4FieldTrack& track, G4double hstep,
G4double eps, G4double hinitial)
{
++fNoAccurateAdvanceCalls;
if (hstep == 0.0)
{
std::ostringstream message;
message << "Proposed step is zero; hstep = " << hstep << " !";
G4Exception("G4IntegrationDriver::AccurateAdvance()",
"GeomField1001", JustWarning, message);
return true;
}
if (hstep < 0)
{
std::ostringstream message;
message << "Invalid run condition." << G4endl
<< "Proposed step is negative; hstep = " << hstep << "."
<< G4endl
<< "Requested step cannot be negative! Aborting event.";
G4Exception("G4IntegrationDriver::AccurateAdvance()",
"GeomField0003", EventMustBeAborted, message);
return false;
}
G4double hnext, hdid;
G4double dydx[G4FieldTrack::ncompSVEC];
G4bool succeeded = true, lastStepSucceeded;
G4int noFullIntegr = 0, noSmallIntegr = 0;
G4double y[G4FieldTrack::ncompSVEC];
track.DumpToArray(y);
const G4double startCurveLength = track.GetCurveLength();
const G4double endCurveLength = startCurveLength + hstep;
const G4double hThreshold =
std::min(eps * hstep, fSmallestFraction * startCurveLength);
G4double h = hstep;
if (hinitial > CLHEP::perMillion * hstep && hinitial < hstep)
{
h = hinitial;
}
#ifdef G4DEBUG_FIELD
if (fVerboseLevel > 3)
G4cout << "IDriver::AccurAdv called. "
<< " Input: hstep = " << hstep << " hinitial= " << hinitial
<< " , current: h = " << h << G4endl;
#endif
G4double curveLength = startCurveLength;
for (G4int nstp = 0; nstp < Base::GetMaxNoSteps(); ++nstp)
{
const G4ThreeVector StartPos =
field_utils::makeVector(y, field_utils::Value3D::Position);
#ifdef G4DEBUG_FIELD
const int nvar= Base::GetStepper()->GetNumberOfVariables();
G4double xStepStart= curveLength; // Initial: track.GetCurveLength();
G4double yStepStart[G4FieldTrack::ncompSVEC];
for (int i=0; i<nvar; ++i) { yStepStart[i] = y[i]; }
// G4FieldTrack yFldTrkStart( StartPos,
// field_utils::makeVector(y, field_utils::Value3D::Momentum),
// ... );
// G4FieldTrack yFldTrkStart('0');
// yFldTrkStart.LoadFromArray(y, Base::GetStepper()->GetNumberOfVariables());
// yFldTrkStart.SetCurveLength(curveLength);
G4cout << "----- Iteration = " << nstp << G4endl; // + 1
#endif
Base::GetStepper()->RightHandSide(y, dydx);
if (h > GetMinimumStep())
{
OneGoodStep(y, dydx, curveLength, h, eps, hdid, hnext);
lastStepSucceeded = (hdid == h);
#ifdef G4DEBUG_FIELD
G4cout << "IntegrationDriver -- after OneGoodStep / requesting step = " << h << G4endl;
G4DriverReporter::PrintStatus( yStepStart, xStepStart, y, curveLength, h, nstp+1, nvar); // Only
#endif
}
else
{
G4FieldTrack yFldTrk('0');
G4double dchord_step, dyerr, dyerr_len;
yFldTrk.LoadFromArray(y, Base::GetStepper()->GetNumberOfVariables());
yFldTrk.SetCurveLength(curveLength);
QuickAdvance(yFldTrk, dydx, h, dchord_step, dyerr_len);
yFldTrk.DumpToArray(y);
if (h == 0.0)
{
G4Exception("G4IntegrationDriver::AccurateAdvance()",
"GeomField0003", FatalException,
"Integration Step became Zero!");
}
dyerr = dyerr_len / h;
hdid = h;
curveLength += hdid;
hnext = Base::ComputeNewStepSize(dyerr / eps, h);
lastStepSucceeded = (dyerr <= eps);
}
if (lastStepSucceeded) { ++noFullIntegr; }
else { ++noSmallIntegr; }
const G4ThreeVector EndPos =
field_utils::makeVector(y, field_utils::Value3D::Position);
CheckStep(EndPos, StartPos, hdid);
// Avoid numerous small last steps
if (h < hThreshold || curveLength >= endCurveLength)
{
break;
}
h = std::max(hnext, GetMinimumStep());
if (curveLength + h > endCurveLength)
{
h = endCurveLength - curveLength;
}
}
// Have we reached the end ?
// --> a better test might be x-endCurveLength > an_epsilon
succeeded = (curveLength >= endCurveLength);
// If it was a "forced" last step
track.LoadFromArray(y, Base::GetStepper()->GetNumberOfVariables());
track.SetCurveLength(curveLength);
return succeeded;
}
// Driver for one Runge-Kutta Step with monitoring of local truncation error
// to ensure accuracy and adjust stepsize. Input are dependent variable
// array y[0,...,5] and its derivative dydx[0,...,5] at the
// starting value of the independent variable x . Also input are stepsize
// to be attempted htry, and the required accuracy eps. On output y and x
// are replaced by their new values, hdid is the stepsize that was actually
// accomplished, and hnext is the estimated next stepsize.
// This is similar to the function rkqs from the book:
// Numerical Recipes in C: The Art of Scientific Computing (NRC), Second
// Edition, by William H. Press, Saul A. Teukolsky, William T.
// Vetterling, and Brian P. Flannery (Cambridge University Press 1992),
// 16.2 Adaptive StepSize Control for Runge-Kutta, p. 719
//
template <class T>
void G4IntegrationDriver<T>::OneGoodStep(G4double y[], // InOut
const G4double dydx[],
G4double& curveLength, // InOut
G4double htry,
G4double eps_rel_max,
G4double& hdid, // Out
G4double& hnext) // Out
{
G4double error2 = DBL_MAX;
G4double yerr[G4FieldTrack::ncompSVEC], ytemp[G4FieldTrack::ncompSVEC];
G4double h = htry;
static G4ThreadLocal G4int tot_no_trials = 0;
const G4int max_trials = 100;
for (G4int iter = 0; iter < max_trials; ++iter)
{
tot_no_trials++;
Base::GetStepper()->Stepper(y, dydx, h, ytemp, yerr);
error2 = field_utils::relativeError2(y, yerr, std::max(h, fMinimumStep),
eps_rel_max);
if (error2 <= 1.0)
{
break;
}
h = Base::ShrinkStepSize2(h, error2);
G4double xnew = curveLength + h;
if(xnew == curveLength)
{
std::ostringstream message;
message << "Stepsize underflow in Stepper !" << G4endl
<< "- Step's start x=" << curveLength
<< " and end x= " << xnew
<< " are equal !! " << G4endl
<< " Due to step-size= " << h
<< ". Note that input step was " << htry;
G4Exception("G4IntegrationDriver::OneGoodStep()",
"GeomField1001", JustWarning, message);
break;
}
}
hnext = Base::GrowStepSize2(h, error2);
curveLength += (hdid = h);
field_utils::copy(y, ytemp, Base::GetStepper()->GetNumberOfVariables());
}
template <class T>
G4bool G4IntegrationDriver<T>::QuickAdvance(G4FieldTrack& track, // INOUT
const G4double dydx[],
G4double hstep,
G4double& dchord_step,
G4double& dyerr)
{
++fNoQuickAvanceCalls;
G4double yIn[G4FieldTrack::ncompSVEC],
yOut[G4FieldTrack::ncompSVEC],
yError[G4FieldTrack::ncompSVEC];
G4FieldTrack startTrack( track ); // For debugging
track.DumpToArray(yIn);
Base::GetStepper()->Stepper(yIn, dydx, hstep, yOut, yError);
dchord_step = Base::GetStepper()->DistChord();
dyerr = field_utils::absoluteError(yOut, yError, hstep);
track.LoadFromArray(yOut, Base::GetStepper()->GetNumberOfVariables());
track.SetCurveLength(track.GetCurveLength() + hstep);
#ifdef G4DEBUG_FIELD
// For debugging
static unsigned int numCall= 0;
G4cout // << "G4IntegratorDriver::"
<< "QuickAdvance call # " << ++numCall << G4endl
<< " Input: hstep= " << hstep << G4endl
<< " track= " << startTrack << G4endl
<< " Output: track= " << track << G4endl
<< " d_chord = " << dchord_step
<< " dyerr = " << dyerr << G4endl;
#endif
return true;
}
template <class T>
void G4IntegrationDriver<T>::SetSmallestFraction(G4double newFraction)
{
if (newFraction > 1.e-16 && newFraction < 1e-8)
{
fSmallestFraction = newFraction;
}
else
{
std::ostringstream message;
message << "Smallest Fraction not changed. " << G4endl
<< " Proposed value was " << newFraction << G4endl
<< " Value must be between 1.e-8 and 1.e-16";
G4Exception("G4IntegrationDriver::SetSmallestFraction()",
"GeomField1001", JustWarning, message);
}
}
template <class T>
void G4IntegrationDriver<T>::CheckStep(const G4ThreeVector& posIn,
const G4ThreeVector& posOut,
G4double hdid)
{
const G4double endPointDist = (posOut - posIn).mag();
if (endPointDist >= hdid * (1. + CLHEP::perMillion))
{
++fNoAccurateAdvanceBadSteps;
#ifdef G4DEBUG_FIELD
// Issue a warning only for gross differences -
// we understand how small difference occur.
if (endPointDist >= hdid * (1. + perThousand))
{
G4Exception("G4IntegrationDriver::CheckStep()",
"GeomField1002", JustWarning,
"endPointDist >= hdid!");
}
#endif
}
else
{
++fNoAccurateAdvanceGoodSteps;
}
}
template <class T>
inline G4double G4IntegrationDriver<T>::GetMinimumStep() const
{
return fMinimumStep;
}
template <class T>
void G4IntegrationDriver<T>::SetMinimumStep(G4double minimumStepLength)
{
fMinimumStep = minimumStepLength;
}
template <class T>
G4int G4IntegrationDriver<T>::GetVerboseLevel() const
{
return fVerboseLevel;
}
template <class T>
void G4IntegrationDriver<T>::SetVerboseLevel(G4int newLevel)
{
fVerboseLevel = newLevel;
}
template <class T>
G4double G4IntegrationDriver<T>::GetSmallestFraction() const
{
return fSmallestFraction;
}
template <class T>
void G4IntegrationDriver<T>::IncrementQuickAdvanceCalls()
{
++fNoQuickAvanceCalls;
}
template <class T>
void G4IntegrationDriver<T>::StreamInfo( std::ostream& os ) const
{
// Write out the parameters / state of the driver
os << "State of G4IntegrationDriver: " << std::endl;
os << "--Base state (G4RKIntegrationDriver): " << std::endl;
Base::StreamInfo( os );
os << "--Own state (G4IntegrationDriver<>): " << std::endl;
os << " fMinimumStep = " << fMinimumStep << std::endl;
os << " Smallest Fraction = " << fSmallestFraction << std::endl;
os << " verbose level = " << fVerboseLevel << std::endl;
os << " Reintegrates = " << DoesReIntegrate() << std::endl;
os << "--Chord Finder Delegate state: " << std::endl;
ChordFinderDelegate::StreamDelegateInfo( os );
}
@@ -30,7 +30,7 @@
// Driver class which uses Runge-Kutta stepper with interpolation property
// to integrate track with error control
// Created: D.Sorokin, 2018
// Author: Dmitry Sorokin (CERN), 26.09.2018
// --------------------------------------------------------------------
#ifndef G4INTERPOLATION_DRIVER_HH
#define G4INTERPOLATION_DRIVER_HH
@@ -42,43 +42,92 @@
#include <memory>
#include <vector>
/**
* @brief G4InterpolationDriver is a templated driver class which uses
* Runge-Kutta stepper with interpolation property to integrate track with
* error control.
*/
template <class T, G4bool StepperCachesDchord = true>
class G4InterpolationDriver : public G4RKIntegrationDriver<T>
{
public:
/**
* Constructor for G4IntegrationDriver.
* @param[in] hminimum Minimum allowed step.
* @param[in] stepper Pointer to the stepper algorithm.
* @param[in] numberOfComponents The number of integration variables,
* if not matching stepper's number of variables, issue exception.
* @param[in] statisticsVerbosity Verbosity level.
*/
G4InterpolationDriver(G4double hminimum,
T* stepper,
G4int numberOfComponents = 6,
G4int statisticsVerbosity = 0);
~G4InterpolationDriver() override;
/**
* Destructor. Provides statistics if verbosity level is greater than zero.
*/
~G4InterpolationDriver() override;
/**
* Copy constructor and assignment operator not allowed.
*/
G4InterpolationDriver(const G4InterpolationDriver&) = delete;
const G4InterpolationDriver& operator=(const G4InterpolationDriver&) = delete;
/**
* Computes the step to take, based on chord limits.
* @param[in,out] track The current track in field.
* @param[in] hstep Proposed step length.
* @param[in] eps Requested accuracy, y_err/hstep.
* @param[in] chordDistance Maximum sagitta distance.
* @returns The length of step taken.
*/
G4double AdvanceChordLimited(G4FieldTrack& track,
G4double hstep,
G4double eps,
G4double chordDistance) override;
/**
* Dispatch interface method for initialisation/reset of driver.
*/
void OnStartTracking() override;
void OnComputeStep(const G4FieldTrack* /*track*/ = nullptr) override;
G4bool DoesReIntegrate() const override { return false; }
// Interpolation driver does not recalculate when AccurateAdvance
// is called -- reintegration would require other calls
/**
* Dispatch interface method for computing step. Does nothing here.
*/
void OnComputeStep(const G4FieldTrack* /*track*/ = nullptr) override;
/**
* The driver does not implement re-integration. Returns false.
*/
G4bool DoesReIntegrate() const override { return false; }
/**
* Advances integration accurately by relative accuracy better than 'eps'.
* On output the track is replaced by the value at the end of interval.
* @param[in,out] track The current track in field.
* @param[in] hstep Proposed step length.
* @param[in] eps Requested accuracy, y_err/hstep.
* @param[in] hinitial Initial minimum integration step.
* @returns true if integration succeeds.
*/
G4bool AccurateAdvance(G4FieldTrack& track,
G4double hstep,
G4double eps, // Requested y_err/hstep
G4double hinitial = 0) override;
// Integrates ODE from current s (s=s0) to s=s0+h with accuracy eps.
// On output track is replaced by value at end of interval.
// The concept is similar to the odeint routine from NRC p.721-722.
/**
* Setter and getter for verbosity.
*/
void SetVerboseLevel(G4int level) override;
G4int GetVerboseLevel() const override;
/**
* Writes out to stream the parameters/state of the driver.
*/
void StreamInfo(std::ostream& os) const override;
protected:
@@ -94,6 +143,18 @@ class G4InterpolationDriver : public G4RKIntegrationDriver<T>
using StepperIterator = typename std::vector<InterpStepper>::iterator;
using ConstStepperIterator = typename std::vector<InterpStepper>::const_iterator;
/**
* Takes one Step that is as large as possible while satisfying the
* accuracy criterion.
* @param[in] it Stepper iterator.
* @param[in,out] y The current track state, y.
* @param[in] dydx dydx array.
* @param[in,out] hstep Step to attempt.
* @param[in] eps The relative accuracy.
* @param[in] curveLength Step start, x.
* @param[in,out] track Pointer to the Field track. Not used.
* @returns The step achieved.
*/
virtual G4double OneGoodStep(StepperIterator it,
field_utils::State& y,
field_utils::State& dydx,
@@ -101,37 +162,48 @@ class G4InterpolationDriver : public G4RKIntegrationDriver<T>
G4double eps,
G4double curveLength,
G4FieldTrack* track = nullptr);
// This takes one Step that is of size htry, or as large
// as possible while satisfying the accuracy criterion of:
// yerr < eps * |y_end-y_start|
// return hdid
/**
* Track interpolation.
* @param[in] curveLength Step start, x.
* @param[in,out] y The current track state, y.
*/
void Interpolate(G4double curveLength, field_utils::State& y) const;
/**
* Wrapper method for interpolation.
*/
void InterpolateImpl(G4double curveLength,
ConstStepperIterator it,
field_utils::State& y) const;
/**
* Methods for calculation of chord step and distance.
*/
G4double DistChord(const field_utils::State& yBegin,
G4double curveLengthBegin,
const field_utils::State& yEnd,
G4double curveLengthEnd) const;
G4double FindNextChord(const field_utils::State& yBegin,
G4double curveLengthBegin,
field_utils::State& yEnd,
G4double curveLengthEnd,
G4double dChord,
G4double maxChordDistance);
G4double CalcChordStep(G4double stepTrialOld,
G4double dChordStep,
G4double fDeltaChord);
void PrintState() const;
/**
* Internal methods for printing/checking the state.
*/
void PrintState() const;
void CheckState() const;
/**
* Increments number of trials and calls.
*/
void AccumulateStatistics(G4int noTrials);
protected:
@@ -140,11 +212,11 @@ class G4InterpolationDriver : public G4RKIntegrationDriver<T>
StepperIterator fLastStepper;
G4bool fKeepLastStepper = false;
/** Memory of last good step size for integration. */
G4double fhnext = DBL_MAX;
// Memory of last good step size for integration
/** Minimum Step allowed (in units of length). */
G4double fMinimumStep;
// Minimum Step allowed in a Step (in units of length) // Parameter
G4double fChordStepEstimate = DBL_MAX;
const G4double fFractionNextEstimate = 0.98; // Constant
@@ -158,7 +230,7 @@ class G4InterpolationDriver : public G4RKIntegrationDriver<T>
G4int fMaxTrials = 100; // Constant
G4int fTotalStepsForTrack = 0;
// statistics
/** Statistics. */
G4int fTotalNoTrials = 0;
G4int fNoCalls = 0;
G4int fmaxTrials = 0;
@@ -25,7 +25,7 @@
//
// G4InterpolationDriver inline implementation
//
// Created: D.Sorokin, 2018
// Author: Dmitry Sorokin (CERN), 26.09.2018
// --------------------------------------------------------------------
#include "G4Exception.hh"
@@ -41,14 +41,16 @@ G4InterpolationDriver<T, StepperCachesDchord>::G4InterpolationDriver(
G4double hminimum, T* pStepper, G4int numComponents, G4int statisticsVerbose)
: G4RKIntegrationDriver<T>(pStepper), fMinimumStep(hminimum), fVerboseLevel(statisticsVerbose)
{
if (numComponents != Base::GetStepper()->GetNumberOfVariables()) {
if (numComponents != Base::GetStepper()->GetNumberOfVariables())
{
std::ostringstream message;
message << "Driver's number of integrated components " << numComponents
<< " != Stepper's number of components " << pStepper->GetNumberOfVariables();
G4Exception("G4InterpolationDriver", "GeomField0002", FatalException, message);
}
for (G4int i = 0; i < Base::GetMaxNoSteps(); ++i) {
for (G4int i = 0; i < Base::GetMaxNoSteps(); ++i)
{
fSteppers.push_back(
{std::unique_ptr<T>(
new T(pStepper->GetSpecificEquation(), // Interpolating stepper must have this!
@@ -63,7 +65,8 @@ template <class T, G4bool StepperCachesDchord>
G4InterpolationDriver<T, StepperCachesDchord>::~G4InterpolationDriver()
{
#ifdef G4VERBOSE
if (fVerboseLevel > 0) {
if (fVerboseLevel > 0)
{
G4cout << "G4ChordFinder statistics report: \n"
<< " No trials: " << fTotalNoTrials << " No Calls: " << fNoCalls
<< " Max-trial: " << fmaxTrials << G4endl;
@@ -103,7 +106,8 @@ template <class T, G4bool StepperCachesDchord>
void G4InterpolationDriver<T, StepperCachesDchord>::Interpolate(
G4double curveLength, field_utils::State& y) const
{
if (fLastStepper == fSteppers.end()) {
if (fLastStepper == fSteppers.end())
{
std::ostringstream message;
message << "LOGICK ERROR: fLastStepper == end";
G4Exception("G4InterpolationDriver::Interpolate()", "GeomField1001", FatalException, message);
@@ -114,8 +118,10 @@ void G4InterpolationDriver<T, StepperCachesDchord>::Interpolate(
auto it = std::lower_bound(fSteppers.cbegin(), end, curveLength,
[](const InterpStepper& stepper, G4double value) { return stepper.end < value; });
if (it == end) {
if (curveLength - fLastStepper->end > CLHEP::perMillion) {
if (it == end)
{
if (curveLength - fLastStepper->end > CLHEP::perMillion)
{
std::ostringstream message;
message << "curveLength = " << curveLength << " > " << fLastStepper->end;
G4Exception("G4InterpolationDriver::Interpolate()", "GeomField1001", JustWarning, message);
@@ -124,8 +130,10 @@ void G4InterpolationDriver<T, StepperCachesDchord>::Interpolate(
return fLastStepper->stepper->Interpolate(1, y);
}
if (curveLength < it->begin) {
if (it->begin - curveLength > CLHEP::perMillion) {
if (curveLength < it->begin)
{
if (it->begin - curveLength > CLHEP::perMillion)
{
std::ostringstream message;
message << "curveLength = " << curveLength << " < " << it->begin;
G4Exception("G4InterpolationDriver::Interpolate()", "GeomField1001", JustWarning, message);
@@ -149,10 +157,12 @@ template <class T, G4bool StepperCachesDchord>
G4double G4InterpolationDriver<T, StepperCachesDchord>::DistChord(const field_utils::State& yBegin,
G4double curveLengthBegin, const field_utils::State& yEnd, G4double curveLengthEnd) const
{
if (StepperCachesDchord) {
if (StepperCachesDchord)
{
// optimization check if it worth
//
if (curveLengthBegin == fLastStepper->begin && curveLengthEnd == fLastStepper->end) {
if (curveLengthBegin == fLastStepper->begin && curveLengthEnd == fLastStepper->end)
{
return fLastStepper->stepper
->DistChord(); // QssStepper Returns 0.0 !??? Not implemented => WRONG
}
@@ -184,21 +194,25 @@ G4double G4InterpolationDriver<T, StepperCachesDchord>::AdvanceChordLimited(
track.DumpToArray(yBegin);
track.DumpToArray(y);
if (fFirstStep) {
if (fFirstStep)
{
Base::GetEquationOfMotion()->RightHandSide(y, fdydx);
fFirstStep = false;
}
if (fKeepLastStepper) {
if (fKeepLastStepper)
{
std::swap(*fSteppers.begin(), *fLastStepper);
it = fSteppers.begin(); // new begin, update iterator
fLastStepper = it;
hdid = it->end - curveLengthBegin;
if (hdid > hend) {
if (hdid > hend)
{
hdid = hend;
InterpolateImpl(curveLengthBegin + hdid, it, y);
}
else {
else
{
field_utils::copy(y, it->stepper->GetYOut());
}
@@ -209,7 +223,8 @@ G4double G4InterpolationDriver<T, StepperCachesDchord>::AdvanceChordLimited(
// accurate advance & check chord distance
G4double h = fhnext;
for (; hdid < hend && dChordStep < chordDistance && it != fSteppers.end(); ++it) {
for (; hdid < hend && dChordStep < chordDistance && it != fSteppers.end(); ++it)
{
h = std::min(h, hstep - hdid);
// make one step
@@ -229,7 +244,8 @@ G4double G4InterpolationDriver<T, StepperCachesDchord>::AdvanceChordLimited(
// - reached maximum number of steps (from number of steppers.)
// update step estimation
if (h > fMinimumStep) {
if (h > fMinimumStep)
{
fhnext = h;
}
@@ -257,7 +273,8 @@ G4double G4InterpolationDriver<T, StepperCachesDchord>::FindNextChord(
G4double curveLength = curveLengthEnd;
G4int i = 1;
for (; i < fMaxTrials && dChord > chordDistance && curveLength > fLastStepper->begin; ++i) {
for (; i < fMaxTrials && dChord > chordDistance && curveLength > fLastStepper->begin; ++i)
{
// crop step size
hstep = CalcChordStep(hstep, dChord, chordDistance);
@@ -274,11 +291,13 @@ G4double G4InterpolationDriver<T, StepperCachesDchord>::FindNextChord(
// dChord may be zero
//
if (dChord > 0.0) {
if (dChord > 0.0)
{
fChordStepEstimate = hstep * std::sqrt(chordDistance / dChord);
}
if (i == fMaxTrials) {
if (i == fMaxTrials)
{
G4Exception(
"G4InterpolationDriver::FindNextChord()", "GeomField1001", JustWarning, "cannot converge");
}
@@ -299,12 +318,16 @@ G4double G4InterpolationDriver<T, StepperCachesDchord>::CalcChordStep(
const G4double chordStepEstimate = stepTrialOld * std::sqrt(chordDistance / dChordStep);
G4double stepTrial = fFractionNextEstimate * chordStepEstimate;
if (stepTrial <= 0.001 * stepTrialOld) {
if (dChordStep > 1000.0 * chordDistance) {
if (stepTrial <= 0.001 * stepTrialOld)
{
if (dChordStep > 1000.0 * chordDistance)
{
stepTrial = stepTrialOld * 0.03;
}
else {
if (dChordStep > 100. * chordDistance) {
else
{
if (dChordStep > 100. * chordDistance)
{
stepTrial = stepTrialOld * 0.1;
}
else // Try halving the length until dChordStep OK
@@ -313,11 +336,13 @@ G4double G4InterpolationDriver<T, StepperCachesDchord>::CalcChordStep(
}
}
}
else if (stepTrial > 1000.0 * stepTrialOld) {
else if (stepTrial > 1000.0 * stepTrialOld)
{
stepTrial = 1000.0 * stepTrialOld;
}
if (stepTrial == 0.0) {
if (stepTrial == 0.0)
{
stepTrial = 0.000001;
}
@@ -338,14 +363,16 @@ G4bool G4InterpolationDriver<T, StepperCachesDchord>::AccurateAdvance(
G4FieldTrack& track, G4double hstep, G4double /*eps*/, G4double /*hinitial*/
)
{
if (hstep == 0.0) {
if (hstep == 0.0)
{
std::ostringstream message;
message << "Proposed step is zero; hstep = " << hstep << " !";
G4Exception("G4InterpolationDriver::AccurateAdvance()", "GeomField1001", JustWarning, message);
return true;
}
if (hstep < 0) {
if (hstep < 0)
{
std::ostringstream message;
message << "Invalid run condition." << G4endl << "Proposed step is negative; hstep = " << hstep
<< "." << G4endl << "Requested step cannot be negative! Aborting event.";
@@ -390,17 +417,20 @@ G4double G4InterpolationDriver<T, StepperCachesDchord>::OneGoodStep(StepperItera
G4double h = hstep;
G4int i = 0;
for (; i < fMaxTrials; ++i) {
for (; i < fMaxTrials; ++i)
{
it->stepper->Stepper(y, dydx, h, ytemp, yerr, dydxtemp);
error2 = field_utils::relativeError2(y, yerr, h, epsStep);
if (error2 <= 1.0) {
if (error2 <= 1.0)
{
hstep = std::max(Base::GrowStepSize2(h, error2), fMinimumStep);
break;
}
// don't control error for small steps
if (h <= fMinimumStep) {
if (h <= fMinimumStep)
{
hstep = fMinimumStep;
break;
}
@@ -408,7 +438,8 @@ G4double G4InterpolationDriver<T, StepperCachesDchord>::OneGoodStep(StepperItera
h = std::max(Base::ShrinkStepSize2(h, error2), fMinimumStep);
}
if (i == fMaxTrials) {
if (i == fMaxTrials)
{
G4Exception(
"G4InterpolationDriver::OneGoodStep()", "GeomField1001", JustWarning, "cannot converge");
hstep = std::max(Base::ShrinkStepSize2(h, error2), fMinimumStep);
@@ -436,13 +467,15 @@ void G4InterpolationDriver<T, StepperCachesDchord>::PrintState() const
auto prev = fSteppers.begin();
G4cout << "====== curr state ========" << G4endl;
for (auto i = fSteppers.begin(); i <= fLastStepper; ++i) {
for (auto i = fSteppers.begin(); i <= fLastStepper; ++i)
{
i->stepper->Interpolate(0, currBegin);
G4cout << "cl_begin: " << i->begin << " "
<< "cl_end: " << i->end << " ";
if (prev != i) {
if (prev != i)
{
prev->stepper->Interpolate(1, prevEnd);
auto prevPos = makeVector(prevEnd, Value3D::Position);
auto currPos = makeVector(currBegin, Value3D::Position);
@@ -458,7 +491,8 @@ void G4InterpolationDriver<T, StepperCachesDchord>::PrintState() const
const G4double hstep = (clEnd - clBegin) / 10.;
State yBegin, yCurr;
Interpolate(0, yBegin);
for (G4double cl = clBegin; cl <= clEnd + 1e-12; cl += hstep) {
for (G4double cl = clBegin; cl <= clEnd + 1e-12; cl += hstep)
{
Interpolate(cl, yCurr);
auto d = DistChord(yBegin, clBegin, yCurr, cl);
G4cout << "cl: " << cl << " chord_distance: " << d << G4endl;
@@ -471,17 +505,21 @@ template <class T, G4bool StepperCachesDchord>
void G4InterpolationDriver<T, StepperCachesDchord>::CheckState() const
{
G4int smallSteps = 0;
for (auto i = fSteppers.begin(); i <= fLastStepper; ++i) {
for (auto i = fSteppers.begin(); i <= fLastStepper; ++i)
{
G4double stepLength = i->end - i->begin;
if (stepLength < fMinimumStep) {
if (stepLength < fMinimumStep)
{
++smallSteps;
}
}
if (smallSteps > 1) {
if (smallSteps > 1)
{
std::ostringstream message;
message << "====== curr state ========\n";
for (auto i = fSteppers.begin(); i <= fLastStepper; ++i) {
for (auto i = fSteppers.begin(); i <= fLastStepper; ++i)
{
message << "cl_begin: " << i->begin << " "
<< "cl_end: " << i->end << "\n";
}
@@ -496,7 +534,8 @@ void G4InterpolationDriver<T, StepperCachesDchord>::AccumulateStatistics(G4int n
fTotalNoTrials += noTrials;
++fNoCalls;
if (noTrials > fmaxTrials) {
if (noTrials > fmaxTrials)
{
fmaxTrials = noTrials;
}
}
@@ -32,22 +32,44 @@
// The line current is directed along Z axis and crosses the XY
// plane in the origin point (0,0).
// Author: V.Grichine, 03.02.1997
// Author: Vladimir Grichine (CERN), 03.02.1997
// --------------------------------------------------------------------
#ifndef G4LINECURRENTMAGFIELD_HH
#define G4LINECURRENTMAGFIELD_HH
#include "G4MagneticField.hh"
/**
* @brief G4LineCurrentMagField is a class describing a line current magnetic
* field. The line current is directed along the Z axis and crosses the XY
* plane in the origin point.
*/
class G4LineCurrentMagField : public G4MagneticField
{
public:
/**
* Constructor for G4LineCurrentMagField.
* @param[in] pFieldConstant Value of the constant field.
*/
G4LineCurrentMagField(G4double pFieldConstant);
~G4LineCurrentMagField() override;
void GetFieldValue(const G4double yTrack[],
G4double B[] ) const override;
/**
* Default Destructor.
*/
~G4LineCurrentMagField() override = default;
/**
* Returns the field value on the given position 'yTrack'.
* @param[in] yTrack Time position array.
* @param[out] B The returned field array.
*/
void GetFieldValue(const G4double yTrack[], G4double B[]) const override;
/**
* Returns a pointer to a new allocated clone of this object.
*/
G4Field* Clone() const override;
private:
@@ -30,7 +30,7 @@
// A utility class that calculates the distance of a point from a
// line section.
// Created: J.Apostolakis, 1999
// Author: John Apostolakis (CERN), 1999
// --------------------------------------------------------------------
#ifndef G4LineSection_hh
@@ -39,25 +39,49 @@
#include "G4Types.hh"
#include "G4ThreeVector.hh"
/**
* @brief G4LineSection is a utility class that calculates the distance
* of a point from a line section.
*/
class G4LineSection
{
public: // with description
public:
G4LineSection( const G4ThreeVector& PntA,
const G4ThreeVector& PntB );
/**
* Constructor for G4LineSection.
* @param[in] PntA Coordinates of point A defining the line.
* @param[in] PntB Coordinates of point B defining the line.
*/
G4LineSection( const G4ThreeVector& PntA,
const G4ThreeVector& PntB );
G4double Dist( const G4ThreeVector& OtherPnt ) const;
/**
* Default Destructor.
*/
~G4LineSection() = default;
inline G4double GetABdistanceSq() const;
/**
* Returns the distance of point 'OtherPnt' from the line.
*/
G4double Dist( const G4ThreeVector& OtherPnt ) const;
inline static G4double Distline( const G4ThreeVector& OtherPnt,
const G4ThreeVector& LinePntA,
const G4ThreeVector& LinePntB );
/**
* Returns the distance squared.
*/
inline G4double GetABdistanceSq() const;
/**
* Defines line and returns the distance of point 'OtherPnt' from it.
*/
inline static G4double Distline( const G4ThreeVector& OtherPnt,
const G4ThreeVector& LinePntA,
const G4ThreeVector& LinePntB );
private:
G4ThreeVector EndpointA;
G4ThreeVector VecAtoB;
G4double fABdistanceSq = 0.0;
G4ThreeVector EndpointA;
G4ThreeVector VecAtoB;
G4double fABdistanceSq = 0.0;
};
// Inline methods implementations
@@ -30,7 +30,7 @@
// Abstract base class for integrator of particle's equation of motion,
// used in tracking in space dependent magnetic field.
// Author: W.Wander <wwc@mit.edu>, 09.12.1997
// Author: W.Wander (MIT), 09.12.1997
// --------------------------------------------------------------------
#ifndef G4MAGERRORSTEPPER_HH
#define G4MAGERRORSTEPPER_HH
@@ -40,47 +40,77 @@
#include "G4Mag_EqRhs.hh"
#include "G4ThreeVector.hh"
/**
* @brief G4MagErrorStepper is an abstract base class for integrator of
* particle's equation of motion, used in tracking in space dependent
* magnetic field.
*/
class G4MagErrorStepper : public G4MagIntegratorStepper
{
public:
/**
* Constructor for G4MagErrorStepper.
* @param[in] EqRhs Pointer to the provided equation of motion.
* @param[in] numberOfVariables The number of integration variables.
* @param[in] numberOfVariables The number of state variables.
*/
G4MagErrorStepper(G4EquationOfMotion*EqRhs,
G4int numberOfVariables,
G4int numStateVariables = 12);
/**
* Destructor.
*/
~G4MagErrorStepper() override;
/**
* Copy constructor and assignment operator not allowed.
*/
G4MagErrorStepper(const G4MagErrorStepper&) = delete;
G4MagErrorStepper& operator=(const G4MagErrorStepper&) = delete;
/**
* The stepper for the Runge Kutta integration.
* The stepsize is fixed, with the step size given by 'h'.
* Integrates ODE starting values y[0 to 6].
* Outputs yout[] and its estimated error yerr[].
* @param[in] y Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[in] h The given step size.
* @param[out] yout Integration output.
* @param[out] yerr The estimated error.
*/
void Stepper( const G4double y[],
const G4double dydx[],
G4double h,
G4double yout[],
G4double yerr[] ) override;
// The stepper for the Runge Kutta integration. The stepsize
// is fixed, with the Step size given by h.
// Integrates ODE starting values y[0 to 6].
// Outputs yout[] and its estimated error yerr[].
virtual void DumbStepper( const G4double y[],
const G4double dydx[],
G4double h,
G4double yout[] ) = 0;
// Performs a 'dump' Step without error calculation.
/**
* Same as Stepper() function above, but should perform a 'dump' step
* without error calculation. To be implemented in concrete derived classes.
*/
virtual void DumbStepper( const G4double y[],
const G4double dydx[],
G4double h,
G4double yout[] ) = 0;
/**
* Estimates the maximum distance of curved solution and chord.
*/
G4double DistChord() const override;
private:
// STATE
/** Data stored in order to find the chord. */
G4ThreeVector fInitialPoint, fMidPoint, fFinalPoint;
// Data stored in order to find the chord
// Dependent Objects, owned --- part of the STATE
/** Arrays 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(). */
G4double *yInitial, *yMiddle, *dydxMid, *yOneStep;
// 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().
};
#include "G4MagErrorStepper.icc"
@@ -25,7 +25,7 @@
//
// G4MagErrorStepper inline methods implementation
//
// Author: W.Wander <wwc@mit.edu>, 09.12.1997
// Author: W.Wander (MIT), 09.12.1997
// --------------------------------------------------------------------
inline
@@ -35,7 +35,7 @@
// - Most obtain an error by breaking up the step in two
// - G4ExactHelicalStepper does not provide an error estimate
// Created: J.Apostolakis, CERN - 05.11.1998
// Author: John Apostolakis (CERN), 05.11.1998
// --------------------------------------------------------------------
#ifndef G4MAGHELICALSTEPPER_HH
#define G4MAGHELICALSTEPPER_HH
@@ -47,76 +47,115 @@
#include "G4Mag_EqRhs.hh"
#include "G4ThreeVector.hh"
/**
* @brief G4MagHelicalStepper is an abstract base class for integrator of
* particle's equation of motion, used in tracking in space dependent magnetic
* field, and for a set of steppers which use the helix as 'first order'
* solution.
*/
class G4MagHelicalStepper : public G4MagIntegratorStepper
{
public:
/**
* Constructor for G4MagHelicalStepper.
* @param[in] EqRhs Pointer to the provided equation of motion.
*/
G4MagHelicalStepper(G4Mag_EqRhs *EqRhs);
~G4MagHelicalStepper() override;
/**
* Default Destructor.
*/
~G4MagHelicalStepper() override = default;
/**
* Copy constructor and assignment operator not allowed.
*/
G4MagHelicalStepper(const G4MagHelicalStepper&) = delete;
G4MagHelicalStepper& operator=(const G4MagHelicalStepper&) = delete;
/**
* The stepper for the Runge Kutta integration.
* The stepsize is fixed, with the step size given by 'h'.
* Integrates ODE starting values y[0 to 6].
* Outputs yout[] and its estimated error yerr[].
* @param[in] y Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[in] h The given step size.
* @param[out] yout Integration output.
* @param[out] yerr The estimated error.
*/
void Stepper( const G4double y[], // VIRTUAL for ExactHelix
const G4double dydx[],
G4double h,
G4double yout[],
G4double yerr[] ) override;
// The stepper for the Runge Kutta integration.
// The stepsize is fixed, equal to h.
// Integrates ODE starting values y[0 to 6]
// Outputs yout[] and its estimated error yerr[].
virtual void DumbStepper( const G4double y[],
G4ThreeVector Bfld,
G4double h,
G4double yout[] ) = 0;
// Performs a 'dump' Step without error calculation.
/**
* Same as Stepper() function above, but should perform a 'dump' step
* without error calculation. To be implemented in concrete derived classes.
*/
virtual void DumbStepper( const G4double y[],
G4ThreeVector Bfld,
G4double h,
G4double yout[] ) = 0;
/**
* Estimates the maximum distance of curved solution and chord.
*/
G4double DistChord()const override ;
// Estimate maximum distance of curved solution and chord ...
protected:
/**
* Performs a linear Step in regions without magnetic field.
*/
inline void LinearStep( const G4double yIn[],
G4double h,
G4double yHelix[]) const;
// A linear Step in regions without magnetic field.
/**
* A first order Step along a helix inside the field.
*/
void AdvanceHelix( const G4double yIn[],
const G4ThreeVector& Bfld,
G4double h,
G4double yHelix[], G4double yHelix2[] = nullptr);
// A first order Step along a helix inside the field.
/**
* Evaluates the field at a certain point.
*/
inline void MagFieldEvaluate( const G4double y[], G4ThreeVector& Bfield );
// Evaluate the field at a certain point.
/**
* Evaluates inverse of Curvature of Track.
*/
inline G4double GetInverseCurve( const G4double Momentum,
const G4double Bmag );
// Evaluate Inverse of Curvature of Track
// Store and use the parameters of track :
// radius of curve, Stepping angle, Radius of projected helix
/**
* Modifiers and accessors for storing and using the parameters of a track:
* radius of curve, Stepping angle, Radius of projected helix.
*/
inline void SetAngCurve(const G4double Ang);
inline G4double GetAngCurve()const;
inline void SetCurve(const G4double Curve);
inline G4double GetCurve()const;
inline void SetRadHelix(const G4double Rad);
inline G4double GetRadHelix()const;
private:
/** As in G4Mag_EqRhs.hh/cc where it is not used. */
static const G4double fUnitConstant;
// As in G4Mag_EqRhs.hh/cc where it is not used.
G4Mag_EqRhs* fPtrMagEqOfMot = nullptr;
// Data stored in order to find the chord
//
/** Data stored in order to find the chord. */
G4double fAngCurve = 0.0;
G4double frCurve = 0.0;
G4double frHelix = 0.0;
@@ -25,7 +25,7 @@
//
// G4MagHelicalStepper inline methods implementation
//
// Created: J.Apostolakis, CERN - 05.11.1998
// Author: John Apostolakis (CERN), 05.11.1998
// --------------------------------------------------------------------
inline void
@@ -30,9 +30,8 @@
// Provides a driver that talks to the Integrator Stepper, and insures that
// the error is within acceptable bounds.
// V.Grichine, 07.10.1996 - Created
// W.Wander, 28.01.1998 - Added ability for low order integrators
// J.Apostolakis, 08.11.2001 - Respect minimum step in AccurateAdvance
// Author: Vladimir Grichine (CERN), 07.10.1996 - Created
// W.Wander (MIT), 28.01.1998 - Added ability for low order integrators
// --------------------------------------------------------------------
#ifndef G4MAGINT_DRIVER_HH
#define G4MAGINT_DRIVER_HH
@@ -41,61 +40,123 @@
#include "G4MagIntegratorStepper.hh"
#include "G4ChordFinderDelegate.hh"
/**
* @brief G4MagInt_Driver provides a driver that talks to the Integrator
* Stepper and insures that the error is within acceptable bounds.
*/
class G4MagInt_Driver : public G4VIntegrationDriver,
public G4ChordFinderDelegate<G4MagInt_Driver>
{
public:
/**
* Constructor for G4MagInt_Driver.
* @param[in] hminimum The minumum allowed step.
* @param[in] pItsStepper Pointer to the integrator stepper.
* @param[in] numberOfComponents The number of integration variables.
* @param[in] statisticsVerbosity Flag for verbosity.
*/
G4MagInt_Driver(G4double hminimum,
G4MagIntegratorStepper* pItsStepper,
G4int numberOfComponents = 6,
G4int statisticsVerbosity = 0);
~G4MagInt_Driver() override;
// Constructor, destructor.
/**
* Destructor. Provides statistics if verbosity level is greater than 1.
*/
~G4MagInt_Driver() override;
/**
* Copy constructor and assignment operator not allowed.
*/
G4MagInt_Driver(const G4MagInt_Driver&) = delete;
G4MagInt_Driver& operator=(const G4MagInt_Driver&) = delete;
/**
* Computes the step to take, based on chord limits.
* @param[in,out] track The current track in field.
* @param[in] stepMax Proposed maximum step length.
* @param[in] epsStep Requested accuracy, y_err/hstep.
* @param[in] chordDistance Maximum sagitta distance.
* @returns The length of step taken.
*/
inline G4double AdvanceChordLimited(G4FieldTrack& track,
G4double stepMax,
G4double epsStep,
G4double chordDistance) override;
/**
* Dispatch interface method for initialisation/reset of driver.
*/
inline void OnStartTracking() override;
/**
* Dispatch interface method for computing step. Does nothing here.
*/
inline void OnComputeStep(const G4FieldTrack* = nullptr) override {}
/**
* The driver implements re-integration, so returns true.
*/
G4bool DoesReIntegrate() const override { return true; }
/**
* Advances integration accurately by relative accuracy better than 'eps'.
* @param[in,out] y_current The current track in field.
* @param[in] hstep Proposed step length.
* @param[in] eps Requested accuracy, y_err/hstep.
* @param[in] hinitial Initial minimum integration step.
* @returns true if integration succeeds.
*/
G4bool AccurateAdvance(G4FieldTrack& y_current,
G4double hstep,
G4double eps, // Requested y_err/hstep
G4double hinitial = 0.0) override;
// Above drivers for integrator (Runge-Kutta) with stepsize control.
// Integrates ODE starting values y_current
// from current s (s=s0) to s=s0+h with accuracy eps.
// On output ystart is replaced by value at end of interval.
// The concept is similar to the odeint routine from NRC p.721-722.
G4bool QuickAdvance( G4FieldTrack& y_val, // INOUT
/**
* Attempts one integration step, and returns estimated error 'dyerr'.
* It does not ensure accuracy.
* @param[in,out] y_val The current track in field.
* @param[in] dydx dydx array.
* @param[in] hstep Proposed step length.
* @param[out] dchord_step Estimated sagitta distance.
* @param[out] dyerr Estimated error.
* @returns true if integration succeeds.
*/
G4bool QuickAdvance(G4FieldTrack& y_val, // In/Out
const G4double dydx[],
G4double hstep,
G4double& dchord_step,
G4double& dyerr) override;
// QuickAdvance just tries one Step - it does not ensure accuracy.
G4double hstep,
G4double& dchord_step,
G4double& dyerr) override;
void StreamInfo( std::ostream& os ) const override;
// Write out the parameters / state of the driver
/**
* Writes out to stream the parameters/state of the driver.
*/
void StreamInfo( std::ostream& os ) const override;
G4bool QuickAdvance( G4FieldTrack& y_posvel, // INOUT
/**
* Attempts one integration step, and returns estimated error 'dyerr'.
* It does not ensure accuracy.
* @param[in,out] y_posvel The current track in field.
* @param[in] dydx dydx array.
* @param[in] hstep Proposed step length.
* @param[out] dchord_step Estimated sagitta distance.
* @param[out] dyerr_pos_sq Estimated error in position.
* @param[out] dyerr_mom_rel_sq Estimated error in momentum
* (normalised: Delta_Integration(p^2)/(p^2)).
* @returns true if integration succeeds.
*/
G4bool QuickAdvance(G4FieldTrack& y_posvel, // In/Out
const G4double dydx[],
G4double hstep, // IN
G4double& dchord_step,
G4double& dyerr_pos_sq,
G4double& dyerr_mom_rel_sq );
// New QuickAdvance that also just tries one Step
// (so also does not ensure accuracy)
// but does return the errors in position and
// momentum (normalised: Delta_Integration(p^2)/(p^2) )
G4double hstep, // In
G4double& dchord_step,
G4double& dyerr_pos_sq,
G4double& dyerr_mom_rel_sq );
/**
* Accessors.
*/
inline G4double GetHmin() const;
inline G4double Hmin() const; // Obsolete
inline G4double GetSafety() const;
@@ -104,95 +165,125 @@ class G4MagInt_Driver : public G4VIntegrationDriver,
inline G4double GetErrcon() const;
void GetDerivatives(const G4FieldTrack& y_curr, // INput
G4double dydx[]) const override; // OUTput
void GetDerivatives(const G4FieldTrack& track,
G4double dydx[],
G4double field[]) const override;
// Accessors
/**
* Getter and setter for the equation of motion.
*/
G4EquationOfMotion* GetEquationOfMotion() override;
void SetEquationOfMotion(G4EquationOfMotion* equation) override;
/**
* Sets a new stepper 'pItsStepper' for this driver. Then it calls
* ResetParameters() to update its parameters accordingly.
*/
void RenewStepperAndAdjust(G4MagIntegratorStepper* pItsStepper) override;
// Sets a new stepper pItsStepper for this driver. Then it calls
// ReSetParameters to reset its parameters accordingly.
/**
* Resets the qarameters according to the new provided safety value.
* i) sets the exponents (pgrow & pshrnk), using the current order;
* ii) sets the safety and calculates "errcon" according to the above values.
*/
inline void ReSetParameters(G4double new_safety = 0.9);
// i) sets the exponents (pgrow & pshrnk),
// using the current Stepper's order,
// ii) sets the safety
// ii) calculates "errcon" according to the above values.
/**
* Modifiers. When setting safety or pgrow, errcon will be set
* to a compatible value.
*/
inline void SetSafety(G4double valS);
inline void SetPshrnk(G4double valPs);
inline void SetPgrow (G4double valPg);
inline void SetErrcon(G4double valEc);
// When setting safety or pgrow, errcon will be set to a compatible value.
inline G4double ComputeAndSetErrcon();
/**
* Accessors for the integrator stepper.
*/
const G4MagIntegratorStepper* GetStepper() const override;
G4MagIntegratorStepper* GetStepper() override;
G4MagIntegratorStepper* GetStepper() override;
void OneGoodStep( G4double ystart[], // Like old RKF45step()
const G4double dydx[],
G4double& x,
G4double htry,
G4double eps, // memb variables ?
G4double& hdid,
G4double& hnext ) ;
// This takes one Step that is as large as possible while
// satisfying the accuracy criterion of:
// yerr < eps * |y_end-y_start|
/**
* Takes one Step that is as large as possible while satisfying the
* accuracy criterion of: yerr < eps * |y_end-y_start|.
* @param[in,out] ystart The current track state, y.
* @param[in] dydx The derivatives array.
* @param[in,out] x Step start, x.
* @param[in] htry Step to attempt.
* @param[in] eps The relative accuracy.
* @param[out] hdid Step achieved.
* @param[out] hnext Proposed next step.
* @returns true if integration succeeds.
*/
void OneGoodStep(G4double ystart[], // Like old RKF45step()
const G4double dydx[],
G4double& x,
G4double htry,
G4double eps,
G4double& hdid,
G4double& hnext ) ;
/**
* Takes the last step's normalised error and calculates a step size
* for the next step. Does it limit the next step's size within a factor
* of the current?
* -- DOES NOT limit for very bad steps
* -- DOES limit for very good (x5).
*/
G4double ComputeNewStepSize(G4double errMaxNorm, // normalised
G4double hstepCurrent) override;
// Taking the last step's normalised error, calculate
// a step size for the next step.
// Does it limit the next step's size within a factor of the current?
// -- DOES NOT limit for very bad steps
// -- DOES limit for very good (x5)
G4double
ComputeNewStepSize_WithoutReductionLimit(G4double errMaxNorm,
G4double hstepCurrent);
// Taking the last step's normalised error, calculate
// a step size for the next step.
// Do not limit the next step's size within a factor of the
// current one when *reducing* the size, i.e. for badly failing steps.
/**
* Taking the last step's normalised error, calculates a step size for
* the next step. Does not limit the next step's size within a factor of
* the current one when *reducing* the size, i.e. for badly failing steps.
*/
G4double ComputeNewStepSize_WithoutReductionLimit(G4double errMaxNorm,
G4double hstepCurrent);
/**
* Taking the last step's normalised error, calculates a step size for
* the next step. Limits the next step's size within a range around the
* current one.
*/
G4double ComputeNewStepSize_WithinLimits(G4double errMaxNorm, // normalised
G4double hstepCurrent);
// Taking the last step's normalised error, calculate
// a step size for the next step.
// Limit the next step's size within a range around the current one.
/**
* Modifier and accessor for the maximum number of steps that can be taken
* for the integration of a single segment, i.e. a single call to
* AccurateAdvance().
*/
inline G4int GetMaxNoSteps() const;
inline void SetMaxNoSteps(G4int val);
// Modify and Get the Maximum number of Steps that can be
// taken for the integration of a single segment -
// (i.e. a single call to AccurateAdvance).
/**
* More modifiers and accessors.
*/
inline void SetHmin(G4double newval);
void SetVerboseLevel(G4int newLevel) override;
G4int GetVerboseLevel() const override;
inline G4double GetSmallestFraction() const;
void SetSmallestFraction( G4double val );
protected:
/**
* Loggers, issuing warnings for undesirable situations.
*/
void WarnSmallStepSize(G4double hnext, G4double hstep,
G4double h, G4double xDone,
G4int noSteps);
void WarnTooManyStep(G4double x1start, G4double x2end, G4double xCurrent);
void WarnEndPointTooFar(G4double endPointDist,
G4double hStepSize ,
G4double epsilonRelative,
G4int debugFlag);
// Issue warnings for undesirable situations
/**
* Loggers for verbosity printouts.
*/
void PrintStatus(const G4double* StartArr,
G4double xstart,
const G4double* CurrentArr,
@@ -209,10 +300,10 @@ class G4MagInt_Driver : public G4VIntegrationDriver,
G4int subStepNo,
G4double subStepSize,
G4double dotVelocities);
// Verbose output for debugging
/**
* Reports on the number of steps, maximum errors etc.
*/
void PrintStatisticsReport();
// Report on the number of steps, maximum errors etc.
#ifdef QUICK_ADV_TWO
G4bool QuickAdvance( G4double yarrin[], // In
@@ -228,25 +319,31 @@ class G4MagInt_Driver : public G4VIntegrationDriver,
// ---------------------------------------------------------------
// INVARIANTS
/** Minimum Step allowed in a Step (in absolute units). */
G4double fMinimumStep = 0.0;
// Minimum Step allowed in a Step (in absolute units)
/** Smallest fraction of (existing) curve length, in relative units.
Below this fraction the current step will be the last. */
G4double fSmallestFraction = 1.0e-12; // Expected range 1e-12 to 5e-15
// Smallest fraction of (existing) curve length - in relative units
// below this fraction the current step will be the last
const G4int fNoIntegrationVariables = 0; // Variables in integration
const G4int fMinNoVars = 12; // Minimum number for FieldTrack
const G4int fNoVars = 0; // Full number of variable
/** Variables in integration. */
const G4int fNoIntegrationVariables = 0;
/** Minimum number for FieldTrack. */
const G4int fMinNoVars = 12;
/** Full number of variable. */
const G4int fNoVars = 0;
/** Default maximum number of steps is Base divided by the order of Stepper. */
G4int fMaxNoSteps;
G4int fMaxStepBase = 250; // was 5000
// Default maximum number of steps is Base divided by the order of Stepper
/** Parameters used to grow and shrink trial stepsize. */
G4double safety;
G4double pshrnk; // exponent for shrinking
G4double pgrow; // exponent for growth
G4double errcon;
// Parameters used to grow and shrink trial stepsize.
G4int fStatisticsVerboseLevel = 0;
@@ -258,15 +355,15 @@ class G4MagInt_Driver : public G4VIntegrationDriver,
// ---------------------------------------------------------------
// STATE
/** Step Statistics. */
unsigned long fNoTotalSteps=0, fNoBadSteps=0;
unsigned long fNoSmallSteps=0, fNoInitialSmallSteps=0, fNoCalls=0;
G4double fDyerr_max=0.0, fDyerr_mx2=0.0;
G4double fDyerrPos_smTot=0.0, fDyerrPos_lgTot=0.0, fDyerrVel_lgTot=0.0;
G4double fSumH_sm=0.0, fSumH_lg=0.0;
// Step Statistics
/** Could be varied during tracking - to help identify issues. */
G4int fVerboseLevel = 0; // Verbosity level for printing (debug, ..)
// Could be varied during tracking - to help identify issues
using ChordFinderDelegate = G4ChordFinderDelegate<G4MagInt_Driver>;
};
@@ -25,7 +25,7 @@
//
// G4MagInt_Driver inline methods implementation
//
// V.Grichine, 07.10.1996 - Created
// Author: Vladimir Grichine (CERN), 07.10.1996 - Created
// --------------------------------------------------------------------
inline
@@ -28,7 +28,7 @@
// Class description:
//
// Abstract base class for integrator of particle's equation of motion,
// used in tracking in space dependent magnetic field
// used in tracking in space dependent magnetic field.
//
// A Stepper must integrate over NumberOfVariables elements,
// and also copy (from input to output) any of NoStateVariables
@@ -36,117 +36,183 @@
//
// So it is expected that NoStateVariables >= NumberOfVariables
// Author: J.Apostolakis, CERN - 15.01.1997
// Author: John Apostolakis (CERN), 15.01.1997
// --------------------------------------------------------------------
#ifndef G4MAGINTEGRATORSTEPPER_HH
#define G4MAGINTEGRATORSTEPPER_HH
#include "G4Types.hh"
#include "G4EquationOfMotion.hh"
#include "G4FieldParameters.hh"
#include "G4VIntegrationDriver.hh"
#include "G4IntegrationDriver.hh"
class G4VIntegrationDriver;
/**
* @brief G4MagIntegratorStepper is an abstract base class for integrator
* of particle's equation of motion, used in tracking in space dependent
* magnetic field.
*/
class G4MagIntegratorStepper
{
public: // with description
public:
G4MagIntegratorStepper(G4EquationOfMotion* Equation,
G4int numIntegrationVariables,
G4int numStateVariables = 12,
G4bool isFSAL = false );
/**
* Constructor for G4MagIntegratorStepper.
* @param[in] Equation Pointer to the provided equation of motion.
* @param[in] numIntegrationVariables The number of integration variables.
* @param[in] numStateVariables The number of state variables.
* @param[in] isFSAL Flag to indicate if it is an FSAL (First Same As Last)
* type driver.
*/
G4MagIntegratorStepper(G4EquationOfMotion* Equation,
G4int numIntegrationVariables,
G4int numStateVariables = 12,
G4bool isFSAL = false );
virtual ~G4MagIntegratorStepper() = default;
// Constructor and destructor. No actions.
/**
* Default virtual Destructor.
*/
virtual ~G4MagIntegratorStepper() = default;
G4MagIntegratorStepper(const G4MagIntegratorStepper&) = delete;
G4MagIntegratorStepper& operator=(const G4MagIntegratorStepper&) = delete;
/**
* Copy constructor and assignment operator not allowed.
*/
G4MagIntegratorStepper(const G4MagIntegratorStepper&) = delete;
G4MagIntegratorStepper& operator=(const G4MagIntegratorStepper&) = delete;
virtual void Stepper( const G4double y[],
const G4double dydx[],
G4double h,
G4double yout[],
G4double yerr[] ) = 0;
// The stepper for the Runge Kutta integration.
// The stepsize is fixed, with the Step size given by h.
// Integrates ODE starting values y[0 to 6].
// Outputs yout[] and its estimated error yerr[].
/**
* The stepper for the Runge Kutta integration.
* The stepsize is fixed, with the step size given by 'h'.
* Integrates ODE starting values y[0 to 6].
* Outputs yout[] and its estimated error yerr[].
* @param[in] y Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[in] h The given step size.
* @param[out] yout Integration output.
* @param[out] yerr The estimated error.
*/
virtual void Stepper( const G4double y[],
const G4double dydx[],
G4double h,
G4double yout[],
G4double yerr[] ) = 0;
virtual G4double DistChord() const = 0;
// Estimate the maximum distance of a chord from the true path
// over the segment last integrated.
/**
* Estimates the maximum distance of a chord from the true path
* over the segment last integrated.
*/
virtual G4double DistChord() const = 0;
inline void NormaliseTangentVector( G4double vec[6] );
// Simple utility function to (re)normalise 'unit velocity' vector.
/**
* Simple utility function to (re)normalise 'unit velocity' vector.
*/
inline void NormaliseTangentVector( G4double vec[6] );
inline void NormalisePolarizationVector( G4double vec[12] );
// Simple utility function to (re)normalise 'unit spin' vector.
/**
* Simple utility function to (re)normalise 'unit spin' vector.
*/
inline void NormalisePolarizationVector( G4double vec[12] );
inline void RightHandSide( const G4double y[], G4double dydx[] ) const;
// Utility method to supply the standard Evaluation of the
// Right Hand side of the associated equation.
/**
* Utility method to supply the standard Evaluation of the
* Right Hand side of the associated equation.
*/
inline void RightHandSide( const G4double y[], G4double dydx[] ) const;
inline void RightHandSide( const G4double y[],
G4double dydx[],
G4double field[] ) const;
// Calculate dydx and field at point y.
/**
* Calculates 'dydx' and 'field' at point 'y'.
*/
inline void RightHandSide( const G4double y[],
G4double dydx[],
G4double field[] ) const;
inline G4int GetNumberOfVariables() const;
// Get the number of variables that the stepper will integrate over.
/**
* Returns the number of variables that the stepper will integrate over.
*/
inline G4int GetNumberOfVariables() const;
inline G4int GetNumberOfStateVariables() const;
// Get the number of variables of state variables (>= above, integration)
/**
* Returns the number of variables of state variables (>= above, integration).
*/
inline G4int GetNumberOfStateVariables() const;
virtual G4int IntegratorOrder() const = 0;
// Returns the order of the integrator
// i.e. its error behaviour is of the order O(h^order).
/**
* Returns the order of the integrator, i.e. its error behaviour is of
* the order O(h^order).
*/
virtual G4int IntegratorOrder() const = 0;
inline G4int IntegrationOrder();
// Replacement method - using new data member
/**
* Returns the stepper type ID ('kUserStepper').
* This function should be overriden in derived classes.
*/
virtual G4StepperType StepperType() const { return kUserStepper; }
/**
* Replacement method - using new data member.
*/
inline G4int IntegrationOrder();
inline G4EquationOfMotion* GetEquationOfMotion();
inline const G4EquationOfMotion* GetEquationOfMotion() const;
// As some steppers (eg RKG3) require other methods of Eq_Rhs
// this function allows for access to them.
/**
* Methods returning the pointer to the associated equation of motion.
* As some steppers (e.g. RKG3) require other methods of Eq_Rhs this
* function allows for access to them.
*/
inline G4EquationOfMotion* GetEquationOfMotion();
inline const G4EquationOfMotion* GetEquationOfMotion() const;
inline void SetEquationOfMotion(G4EquationOfMotion* newEquation);
/**
* Setter for the equation of motion.
*/
inline void SetEquationOfMotion(G4EquationOfMotion* newEquation);
inline unsigned long GetfNoRHSCalls();
inline void ResetfNORHSCalls();
// Count number of calls to RHS method(s)
/**
* Methods for counting/resetting the number of calls to RHS method(s).
*/
inline unsigned long GetfNoRHSCalls();
inline void ResetfNORHSCalls();
inline G4bool IsFSAL() const;
/**
* Returns true if the stepper is of FSAL (First Same As Last) type.
*/
inline G4bool IsFSAL() const;
// TODO - QSS
inline G4bool isQSS() const { return fIsQSS; }
void SetIsQSS(G4bool val){ fIsQSS= val;}
/**
* Returns true if the stepper is of QSS (Quantum State Simulation) type.
*/
inline G4bool isQSS() const;
inline void SetIsQSS(G4bool val);
protected:
protected:
inline void SetIntegrationOrder(G4int order);
inline void SetFSAL(G4bool flag = true);
/**
* Setters for the integration order and FSAL type.
*/
inline void SetIntegrationOrder(G4int order);
inline void SetFSAL(G4bool flag = true);
private:
G4EquationOfMotion* fEquation_Rhs = nullptr;
const G4int fNoIntegrationVariables = 0; // Variables in integration
const G4int fNoStateVariables = 0; // Number required for FieldTrack
G4EquationOfMotion* fEquation_Rhs = nullptr;
const G4int fNoIntegrationVariables = 0; // Variables in integration
const G4int fNoStateVariables = 0; // Number required for FieldTrack
mutable unsigned long fNoRHSCalls = 0UL;
// Counter for calls to RHS method
/** Counter for calls to RHS method. */
mutable unsigned long fNoRHSCalls = 0UL;
// Parameters of a RK method -- must be shared by all steppers of a type
// -- Invariants for a class
// Parameters of a RK method -- must be shared by all steppers of a type
// -- Invariants for a class
G4int fIntegrationOrder = -1; // must be set by stepper !!!
// All ClassicalRK4 steppers are 4th order
G4bool fIsFSAL = false;
// Depends on RK method & implementation
G4bool fIsQSS = false;
G4int fIntegrationOrder = -1; // must be set by stepper !!!
// All ClassicalRK4 steppers are 4th order
G4bool fIsFSAL = false;
// Depends on RK method & implementation
G4bool fIsQSS = false;
};
#include "G4MagIntegratorStepper.icc"
#endif /* G4MAGIntegratorSTEPPER */
#endif
@@ -25,7 +25,7 @@
//
// G4MagIntegratorStepper inline methods implementation
//
// Author: J.Apostolakis, CERN - 15.01.1997
// Author: John Apostolakis (CERN), 15.01.1997
// --------------------------------------------------------------------
inline
@@ -73,6 +73,18 @@ G4bool G4MagIntegratorStepper::IsFSAL() const
return fIsFSAL;
}
inline
G4bool G4MagIntegratorStepper::isQSS() const
{
return fIsQSS;
}
inline
void G4MagIntegratorStepper::SetIsQSS(G4bool val)
{
fIsQSS = val;
}
inline
void G4MagIntegratorStepper::SetIntegrationOrder(G4int order)
{
@@ -32,7 +32,7 @@
// i) is when using a moving reference frame ... or
// ii) extending for other forces, e.g. an electric field
// Created: J.Apostolakis, CERN - 13.01.1997
// Author: John Apostolakis (CERN), 13.01.1997
// --------------------------------------------------------------------
#ifndef G4MAG_EQRHS_HH
#define G4MAG_EQRHS_HH
@@ -43,36 +43,53 @@
class G4MagneticField;
/**
* @brief G4Mag_EqRhs is the "standard" equation of motion of a particle
* in a pure magnetic field.
*/
class G4Mag_EqRhs : public G4EquationOfMotion
{
public:
/**
* Constructor for G4Mag_EqRhs.
* @param[in] magField Pointer to the associated magnetic field.
*/
G4Mag_EqRhs(G4MagneticField* magField);
~G4Mag_EqRhs() override;
// Constructor and destructor. No actions.
/**
* Default Destructor.
*/
~G4Mag_EqRhs() override = default;
/**
* Calculates the value of the derivative, given the value of the field.
* @param[in] y Coefficients array.
* @param[in] B Field value.
* @param[out] dydx Derivatives array.
*/
void EvaluateRhsGivenB( const G4double y[],
const G4double B[3],
G4double dydx[] ) const override = 0;
// Given the value of the field "B", this function
// calculates the value of the derivative dydx.
// This is the _only_ function a subclass must define.
// The other two functions use Rhs_givenB.
/**
* Returns and sets the charge momentum mass value.
*/
inline G4double FCof() const { return fCof_val; }
void SetChargeMomentumMass( G4ChargeState particleCharge,
G4double MomentumXc,
G4double mass ) override;
private:
/** Charge momentum mass. */
G4double fCof_val = 0.0;
/** Coefficient in the Lorentz motion equation (Lorentz force), if the
magnetic field B is in Tesla, the particle charge in units of the
elementary charge, the momentum P in MeV/c, and the space coordinates
and path along the trajectory in mm. */
static const G4double fUnitConstant; // Set to 0.299792458
// Coefficient in the Lorentz motion equation (Lorentz force), if the
// magnetic field B is in Tesla, the particle charge in units of the
// elementary (positron?) charge, the momentum P in MeV/c, and the
// space coordinates and path along the trajectory in mm.
};
#endif
@@ -31,7 +31,7 @@
// magnetic field. The three components of the particle's spin are
// treated utilising BMT equation.
// Created: J.Apostolakis, P.Gumplinger - 08.02.1999
// Authors: John Apostolakis (CERN) & Peter Gumplinger (TRIUMF), 08.02.1999
// --------------------------------------------------------------------
#ifndef G4MAG_SPIN_EQRHS_HH
#define G4MAG_SPIN_EQRHS_HH
@@ -42,33 +42,60 @@
class G4MagneticField;
/**
* @brief G4Mag_SpinEqRhs defines the equation of motion for a particle with
* spin in a pure magnetic field. The three components of the particle's spin
* are treated utilising BMT equation.
*/
class G4Mag_SpinEqRhs : public G4Mag_EqRhs
{
public:
public:
G4Mag_SpinEqRhs( G4MagneticField* MagField );
~G4Mag_SpinEqRhs() override;
// Constructor and destructor. No actions.
/**
* Constructor for G4Mag_SpinEqRhs.
* @param[in] MagField Pointer to the associated magnetic field.
*/
G4Mag_SpinEqRhs( G4MagneticField* MagField );
void SetChargeMomentumMass(G4ChargeState particleCharge,
G4double MomentumXc,
G4double mass) override;
/**
* Default Destructor.
*/
~G4Mag_SpinEqRhs() override = default;
void EvaluateRhsGivenB( const G4double y[],
const G4double B[3],
G4double dydx[] ) const override;
// Given the value of the magnetic field B, this function
// calculates the value of the derivative dydx.
/**
* Sets the charge momentum mass value.
*/
void SetChargeMomentumMass(G4ChargeState particleCharge,
G4double MomentumXc,
G4double mass) override;
inline void SetAnomaly(G4double a) { anomaly = a; }
inline G4double GetAnomaly() const { return anomaly; }
// set/get magnetic anomaly
/**
* Calculates the value of the derivative, given the value of the field.
* @param[in] y Coefficients array.
* @param[in] B Field value.
* @param[out] dydx Derivatives array.
*/
void EvaluateRhsGivenB( const G4double y[],
const G4double B[3],
G4double dydx[] ) const override;
private:
/**
* Setter and getter for the magnetic anomaly.
*/
inline void SetAnomaly(G4double a) { anomaly = a; }
inline G4double GetAnomaly() const { return anomaly; }
G4double charge=0.0, mass=0.0, magMoment=0.0, spin=0.0;
G4double omegac=0.0, anomaly=0.0011659208;
G4double beta=0.0, gamma=0.0;
/**
* Returns the equation of motion type ID, i.e. "kEqMagneticWithSpin".
*/
inline G4EquationType GetEquationType() const override { return kEqMagneticWithSpin; }
private:
G4double charge=0.0, mass=0.0, magMoment=0.0, spin=0.0;
G4double omegac=0.0, anomaly=0.0011659208;
G4double beta=0.0, gamma=0.0;
};
#endif
@@ -32,7 +32,7 @@
// frame ... or extending the class to include additional Forces,
// eg an electric field
// Created: J.Apostolakis, CERN - 13.01.1997
// Author: John Apostolakis (CERN), 13.01.1997
// --------------------------------------------------------------------
#ifndef G4MAG_USUAL_EQRHS
#define G4MAG_USUAL_EQRHS
@@ -42,23 +42,48 @@
class G4MagneticField;
/**
* @brief G4Mag_UsualEqRhs defines the standard right-hand side
* for equation of motion.
*/
class G4Mag_UsualEqRhs : public G4Mag_EqRhs
{
public:
public:
G4Mag_UsualEqRhs( G4MagneticField* MagField );
~G4Mag_UsualEqRhs() override;
// Constructor and destructor. No actions.
/**
* Constructor for G4Mag_UsualEqRhs.
* @param[in] MagField Pointer to the associated magnetic field.
*/
G4Mag_UsualEqRhs( G4MagneticField* MagField );
void EvaluateRhsGivenB( const G4double y[],
const G4double B[3],
G4double dydx[] ) const override;
// Given the value of the magnetic field B, this function
// calculates the value of the derivative dydx.
/**
* Default Destructor.
*/
~G4Mag_UsualEqRhs() override = default;
// Constructor and destructor. No actions.
void SetChargeMomentumMass( G4ChargeState particleCharge,
G4double MomentumXc,
G4double mass ) override;
/**
* Calculates the value of the derivative, given the value of the field.
* @param[in] y Coefficients array.
* @param[in] B Field value.
* @param[out] dydx Derivatives array.
*/
void EvaluateRhsGivenB( const G4double y[],
const G4double B[3],
G4double dydx[] ) const override;
/**
* Sets the charge momentum mass value.
*/
void SetChargeMomentumMass( G4ChargeState particleCharge,
G4double MomentumXc,
G4double mass ) override;
/**
* Returns the equation of motion type ID, i.e. "kEqMagnetic".
*/
inline G4EquationType GetEquationType() const override { return kEqMagnetic; }
};
#endif
@@ -29,7 +29,7 @@
//
// Magnetic Field abstract class, implements inquiry function interface.
// Created: J.Apostolakis, CERN - 13.01.1996
// Author: John Apostolakis (CERN), 13.01.1996
// --------------------------------------------------------------------
#ifndef G4MAGNETIC_FIELD_HH
#define G4MAGNETIC_FIELD_HH
@@ -41,19 +41,37 @@ class G4MagneticField : public G4Field
{
public:
/**
* Default Constructor and Destructor.
*/
G4MagneticField();
~G4MagneticField() override;
// Constructor and destructor. No actions.
~G4MagneticField() override = default;
/**
* Copy constructor and assignment operator.
*/
G4MagneticField(const G4MagneticField& r);
G4MagneticField& operator= (const G4MagneticField& p);
// Copy constructor & assignment operator.
/**
* Since a pure magnetic field does not change track energy, returns false.
*/
inline G4bool DoesFieldChangeEnergy() const override { return false; }
// Since a pure magnetic field does not change track energy
/**
* Given the position time vector 'Point', returns the value of the
* field in the array 'Bfield'.
* @param[in] Point The position time vector.
* @param[out] Bfield The field array in output.
*/
void GetFieldValue( const G4double Point[4],
G4double* Bfield ) const override = 0;
/**
* Returns the field type-ID, "kMagnetic".
* This should be overriden in derived classes.
*/
inline G4FieldType GetFieldType() const override { return kMagnetic; }
};
#endif
@@ -26,10 +26,10 @@
//
// Class description:
//
// Modified midpoint method implementation, based on Boost odeint
// Modified midpoint method implementation, based on Boost odeint.
// Author: Dmitry Sorokin, Google Summer of Code 2016
// Supervision: John Apostolakis, CERN
// Author: Dmitry Sorokin (CERN, Google Summer of Code 2016), 07.10.2016
// Supervision: John Apostolakis (CERN)
// --------------------------------------------------------------------
#ifndef G4MODIFIED_MIDPOINT_HH
#define G4MODIFIED_MIDPOINT_HH
@@ -38,31 +38,74 @@
#include "G4EquationOfMotion.hh"
#include "G4FieldTrack.hh"
/**
* @brief G4ModifiedMidpoint implements a midpoint method adapted from
* Boost odeint.
*/
class G4ModifiedMidpoint
{
public:
/**
* Constructor for G4ModifiedMidpoint.
* @param[in] equation Pointer to the provided equation of motion.
* @param[in] nvar The number of integration variables.
* @param[in] steps The minimum number of steps.
*/
G4ModifiedMidpoint( G4EquationOfMotion* equation,
G4int nvar = 6, G4int steps = 2 );
~G4ModifiedMidpoint() = default;
/**
* Default Destructor.
*/
~G4ModifiedMidpoint() = default;
/**
* Computes one step.
* @param[in] yIn Starting values array of integration variables.
* @param[in] dydxIn Derivatives array in input.
* @param[out] yOut Integration output.
* @param[in] hstep The given step size.
*/
void DoStep( const G4double yIn[], const G4double dydxIn[],
G4double yOut[], G4double hstep) const;
/**
* Computes one step, as above but using also intermediate values.
* @param[in] yIn Starting values array of integration variables.
* @param[in] dydxIn Derivatives array in input.
* @param[out] yOut Integration output.
* @param[in] hstep The given step size.
* @param[in] yMid Mid point integration variables.
* @param[in] derivs Intermediate derivatives.
*/
void DoStep( const G4double yIn[], const G4double dydxIn[],
G4double yOut[], G4double hstep, G4double yMid[],
G4double derivs[][G4FieldTrack::ncompSVEC]) const;
/**
* Setter and getter for steps.
*/
inline void SetSteps(G4int steps);
inline G4int GetSteps() const;
/**
* Setter and getter for the equation of motion.
*/
inline void SetEquationOfMotion(G4EquationOfMotion* equation);
inline G4EquationOfMotion* GetEquationOfMotion();
inline G4EquationOfMotion* GetEquationOfMotion() const;
/**
* Returns the number of integration variables.
*/
inline G4int GetNumberOfVariables() const;
private:
/**
* Utility for copying array content from 'src' to 'dst'.
*/
void copy(G4double dst[], const G4double src[]) const;
private:
@@ -25,31 +25,31 @@
//
// G4ModifiedMidpoint inline methods implementation
//
// Author: Dmitry Sorokin, Google Summer of Code 2016
// Supervision: John Apostolakis, CERN
// Author: Dmitry Sorokin (CERN, Google Summer of Code 2016), 07.10.2016
// Supervision: John Apostolakis (CERN)
// --------------------------------------------------------------------
inline void G4ModifiedMidpoint::SetSteps(G4int steps)
{
fsteps = steps;
fsteps = steps;
}
inline G4int G4ModifiedMidpoint::GetSteps() const
{
return fsteps;
return fsteps;
}
inline void G4ModifiedMidpoint::SetEquationOfMotion(G4EquationOfMotion* eq)
{
fEquation = eq;
fEquation = eq;
}
inline G4EquationOfMotion* G4ModifiedMidpoint::GetEquationOfMotion()
inline G4EquationOfMotion* G4ModifiedMidpoint::GetEquationOfMotion() const
{
return fEquation;
return fEquation;
}
inline G4int G4ModifiedMidpoint::GetNumberOfVariables() const
{
return fnvar;
return fnvar;
}
@@ -29,9 +29,9 @@
//
// This is the right-hand side of equation of motion for monopole
// in a combined electric and magnetic field:
// d(p_c)/ds=g{c-energyB_ - p_c x E}/pc
// d(p_c)/ds=g{c-energyB_ - p_c x E}/pc.
// Created: V.Grichine, 17.11.2009
// Author: Vladimir Grichine (CERN), 17.11.2009
// -------------------------------------------------------------------
#ifndef G4EQMAGELECTRICFIELD_HH
#define G4EQMAGELECTRICFIELD_HH
@@ -40,22 +40,52 @@
#include "G4EquationOfMotion.hh"
#include "G4ElectroMagneticField.hh"
/**
* @brief G4MonopoleEq defines the right-hand side of equation of motion
* for monopole in a combined electric and magnetic field:
* d(p_c)/ds=g{c-energyB_ - p_c x E}/pc.
*/
class G4MonopoleEq : public G4EquationOfMotion
{
public:
G4MonopoleEq(G4ElectroMagneticField* emField );
~G4MonopoleEq() override;
/**
* Constructor for G4MonopoleEq.
* @param[in] emField Pointer to the field.
*/
G4MonopoleEq(G4ElectroMagneticField* emField);
/**
* Default Destructor.
*/
~G4MonopoleEq() override = default;
/**
* Sets the charge, momentum and mass of the current particle.
* Used to set the equation's coefficients.
* @param[in] particleCharge Magnetic charge and moments in e+ units.
* @param[in] MomentumXc Particle momentum.
* @param[in] mass Particle mass.
*/
void SetChargeMomentumMass(G4ChargeState particleCharge,
G4double MomentumXc,
G4double mass) override;
/**
* Calculates the value of the derivative, given the value of the field.
* @param[in] y Coefficients array.
* @param[in] Field Field value.
* @param[out] dydx Derivatives array.
*/
void EvaluateRhsGivenB(const G4double y[],
const G4double Field[],
G4double dydx[] ) const override;
// Given the value of the electromagnetic field, this function
// calculates the value of the derivative dydx.
/**
* Returns the equation type-ID, "kEqMonopole".
*/
inline G4EquationType GetEquationType() const override { return kEqMonopole; }
private:
@@ -34,10 +34,9 @@
// Notes: 1) field must be time-independent.
// 2) time is not integrated
// Created: I.Gavrilenko, 15.05.2009 (as G4AtlasRK4)
// Adaptations: J.Apostolakis, November 2009
// Author: Igor Gavrilenko (CERN), 15.05.2009 (as G4AtlasRK4)
// Adaptations: John Apostolakis (CERN), 05.11.2009
// -------------------------------------------------------------------
#ifndef G4NYSTROMRK4_HH
#define G4NYSTROMRK4_HH
@@ -48,37 +47,81 @@
#include <memory>
/**
* @brief G4NystromRK4 integrates the equations of the motion of a particle
* in a magnetic field using 4th Runge-Kutta-Nystrom method with errors
* estimation. The current form can be used only for 'pure' magnetic field.
*/
class G4NystromRK4 : public G4MagIntegratorStepper
{
public:
/**
* Constructor for G4NystromRK4. Can be used only for Magnetic Fields
* and for 6 variables (x,p).
* @param[in] EquationMotion Pointer to the provided equation of motion.
* @param[in] distanceConstField Distance value for constant field.
*/
G4NystromRK4(G4Mag_EqRhs* EquationMotion,
G4double distanceConstField = 0.0);
// Can be used only for Magnetic Fields - and for 6 variables (x,p)
/**
* Default Destructor.
*/
~G4NystromRK4() override = default;
/**
* 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 6].
* Outputs yOut[] and its estimated error yError[].
* Provides error via analytical method.
* @param[in] y Starting values array of integration variables.
* @param[in] dydx Derivatives array.
* @param[in] hstep The given step size.
* @param[out] yOut Integration output.
* @param[out] yError The estimated error.
*/
void Stepper(const G4double y[],
const G4double dydx[],
G4double hstep,
G4double yOut[],
G4double yError[]) override;
// Single call for integration result and error
// Provides error via analytical method
/**
* Setter and getter for the distance value for constant field.
*/
void SetDistanceForConstantField(G4double length);
G4double GetDistanceForConstantField() const;
G4int IntegratorOrder() const override { return 4; }
/**
* Returns the order, 4, of integration.
*/
inline G4int IntegratorOrder() const override;
/**
* Returns the distance from chord line.
*/
G4double DistChord() const override;
/**
* Returns the stepper type-ID, "kNystromRK4".
*/
inline G4StepperType StepperType() const override;
private:
/**
* Private accessors for field data.
*/
inline void GetFieldValue(const G4double point[4], G4double field[3]);
inline G4double GetFCof();
G4CachedMagneticField* GetField();
const G4CachedMagneticField* GetField() const;
private:
G4double fMomentum = 0.0;
G4double fMomentum2 = 0.0;
G4double fInverseMomentum = 0.0;
@@ -25,8 +25,8 @@
//
// G4NystromRK4 inline methods implementation
//
// Created: I.Gavrilenko, 15.05.2009 (as G4AtlasRK4)
// Adaptations: J.Apostolakis, November 2009
// Author: Igor Gavrilenko (CERN), 15.05.2009 (as G4AtlasRK4)
// Adaptations: John Apostolakis (CERN), 05.11.2009
// -------------------------------------------------------------------
void G4NystromRK4::GetFieldValue(const G4double point[4], G4double field[3])
@@ -38,3 +38,13 @@ G4double G4NystromRK4::GetFCof()
{
return static_cast<G4Mag_EqRhs*>(GetEquationOfMotion())->FCof();
}
G4int G4NystromRK4::IntegratorOrder() const
{
return 4;
}
G4StepperType G4NystromRK4::StepperType() const
{
return kNystromRK4;
}
@@ -30,9 +30,8 @@
// Provides a driver that talks to the Integrator Stepper, and insures that
// the error is within acceptable bounds.
// V.Grichine, 07.10.1996 - Created
// W.Wander, 28.01.1998 - Added ability for low order integrators
// J.Apostolakis, 08.11.2001 - Respect minimum step in AccurateAdvance
// Author: Vladimir Grichine (CERN), 07.10.1996 - Created
// W.Wander (MIT), 28.01.1998 - Added ability for low order integrators
// --------------------------------------------------------------------
#ifndef G4OLD_MAGINT_DRIVER_HH
#define G4OLD_MAGINT_DRIVER_HH
@@ -41,57 +40,118 @@
#include "G4MagIntegratorStepper.hh"
#include "G4ChordFinderDelegate.hh"
/**
* @brief G4OldMagIntDriver provides a driver that talks to the Integrator
* Stepper and insures that the error is within acceptable bounds.
*/
class G4OldMagIntDriver : public G4VIntegrationDriver,
public G4ChordFinderDelegate<G4OldMagIntDriver>
{
public:
/**
* Constructor for G4OldMagIntDriver.
* @param[in] hminimum The minumum allowed step.
* @param[in] pItsStepper Pointer to the integrator stepper.
* @param[in] numberOfComponents The number of integration variables.
* @param[in] statisticsVerbosity Flag for verbosity.
*/
G4OldMagIntDriver(G4double hminimum,
G4MagIntegratorStepper* pItsStepper,
G4int numberOfComponents = 6,
G4int statisticsVerbosity = 0);
~G4OldMagIntDriver() override;
// Constructor, destructor.
/**
* Destructor. Provides statistics if verbosity level is greater than 1.
*/
~G4OldMagIntDriver() override;
/**
* Copy constructor and assignment operator not allowed.
*/
G4OldMagIntDriver(const G4OldMagIntDriver&) = delete;
G4OldMagIntDriver& operator=(const G4OldMagIntDriver&) = delete;
/**
* Computes the step to take, based on chord limits.
* @param[in,out] track The current track in field.
* @param[in] stepMax Proposed maximum step length.
* @param[in] epsStep Requested accuracy, y_err/hstep.
* @param[in] chordDistance Maximum sagitta distance.
* @returns The length of step taken.
*/
inline G4double AdvanceChordLimited(G4FieldTrack& track,
G4double stepMax,
G4double epsStep,
G4double chordDistance) override;
/**
* Dispatch interface method for initialisation/reset of driver.
*/
inline void OnStartTracking() override;
inline void OnComputeStep(const G4FieldTrack* = nullptr) override {}
inline G4bool DoesReIntegrate() const override { return true; }
/**
* Dispatch interface method for computing step. Does nothing here.
*/
inline void OnComputeStep(const G4FieldTrack* = nullptr) override;
/**
* The driver implements re-integration, so returns true.
*/
inline G4bool DoesReIntegrate() const override;
/**
* Advances integration accurately by relative accuracy better than 'eps'.
* @param[in,out] y_current The current track in field.
* @param[in] hstep Proposed step length.
* @param[in] eps Requested accuracy, y_err/hstep.
* @param[in] hinitial Initial minimum integration step.
* @returns true if integration succeeds.
*/
G4bool AccurateAdvance(G4FieldTrack& y_current,
G4double hstep,
G4double eps, // Requested y_err/hstep
G4double hinitial = 0.0) override;
// Above drivers for integrator (Runge-Kutta) with stepsize control.
// Integrates ODE starting values y_current
// from current s (s=s0) to s=s0+h with accuracy eps.
// On output ystart is replaced by value at end of interval.
// The concept is similar to the odeint routine from NRC p.721-722.
G4bool QuickAdvance(G4FieldTrack& y_val, // INOUT
/**
* Attempts one integration step, and returns estimated error 'dyerr'.
* It does not ensure accuracy.
* @param[in,out] y_val The current track in field.
* @param[in] dydx dydx array.
* @param[in] hstep Proposed step length.
* @param[out] dchord_step Estimated sagitta distance.
* @param[out] dyerr Estimated error.
* @returns true if integration succeeds.
*/
G4bool QuickAdvance(G4FieldTrack& y_val, // In/Out
const G4double dydx[],
G4double hstep,
G4double& dchord_step,
G4double& dyerr) override;
// QuickAdvance just tries one Step - it does not ensure accuracy.
G4bool QuickAdvance( G4FieldTrack& y_posvel, // INOUT
/**
* Attempts one integration step, and returns estimated error 'dyerr'.
* It does not ensure accuracy.
* @param[in,out] y_posvel The current track in field.
* @param[in] dydx dydx array.
* @param[in] hstep Proposed step length.
* @param[out] dchord_step Estimated sagitta distance.
* @param[out] dyerr_pos_sq Estimated error in position.
* @param[out] dyerr_mom_rel_sq Estimated error in momentum
* (normalised: Delta_Integration(p^2)/(p^2)).
* @returns true if integration succeeds.
*/
G4bool QuickAdvance(G4FieldTrack& y_posvel, // In/Out
const G4double dydx[],
G4double hstep, // IN
G4double& dchord_step,
G4double& dyerr_pos_sq,
G4double& dyerr_mom_rel_sq);
// QuickAdvance that also just tries one Step (so also does not
// ensure accuracy), but does return the errors in position and
// momentum (normalised: Delta_Integration(p^2)/(p^2) ).
G4double hstep, // In
G4double& dchord_step,
G4double& dyerr_pos_sq,
G4double& dyerr_mom_rel_sq);
/**
* Accessors.
*/
inline G4double GetHmin() const;
inline G4double Hmin() const; // Obsolete
inline G4double GetSafety() const;
@@ -100,46 +160,63 @@ class G4OldMagIntDriver : public G4VIntegrationDriver,
inline G4double GetErrcon() const;
void GetDerivatives(const G4FieldTrack& y_curr, // INput
G4double dydx[]) const override; // OUTput
void GetDerivatives(const G4FieldTrack& track,
G4double dydx[],
G4double field[]) const override;
// Accessors
/**
* Getter and setter for the equation of motion.
*/
G4EquationOfMotion* GetEquationOfMotion() override;
void SetEquationOfMotion(G4EquationOfMotion* equation) override;
/**
* Sets a new stepper 'pItsStepper' for this driver. Then it calls
* ResetParameters() to update its parameters accordingly.
*/
void RenewStepperAndAdjust(G4MagIntegratorStepper* pItsStepper) override;
// Sets a new stepper pItsStepper for this driver. Then it calls
// ReSetParameters to reset its parameters accordingly.
/**
* Resets the qarameters according to the new provided safety value.
* i) sets the exponents (pgrow & pshrnk), using the current order;
* ii) sets the safety and calculates "errcon" according to the above values.
*/
inline void ReSetParameters(G4double new_safety = 0.9);
// i) sets the exponents (pgrow & pshrnk),
// using the current Stepper's order,
// ii) sets the safety
// ii) calculates "errcon" according to the above values.
/**
* Modifiers. When setting safety or pgrow, errcon will be set
* to a compatible value.
*/
inline void SetSafety(G4double valS);
inline void SetPshrnk(G4double valPs);
inline void SetPgrow (G4double valPg);
inline void SetErrcon(G4double valEc);
// When setting safety or pgrow, errcon will be set to a compatible value.
inline G4double ComputeAndSetErrcon();
/**
* Accessors for the integrator stepper.
*/
const G4MagIntegratorStepper* GetStepper() const override;
G4MagIntegratorStepper* GetStepper() override;
G4MagIntegratorStepper* GetStepper() override;
void OneGoodStep( G4double ystart[], // Like old RKF45step()
const G4double dydx[],
G4double& x,
G4double htry,
G4double eps, // memb variables ?
G4double& hdid,
G4double& hnext) ;
// This takes one Step that is as large as possible while
// satisfying the accuracy criterion of:
// yerr < eps * |y_end-y_start|
/**
* Takes one Step that is as large as possible while satisfying the
* accuracy criterion of: yerr < eps * |y_end-y_start|.
* @param[in,out] ystart The current track state, y.
* @param[in] dydx The derivatives array.
* @param[in,out] x Step start, x.
* @param[in] htry Step to attempt.
* @param[in] eps The relative accuracy.
* @param[out] hdid Step achieved.
* @param[out] hnext Proposed next step.
* @returns true if integration succeeds.
*/
void OneGoodStep(G4double ystart[], // Like old RKF45step()
const G4double dydx[],
G4double& x,
G4double htry,
G4double eps,
G4double& hdid,
G4double& hnext) ;
G4double ComputeNewStepSize(G4double errMaxNorm, // normalised
G4double hstepCurrent) override;
@@ -148,40 +225,53 @@ class G4OldMagIntDriver : public G4VIntegrationDriver,
// Do not limit the next step's size within a factor of the
// current one.
/**
* Writes out to stream the parameters/state of the driver.
*/
void StreamInfo( std::ostream& os ) const override;
/**
* Takes the last step's normalised error and calculates a step size
* for the next step. Limits the next step's size within a range around
* the current one.
*/
G4double ComputeNewStepSize_WithinLimits(G4double errMaxNorm, // normalised
G4double hstepCurrent);
// Taking the last step's normalised error, calculate
// a step size for the next step.
// Limit the next step's size within a range around the current one.
/**
* Modifier and accessor for the maximum number of steps that can be taken
* for the integration of a single segment, i.e. a single call to
* AccurateAdvance().
*/
inline G4int GetMaxNoSteps() const;
inline void SetMaxNoSteps(G4int val);
// Modify and Get the Maximum number of Steps that can be
// taken for the integration of a single segment -
// (i.e. a single call to AccurateAdvance).
/**
* More modifiers and accessors.
*/
inline void SetHmin(G4double newval);
void SetVerboseLevel(G4int newLevel) override;
G4int GetVerboseLevel() const override;
inline G4double GetSmallestFraction() const;
void SetSmallestFraction( G4double val );
protected:
/**
* Loggers, issuing warnings for undesirable situations.
*/
void WarnSmallStepSize(G4double hnext, G4double hstep,
G4double h, G4double xDone,
G4int noSteps);
void WarnTooManyStep(G4double x1start, G4double x2end, G4double xCurrent);
void WarnEndPointTooFar(G4double endPointDist,
G4double hStepSize ,
G4double epsilonRelative,
G4int debugFlag);
// Issue warnings for undesirable situations
/**
* Loggers for verbosity printouts.
*/
void PrintStatus(const G4double* StartArr,
G4double xstart,
const G4double* CurrentArr,
@@ -198,10 +288,11 @@ class G4OldMagIntDriver : public G4VIntegrationDriver,
G4int subStepNo,
G4double subStepSize,
G4double dotVelocities);
// Verbose output for debugging
/**
* Reports on the number of steps, maximum errors etc.
*/
void PrintStatisticsReport();
// Report on the number of steps, maximum errors etc.
#ifdef QUICK_ADV_TWO
G4bool QuickAdvance( G4double yarrin[], // In
@@ -217,25 +308,31 @@ class G4OldMagIntDriver : public G4VIntegrationDriver,
// ---------------------------------------------------------------
// INVARIANTS
/** Minimum Step allowed in a Step (in absolute units). */
G4double fMinimumStep = 0.0;
// Minimum Step allowed in a Step (in absolute units)
/** Smallest fraction of (existing) curve length, in relative units.
Below this fraction the current step will be the last. */
G4double fSmallestFraction = 1.0e-12; // Expected range 1e-12 to 5e-15
// Smallest fraction of (existing) curve length - in relative units
// below this fraction the current step will be the last
const G4int fNoIntegrationVariables = 0; // Variables in integration
const G4int fMinNoVars = 12; // Minimum number for FieldTrack
const G4int fNoVars = 0; // Full number of variable
/** Variables in integration. */
const G4int fNoIntegrationVariables = 0;
/** Minimum number for FieldTrack. */
const G4int fMinNoVars = 12;
/** Full number of variable. */
const G4int fNoVars = 0;
/** Default maximum number of steps is Base divided by the order of Stepper. */
G4int fMaxNoSteps;
G4int fMaxStepBase = 250; // was 5000
// Default maximum number of steps is Base divided by the order of Stepper
/** Parameters used to grow and shrink trial stepsize. */
G4double safety;
G4double pshrnk; // exponent for shrinking
G4double pgrow; // exponent for growth
G4double errcon;
// Parameters used to grow and shrink trial stepsize.
G4int fStatisticsVerboseLevel = 0;
@@ -247,15 +344,15 @@ class G4OldMagIntDriver : public G4VIntegrationDriver,
// ---------------------------------------------------------------
// STATE
/** Step Statistics. */
unsigned long fNoTotalSteps=0, fNoBadSteps=0;
unsigned long fNoSmallSteps=0, fNoInitialSmallSteps=0, fNoCalls=0;
G4double fDyerr_max=0.0, fDyerr_mx2=0.0;
G4double fDyerrPos_smTot=0.0, fDyerrPos_lgTot=0.0, fDyerrVel_lgTot=0.0;
G4double fSumH_sm=0.0, fSumH_lg=0.0;
// Step Statistics
/** Could be varied during tracking - to help identify issues. */
G4int fVerboseLevel = 0; // Verbosity level for printing (debug, ..)
// Could be varied during tracking - to help identify issues
using ChordFinderDelegate = G4ChordFinderDelegate<G4OldMagIntDriver>;
};
@@ -25,7 +25,7 @@
//
// G4OldMagIntDriver inline methods implementation
//
// V.Grichine, 07.10.1996 - Created
// Author: Vladimir Grichine (CERN), 07.10.1996 - Created
// --------------------------------------------------------------------
inline
@@ -43,6 +43,17 @@ void G4OldMagIntDriver::OnStartTracking()
ChordFinderDelegate::ResetStepEstimate();
}
inline
void G4OldMagIntDriver::OnComputeStep(const G4FieldTrack*)
{
}
inline
G4bool G4OldMagIntDriver::DoesReIntegrate() const
{
return true;
}
inline
G4double G4OldMagIntDriver::GetHmin() const
{
@@ -27,10 +27,10 @@
//
// G4QSS2 simulator
// Authors: Lucio Santi, Rodrigo Castro (Univ. Buenos Aires) - 2018-2021
// Authors: Lucio Santi, Rodrigo Castro (Univ. Buenos Aires), 2018-2021
// --------------------------------------------------------------------
#ifndef _G4QSS2_H_
#define _G4QSS2_H_ 1
#ifndef G4QSS2_HH
#define G4QSS2_HH
#include "G4Types.hh"
#include "G4qss_misc.hh"
@@ -45,11 +45,15 @@
#include "G4Log.hh"
#endif
/**
* @brief G4QSS2 defines the QSS2 simulator engine used in QSS field stepper.
*/
class G4QSS2
{
public:
G4QSS2(QSS_simulator sim) : simulator(sim) {}
inline G4QSS2(QSS_simulator sim) : simulator(sim) {}
inline QSS_simulator getSimulator() const { return this->simulator; }
@@ -27,16 +27,20 @@
//
// G4QSS3 simulator
// Authors: Lucio Santi, Rodrigo Castro (Univ. Buenos Aires) - 2018-2021
// Authors: Lucio Santi, Rodrigo Castro (Univ. Buenos Aires), 2018-2021
// --------------------------------------------------------------------
#ifndef _G4QSS3_H_
#define _G4QSS3_H_ 1
#ifndef G4QSS3_HH
#define G4QSS3_HH
#include "G4Types.hh"
#include "G4qss_misc.hh"
#include <cmath>
/**
* @brief G4QSS3 defines the QSS3 simulator engine used in QSS field stepper.
*/
class G4QSS3
{
public:
@@ -27,47 +27,83 @@
//
// QSS Interpolator Driver
// Authors: Lucio Santi, Rodrigo Castro (Univ. Buenos Aires) - 2018-2021
// Authors: Lucio Santi, Rodrigo Castro (Univ. Buenos Aires), 2018-2021
// --------------------------------------------------------------------
#ifndef G4QSSDriver_HH
#define G4QSSDriver_HH 1
#define G4QSSDriver_HH
#include "G4InterpolationDriver.hh"
#include "G4QSSMessenger.hh"
/**
* @brief G4QSSDriver is a templated driver class defining the QSS
* (Quantum State Simulation) Interpolator Driver.
*/
template <class T>
class G4QSSDriver : public G4InterpolationDriver<T, true>
{
public:
G4QSSDriver(T* stepper);
// Hacky way of getting and setting precision parameters
// from messenger on first run
void OnStartTracking() override;
/**
* Constructor for G4QSSDriver.
* @param[in] T Pointer to the stepper algorithm.
*/
inline G4QSSDriver(T* stepper);
/**
* Copy constructor and assignment operator not allowed.
*/
G4QSSDriver(const G4QSSDriver&) = delete;
const G4QSSDriver& operator=(const G4QSSDriver&) = delete;
G4double AdvanceChordLimited(G4FieldTrack& track,
G4double hstep,
G4double eps,
G4double chordDistance) override;
/**
* Dispatch interface method for initialisation/reset of driver.
*/
void OnStartTracking() override;
void OnComputeStep(const G4FieldTrack* track) override
{
Base::OnComputeStep(track);
}
/**
* Computes the step to take, based on chord limits.
* @param[in,out] track The current track in field.
* @param[in] hstep Proposed step length.
* @param[in] eps Requested accuracy, y_err/hstep.
* @param[in] chordDistance Maximum sagitta distance.
* @returns The length of step taken.
*/
inline G4double AdvanceChordLimited(G4FieldTrack& track,
G4double hstep,
G4double eps,
G4double chordDistance) override;
void SetPrecision(G4double dq_rel, G4double dq_min);
/**
* Dispatch interface method for computing step.
*/
inline void OnComputeStep(const G4FieldTrack* track) override;
G4double OneGoodStep(typename G4InterpolationDriver<T, true>::StepperIterator it,
field_utils::State& y,
field_utils::State& dydx,
G4double& hstep,
G4double epsStep,
G4double curveLength,
G4FieldTrack* track) override;
/**
* Setter for driver precision parameters.
*/
inline void SetPrecision(G4double dq_rel, G4double dq_min);
/**
* Takes one Step that is as large as possible while satisfying the
* accuracy criterion.
* @param[in] it Stepper iterator.
* @param[in,out] y The current track state, y.
* @param[in] dydx dydx array.
* @param[in,out] hstep Step to attempt.
* @param[in] epsStep The relative accuracy.
* @param[in] curveLength Step start, x.
* @param[in,out] track Pointer to the Field track. Not used.
* @returns The step achieved.
*/
inline G4double OneGoodStep(typename G4InterpolationDriver<T, true>::StepperIterator it,
field_utils::State& y,
field_utils::State& dydx,
G4double& hstep,
G4double epsStep,
G4double curveLength,
G4FieldTrack* track) override;
private:
@@ -23,7 +23,7 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// Authors: Lucio Santi, Rodrigo Castro (Univ. Buenos Aires) - 2018-2021
// Authors: Lucio Santi, Rodrigo Castro (Univ. Buenos Aires), 2018-2021
// --------------------------------------------------------------------
template <class T>
@@ -37,23 +37,24 @@ template <class T>
void G4QSSDriver<T>::OnStartTracking()
{
Base::OnStartTracking();
if (! initializedOnFirstRun) {
// this->SetPrecision( G4QSSMessenger::instance()->dQRel, G4QSSMessenger::instance()->dQMin);
G4double dqRel = G4QSSMessenger::instance()->dQRel;
G4double dQMin = G4QSSMessenger::instance()->dQMin;
if (dqRel == 0) {
dqRel = 0.001;
}
if (dQMin == 0) {
dQMin = 0.0001;
}
if (! initializedOnFirstRun)
{
G4double dqRel = G4QSSMessenger::instance()->Get_dQRel();
G4double dQMin = G4QSSMessenger::instance()->Get_dQMin();
if (dqRel == 0) { dqRel = 0.001; }
if (dQMin == 0) { dQMin = 0.0001; }
this->SetPrecision(dqRel, dQMin);
initializedOnFirstRun = true;
}
}
template <class T>
void G4QSSDriver<T>::OnComputeStep(const G4FieldTrack* track)
{
Base::OnComputeStep(track);
}
template <class T>
void G4QSSDriver<T>::SetPrecision(G4double dq_rel, G4double dq_min)
{
@@ -61,7 +62,8 @@ void G4QSSDriver<T>::SetPrecision(G4double dq_rel, G4double dq_min)
<< "dQRel = " << dq_rel << " - "
<< "dQMin = " << dq_min << G4endl;
for (const auto& item : this->fSteppers) {
for (const auto& item : this->fSteppers)
{
item.stepper->SetPrecision(dq_rel, dq_min);
}
}
@@ -27,10 +27,10 @@
//
// Messenger for QSS Integrator driver
// Author: Leandro Gomez Vidal (Univ. Buenos Aires) - October 2021
// Author: Leandro Gomez Vidal (Univ. Buenos Aires), October 2021
// --------------------------------------------------------------------
#ifndef GEANT4_G4QSSMessenger_H
#define GEANT4_G4QSSMessenger_H 1
#ifndef G4QSSMessenger_HH
#define G4QSSMessenger_HH
#include "G4UIcmdWithABool.hh"
#include "G4UIcmdWithADouble.hh"
@@ -41,48 +41,75 @@
#include "G4UIdirectory.hh"
#include "G4UImessenger.hh"
#include "G4QSSParameters.hh"
class G4QSSMessenger : public G4UImessenger
{
public:
G4QSSMessenger();
~G4QSSMessenger() override;
void SetNewValue(G4UIcommand* command, G4String newValues) override;
/* Hacky - much easier to access G4QSSMessenger from G4QSSDriver than the other way around
* Multithreading seems to cause weird stuff with Driver/Stepper instances, maybe making
* some thread-local copies or something, outside of construction? */
static G4QSSMessenger* instance();
enum StepperSelection
{
None = 0,
TemplatedDoPri,
OldRK45,
G4QSS2
};
void selectStepper(const std::string&);
StepperSelection selectedStepper();
public:
G4double dQMin = 0.00001;
G4double dQRel = 0.001;
G4double trialProposedStepModifier = 1.0;
G4int maxSubsteps = 5000;
G4int QssOrder = 2;
/**
* Constructor and Destructor.
*/
G4QSSMessenger();
~G4QSSMessenger() override;
/**
* Applies command to the associated object.
*/
void SetNewValue(G4UIcommand* command, G4String newValues) override;
/* Hacky - much easier to access G4QSSMessenger from G4QSSDriver than the other way around
* Multithreading seems to cause weird stuff with Driver/Stepper instances, maybe making
* some thread-local copies or something, outside of construction? */
static G4QSSMessenger* instance();
/**
* Accessors.
*/
inline G4int GetQssOrder() { return G4QSSParameters::Instance()->GetQssOrder(); }
inline G4double Get_dQRel() { return G4QSSParameters::Instance()->Get_dQRel(); }
inline G4double Get_dQMin() { return G4QSSParameters::Instance()->Get_dQMin(); }
inline G4int GetMaxSubsteps() { return G4QSSParameters::Instance()->GetMaxSubsteps(); }
enum StepperSelection
{
None = 1,
G4QSS2 = 2,
G4QSS3 = 3,
NumMethods,
};
/**
* Stepper selection, G4QSS2 or G4QSS3.
*/
void selectStepper(const std::string&);
StepperSelection selectedStepper();
/**
* Sets QSS order. To be suppressed in favour of the method
* it calls in G4QSSParameters.
*/
G4bool SetQssOrder(G4int order);
private:
StepperSelection _selectedStepper;
G4UIdirectory* qssCmdDir;
/**
* Internal methods -- could be suppressed in future.
*/
G4bool Set_dQMin( G4double dvalue );
G4bool Set_dQRel( G4double value );
G4bool SetMaxSubsteps( G4int number );
private:
StepperSelection _selectedStepper= StepperSelection::None;
G4UIdirectory* qssCmdDir;
G4UIcmdWithADoubleAndUnit* dQMinCmd;
G4UIcmdWithADouble* dQRelCmd;
G4UIcmdWithAString* stepperSelectorCmd;
G4UIcmdWithADouble* trialProposedStepModifierCmd;
G4UIcmdWithAnInteger* maxSubstepsCmd;
G4UIcmdWithADouble* dQRelCmd;
G4UIcmdWithAString* stepperSelectorCmd;
G4UIcmdWithAnInteger* maxSubstepsCmd;
};
#endif // GEANT4_G4QSSMessenger_H
#endif
@@ -0,0 +1,90 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// G4QSSParameters
//
// Hold parameters for QSS Integrator driver -- used to create
// all QSStepper objects (directly or via IntegrationDriver).
// Checks consistency of values proposed.
//
// This design means that objects of only *one* order of QSS driver
// can be created (QSS2 or QSS3 must be used globally).
//
// Author: John Apostolakis (CERN), 19.08.2025
// --------------------------------------------------------------------
#ifndef G4QSSParameters_HH
#define G4QSSParameters_HH
#include "G4Types.hh"
/**
* @brief G4QSSParameters hold parameters for the QSS Integrator driver.
* It is used to create all QSStepper objects, directly or via the
* Integration Driver. Checks for consistency of the proposed values.
*/
class G4QSSParameters
{
public:
static G4QSSParameters* Instance();
/**
* Default Destructor.
*/
~G4QSSParameters() = default;
/**
* Accessors.
*/
inline G4int GetQssOrder() { return fQssOrder; }
inline G4double Get_dQRel() { return fdQRel; }
inline G4double Get_dQMin() { return fdQMin; }
inline G4int GetMaxSubsteps() { return fMaxSubsteps; }
/**
* Modifiers.
*/
G4bool SetQssOrder( G4int value, G4bool onlyWarn= false );
G4bool Set_dQRel( G4double dQRel );
G4bool Set_dQMin( G4double dQMin );
G4bool SetMaxSubsteps( G4int maxSubsteps );
private:
/**
* Private default Constructor.
*/
G4QSSParameters() = default;
private:
G4int fQssOrder = 2;
G4double fdQMin = 0.00001;
G4double fdQRel = 0.001;
G4int fMaxSubsteps = 5000;
};
#endif
@@ -27,10 +27,10 @@
//
// QSS statistics
// Authors: Lucio Santi, Rodrigo Castro (Univ. Buenos Aires) - 2018-2021
// Authors: Lucio Santi, Rodrigo Castro (Univ. Buenos Aires), 2018-2021
// --------------------------------------------------------------------
#ifndef _QSS_CUSTOM_STATS_HH_
#define _QSS_CUSTOM_STATS_HH_ 1
#ifndef QSS_CUSTOM_STATS_HH
#define QSS_CUSTOM_STATS_HH
#include <time.h>
@@ -44,8 +44,14 @@
#include "G4qss_misc.hh"
#include "G4Types.hh"
#include "G4ios.hh"
#include <atomic>
#include <map>
/**
* @brief QSSStats contains functions for statistics on the QSS drivers.
*/
struct QSSStats
{
@@ -69,7 +75,8 @@ struct QSSStats
reset_time = 0;
integration_time = 0;
for (size_t i = 0; i < Qss_misc::VAR_IDX_END; i++) {
for (std::size_t i = 0; i < Qss_misc::VAR_IDX_END; ++i)
{
dqrel_changes[i] = 0;
dqmin_changes[i] = 0;
max_error[i] = 0;
@@ -98,12 +105,12 @@ struct QSSStats
<< " Substeps average per step: " << avg_substeps << std::endl;
ss << " Substeps by track-step:" << std::endl;
for (auto it = substepsByStepNumberByTrackID.begin(); it != substepsByStepNumberByTrackID.end();
++it)
for (const auto& stp : substepsByStepNumberByTrackID)
{
ss << " Track #" << it->first << std::endl;
for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2) {
ss << " Step " << it2->first << " => " << it2->second << " substeps" << std::endl;
ss << " Track #" << stp.first << std::endl;
for (const auto& stp2 : stp.second)
{
ss << " Step " << stp2.first << " => " << stp2.second << " substeps" << std::endl;
}
}
@@ -114,14 +121,15 @@ struct QSSStats
ss << " Reset time: " << reset_time << std::endl
<< " Reset time average: " << avg_reset_time << std::endl;
for (G4int index = 0; index < Qss_misc::VAR_IDX_END; index++) {
for (std::size_t index = 0; index < Qss_misc::VAR_IDX_END; ++index)
{
ss << " Variable " << vars[index] << ":" << std::endl;
ss << " dQRel changes: " << dqrel_changes[index] << std::endl;
ss << " dQMin changes: " << dqmin_changes[index] << std::endl;
ss << " Max error: " << max_error[index] << std::endl;
}
std::cout << ss.rdbuf();
G4cout << ss.rdbuf();
};
};
@@ -27,174 +27,226 @@
//
// QSS Integrator Stepper
//
// Authors - version 1 : Lucio Santi, Rodrigo Castro (Univ. Buenos Aires) - 2018-2021
// - version 2 : Mattias Portnoy (Univ. Buenos Aires) - 2024
// Authors: version 1 - Lucio Santi, Rodrigo Castro (Univ. Buenos Aires), 2018-2021
// version 2 - Mattias Portnoy (Univ. Buenos Aires), 2024
// --------------------------------------------------------------------
#ifndef G4QSS_STEPPER_HH
#define G4QSS_STEPPER_HH 1
#define G4QSS_STEPPER_HH
#include "G4FieldTrack.hh"
#include "G4MagIntegratorStepper.hh"
#include "G4QSSMessenger.hh"
#include "G4QSSubstepStruct.hh"
#include <cmath>
#include <CLHEP/Units/PhysicalConstants.h>
/**
* @brief G4QSStepper is an integrator of particle's equation of
* motion based on the QSS implementation.
*/
class G4QSStepper : public G4MagIntegratorStepper
{
public:
/**
* Constructor for G4QSStepper.
* @param[in] equation Pointer to the provided equation of motion.
* @param[in] num_integration_vars The number of integration variables.
* @param[in] qssOrder The QSS order (2 or 3 expected; if <= 0 , use value
* from Messenger.
*/
G4QSStepper( G4EquationOfMotion* equation,
G4int num_integration_vars,
G4int num_state_vars,
G4bool isFSAL,
G4int verbosity=0 );
G4int num_integration_vars = 6, // always 6 -- ignore
G4int qssOrder= -1 );
G4QSStepper(G4EquationOfMotion *EqRhs,
G4int numberOfVariables = 6,
G4bool primary = true);
virtual ~G4QSStepper();
/**
* Default Destructor. Freeing of memory is done in susbsteps destructor.
*/
~G4QSStepper() override = default;
/**
* Utility methods.
*/
inline constexpr G4double Cubic_Function(const QSStateVector* states,
G4int index, G4double delta_t);
inline constexpr G4double Parabolic_Function(const QSStateVector* states,
G4int index, G4double delta_t);
inline constexpr G4double Linear_Function(const QSStateVector* states,
G4int index, G4double delta_t);
/* 0 means position type, 1 means velocity type. */
/**
* 0 means position type, 1 means velocity type.
*/
inline constexpr int INDEX_TYPE(G4int i);
inline void set_qss_order(G4int order);
// auxiliary methods
/**
* Auxiliary methods.
*/
inline void momentum_to_velocity(const G4double* momentum, G4double* out);
void set_relativistic_coeff(const G4double* momentum);
inline void velocity_to_momentum(G4double *y);
// Key methods
/**
* Key methods.
*/
void initialize(const G4double y[]);
inline void compare_time_and_update(G4int index, G4int i);
inline void compare_time_and_update(G4int& index, G4int i);
inline G4int get_next_sync_index();
inline void update_field();
inline G4double extrapolate_polynomial(QSStateVector* states,
G4int index, G4double delta_t, G4int order);
inline void extrapolate_all_states_to_t(Substep* substep,
G4double t, G4double* yOut);
/* Moves all the x states of variable index to the current time t. */
/**
* Moves all the x states of variable index to the current time t.
*/
inline void update_x(G4int index, G4double t);
/* Moves all the q states of variable index to the current t. */
/**
* Moves all the q states of variable index to the current t.
*/
inline void update_q(G4int index, G4double t);
/**
* Update methods.
*/
inline void update_x_position_derivates_using_q(G4int index);
inline void update_x_velocity_derivates_using_q(G4int index);
inline void update_x_derivates_using_q(G4int index);
inline void update_sync_time_one_coefficient(G4int index);
/* Updates when does the x,q distance goes beyond the quantum.
Uses polynomial roots-finding formulas. */
/*
* Updates when does the x,q distance goes beyond the quantum.
* Uses polynomial roots-finding formulas.
*/
void update_sync_time(G4int index);
/* Key method called by driver. */
/**
* The stepper for the integration.
* The stepsize is fixed, with the step size given by 'h'.
* Integrates ODE starting values y[0 to 6]. Outputs yout[].
* @param[in] y Starting values array of integration variables.
* @param[in] dydx Derivatives array - Not used.
* @param[in] h The given step size.
* @param[out] yout Integration output.
* @param[out] yError The estimated error - Not used.
*/
void Stepper( const G4double y[],
const G4double /*dydx*/ [],
G4double h,
G4double yout[],
G4double /* yerr */ [] ) override;
/* Obligatory G4InterpolationDriver methods. */
/**
* Returns the QSS order of integration.
*/
inline G4int IntegratorOrder() const override;
/**
* Returns the stepper type-ID, "kQSStepper".
*/
inline G4StepperType StepperType() const override { return kQSStepper; }
/**
* Returns a pointer to the equation of motion.
*/
inline G4EquationOfMotion* GetSpecificEquation();
/**
* Returns current track state.
*/
inline const field_utils::State& GetYOut() const;
void Interpolate(G4double tau,G4double yOut[]);
/**
* Track interpolation.
* @param[in] tau Step start, x.
* @param[in,out] yOut The current track state, y.
*/
void Interpolate(G4double tau, G4double yOut[]);
/**
* Returns the distance from chord line.
*/
inline G4double DistChord() const override;
/**
* Wrapper for the Stepper() function above.
*/
inline void Stepper(const G4double yInput[],
const G4double dydx[],
G4double hstep, G4double yOutput[], G4double yError[],
G4double hstep,
G4double yOutput[],
G4double yError[],
G4double /*dydxOutput*/ []);
/**
* Sets up interpolation. Does nothing.
*/
inline void SetupInterpolation();
/* obligatory qss driver methods. */
/*
* Obligatory qss driver methods.
*/
inline void reset(const G4FieldTrack* track);
inline void SetPrecision(G4double dq_rel, G4double dq_min);
inline G4double GetLastStepLength();
/*
* Sets the mass at rest. Checking/ensuring that it is positive.
*/
inline void setRestMass(G4double restMass);
private:
// Constants
static constexpr int DERIVATIVE_0 = 0;
static constexpr int DERIVATIVE_1 = 1;
static constexpr int DERIVATIVE_2 = 2;
static constexpr int DERIVATIVE_3 = 3;
static constexpr int DERIVATIVE_0{0};
static constexpr int DERIVATIVE_1{1};
static constexpr int DERIVATIVE_2{2};
static constexpr int DERIVATIVE_3{3};
static constexpr int VX = 3;
static constexpr int VY = 4;
static constexpr int VZ = 5;
static constexpr int VX{3};
static constexpr int VY{4};
static constexpr int VZ{5};
static constexpr int POSITION_IDX = 0;
static constexpr int VELOCITY_IDX = 3;
static constexpr int NUMBER_OF_VARIABLES_QSS = 6;
static constexpr int POSITION_IDX{0};
static constexpr int VELOCITY_IDX{3};
static constexpr G4double INFTY = 1e+20;
static constexpr G4double INFTY{1e+20};
/* Used to check if field changed from last update field during substeps. */
G4bool fField_changed = true;
G4bool fTrack_changed = true;
/** Used to check if field changed from last update field during substeps. */
G4bool fField_changed{true};
G4bool fTrack_changed{true};
G4int qss_order = 2;
const G4int qss_order{2};
Substeps substeps;
Substep current_substep;
const G4FieldTrack* fCurrent_track = nullptr;
const G4FieldTrack* fCurrent_track{nullptr};
QSStateVector dq_vector;
// Invariants for this track -- during propagation
//
G4double fCharge;
/** Invariants for this track -- during propagation. */
G4double fCharge{-1.0};
G4double fCharge_c2;
G4double fRestMass;
G4double fGamma;
G4double fRestMass{CLHEP::electron_mass_c2};
G4double fGamma{1.0};
G4double fCoeff; // coeff;
// Cached values -- for tiny speed up
//
/** Cached values -- for tiny speed up. */
G4double fMassOverC ; // was mass_times_gamma_over_speed_of_light;
G4double fInv_mass_over_c;
/* used by interpolation driver, need to copy state here
when stepper finished. */
/** Used by interpolation driver, need to copy state here when stepper finished. */
G4double fYout[12];
// QSS parameters separated into velocity and position
//
/** QSS parameters separated into velocity and position. */
G4double dqrel[2] = {0.0,0.0};
G4double dqmin[2] = {0.001,0.001};
G4double fVelocity;
G4double fFinal_t;
G4double fVelocity{0.0};
G4double fFinal_t{0.0};
};
// ----------------------------------------------------------------------------

Some files were not shown because too many files have changed in this diff Show More