Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
G4NystromRK4.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26// G4NystromRK4 implmentation
27//
28// Created: I.Gavrilenko, 15.05.2009 (as G4AtlasRK4)
29// Adaptations: J.Apostolakis, November 2009
30// -------------------------------------------------------------------
31
32#include "G4NystromRK4.hh"
33
34#include "G4Exception.hh"
35#include "G4SystemOfUnits.hh"
36#include "G4FieldUtils.hh"
37#include "G4LineSection.hh"
38
39using namespace field_utils;
40
41namespace
42{
43 G4bool notEquals(G4double p1, G4double p2)
44 {
45 return std::fabs(p1 - p2) > perMillion * p2;
46 }
47 constexpr G4int INTEGRATED_COMPONENTS = 6;
48} // namespace
49
50
51G4NystromRK4::G4NystromRK4(G4Mag_EqRhs* equation, G4double distanceConstField)
52 : G4MagIntegratorStepper(equation, INTEGRATED_COMPONENTS)
53{
54 if (distanceConstField > 0)
55 {
56 SetDistanceForConstantField(distanceConstField);
57 }
58}
59
61 const G4double dydx[],
62 G4double hstep,
63 G4double yOut[],
64 G4double yError[])
65{
66 fInitialPoint = { y[0], y[1], y[2] };
67
68 G4double field[3];
69
70 constexpr G4double one_sixth= 1./6.;
71 const G4double S5 = 0.5 * hstep;
72 const G4double S4 = .25 * hstep;
73 const G4double S6 = hstep * one_sixth;
74
75 const G4double momentum2 = getValue2(y, Value3D::Momentum);
76 if (notEquals(momentum2, fMomentum2))
77 {
78 fMomentum = std::sqrt(momentum2);
79 fMomentum2 = momentum2;
80 fInverseMomentum = 1. / fMomentum;
81 fCoefficient = GetFCof() * fInverseMomentum;
82 }
83
84 // Point 1
85 const G4double K1[3] = {
86 fInverseMomentum * dydx[3],
87 fInverseMomentum * dydx[4],
88 fInverseMomentum * dydx[5]
89 };
90
91 // Point2
92 G4double p[4] = {
93 y[0] + S5 * (dydx[0] + S4 * K1[0]),
94 y[1] + S5 * (dydx[1] + S4 * K1[1]),
95 y[2] + S5 * (dydx[2] + S4 * K1[2]),
96 y[7]
97 };
98
99 GetFieldValue(p, field);
100
101 const G4double A2[3] = {
102 dydx[0] + S5 * K1[0],
103 dydx[1] + S5 * K1[1],
104 dydx[2] + S5 * K1[2]
105 };
106
107 const G4double K2[3] = {
108 (A2[1] * field[2] - A2[2] * field[1]) * fCoefficient,
109 (A2[2] * field[0] - A2[0] * field[2]) * fCoefficient,
110 (A2[0] * field[1] - A2[1] * field[0]) * fCoefficient
111 };
112
113 fMidPoint = { p[0], p[1], p[2] };
114
115 // Point 3 with the same magnetic field
116 const G4double A3[3] = {
117 dydx[0] + S5 * K2[0],
118 dydx[1] + S5 * K2[1],
119 dydx[2] + S5 * K2[2]
120 };
121
122 const G4double K3[3] = {
123 (A3[1] * field[2] - A3[2] * field[1]) * fCoefficient,
124 (A3[2] * field[0] - A3[0] * field[2]) * fCoefficient,
125 (A3[0] * field[1] - A3[1] * field[0]) * fCoefficient
126 };
127
128 // Point 4
129 p[0] = y[0] + hstep * (dydx[0] + S5 * K3[0]);
130 p[1] = y[1] + hstep * (dydx[1] + S5 * K3[1]);
131 p[2] = y[2] + hstep * (dydx[2] + S5 * K3[2]);
132
133 GetFieldValue(p, field);
134
135 const G4double A4[3] = {
136 dydx[0] + hstep * K3[0],
137 dydx[1] + hstep * K3[1],
138 dydx[2] + hstep * K3[2]
139 };
140
141 const G4double K4[3] = {
142 (A4[1] * field[2] - A4[2] * field[1]) * fCoefficient,
143 (A4[2] * field[0] - A4[0] * field[2]) * fCoefficient,
144 (A4[0] * field[1] - A4[1] * field[0]) * fCoefficient
145 };
146
147 // New position
148 yOut[0] = y[0] + hstep * (dydx[0] + S6 * (K1[0] + K2[0] + K3[0]));
149 yOut[1] = y[1] + hstep * (dydx[1] + S6 * (K1[1] + K2[1] + K3[1]));
150 yOut[2] = y[2] + hstep * (dydx[2] + S6 * (K1[2] + K2[2] + K3[2]));
151 // New direction
152 yOut[3] = dydx[0] + S6 * (K1[0] + K4[0] + 2. * (K2[0] + K3[0]));
153 yOut[4] = dydx[1] + S6 * (K1[1] + K4[1] + 2. * (K2[1] + K3[1]));
154 yOut[5] = dydx[2] + S6 * (K1[2] + K4[2] + 2. * (K2[2] + K3[2]));
155 // Pass Energy, time unchanged -- time is not integrated !!
156 yOut[6] = y[6];
157 yOut[7] = y[7];
158
159 fEndPoint = { yOut[0], yOut[1], yOut[2] };
160
161 // Errors
162 yError[3] = hstep * std::fabs(K1[0] - K2[0] - K3[0] + K4[0]);
163 yError[4] = hstep * std::fabs(K1[1] - K2[1] - K3[1] + K4[1]);
164 yError[5] = hstep * std::fabs(K1[2] - K2[2] - K3[2] + K4[2]);
165 yError[0] = hstep * yError[3];
166 yError[1] = hstep * yError[4];
167 yError[2] = hstep * yError[5];
168 yError[3] *= fMomentum;
169 yError[4] *= fMomentum;
170 yError[5] *= fMomentum;
171
172 // Normalize momentum
173 const G4double normF = fMomentum / getValue(yOut, Value3D::Momentum);
174 yOut[3] *= normF;
175 yOut[4] *= normF;
176 yOut[5] *= normF;
177
178 // My trial code:
179 // G4double endMom2 = yOut[3]*yOut[3]+yOut[4]*yOut[4]+yOut[5]*yOut[5];
180 // G4double normF = std::sqrt( startMom2 / endMom2 );
181}
182
184{
185 return G4LineSection::Distline(fMidPoint, fInitialPoint, fEndPoint);
186}
187
189{
190 if (GetField() == nullptr)
191 {
192 G4Exception("G4NystromRK4::SetDistanceForConstantField",
193 "Nystrom 001", JustWarning,
194 "Provided field is not G4CachedMagneticField. Changing field type.");
195
196 fCachedField = std::unique_ptr<G4CachedMagneticField>(
198 dynamic_cast<G4MagneticField*>(GetEquationOfMotion()->GetFieldObj()),
199 length));
200
201 GetEquationOfMotion()->SetFieldObj(fCachedField.get());
202 }
203 GetField()->SetConstDistance(length);
204}
205
207{
208 if (GetField() == nullptr)
209 {
210 return 0.0;
211 }
212 return GetField()->GetConstDistance();
213}
214
215G4CachedMagneticField* G4NystromRK4::GetField()
216{
217 return dynamic_cast<G4CachedMagneticField*>(GetEquationOfMotion()->GetFieldObj());
218}
219
220const G4CachedMagneticField* G4NystromRK4::GetField() const
221{
222 return const_cast<G4NystromRK4*>(this)->GetField();
223}
@ JustWarning
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
Definition: G4Exception.cc:59
double G4double
Definition: G4Types.hh:83
bool G4bool
Definition: G4Types.hh:86
int G4int
Definition: G4Types.hh:85
G4double GetConstDistance() const
void SetConstDistance(G4double dist)
const G4Field * GetFieldObj() const
void SetFieldObj(G4Field *pField)
static G4double Distline(const G4ThreeVector &OtherPnt, const G4ThreeVector &LinePntA, const G4ThreeVector &LinePntB)
G4EquationOfMotion * GetEquationOfMotion()
G4double GetDistanceForConstantField() const
virtual void Stepper(const G4double y[], const G4double dydx[], G4double hstep, G4double yOut[], G4double yError[]) override
Definition: G4NystromRK4.cc:60
virtual G4double DistChord() const override
void SetDistanceForConstantField(G4double length)
G4NystromRK4(G4Mag_EqRhs *EquationMotion, G4double distanceConstField=0.0)
Definition: G4NystromRK4.cc:51
G4double getValue(const ArrayType &array, Value1D value)
G4double getValue2(const ArrayType &array, Value1D value)