Geant4-11
G4IntegrationDriver.icc
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// G4IntegrationDriver inline implementation
27//
28// Author: Dmitry Sorokin, Google Summer of Code 2017
29// Supervision: John Apostolakis, CERN
30// --------------------------------------------------------------------
31
32#include "G4FieldUtils.hh"
33
34template <class T>
35G4IntegrationDriver<T>::
36G4IntegrationDriver ( G4double hminimum, T* pStepper,
37 G4int numComponents, G4int statisticsVerbose )
38 : G4RKIntegrationDriver<T>(pStepper),
39 fMinimumStep(hminimum),
40 fSmallestFraction(1e-12),
41 fVerboseLevel(statisticsVerbose),
42 fNoQuickAvanceCalls(0),
43 fNoAccurateAdvanceCalls(0),
44 fNoAccurateAdvanceBadSteps(0),
45 fNoAccurateAdvanceGoodSteps(0)
46{
47 if (numComponents != Base::GetStepper()->GetNumberOfVariables())
48 {
49 std::ostringstream message;
50 message << "Driver's number of integrated components "
51 << numComponents
52 << " != Stepper's number of components "
53 << pStepper->GetNumberOfVariables();
54 G4Exception("G4IntegrationDriver","GeomField0002",
55 FatalException, message);
56 }
57}
58
59template <class T>
60G4IntegrationDriver<T>::~G4IntegrationDriver()
61{
62#ifdef G4VERBOSE
63 if (fVerboseLevel > 0)
64 {
65 G4cout << "G4Integration Driver Stats: "
66 << "#QuickAdvance " << fNoQuickAvanceCalls
67 << " - #AccurateAdvance " << fNoAccurateAdvanceCalls << " "
68 << "#good steps " << fNoAccurateAdvanceGoodSteps << " "
69 << "#bad steps " << fNoAccurateAdvanceBadSteps << G4endl;
70 }
71#endif
72}
73
74template <class T>
75G4double G4IntegrationDriver<T>::AdvanceChordLimited(G4FieldTrack& track,
76 G4double stepMax,
77 G4double epsStep,
78 G4double chordDistance)
79{
80 return ChordFinderDelegate::AdvanceChordLimitedImpl(track, stepMax, epsStep,
81 chordDistance);
82}
83
84template <class T>
85void G4IntegrationDriver<T>::OnStartTracking()
86{
87 ChordFinderDelegate::ResetStepEstimate();
88}
89
90// Runge-Kutta driver with adaptive stepsize control. Integrate starting
91// values at y_current over hstep x2 with accuracy eps.
92// On output ystart is replaced by values at the end of the integration
93// interval. RightHandSide is the right-hand side of ODE system.
94// The source is similar to odeint routine from NRC p.721-722 .
95//
96template <class T>
97G4bool G4IntegrationDriver<T>::
98AccurateAdvance(G4FieldTrack& track, G4double hstep,
99 G4double eps, G4double hinitial)
100{
101 ++fNoAccurateAdvanceCalls;
102
103 if (hstep == 0.0)
104 {
105 std::ostringstream message;
106 message << "Proposed step is zero; hstep = " << hstep << " !";
107 G4Exception("G4IntegrationDriver::AccurateAdvance()",
108 "GeomField1001", JustWarning, message);
109 return true;
110 }
111
112 if (hstep < 0)
113 {
114 std::ostringstream message;
115 message << "Invalid run condition." << G4endl
116 << "Proposed step is negative; hstep = " << hstep << "."
117 << G4endl
118 << "Requested step cannot be negative! Aborting event.";
119 G4Exception("G4IntegrationDriver::AccurateAdvance()",
120 "GeomField0003", EventMustBeAborted, message);
121 return false;
122 }
123
124 G4double hnext, hdid;
125
126 G4double dydx[G4FieldTrack::ncompSVEC];
127 G4bool succeeded = true, lastStepSucceeded;
128
129 G4int noFullIntegr = 0, noSmallIntegr = 0;
130
131 G4double y[G4FieldTrack::ncompSVEC];
132 track.DumpToArray(y);
133
134 const G4double startCurveLength = track.GetCurveLength();
135 const G4double endCurveLength = startCurveLength + hstep;
136 const G4double hThreshold =
137 std::min(eps * hstep, fSmallestFraction * startCurveLength);
138
139 G4double h = hstep;
140 if (hinitial > CLHEP::perMillion * hstep && hinitial < hstep)
141 {
142 h = hinitial;
143 }
144
145 G4double curveLength = startCurveLength;
146
147 for (G4int nstp = 0; nstp < Base::GetMaxNoSteps(); ++nstp)
148 {
149 const G4ThreeVector StartPos =
150 field_utils::makeVector(y, field_utils::Value3D::Position);
151
152 Base::GetStepper()->RightHandSide(y, dydx);
153
154 if (h > GetMinimumStep())
155 {
156 OneGoodStep(y, dydx, curveLength, h, eps, hdid, hnext);
157 lastStepSucceeded = (hdid == h);
158 }
159 else
160 {
161 G4FieldTrack yFldTrk('0');
162 G4double dchord_step, dyerr, dyerr_len;
163 yFldTrk.LoadFromArray(y, Base::GetStepper()->GetNumberOfVariables());
164 yFldTrk.SetCurveLength(curveLength);
165
166 QuickAdvance(yFldTrk, dydx, h, dchord_step, dyerr_len);
167
168 yFldTrk.DumpToArray(y);
169
170 if (h == 0.0)
171 {
172 G4Exception("G4IntegrationDriver::AccurateAdvance()",
173 "GeomField0003", FatalException,
174 "Integration Step became Zero!");
175 }
176 dyerr = dyerr_len / h;
177 hdid = h;
178 curveLength += hdid;
179 hnext = Base::ComputeNewStepSize(dyerr / eps, h);
180 lastStepSucceeded = (dyerr <= eps);
181 }
182
183 if (lastStepSucceeded) { ++noFullIntegr; }
184 else { ++noSmallIntegr; }
185
186 const G4ThreeVector EndPos =
187 field_utils::makeVector(y, field_utils::Value3D::Position);
188
189 CheckStep(EndPos, StartPos, hdid);
190
191 // Avoid numerous small last steps
192 if (h < hThreshold || curveLength >= endCurveLength)
193 {
194 break;
195 }
196
197 h = std::max(hnext, GetMinimumStep());
198 if (curveLength + h > endCurveLength)
199 {
200 h = endCurveLength - curveLength;
201 }
202 }
203 // Have we reached the end ?
204 // --> a better test might be x-endCurveLength > an_epsilon
205 succeeded = (curveLength >= endCurveLength);
206 // If it was a "forced" last step
207
208 track.LoadFromArray(y, Base::GetStepper()->GetNumberOfVariables());
209 track.SetCurveLength(curveLength);
210
211 return succeeded;
212}
213
214// Driver for one Runge-Kutta Step with monitoring of local truncation error
215// to ensure accuracy and adjust stepsize. Input are dependent variable
216// array y[0,...,5] and its derivative dydx[0,...,5] at the
217// starting value of the independent variable x . Also input are stepsize
218// to be attempted htry, and the required accuracy eps. On output y and x
219// are replaced by their new values, hdid is the stepsize that was actually
220// accomplished, and hnext is the estimated next stepsize.
221// This is similar to the function rkqs from the book:
222// Numerical Recipes in C: The Art of Scientific Computing (NRC), Second
223// Edition, by William H. Press, Saul A. Teukolsky, William T.
224// Vetterling, and Brian P. Flannery (Cambridge University Press 1992),
225// 16.2 Adaptive StepSize Control for Runge-Kutta, p. 719
226//
227template <class T>
228void G4IntegrationDriver<T>::OneGoodStep(G4double y[], // InOut
229 const G4double dydx[],
230 G4double& curveLength, // InOut
231 G4double htry,
232 G4double eps_rel_max,
233 G4double& hdid, // Out
234 G4double& hnext) // Out
235
236{
237 G4double error2 = DBL_MAX;
238
239 G4double yerr[G4FieldTrack::ncompSVEC], ytemp[G4FieldTrack::ncompSVEC];
240
241 G4double h = htry;
242
243 static G4ThreadLocal G4int tot_no_trials = 0;
244 const G4int max_trials = 100;
245
246 for (G4int iter = 0; iter < max_trials; ++iter)
247 {
248 tot_no_trials++;
249
250 Base::GetStepper()->Stepper(y, dydx, h, ytemp, yerr);
251 error2 = field_utils::relativeError2(y, yerr, std::max(h, fMinimumStep),
252 eps_rel_max);
253 if (error2 <= 1.0)
254 {
255 break;
256 }
257
258 h = Base::ShrinkStepSize2(h, error2);
259
260 G4double xnew = curveLength + h;
261 if(xnew == curveLength)
262 {
263 std::ostringstream message;
264 message << "Stepsize underflow in Stepper !" << G4endl
265 << "- Step's start x=" << curveLength
266 << " and end x= " << xnew
267 << " are equal !! " << G4endl
268 << " Due to step-size= " << h
269 << ". Note that input step was " << htry;
270 G4Exception("G4IntegrationDriver::OneGoodStep()",
271 "GeomField1001", JustWarning, message);
272 break;
273 }
274 }
275
276 hnext = Base::GrowStepSize2(h, error2);
277 curveLength += (hdid = h);
278
279 field_utils::copy(y, ytemp, Base::GetStepper()->GetNumberOfVariables());
280}
281
282template <class T>
283G4bool G4IntegrationDriver<T>::QuickAdvance(G4FieldTrack& track, // INOUT
284 const G4double dydx[],
285 G4double hstep,
286 G4double& dchord_step,
287 G4double& dyerr)
288{
289 ++fNoQuickAvanceCalls;
290
291 G4double yIn[G4FieldTrack::ncompSVEC],
292 yOut[G4FieldTrack::ncompSVEC],
293 yError[G4FieldTrack::ncompSVEC];
294
295 track.DumpToArray(yIn);
296
297 Base::GetStepper()->Stepper(yIn, dydx, hstep, yOut, yError);
298
299 dchord_step = Base::GetStepper()->DistChord();
300 dyerr = field_utils::absoluteError(yOut, yError, hstep);
301 track.LoadFromArray(yOut, Base::GetStepper()->GetNumberOfVariables());
302 track.SetCurveLength(track.GetCurveLength() + hstep);
303
304 return true;
305}
306
307template <class T>
308void G4IntegrationDriver<T>::SetSmallestFraction(G4double newFraction)
309{
310 if (newFraction > 1.e-16 && newFraction < 1e-8)
311 {
312 fSmallestFraction = newFraction;
313 }
314 else
315 {
316 std::ostringstream message;
317 message << "Smallest Fraction not changed. " << G4endl
318 << " Proposed value was " << newFraction << G4endl
319 << " Value must be between 1.e-8 and 1.e-16";
320 G4Exception("G4IntegrationDriver::SetSmallestFraction()",
321 "GeomField1001", JustWarning, message);
322 }
323}
324
325template <class T>
326void G4IntegrationDriver<T>::CheckStep(const G4ThreeVector& posIn,
327 const G4ThreeVector& posOut,
328 G4double hdid)
329{
330 const G4double endPointDist = (posOut - posIn).mag();
331 if (endPointDist >= hdid * (1. + CLHEP::perMillion))
332 {
333 ++fNoAccurateAdvanceBadSteps;
334#ifdef G4DEBUG_FIELD
335 // Issue a warning only for gross differences -
336 // we understand how small difference occur.
337 if (endPointDist >= hdid * (1. + perThousand))
338 {
339 G4Exception("G4IntegrationDriver::CheckStep()",
340 "GeomField1002", JustWarning,
341 "endPointDist >= hdid!");
342 }
343#endif
344 }
345 else
346 {
347 ++fNoAccurateAdvanceGoodSteps;
348 }
349}
350
351template <class T>
352inline G4double G4IntegrationDriver<T>::GetMinimumStep() const
353{
354 return fMinimumStep;
355}
356
357template <class T>
358void G4IntegrationDriver<T>::SetMinimumStep(G4double minimumStepLength)
359{
360 fMinimumStep = minimumStepLength;
361}
362
363template <class T>
364G4int G4IntegrationDriver<T>::GetVerboseLevel() const
365{
366 return fVerboseLevel;
367}
368
369template <class T>
370void G4IntegrationDriver<T>::SetVerboseLevel(G4int newLevel)
371{
372 fVerboseLevel = newLevel;
373}
374
375template <class T>
376G4double G4IntegrationDriver<T>::GetSmallestFraction() const
377{
378 return fSmallestFraction;
379}
380
381template <class T>
382void G4IntegrationDriver<T>::IncrementQuickAdvanceCalls()
383{
384 ++fNoQuickAvanceCalls;
385}
386
387template <class T>
388void G4IntegrationDriver<T>::StreamInfo( std::ostream& os ) const
389{
390// Write out the parameters / state of the driver
391 os << "State of G4IntegrationDriver: " << std::endl;
392 os << "--Base state (G4RKIntegrationDriver): " << std::endl;
393 Base::StreamInfo( os );
394 os << "--Own state (G4IntegrationDriver<>): " << std::endl;
395 os << " fMinimumStep = " << fMinimumStep << std::endl;
396 os << " Smallest Fraction = " << fSmallestFraction << std::endl;
397
398 os << " verbose level = " << fVerboseLevel << std::endl;
399 os << " Reintegrates = " << DoesReIntegrate() << std::endl;
400 os << "--Chord Finder Delegate state: " << std::endl;
401 ChordFinderDelegate::StreamDelegateInfo( os );
402}