Geant4-11
G4BulirschStoerDriver.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// G4BulirschStoer driver inline methods implementation
27
28// Author: Dmitry Sorokin, Google Summer of Code 2016
29// Supervision: John Apostolakis, CERN
30// --------------------------------------------------------------------
31
32#include <cassert>
33
34#include "G4LineSection.hh"
35#include "G4FieldUtils.hh"
36
37G4IntegrationDriver<G4BulirschStoer>::
38G4IntegrationDriver( G4double hminimum, G4BulirschStoer* stepper,
39 G4int numberOfComponents, G4int statisticsVerbosity )
40 : fMinimumStep(hminimum),
41 fVerbosity(statisticsVerbosity),
42 fMidpointMethod(stepper->GetEquationOfMotion(),
43 stepper->GetNumberOfVariables()),
44 bulirschStoer(stepper),
45 interval_sequence{2,4}
46{
47 assert(stepper->GetNumberOfVariables() == numberOfComponents);
48
49 if(stepper->GetNumberOfVariables() != numberOfComponents)
50 {
51 std::ostringstream msg;
52 msg << "Disagreement in number of variables = "
53 << stepper->GetNumberOfVariables()
54 << " vs no of components = " << numberOfComponents;
55 G4Exception("G4IntegrationDriver<G4BulirschStoer> Constructor:",
56 "GeomField1001", FatalException, msg);
57 }
58}
59
60G4bool G4IntegrationDriver<G4BulirschStoer>::
61AccurateAdvance( G4FieldTrack& track, G4double hstep,
62 G4double eps, G4double hinitial)
63{
64 G4int fNoTotalSteps = 0;
65 G4int fMaxNoSteps = 10000;
66 G4double fNoBadSteps = 0.0;
67 G4double fSmallestFraction = 1.0e-12;
68
69 // Driver with adaptive stepsize control. Integrate starting
70 // values at y_current over hstep x2 with accuracy eps.
71 // On output ystart is replaced by values at the end of the integration
72 // interval. RightHandSide is the right-hand side of ODE system.
73 // The source is similar to odeint routine from NRC p.721-722 .
74
75 // Ensure that hstep > 0
76 if(hstep == 0)
77 {
78 std::ostringstream message;
79 message << "Proposed step is zero; hstep = " << hstep << " !";
80 G4Exception("G4IntegrationDriver<G4BulirschStoer>::AccurateAdvance()",
81 "GeomField1001", JustWarning, message);
82
83 return true;
84 }
85 if(hstep < 0)
86 {
87 std::ostringstream message;
88 message << "Invalid run condition." << G4endl
89 << "Proposed step is negative; hstep = "
90 << hstep << "." << G4endl
91 << "Requested step cannot be negative! Aborting event.";
92 G4Exception("G4IntegrationDriver<G4BulirschStoer>::AccurateAdvance()",
93 "GeomField0003", EventMustBeAborted, message);
94
95 return false;
96 }
97
98 // init first step size
99 //
100 G4double h;
101 if ( (hinitial > 0) && (hinitial < hstep)
102 && (hinitial > perMillion * hstep) )
103 {
104 h = hinitial;
105 }
106 else // Initial Step size "h" defaults to the full interval
107 {
108 h = hstep;
109 }
110
111 // integration variables
112 //
113 track.DumpToArray(yCurrent);
114
115 // copy non-integration variables to out array
116 //
117 std::memcpy(yOut + GetNumberOfVarialbles(),
118 yCurrent + GetNumberOfVarialbles(),
119 sizeof(G4double)*(G4FieldTrack::ncompSVEC-GetNumberOfVarialbles()));
120
121 G4double startCurveLength = track.GetCurveLength();
122 G4double curveLength = startCurveLength;
123 G4double endCurveLength = startCurveLength + hstep;
124
125 // loop variables
126 //
127 G4int nstp = 1, no_warnings = 0;
128 G4double hnext, hdid;
129
130 G4bool succeeded = true, lastStepSucceeded;
131
132 G4int noFullIntegr = 0, noSmallIntegr = 0 ;
133 static G4ThreadLocal G4int noGoodSteps = 0 ; // Bad = chord > curve-len
134
135 G4bool lastStep = false;
136
137 // BulirschStoer->reset();
138
139 G4FieldTrack yFldTrk(track);
140
141 do
142 {
143 G4ThreeVector StartPos(yCurrent[0], yCurrent[1], yCurrent[2]);
144 GetEquationOfMotion()->RightHandSide(yCurrent, dydxCurrent);
145 fNoTotalSteps++;
146
147 // Perform the Integration
148 //
149 if(h == 0)
150 {
151 G4Exception("G4IntegrationDriver<G4BulirschStoer>::AccurateAdvance()",
152 "GeomField0003", FatalException,
153 "Integration Step became Zero!");
154 }
155 else if(h > fMinimumStep)
156 {
157 // step size if Ok
158 //
159 OneGoodStep(yCurrent,dydxCurrent,curveLength,h,eps,hdid,hnext);
160 lastStepSucceeded = (hdid == h);
161 }
162 else // for small steps call QuickAdvance for speed
163 {
164 G4double dchord_step, dyerr, dyerr_len; // What to do with these ?
165 yFldTrk.LoadFromArray(yCurrent, G4FieldTrack::ncompSVEC);
166 yFldTrk.SetCurveLength(curveLength);
167
168 QuickAdvance(yFldTrk, dydxCurrent, h, dchord_step, dyerr_len);
169
170 yFldTrk.DumpToArray(yCurrent);
171
172
173 dyerr = dyerr_len / h;
174 hdid = h;
175 curveLength += hdid;
176
177 // Compute suggested new step
178 // hnext = ComputeNewStepSize(dyerr/eps, h);
179 hnext = h;
180
181 // hnext= ComputeNewStepSize_WithinLimits( dyerr/eps, h);
182 lastStepSucceeded = (dyerr <= eps);
183 }
184
185 lastStepSucceeded ? ++noFullIntegr : ++noSmallIntegr;
186
187 G4ThreeVector EndPos(yCurrent[0], yCurrent[1], yCurrent[2]);
188
189 // Check the endpoint
190 //
191 G4double endPointDist = (EndPos - StartPos).mag();
192 if (endPointDist >= hdid*(1. + perMillion))
193 {
194 ++fNoBadSteps;
195
196 // Issue a warning only for gross differences -
197 // we understand how small difference occur.
198 //
199 if (endPointDist >= hdid*(1.+perThousand))
200 {
201 ++no_warnings;
202 }
203 }
204 else
205 {
206 ++noGoodSteps;
207 }
208
209 // Avoid numerous small last steps
210 //
211 if((h < eps * hstep) || (h < fSmallestFraction * startCurveLength))
212 {
213 // No more integration -- the next step will not happen
214 //
215 lastStep = true;
216 }
217 else
218 {
219 // Check the proposed next stepsize
220 //
221 if(std::fabs(hnext) < fMinimumStep)
222 {
223 // Make sure that the next step is at least Hmin
224 //
225 h = fMinimumStep;
226 }
227 else
228 {
229 h = hnext;
230 }
231
232 // Ensure that the next step does not overshoot
233 //
234 if (curveLength + h > endCurveLength)
235 {
236 h = endCurveLength - curveLength;
237 }
238
239 if (h == 0)
240 {
241 // Cannot progress - accept this as last step - by default
242 //
243 lastStep = true;
244 }
245 }
246 } while (((nstp++) <= fMaxNoSteps)
247 && (curveLength < endCurveLength) && (!lastStep));
248 //
249 // Have we reached the end ?
250 // --> a better test might be x-x2 > an_epsilon
251
252 succeeded = (curveLength >= endCurveLength);
253 // If it was a "forced" last step
254
255 // Copy integrated vars to output array
256 //
257 std::memcpy(yOut, yCurrent, sizeof(G4double) * GetNumberOfVarialbles());
258
259 // upload new state
260 track.LoadFromArray(yOut, G4FieldTrack::ncompSVEC);
261 track.SetCurveLength(curveLength);
262
263 if(nstp > fMaxNoSteps)
264 {
265 ++no_warnings;
266 succeeded = false;
267 }
268
269 return succeeded;
270}
271
272G4bool G4IntegrationDriver<G4BulirschStoer>::
273QuickAdvance( G4FieldTrack& track, const G4double dydx[],
274 G4double hstep, G4double& missDist, G4double& dyerr)
275{
276 const auto nvar = fMidpointMethod.GetNumberOfVariables();
277
278 track.DumpToArray(yIn);
279 const G4double curveLength = track.GetCurveLength();
280
281 fMidpointMethod.SetSteps(interval_sequence[0]);
282 fMidpointMethod.DoStep(yIn, dydx, yOut, hstep, yMid, derivs[0]);
283
284 fMidpointMethod.SetSteps(interval_sequence[1]);
285 fMidpointMethod.DoStep(yIn, dydx, yOut2, hstep, yMid2, derivs[1]);
286
287 // extrapolation
288 //
289 static const G4double coeff =
290 1. / (sqr(static_cast<G4double>(interval_sequence[1]) /
291 static_cast<G4double>(interval_sequence[0])) - 1.);
292
293 for (G4int i = 0; i < nvar; ++i)
294 {
295 yOut[i] = yOut2[i] + (yOut2[i] - yOut[i]) * coeff;
296 yMid[i] = yMid2[i] + (yMid2[i] - yMid[i]) * coeff;
297 }
298
299 // calculate chord length
300 //
301 const auto mid = field_utils::makeVector(yMid,
302 field_utils::Value3D::Position);
303 const auto in = field_utils::makeVector(yIn,
304 field_utils::Value3D::Position);
305 const auto out = field_utils::makeVector(yOut,
306 field_utils::Value3D::Position);
307
308 missDist = G4LineSection::Distline(mid, in, out);
309
310 // calculate error
311 //
312 for (G4int i = 0; i < nvar; ++i)
313 {
314 yError[i] = yOut[i] - yOut2[i];
315 }
316
317 dyerr = field_utils::absoluteError(yOut, yError, hstep);
318
319 // copy non-integrated variables to output array
320 //
321 std::memcpy(yOut + nvar, yIn + nvar,
322 sizeof(G4double) * (G4FieldTrack::ncompSVEC - nvar));
323
324 // set new state
325 //
326 track.LoadFromArray(yOut, G4FieldTrack::ncompSVEC);
327 track.SetCurveLength(curveLength + hstep);
328
329 return true;
330}
331
332void G4IntegrationDriver<G4BulirschStoer>::
333OneGoodStep( G4double y[], const G4double dydx[], G4double& curveLength,
334 G4double htry, G4double eps, G4double& hdid, G4double& hnext)
335{
336 hnext = htry;
337 G4double curveLengthBegin = curveLength;
338
339 // set maximum allowed error
340 //
341 bulirschStoer->set_max_relative_error(eps);
342
343 while (true)
344 {
345 auto res = bulirschStoer->try_step(y, dydx, curveLength, yOut, hnext);
346 if (res == G4BulirschStoer::step_result::success)
347 {
348 break;
349 }
350 }
351
352 std::memcpy(y, yOut, sizeof(G4double) * GetNumberOfVarialbles());
353 hdid = curveLength - curveLengthBegin;
354}
355
356void G4IntegrationDriver<G4BulirschStoer>::
357GetDerivatives( const G4FieldTrack& track, G4double dydx[]) const
358{
359 G4double y[G4FieldTrack::ncompSVEC];
360 track.DumpToArray(y);
361 GetEquationOfMotion()->RightHandSide(y, dydx);
362}
363
364void G4IntegrationDriver<G4BulirschStoer>::
365GetDerivatives( const G4FieldTrack& track, G4double dydx[],
366 G4double field[]) const
367{
368 G4double y[G4FieldTrack::ncompSVEC];
369 track.DumpToArray(y);
370 GetEquationOfMotion()->EvaluateRhsReturnB(y, dydx, field);
371}
372
373void G4IntegrationDriver<G4BulirschStoer>::SetVerboseLevel(G4int level)
374{
375 fVerbosity = level;
376}
377
378G4int G4IntegrationDriver<G4BulirschStoer>::GetVerboseLevel() const
379{
380 return fVerbosity;
381}
382
383G4double G4IntegrationDriver<G4BulirschStoer>::
384ComputeNewStepSize( G4double /* errMaxNorm*/, G4double hstepCurrent)
385{
386 return hstepCurrent;
387}
388
389G4EquationOfMotion* G4IntegrationDriver<G4BulirschStoer>::GetEquationOfMotion()
390{
391 assert(bulirschStoer->GetEquationOfMotion() ==
392 fMidpointMethod.GetEquationOfMotion());
393
394 return bulirschStoer->GetEquationOfMotion();
395}
396
397const G4EquationOfMotion*
398G4IntegrationDriver<G4BulirschStoer>::GetEquationOfMotion() const
399{
400 return const_cast<G4IntegrationDriver<G4BulirschStoer>*>(this)->
401 GetEquationOfMotion();
402}
403
404void G4IntegrationDriver<G4BulirschStoer>::
405SetEquationOfMotion( G4EquationOfMotion* equation )
406{
407 bulirschStoer->SetEquationOfMotion(equation);
408 fMidpointMethod.SetEquationOfMotion(equation);
409}
410
411G4int G4IntegrationDriver<G4BulirschStoer>::GetNumberOfVarialbles() const
412{
413 assert(bulirschStoer->GetNumberOfVariables() ==
414 fMidpointMethod.GetNumberOfVariables());
415
416 return bulirschStoer->GetNumberOfVariables();
417}
418
419const G4MagIntegratorStepper*
420G4IntegrationDriver<G4BulirschStoer>::GetStepper() const
421{
422 return nullptr;
423}
424
425G4MagIntegratorStepper*
426G4IntegrationDriver<G4BulirschStoer>::GetStepper()
427{
428 return nullptr;
429}
430
431void
432G4IntegrationDriver<G4BulirschStoer>::StreamInfo( std::ostream& os ) const
433{
434 os << "State of G4IntegrationDriver<G4BulirschStoer>: " << std::endl;
435 os << " Method is implemented, but gives no information. " << std::endl;
436}