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