Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4OldMagIntDriver.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// G4OldMagIntDriver -- same behaviour as old G4MagInt_Driver
27//
28// V.Grichine, 07.10.1996 - Created
29// J.Apostolakis, 08.11.2001 - Respect minimum step in AccurateAdvance
30// --------------------------------------------------------------------
31
32#include <iomanip>
33
34#include "globals.hh"
35#include "G4SystemOfUnits.hh"
37#include "G4OldMagIntDriver.hh"
38#include "G4FieldTrack.hh"
39
40#ifdef G4DEBUG_FIELD
41#include "G4DriverReporter.hh"
42#endif
43
44// ---------------------------------------------------------
45
46// Constructor
47//
49 G4MagIntegratorStepper* pStepper,
50 G4int numComponents,
51 G4int statisticsVerbose)
52 : fNoIntegrationVariables(numComponents),
53 fNoVars( std::max( fNoIntegrationVariables, fMinNoVars )),
54 fStatisticsVerboseLevel(statisticsVerbose)
55{
56 // In order to accomodate "Laboratory Time", which is [7], fMinNoVars=8
57 // is required. For proper time of flight and spin, fMinNoVars must be 12
58
59 RenewStepperAndAdjust( pStepper );
60 fMinimumStep = hminimum;
61
62 fMaxNoSteps = fMaxStepBase / pIntStepper->IntegratorOrder();
63#ifdef G4DEBUG_FIELD
64 fVerboseLevel=2;
65#endif
66
67 if( (fVerboseLevel > 0) || (fStatisticsVerboseLevel > 1) )
68 {
69 G4cout << "MagIntDriver version: Accur-Adv: "
70 << "invE_nS, QuickAdv-2sqrt with Statistics "
71#ifdef G4FLD_STATS
72 << " enabled "
73#else
74 << " disabled "
75#endif
76 << G4endl;
77 }
78}
79
80// ---------------------------------------------------------
81
82// Destructor
83//
85{
86 if( fStatisticsVerboseLevel > 1 )
87 {
89 }
90}
91
92// ---------------------------------------------------------
93
96 G4double hstep,
97 G4double eps,
98 G4double hinitial )
99{
100 // Runge-Kutta driver with adaptive stepsize control. Integrate starting
101 // values at y_current over hstep x2 with accuracy eps.
102 // On output ystart is replaced by values at the end of the integration
103 // interval. RightHandSide is the right-hand side of ODE system.
104 // The source is similar to odeint routine from NRC p.721-722 .
105
106 G4int nstp, i;
107 G4double x, hnext, hdid, h;
108
109#ifdef G4DEBUG_FIELD
110 G4int no_warnings = 0;
111 static G4int dbg = 1;
112 G4double ySubStepStart[G4FieldTrack::ncompSVEC];
113 G4FieldTrack yFldTrkStart(y_current);
114#endif
115
118 G4double x1, x2;
119 G4bool succeeded = true;
120
121 G4double startCurveLength;
122
123 const G4int nvar = fNoVars;
124
125 G4FieldTrack yStartFT(y_current);
126
127 // Ensure that hstep > 0
128 //
129 if( hstep <= 0.0 )
130 {
131 if( hstep == 0.0 )
132 {
133 std::ostringstream message;
134 message << "Proposed step is zero; hstep = " << hstep << " !";
135 G4Exception("G4OldMagIntDriver::AccurateAdvance()",
136 "GeomField1001", JustWarning, message);
137 return succeeded;
138 }
139 else
140 {
141 std::ostringstream message;
142 message << "Invalid run condition." << G4endl
143 << "Proposed step is negative; hstep = " << hstep << "." << G4endl
144 << "Requested step cannot be negative! Aborting event.";
145 G4Exception("G4OldMagIntDriver::AccurateAdvance()",
146 "GeomField0003", EventMustBeAborted, message);
147 return false;
148 }
149 }
150
151 y_current.DumpToArray( ystart );
152
153 startCurveLength= y_current.GetCurveLength();
154 x1= startCurveLength;
155 x2= x1 + hstep;
156
157 if ( (hinitial > 0.0) && (hinitial < hstep)
158 && (hinitial > perMillion * hstep) )
159 {
160 h = hinitial;
161 }
162 else // Initial Step size "h" defaults to the full interval
163 {
164 h = hstep;
165 }
166
167 x = x1;
168
169 for ( i=0; i<nvar; ++i) { y[i] = ystart[i]; }
170
171#ifdef G4DEBUG_FIELD
172 // G4cout << "IDriver: hstep = " << hstep << " hinitial= " << hinitial << " h = " << h << G4endl;
173 G4cout << "IDriver::AccurAdv called. "
174 << " Input: hstep = " << hstep << " hinitial= " << hinitial << " , current: h = " << h << G4endl;
175#endif
176
177 G4bool lastStep= false;
178 nstp = 1;
179
180 do
181 {
182 G4ThreeVector StartPos( y[0], y[1], y[2] );
183
184#ifdef G4DEBUG_FIELD
185 G4double xSubStepStart= x;
186 for (i=0; i<nvar; ++i) { ySubStepStart[i] = y[i]; }
187 yFldTrkStart.LoadFromArray(y, fNoIntegrationVariables);
188 yFldTrkStart.SetCurveLength(x);
189 if(dbg) // Debug
190 G4cout << "----- Iteration = " << nstp-1 << G4endl;
191#endif
192
193 pIntStepper->RightHandSide( y, dydx );
194 ++fNoTotalSteps;
195
196 // Perform the Integration
197 //
198 if( h > fMinimumStep )
199 {
200 OneGoodStep(y,dydx,x,h,eps,hdid,hnext) ;
201 //--------------------------------------
202
203#ifdef G4DEBUG_FIELD
204 if (dbg) // (dbg>2)
205 {
206 G4cout << "IntegrationDriver -- after OneGoodStep / requesting step = " << h << G4endl;
207 // PrintStatus( ySubStepStart, xSubStepStart, y, x, h, nstp); // Only
208 G4DriverReporter::PrintStatus( ySubStepStart, xSubStepStart, y, x, h, nstp, nvar);
209 }
210#endif
211 }
212 else
213 {
214 G4FieldTrack yFldTrk( G4ThreeVector(0,0,0),
215 G4ThreeVector(0,0,0), 0., 0., 0., 0. );
216 G4double dchord_step, dyerr, dyerr_len; // What to do with these ?
217 yFldTrk.LoadFromArray(y, fNoIntegrationVariables);
218 yFldTrk.SetCurveLength( x );
219
220 QuickAdvance( yFldTrk, dydx, h, dchord_step, dyerr_len );
221 //-----------------------------------------------------
222
223 yFldTrk.DumpToArray(y);
224
225#ifdef G4FLD_STATS
226 ++fNoSmallSteps;
227 if ( dyerr_len > fDyerr_max ) { fDyerr_max = dyerr_len; }
228 fDyerrPos_smTot += dyerr_len;
229 fSumH_sm += h; // Length total for 'small' steps
230 if (nstp<=1) { ++fNoInitialSmallSteps; }
231#endif
232#ifdef G4DEBUG_FIELD
233 if (dbg>1)
234 {
235 if(fNoSmallSteps<2) { PrintStatus(ySubStepStart, x1, y, x, h, -nstp); }
236 G4cout << "Another sub-min step, no " << fNoSmallSteps
237 << " of " << fNoTotalSteps << " this time " << nstp << G4endl;
238 PrintStatus( ySubStepStart, x1, y, x, h, nstp); // Only this
239 G4cout << " dyerr= " << dyerr_len << " relative = " << dyerr_len / h
240 << " epsilon= " << eps << " hstep= " << hstep
241 << " h= " << h << " hmin= " << fMinimumStep << G4endl;
242 }
243#endif
244 if( h == 0.0 )
245 {
246 G4Exception("G4OldMagIntDriver::AccurateAdvance()",
247 "GeomField0003", FatalException,
248 "Integration Step became Zero!");
249 }
250 dyerr = dyerr_len / h;
251 hdid = h;
252 x += hdid;
253
254 // Compute suggested new step
255 hnext = ComputeNewStepSize( dyerr/eps, h);
256
257 // .. hnext= ComputeNewStepSize_WithinLimits( dyerr/eps, h);
258 }
259
260 G4ThreeVector EndPos( y[0], y[1], y[2] );
261
262#if (G4DEBUG_FIELD>1)
263 static G4int nStpPr = 50; // For debug printing of long integrations
264 if( (dbg>0) && (dbg<=2) && (nstp>nStpPr))
265 {
266 if( nstp==nStpPr ) { G4cout << "***** Many steps ****" << G4endl; }
267 G4cout << "MagIntDrv: " ;
268 G4cout << "hdid=" << std::setw(12) << hdid << " "
269 << "hnext=" << std::setw(12) << hnext << " "
270 << "hstep=" << std::setw(12) << hstep << " (requested) "
271 << G4endl;
272 PrintStatus( ystart, x1, y, x, h, (nstp==nStpPr) ? -nstp: nstp);
273 }
274#endif
275
276 // Check the endpoint
277 G4double endPointDist= (EndPos-StartPos).mag();
278 if ( endPointDist >= hdid*(1.+perMillion) )
279 {
280 ++fNoBadSteps;
281
282 // Issue a warning only for gross differences -
283 // we understand how small difference occur.
284 if ( endPointDist >= hdid*(1.+perThousand) )
285 {
286#ifdef G4DEBUG_FIELD
287 if (dbg)
288 {
289 WarnEndPointTooFar ( endPointDist, hdid, eps, dbg );
290 G4cerr << " Total steps: bad " << fNoBadSteps
291 << " current h= " << hdid << G4endl;
292 PrintStatus( ystart, x1, y, x, hstep, no_warnings?nstp:-nstp);
293 }
294 ++no_warnings;
295#endif
296 }
297 }
298
299 // Avoid numerous small last steps
300 if( (h < eps * hstep) || (h < fSmallestFraction * startCurveLength) )
301 {
302 // No more integration -- the next step will not happen
303 lastStep = true;
304 }
305 else
306 {
307 // Check the proposed next stepsize
308 if(std::fabs(hnext) <= Hmin())
309 {
310#ifdef G4DEBUG_FIELD
311 // If simply a very small interval is being integrated, do not warn
312 if( (x < x2 * (1-eps) ) && // The last step can be small: OK
313 (std::fabs(hstep) > Hmin()) ) // and if we are asked, it's OK
314 {
315 if(dbg>0)
316 {
317 WarnSmallStepSize( hnext, hstep, h, x-x1, nstp );
318 PrintStatus( ystart, x1, y, x, hstep, no_warnings?nstp:-nstp);
319 }
320 ++no_warnings;
321 }
322#endif
323 // Make sure that the next step is at least Hmin.
324 h = Hmin();
325 }
326 else
327 {
328 h = hnext;
329 }
330
331 // Ensure that the next step does not overshoot
332 if ( x+h > x2 )
333 { // When stepsize overshoots, decrease it!
334 h = x2 - x ; // Must cope with difficult rounding-error
335 } // issues if hstep << x2
336
337 if ( h == 0.0 )
338 {
339 // Cannot progress - accept this as last step - by default
340 lastStep = true;
341#ifdef G4DEBUG_FIELD
342 if (dbg>2)
343 {
344 int prec= G4cout.precision(12);
345 G4cout << "Warning: G4MagIntegratorDriver::AccurateAdvance"
346 << G4endl
347 << " Integration step 'h' became "
348 << h << " due to roundoff. " << G4endl
349 << " Calculated as difference of x2= "<< x2 << " and x=" << x
350 << " Forcing termination of advance." << G4endl;
351 G4cout.precision(prec);
352 }
353#endif
354 }
355 }
356 } while ( ((nstp++)<=fMaxNoSteps) && (x < x2) && (!lastStep) );
357 // Loop checking, 07.10.2016, J. Apostolakis
358
359 // Have we reached the end ?
360 // --> a better test might be x-x2 > an_epsilon
361
362 succeeded = (x>=x2); // If it was a "forced" last step
363
364 for (i=0; i<nvar; ++i) { yEnd[i] = y[i]; }
365
366 // Put back the values.
367 y_current.LoadFromArray( yEnd, fNoIntegrationVariables );
368 y_current.SetCurveLength( x );
369
370 if(nstp > fMaxNoSteps)
371 {
372 succeeded = false;
373#ifdef G4DEBUG_FIELD
374 ++no_warnings;
375 if (dbg)
376 {
377 WarnTooManyStep( x1, x2, x ); // Issue WARNING
378 PrintStatus( yEnd, x1, y, x, hstep, -nstp);
379 }
380#endif
381 }
382
383#ifdef G4DEBUG_FIELD
384 if( dbg && no_warnings )
385 {
386 G4cerr << "G4MagIntegratorDriver exit status: no-steps " << nstp << G4endl;
387 PrintStatus( yEnd, x1, y, x, hstep, nstp);
388 }
389#endif
390
391 return succeeded;
392} // end of AccurateAdvance ...........................
393
394// ---------------------------------------------------------
395
396void
398 G4double h, G4double xDone,
399 G4int nstp)
400{
401 static G4ThreadLocal G4int noWarningsIssued = 0;
402 const G4int maxNoWarnings = 10; // Number of verbose warnings
403 std::ostringstream message;
404 if( (noWarningsIssued < maxNoWarnings) || fVerboseLevel > 10 )
405 {
406 message << "The stepsize for the next iteration, " << hnext
407 << ", is too small - in Step number " << nstp << "." << G4endl
408 << "The minimum for the driver is " << Hmin() << G4endl
409 << "Requested integr. length was " << hstep << " ." << G4endl
410 << "The size of this sub-step was " << h << " ." << G4endl
411 << "The integrations has already gone " << xDone;
412 }
413 else
414 {
415 message << "Too small 'next' step " << hnext
416 << ", step-no: " << nstp << G4endl
417 << ", this sub-step: " << h
418 << ", req_tot_len: " << hstep
419 << ", done: " << xDone << ", min: " << Hmin();
420 }
421 G4Exception("G4OldMagIntDriver::WarnSmallStepSize()", "GeomField1001",
422 JustWarning, message);
423 ++noWarningsIssued;
424}
425
426// ---------------------------------------------------------
427
428void
430 G4double x2end,
431 G4double xCurrent )
432{
433 std::ostringstream message;
434 message << "The number of steps used in the Integration driver"
435 << " (Runge-Kutta) is too many." << G4endl
436 << "Integration of the interval was not completed !" << G4endl
437 << "Only a " << (xCurrent-x1start)*100/(x2end-x1start)
438 << " % fraction of it was done.";
439 G4Exception("G4OldMagIntDriver::WarnTooManyStep()", "GeomField1001",
440 JustWarning, message);
441}
442
443// ---------------------------------------------------------
444
445void
447 G4double h ,
448 G4double eps,
449 G4int dbg)
450{
451 static G4ThreadLocal G4double maxRelError = 0.0;
452 G4bool isNewMax, prNewMax;
453
454 isNewMax = endPointDist > (1.0 + maxRelError) * h;
455 prNewMax = endPointDist > (1.0 + 1.05 * maxRelError) * h;
456 if( isNewMax ) { maxRelError= endPointDist / h - 1.0; }
457
459 && ( (dbg>1) || prNewMax || (endPointDist >= h*(1.+eps) ) ) )
460 {
461 static G4ThreadLocal G4int noWarnings = 0;
462 std::ostringstream message;
463 if( (noWarnings++ < 10) || (dbg>2) )
464 {
465 message << "The integration produced an end-point which " << G4endl
466 << "is further from the start-point than the curve length."
467 << G4endl;
468 }
469 message << " Distance of endpoints = " << endPointDist
470 << ", curve length = " << h << G4endl
471 << " Difference (curveLen-endpDist)= " << (h - endPointDist)
472 << ", relative = " << (h-endPointDist) / h
473 << ", epsilon = " << eps;
474 G4Exception("G4OldMagIntDriver::WarnEndPointTooFar()", "GeomField1001",
475 JustWarning, message);
476 }
477}
478
479// ---------------------------------------------------------
480
481void
483 const G4double dydx[],
484 G4double& x, // InOut
485 G4double htry,
486 G4double eps_rel_max,
487 G4double& hdid, // Out
488 G4double& hnext ) // Out
489
490// Driver for one Runge-Kutta Step with monitoring of local truncation error
491// to ensure accuracy and adjust stepsize. Input are dependent variable
492// array y[0,...,5] and its derivative dydx[0,...,5] at the
493// starting value of the independent variable x . Also input are stepsize
494// to be attempted htry, and the required accuracy eps. On output y and x
495// are replaced by their new values, hdid is the stepsize that was actually
496// accomplished, and hnext is the estimated next stepsize.
497// This is similar to the function rkqs from the book:
498// Numerical Recipes in C: The Art of Scientific Computing (NRC), Second
499// Edition, by William H. Press, Saul A. Teukolsky, William T.
500// Vetterling, and Brian P. Flannery (Cambridge University Press 1992),
501// 16.2 Adaptive StepSize Control for Runge-Kutta, p. 719
502
503{
504 G4double errmax_sq;
505 G4double h, htemp, xnew ;
506
508
509 h = htry ; // Set stepsize to the initial trial value
510
511 G4double inv_eps_vel_sq = 1.0 / (eps_rel_max*eps_rel_max);
512
513 G4double errpos_sq = 0.0; // square of displacement error
514 G4double errvel_sq = 0.0; // square of momentum vector difference
515 G4double errspin_sq = 0.0; // square of spin vector difference
516
517 const G4int max_trials=100;
518
519 G4ThreeVector Spin(y[9],y[10],y[11]);
520 G4double spin_mag2 = Spin.mag2();
521 G4bool hasSpin = (spin_mag2 > 0.0);
522
523 for (G4int iter=0; iter<max_trials; ++iter)
524 {
525 pIntStepper-> Stepper(y,dydx,h,ytemp,yerr);
526 // *******
527 G4double eps_pos = eps_rel_max * std::max(h, fMinimumStep);
528 G4double inv_eps_pos_sq = 1.0 / (eps_pos*eps_pos);
529
530 // Evaluate accuracy
531 //
532 errpos_sq = sqr(yerr[0]) + sqr(yerr[1]) + sqr(yerr[2]) ;
533 errpos_sq *= inv_eps_pos_sq; // Scale relative to required tolerance
534
535 // Accuracy for momentum
536 G4double magvel_sq= sqr(y[3]) + sqr(y[4]) + sqr(y[5]) ;
537 G4double sumerr_sq = sqr(yerr[3]) + sqr(yerr[4]) + sqr(yerr[5]) ;
538 if( magvel_sq > 0.0 )
539 {
540 errvel_sq = sumerr_sq / magvel_sq;
541 }
542 else
543 {
544 std::ostringstream message;
545 message << "Found case of zero momentum." << G4endl
546 << "- iteration= " << iter << "; h= " << h;
547 G4Exception("G4OldMagIntDriver::OneGoodStep()",
548 "GeomField1001", JustWarning, message);
549 errvel_sq = sumerr_sq;
550 }
551 errvel_sq *= inv_eps_vel_sq;
552 errmax_sq = std::max( errpos_sq, errvel_sq ); // Square of maximum error
553
554 if( hasSpin )
555 {
556 // Accuracy for spin
557 errspin_sq = ( sqr(yerr[9]) + sqr(yerr[10]) + sqr(yerr[11]) )
558 / spin_mag2; // ( sqr(y[9]) + sqr(y[10]) + sqr(y[11]) );
559 errspin_sq *= inv_eps_vel_sq;
560 errmax_sq = std::max( errmax_sq, errspin_sq );
561 }
562
563 if ( errmax_sq <= 1.0 ) { break; } // Step succeeded.
564
565 // Step failed; compute the size of retrial Step.
566 htemp = GetSafety() * h * std::pow( errmax_sq, 0.5*GetPshrnk() );
567
568 if (htemp >= 0.1*h) { h = htemp; } // Truncation error too large,
569 else { h = 0.1*h; } // reduce stepsize, but no more
570 // than a factor of 10
571 xnew = x + h;
572 if(xnew == x)
573 {
574 std::ostringstream message;
575 message << "Stepsize underflow in Stepper !" << G4endl
576 << "- Step's start x=" << x << " and end x= " << xnew
577 << " are equal !! " << G4endl
578 << " Due to step-size= " << h
579 << ". Note that input step was " << htry;
580 G4Exception("G4OldMagIntDriver::OneGoodStep()",
581 "GeomField1001", JustWarning, message);
582 break;
583 }
584 }
585
586 // Compute size of next Step
587 if (errmax_sq > errcon*errcon)
588 {
589 hnext = GetSafety()*h*std::pow(errmax_sq, 0.5*GetPgrow());
590 }
591 else
592 {
593 hnext = max_stepping_increase*h ; // No more than a factor of 5 increase
594 }
595 x += (hdid = h);
596
597 for(G4int k=0; k<fNoIntegrationVariables; ++k) { y[k] = ytemp[k]; }
598
599 return;
600}
601
602//----------------------------------------------------------------------
603
604// QuickAdvance just tries one Step - it does not ensure accuracy
605//
607 const G4double dydx[],
608 G4double hstep, // In
609 G4double& dchord_step,
610 G4double& dyerr_pos_sq,
611 G4double& dyerr_mom_rel_sq )
612{
613 G4Exception("G4OldMagIntDriver::QuickAdvance()", "GeomField0001",
614 FatalException, "Not yet implemented.");
615
616 // Use the parameters of this method, to please compiler
617 //
618 dchord_step = dyerr_pos_sq = hstep * hstep * dydx[0];
619 dyerr_mom_rel_sq = y_posvel.GetPosition().mag2();
620 return true;
621}
622
623//----------------------------------------------------------------------
624
626 const G4double dydx[],
627 G4double hstep, // In
628 G4double& dchord_step,
629 G4double& dyerr )
630{
631 G4double dyerr_pos_sq, dyerr_mom_rel_sq;
634 G4double s_start;
635 G4double dyerr_mom_sq, vel_mag_sq, inv_vel_mag_sq;
636
637#ifdef G4DEBUG_FIELD
638 G4FieldTrack startTrack( y_posvel ); // For debugging
639#endif
640
641 // Move data into array
642 y_posvel.DumpToArray( yarrin ); // yarrin <== y_posvel
643 s_start = y_posvel.GetCurveLength();
644
645 // Do an Integration Step
646 pIntStepper-> Stepper(yarrin, dydx, hstep, yarrout, yerr_vec) ;
647
648 // Estimate curve-chord distance
649 dchord_step= pIntStepper-> DistChord();
650
651 // Put back the values. yarrout ==> y_posvel
652 y_posvel.LoadFromArray( yarrout, fNoIntegrationVariables );
653 y_posvel.SetCurveLength( s_start + hstep );
654
655#ifdef G4DEBUG_FIELD
656 if(fVerboseLevel>2)
657 {
658 G4cout << "G4MagIntDrv: Quick Advance" << G4endl;
659 PrintStatus( yarrin, s_start, yarrout, s_start+hstep, hstep, 1);
660 }
661#endif
662
663 // A single measure of the error
664 // TO-DO : account for energy, spin, ... ?
665 vel_mag_sq = ( sqr(yarrout[3])+sqr(yarrout[4])+sqr(yarrout[5]) );
666 inv_vel_mag_sq = 1.0 / vel_mag_sq;
667 dyerr_pos_sq = ( sqr(yerr_vec[0])+sqr(yerr_vec[1])+sqr(yerr_vec[2]));
668 dyerr_mom_sq = ( sqr(yerr_vec[3])+sqr(yerr_vec[4])+sqr(yerr_vec[5]));
669 dyerr_mom_rel_sq = dyerr_mom_sq * inv_vel_mag_sq;
670
671 // Calculate also the change in the momentum squared also ???
672 // G4double veloc_square = y_posvel.GetVelocity().mag2();
673 // ...
674
675#ifdef RETURN_A_NEW_STEP_LENGTH
676 // The following step cannot be done here because "eps" is not known.
677 dyerr_len = std::sqrt( dyerr_len_sq );
678 dyerr_len_sq /= eps ;
679
680 // Look at the velocity deviation ?
681 // sqr(yerr_vec[3])+sqr(yerr_vec[4])+sqr(yerr_vec[5]));
682
683 // Set suggested new step
684 hstep = ComputeNewStepSize( dyerr_len, hstep);
685#endif
686
687 if( dyerr_pos_sq > ( dyerr_mom_rel_sq * sqr(hstep) ) )
688 {
689 dyerr = std::sqrt(dyerr_pos_sq);
690 }
691 else
692 {
693 // Scale it to the current step size - for now
694 dyerr = std::sqrt(dyerr_mom_rel_sq) * hstep;
695 }
696
697#ifdef G4DEBUG_FIELD
698 // For debugging
699 G4cout // << "G4MagInt_Driver::"
700 << "QuickAdvance" << G4endl
701 << " Input: hstep= " << hstep << G4endl
702 << " track= " << startTrack << G4endl
703 << " Output: track= " << y_posvel << G4endl
704 << " d_chord = " << dchord_step
705 << " dyerr = " << dyerr << G4endl;
706#endif
707
708 return true;
709}
710
711// --------------------------------------------------------------------------
712
713#ifdef QUICK_ADV_ARRAY_IN_AND_OUT
715 const G4double dydx[],
716 G4double hstep, // In
717 G4double yarrout[],
718 G4double& dchord_step,
719 G4double& dyerr ) // In length
720{
721 G4Exception("G4OldMagIntDriver::QuickAdvance()", "GeomField0001",
722 FatalException, "Not yet implemented.");
723 dyerr = dchord_step = hstep * yarrin[0] * dydx[0];
724 yarrout[0]= yarrin[0];
725}
726#endif
727
728// --------------------------------------------------------------------------
729
730// This method computes new step sizes - but does not limit changes to
731// within certain factors
732//
734ComputeNewStepSize(G4double errMaxNorm, // max error (normalised)
735 G4double hstepCurrent) // current step size
736{
737 G4double hnew;
738
739 // Compute size of next Step for a failed step
740 if(errMaxNorm > 1.0 )
741 {
742 // Step failed; compute the size of retrial Step.
743 hnew = GetSafety()*hstepCurrent*std::pow(errMaxNorm,GetPshrnk()) ;
744 }
745 else if(errMaxNorm > 0.0 )
746 {
747 // Compute size of next Step for a successful step
748 hnew = GetSafety()*hstepCurrent*std::pow(errMaxNorm,GetPgrow()) ;
749 }
750 else
751 {
752 // if error estimate is zero (possible) or negative (dubious)
753 hnew = max_stepping_increase * hstepCurrent;
754 }
755
756 return hnew;
757}
758
759// ---------------------------------------------------------------------------
760
761// This method computes new step sizes limiting changes within certain factors
762//
763// It shares its logic with AccurateAdvance.
764// They are kept separate currently for optimisation.
765//
768 G4double errMaxNorm, // max error (normalised)
769 G4double hstepCurrent) // current step size
770{
771 G4double hnew;
772
773 // Compute size of next Step for a failed step
774 if (errMaxNorm > 1.0 )
775 {
776 // Step failed; compute the size of retrial Step.
777 hnew = GetSafety()*hstepCurrent*std::pow(errMaxNorm,GetPshrnk()) ;
778
779 if (hnew < max_stepping_decrease*hstepCurrent)
780 {
781 hnew = max_stepping_decrease*hstepCurrent ;
782 // reduce stepsize, but no more
783 // than this factor (value= 1/10)
784 }
785 }
786 else
787 {
788 // Compute size of next Step for a successful step
789 if (errMaxNorm > errcon)
790 { hnew = GetSafety()*hstepCurrent*std::pow(errMaxNorm,GetPgrow()); }
791 else // No more than a factor of 5 increase
792 { hnew = max_stepping_increase * hstepCurrent; }
793 }
794 return hnew;
795}
796
797// ---------------------------------------------------------------------------
798
800 G4double xstart,
801 const G4double* CurrentArr,
802 G4double xcurrent,
803 G4double requestStep,
804 G4int subStepNo )
805 // Potentially add as arguments:
806 // <dydx> - as Initial Force
807 // stepTaken(hdid) - last step taken
808 // nextStep (hnext) - proposal for size
809{
810 G4FieldTrack StartFT(G4ThreeVector(0,0,0),
811 G4ThreeVector(0,0,0), 0., 0., 0., 0. );
812 G4FieldTrack CurrentFT (StartFT);
813
814 StartFT.LoadFromArray( StartArr, fNoIntegrationVariables);
815 StartFT.SetCurveLength( xstart);
816 CurrentFT.LoadFromArray( CurrentArr, fNoIntegrationVariables);
817 CurrentFT.SetCurveLength( xcurrent );
818
819 PrintStatus(StartFT, CurrentFT, requestStep, subStepNo );
820}
821
822// ---------------------------------------------------------------------------
823
825 const G4FieldTrack& CurrentFT,
826 G4double requestStep,
827 G4int subStepNo)
828{
829 G4int verboseLevel= fVerboseLevel;
830 const G4int noPrecision = 5;
831 G4long oldPrec= G4cout.precision(noPrecision);
832 // G4cout.setf(ios_base::fixed,ios_base::floatfield);
833
834 const G4ThreeVector StartPosition= StartFT.GetPosition();
835 const G4ThreeVector StartUnitVelocity= StartFT.GetMomentumDir();
836 const G4ThreeVector CurrentPosition= CurrentFT.GetPosition();
837 const G4ThreeVector CurrentUnitVelocity= CurrentFT.GetMomentumDir();
838
839 G4double DotStartCurrentVeloc= StartUnitVelocity.dot(CurrentUnitVelocity);
840
841 G4double step_len= CurrentFT.GetCurveLength() - StartFT.GetCurveLength();
842 G4double subStepSize = step_len;
843
844 if( (subStepNo <= 1) || (verboseLevel > 3) )
845 {
846 subStepNo = - subStepNo; // To allow printing banner
847
848 G4cout << std::setw( 6) << " " << std::setw( 25)
849 << " G4OldMagIntDriver: Current Position and Direction" << " "
850 << G4endl;
851 G4cout << std::setw( 5) << "Step#" << " "
852 << std::setw( 7) << "s-curve" << " "
853 << std::setw( 9) << "X(mm)" << " "
854 << std::setw( 9) << "Y(mm)" << " "
855 << std::setw( 9) << "Z(mm)" << " "
856 << std::setw( 8) << " N_x " << " "
857 << std::setw( 8) << " N_y " << " "
858 << std::setw( 8) << " N_z " << " "
859 << std::setw( 8) << " N^2-1 " << " "
860 << std::setw(10) << " N(0).N " << " "
861 << std::setw( 7) << "KinEner " << " "
862 << std::setw(12) << "Track-l" << " " // Add the Sub-step ??
863 << std::setw(12) << "Step-len" << " "
864 << std::setw(12) << "Step-len" << " "
865 << std::setw( 9) << "ReqStep" << " "
866 << G4endl;
867 }
868
869 if( (subStepNo <= 0) )
870 {
871 PrintStat_Aux( StartFT, requestStep, 0.,
872 0, 0.0, 1.0);
873 }
874
875 if( verboseLevel <= 3 )
876 {
877 G4cout.precision(noPrecision);
878 PrintStat_Aux( CurrentFT, requestStep, step_len,
879 subStepNo, subStepSize, DotStartCurrentVeloc );
880 }
881
882 G4cout.precision(oldPrec);
883}
884
885// ---------------------------------------------------------------------------
886
888 G4double requestStep,
889 G4double step_len,
890 G4int subStepNo,
891 G4double subStepSize,
892 G4double dotVeloc_StartCurr)
893{
894 const G4ThreeVector Position = aFieldTrack.GetPosition();
895 const G4ThreeVector UnitVelocity = aFieldTrack.GetMomentumDir();
896
897 if( subStepNo >= 0)
898 {
899 G4cout << std::setw( 5) << subStepNo << " ";
900 }
901 else
902 {
903 G4cout << std::setw( 5) << "Start" << " ";
904 }
905 G4double curveLen= aFieldTrack.GetCurveLength();
906 G4cout << std::setw( 7) << curveLen;
907 G4cout << std::setw( 9) << Position.x() << " "
908 << std::setw( 9) << Position.y() << " "
909 << std::setw( 9) << Position.z() << " "
910 << std::setw( 8) << UnitVelocity.x() << " "
911 << std::setw( 8) << UnitVelocity.y() << " "
912 << std::setw( 8) << UnitVelocity.z() << " ";
913 G4long oldprec= G4cout.precision(3);
914 G4cout << std::setw( 8) << UnitVelocity.mag2()-1.0 << " ";
915 G4cout.precision(6);
916 G4cout << std::setw(10) << dotVeloc_StartCurr << " ";
917 G4cout.precision(oldprec);
918 G4cout << std::setw( 7) << aFieldTrack.GetKineticEnergy();
919 G4cout << std::setw(12) << step_len << " ";
920
921 static G4ThreadLocal G4double oldCurveLength = 0.0;
922 static G4ThreadLocal G4double oldSubStepLength = 0.0;
923 static G4ThreadLocal G4int oldSubStepNo = -1;
924
925 G4double subStep_len = 0.0;
926 if( curveLen > oldCurveLength )
927 {
928 subStep_len= curveLen - oldCurveLength;
929 }
930 else if (subStepNo == oldSubStepNo)
931 {
932 subStep_len= oldSubStepLength;
933 }
934 oldCurveLength= curveLen;
935 oldSubStepLength= subStep_len;
936
937 G4cout << std::setw(12) << subStep_len << " ";
938 G4cout << std::setw(12) << subStepSize << " ";
939 if( requestStep != -1.0 )
940 {
941 G4cout << std::setw( 9) << requestStep << " ";
942 }
943 else
944 {
945 G4cout << std::setw( 9) << " InitialStep " << " ";
946 }
947 G4cout << G4endl;
948}
949
950// ---------------------------------------------------------------------------
951
953{
954 G4int noPrecBig = 6;
955 G4long oldPrec = G4cout.precision(noPrecBig);
956
957 G4cout << "G4OldMagIntDriver Statistics of steps undertaken. " << G4endl;
958 G4cout << "G4OldMagIntDriver: Number of Steps: "
959 << " Total= " << fNoTotalSteps
960 << " Bad= " << fNoBadSteps
961 << " Small= " << fNoSmallSteps
962 << " Non-initial small= " << (fNoSmallSteps-fNoInitialSmallSteps)
963 << G4endl;
964 G4cout.precision(oldPrec);
965}
966
967// ---------------------------------------------------------------------------
968
970{
971 if( (newFraction > 1.e-16) && (newFraction < 1e-8) )
972 {
973 fSmallestFraction= newFraction;
974 }
975 else
976 {
977 std::ostringstream message;
978 message << "Smallest Fraction not changed. " << G4endl
979 << " Proposed value was " << newFraction << G4endl
980 << " Value must be between 1.e-8 and 1.e-16";
981 G4Exception("G4OldMagIntDriver::SetSmallestFraction()",
982 "GeomField1001", JustWarning, message);
983 }
984}
985
987GetDerivatives(const G4FieldTrack& y_curr, G4double* dydx) const
988{
990 y_curr.DumpToArray(ytemp);
991 pIntStepper->RightHandSide(ytemp, dydx);
992 // Avoid virtual call for GetStepper
993 // Was: GetStepper()->ComputeRightHandSide(ytemp, dydx);
994}
995
997 G4double dydx[],
998 G4double field[]) const
999{
1001 track.DumpToArray(ytemp);
1002 pIntStepper->RightHandSide(ytemp, dydx, field);
1003}
1004
1006{
1007 return pIntStepper->GetEquationOfMotion();
1008}
1009
1011{
1012 pIntStepper->SetEquationOfMotion(equation);
1013}
1014
1016{
1017 return pIntStepper;
1018}
1019
1021{
1022 return pIntStepper;
1023}
1024
1027{
1028 pIntStepper = pItsStepper;
1030}
1031
1032void G4OldMagIntDriver::StreamInfo( std::ostream& os ) const
1033{
1034 os << "State of G4OldMagIntDriver: " << std::endl;
1035 os << " Max number of Steps = " << fMaxNoSteps
1036 << " (base # = " << fMaxStepBase << " )" << std::endl;
1037 os << " Safety factor = " << safety << std::endl;
1038 os << " Power - shrink = " << pshrnk << std::endl;
1039 os << " Power - grow = " << pgrow << std::endl;
1040 os << " threshold (errcon) = " << errcon << std::endl;
1041
1042 os << " fMinimumStep = " << fMinimumStep << std::endl;
1043 os << " Smallest Fraction = " << fSmallestFraction << std::endl;
1044
1045 os << " No Integrat Vars = " << fNoIntegrationVariables << std::endl;
1046 os << " Min No Vars = " << fMinNoVars << std::endl;
1047 os << " Num-Vars = " << fNoVars << std::endl;
1048
1049 os << " verbose level = " << fVerboseLevel << std::endl;
1050
1051 // auto p= const_cast<G4OldMagIntDriver*>(this);
1052 G4bool does = // p->DoesReIntegrate();
1053 const_cast<G4OldMagIntDriver*>(this)->DoesReIntegrate();
1054 os << " Reintegrates = " << does << std::endl;
1055}
const G4int noPrecision
@ JustWarning
@ FatalException
@ EventMustBeAborted
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
Definition: G4Exception.cc:59
CLHEP::Hep3Vector G4ThreeVector
double G4double
Definition: G4Types.hh:83
long G4long
Definition: G4Types.hh:87
bool G4bool
Definition: G4Types.hh:86
int G4int
Definition: G4Types.hh:85
G4GLOB_DLL std::ostream G4cerr
#define G4endl
Definition: G4ios.hh:57
G4GLOB_DLL std::ostream G4cout
double z() const
double x() const
double mag2() const
double y() const
double dot(const Hep3Vector &) const
static void PrintStatus(const G4double *StartArr, G4double xstart, const G4double *CurrentArr, G4double xcurrent, G4double requestStep, unsigned int subStepNo, unsigned int noIntegrationVariables)
const G4ThreeVector & GetMomentumDir() const
G4double GetCurveLength() const
void SetCurveLength(G4double nCurve_s)
G4double GetKineticEnergy() const
G4ThreeVector GetPosition() const
void DumpToArray(G4double valArr[ncompSVEC]) const
void LoadFromArray(const G4double valArr[ncompSVEC], G4int noVarsIntegrated)
G4double GetSurfaceTolerance() const
static G4GeometryTolerance * GetInstance()
G4EquationOfMotion * GetEquationOfMotion()
void RightHandSide(const G4double y[], G4double dydx[]) const
void SetEquationOfMotion(G4EquationOfMotion *newEquation)
virtual G4int IntegratorOrder() const =0
void PrintStat_Aux(const G4FieldTrack &aFieldTrack, G4double requestStep, G4double actualStep, G4int subStepNo, G4double subStepSize, G4double dotVelocities)
virtual G4bool QuickAdvance(G4FieldTrack &y_val, const G4double dydx[], G4double hstep, G4double &dchord_step, G4double &dyerr) override
virtual G4bool DoesReIntegrate() const override
G4double ComputeNewStepSize_WithinLimits(G4double errMaxNorm, G4double hstepCurrent)
void PrintStatus(const G4double *StartArr, G4double xstart, const G4double *CurrentArr, G4double xcurrent, G4double requestStep, G4int subStepNo)
G4double GetPgrow() const
virtual G4bool AccurateAdvance(G4FieldTrack &y_current, G4double hstep, G4double eps, G4double hinitial=0.0) override
void OneGoodStep(G4double ystart[], const G4double dydx[], G4double &x, G4double htry, G4double eps, G4double &hdid, G4double &hnext)
void WarnSmallStepSize(G4double hnext, G4double hstep, G4double h, G4double xDone, G4int noSteps)
void ReSetParameters(G4double new_safety=0.9)
virtual ~G4OldMagIntDriver() override
virtual void SetEquationOfMotion(G4EquationOfMotion *equation) override
G4double GetSafety() const
void SetSmallestFraction(G4double val)
void StreamInfo(std::ostream &os) const override
virtual G4double ComputeNewStepSize(G4double errMaxNorm, G4double hstepCurrent) override
virtual void GetDerivatives(const G4FieldTrack &y_curr, G4double dydx[]) const override
virtual G4EquationOfMotion * GetEquationOfMotion() override
virtual void RenewStepperAndAdjust(G4MagIntegratorStepper *pItsStepper) override
G4double Hmin() const
G4double GetPshrnk() const
virtual const G4MagIntegratorStepper * GetStepper() const override
G4OldMagIntDriver(G4double hminimum, G4MagIntegratorStepper *pItsStepper, G4int numberOfComponents=6, G4int statisticsVerbosity=0)
void WarnEndPointTooFar(G4double endPointDist, G4double hStepSize, G4double epsilonRelative, G4int debugFlag)
void WarnTooManyStep(G4double x1start, G4double x2end, G4double xCurrent)
static constexpr G4double max_stepping_decrease
static constexpr G4double max_stepping_increase
T sqr(const T &x)
Definition: templates.hh:128
#define G4ThreadLocal
Definition: tls.hh:77