Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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