47 const G4double G4FSALIntegrationDriver::max_stepping_increase = 5.0;
48 const G4double G4FSALIntegrationDriver::max_stepping_decrease = 0.1;
53 const G4int G4FSALIntegrationDriver::fMaxStepBase = 100000;
55 #ifndef G4NO_FIELD_STATISTICS
70 G4int statisticsVerbose)
71 : fSmallestFraction( 1.0e-12 ),
72 fNoIntegrationVariables(numComponents),
74 fNoVars( std::
max( fNoIntegrationVariables, fMinNoVars )),
75 fStatisticsVerboseLevel(statisticsVerbose),
76 fNoTotalSteps(0), fNoBadSteps(0), fNoSmallSteps(0),
77 fNoInitialSmallSteps(0),
78 fDyerr_max(0.0), fDyerr_mx2(0.0),
79 fDyerrPos_smTot(0.0), fDyerrPos_lgTot(0.0), fDyerrVel_lgTot(0.0),
80 fSumH_sm(0.0), fSumH_lg(0.0),
82 TotalNoStepperCalls(0)
88 fMinimumStep= hminimum;
94 if( (fVerboseLevel > 0) || (fStatisticsVerboseLevel > 1) )
96 G4cout <<
"MagIntDriver version: Accur-Adv: "
97 <<
"invE_nS, QuickAdv-2sqrt with Statistics "
113 if( fStatisticsVerboseLevel > 1 )
137 G4int nstp, i, no_warnings=0;
142 static G4int nStpPr=50;
150 G4bool succeeded =
true, lastStepSucceeded;
154 G4int noFullIntegr=0, noSmallIntegr = 0 ;
156 const G4int nvar= fNoVars;
166 std::ostringstream message;
167 message <<
"Proposed step is zero; hstep = " << hstep <<
" !";
168 G4Exception(
"G4FSALIntegrationDriver::AccurateAdvance()",
174 std::ostringstream message;
175 message <<
"Invalid run condition." <<
G4endl
176 <<
"Proposed step is negative; hstep = " << hstep <<
"." <<
G4endl
177 <<
"Requested step cannot be negative! Aborting event.";
178 G4Exception(
"G4FSALIntegrationDriver::AccurateAdvance()",
187 x1= startCurveLength;
190 if ( (hinitial > 0.0) && (hinitial < hstep)
202 for (i=0;i<nvar;i++) { y[i] = ystart[i]; }
216 for (i=0;i<nvar;i++) { ySubStepStart[i] = y[i]; }
228 if( h > fMinimumStep )
232 lastStepSucceeded= (hdid == h);
235 PrintStatus( ySubStepStart, xSubStepStart, y, x, h, nstp);
243 G4double dchord_step, dyerr, dyerr_len;
247 QuickAdvance( yFldTrk, dydx, h, dchord_step, dyerr_len );
254 if ( dyerr_len > fDyerr_max) { fDyerr_max= dyerr_len; }
255 fDyerrPos_smTot += dyerr_len;
257 if (nstp<=1) { fNoInitialSmallSteps++; }
262 if(fNoSmallSteps<2) {
PrintStatus(ySubStepStart, x1, y, x, h, -nstp); }
263 G4cout <<
"Another sub-min step, no " << fNoSmallSteps
264 <<
" of " << fNoTotalSteps <<
" this time " << nstp <<
G4endl;
266 G4cout <<
" dyerr= " << dyerr_len <<
" relative = " << dyerr_len / h
267 <<
" epsilon= " << eps <<
" hstep= " << hstep
268 <<
" h= " << h <<
" hmin= " << fMinimumStep <<
G4endl;
273 G4Exception(
"G4FSALIntegrationDriver::AccurateAdvance()",
275 "Integration Step became Zero!");
277 dyerr = dyerr_len / h;
285 lastStepSucceeded= (dyerr<=
eps);
288 if (lastStepSucceeded) { noFullIntegr++; }
289 else { noSmallIntegr++; }
294 if( (dbg>0) && (dbg<=2) && (nstp>nStpPr))
296 if( nstp==nStpPr ) {
G4cout <<
"***** Many steps ****" <<
G4endl; }
298 G4cout <<
"hdid=" << std::setw(12) << hdid <<
" "
299 <<
"hnext=" << std::setw(12) << hnext <<
" "
300 <<
"hstep=" << std::setw(12) << hstep <<
" (requested) "
302 PrintStatus( ystart, x1, y, x, h, (nstp==nStpPr) ? -nstp: nstp);
307 G4double endPointDist= (EndPos-StartPos).mag();
320 G4cerr <<
" Total steps: bad " << fNoBadSteps
321 <<
" good " << noGoodSteps <<
" current h= " << hdid
323 PrintStatus( ystart, x1, y, x, hstep, no_warnings?nstp:-nstp);
336 if( (h < eps * hstep) || (h < fSmallestFraction * startCurveLength) )
344 if(std::fabs(hnext) <=
Hmin())
348 if( (x < x2 * (1-eps) ) &&
349 (std::fabs(hstep) >
Hmin()) )
354 PrintStatus( ystart, x1, y, x, hstep, no_warnings?nstp:-nstp);
381 G4cout <<
"Warning: FSALMagIntegratorDriver::AccurateAdvance"
383 <<
" Integration step 'h' became "
384 << h <<
" due to roundoff. " <<
G4endl
385 <<
" Calculated as difference of x2= "<< x2 <<
" and x=" << x
386 <<
" Forcing termination of advance." <<
G4endl;
392 }
while ( ((nstp++)<=fMaxNoSteps) && (x < x2) && (!lastStep) );
400 for (i=0;i<nvar;i++) { yEnd[i] = y[i]; }
406 if(nstp > fMaxNoSteps)
420 if( dbg && no_warnings )
422 G4cerr <<
"FSALMagIntegratorDriver exit status: no-steps " << nstp <<
G4endl;
438 const G4int maxNoWarnings = 10;
439 std::ostringstream message;
440 if( (noWarningsIssued < maxNoWarnings) || fVerboseLevel > 10 )
442 message <<
"The stepsize for the next iteration, " << hnext
443 <<
", is too small - in Step number " << nstp <<
"." <<
G4endl
444 <<
"The minimum for the driver is " <<
Hmin() <<
G4endl
445 <<
"Requested integr. length was " << hstep <<
" ." <<
G4endl
446 <<
"The size of this sub-step was " << h <<
" ." <<
G4endl
447 <<
"The integrations has already gone " << xDone;
451 message <<
"Too small 'next' step " << hnext
452 <<
", step-no: " << nstp <<
G4endl
453 <<
", this sub-step: " << h
454 <<
", req_tot_len: " << hstep
455 <<
", done: " << xDone <<
", min: " <<
Hmin();
457 G4Exception(
"G4FSALIntegrationDriver::WarnSmallStepSize()",
"GeomField1001",
469 std::ostringstream message;
470 message <<
"The number of steps used in the Integration driver"
471 <<
" (Runge-Kutta) is too many." <<
G4endl
472 <<
"Integration of the interval was not completed !" <<
G4endl
473 <<
"Only a " << (xCurrent-x1start)*100/(x2end-x1start)
474 <<
" % fraction of it was done.";
475 G4Exception(
"G4FSALIntegrationDriver::WarnTooManyStep()",
"GeomField1001",
488 G4bool isNewMax, prNewMax;
490 isNewMax = endPointDist > (1.0 + maxRelError) * h;
491 prNewMax = endPointDist > (1.0 + 1.05 * maxRelError) * h;
492 if( isNewMax ) { maxRelError= endPointDist / h - 1.0; }
495 && ( (dbg>1) || prNewMax || (endPointDist >= h*(1.+
eps) ) ) )
498 std::ostringstream message;
499 if( (noWarnings ++ < 10) || (dbg>2) )
501 message <<
"The integration produced an end-point which " <<
G4endl
502 <<
"is further from the start-point than the curve length."
505 message <<
" Distance of endpoints = " << endPointDist
506 <<
", curve length = " << h <<
G4endl
507 <<
" Difference (curveLen-endpDist)= " << (h - endPointDist)
508 <<
", relative = " << (h-endPointDist) / h
509 <<
", epsilon = " <<
eps;
510 G4Exception(
"G4FSALIntegrationDriver::WarnEndPointTooFar()",
"GeomField1001",
547 G4double inv_eps_vel_sq = 1.0 / (eps_rel_max*eps_rel_max);
559 const G4int max_trials=100000;
564 G4bool hasSpin= (spin_mag2 > 0.0);
566 for (iter=0; iter<max_trials ;iter++)
569 pIntStepper-> Stepper(y,dydx,h,ytemp,yerr, dydx);
571 TotalNoStepperCalls++;
573 G4double inv_eps_pos_sq = 1.0 / (eps_pos*eps_pos);
577 errpos_sq =
sqr(yerr[0]) +
sqr(yerr[1]) +
sqr(yerr[2]) ;
578 errpos_sq *= inv_eps_pos_sq;
583 if( magvel_sq > 0.0 ) {
584 errvel_sq = sumerr_sq / magvel_sq;
586 G4cerr <<
"** G4MagIntegrationDriver: found case of zero momentum."
587 <<
" iteration= " << iter <<
" h= " << h <<
G4endl;
588 errvel_sq = sumerr_sq;
590 errvel_sq *= inv_eps_vel_sq;
591 errmax_sq =
std::max( errpos_sq, errvel_sq );
596 errspin_sq = (
sqr(yerr[9]) +
sqr(yerr[10]) +
sqr(yerr[11]) )
598 errspin_sq *= inv_eps_vel_sq;
599 errmax_sq =
std::max( errmax_sq, errspin_sq );
602 if ( errmax_sq <= 1.0 ) {
break; }
607 if (htemp >= 0.1*h) { h = htemp; }
613 G4cerr <<
"FSALMagIntegratorDriver::OneGoodStep:" <<
G4endl
614 <<
" Stepsize underflow in Stepper " <<
G4endl ;
615 G4cerr <<
" Step's start x=" << x <<
" and end x= " << xnew
616 <<
" are equal !! " << G4endl
617 <<
" Due to step-size= " << h
618 <<
" . Note that input step was " << htry <<
G4endl;
626 fDyerrPos_lgTot += errpos_sq;
627 fDyerrVel_lgTot += errvel_sq * h * h;
631 if (errmax_sq > errcon*errcon)
637 hnext = max_stepping_increase*h ;
641 for(
G4int k=0;k<fNoIntegrationVariables;k++) { y[k] = ytemp[k]; }
658 G4Exception(
"G4FSALIntegrationDriver::QuickAdvance()",
"GeomField0001",
662 dchord_step = dyerr_pos_sq = hstep * hstep * dydx[0];
676 G4double dyerr_pos_sq, dyerr_mom_rel_sq;
680 G4double dyerr_mom_sq, vel_mag_sq, inv_vel_mag_sq;
690 pIntStepper-> Stepper(yarrin, dydx, hstep, yarrout, yerr_vec, dydx) ;
694 dchord_step= pIntStepper-> DistChord();
705 PrintStatus( yarrin, s_start, yarrout, s_start+hstep, hstep, 1);
711 vel_mag_sq = (
sqr(yarrout[3])+
sqr(yarrout[4])+
sqr(yarrout[5]) );
712 inv_vel_mag_sq = 1.0 / vel_mag_sq;
713 dyerr_pos_sq = (
sqr(yerr_vec[0])+
sqr(yerr_vec[1])+
sqr(yerr_vec[2]));
714 dyerr_mom_sq = (
sqr(yerr_vec[3])+
sqr(yerr_vec[4])+
sqr(yerr_vec[5]));
715 dyerr_mom_rel_sq = dyerr_mom_sq * inv_vel_mag_sq;
721 #ifdef RETURN_A_NEW_STEP_LENGTH
723 dyerr_len = std::sqrt( dyerr_len_sq );
724 dyerr_len_sq /=
eps ;
733 if( dyerr_pos_sq > ( dyerr_mom_rel_sq *
sqr(hstep) ) )
735 dyerr = std::sqrt(dyerr_pos_sq);
740 dyerr = std::sqrt(dyerr_mom_rel_sq) * hstep;
748 #ifdef QUICK_ADV_ARRAY_IN_AND_OUT
757 G4Exception(
"G4FSALIntegrationDriver::QuickAdvance()",
"GeomField0001",
759 dyerr = dchord_step = hstep * yarrin[0] * dydx[0];
760 yarrout[0]= yarrin[0];
777 if(errMaxNorm > 1.0 )
781 }
else if(errMaxNorm > 0.0 ) {
786 hnew = max_stepping_increase * hstepCurrent;
807 if (errMaxNorm > 1.0 )
812 if (hnew < max_stepping_decrease*hstepCurrent)
814 hnew = max_stepping_decrease*hstepCurrent ;
822 if (errMaxNorm > errcon)
825 { hnew = max_stepping_increase * hstepCurrent; }
849 CurrentFT.
LoadFromArray( CurrentArr, fNoIntegrationVariables);
852 PrintStatus(StartFT, CurrentFT, requestStep, subStepNo );
863 G4int verboseLevel= fVerboseLevel;
873 G4double DotStartCurrentVeloc= StartUnitVelocity.
dot(CurrentUnitVelocity);
878 if( (subStepNo <= 1) || (verboseLevel > 3) )
880 subStepNo = - subStepNo;
882 G4cout << std::setw( 6) <<
" " << std::setw( 25)
883 <<
" G4FSALIntegrationDriver: Current Position and Direction" <<
" "
885 G4cout << std::setw( 5) <<
"Step#" <<
" "
886 << std::setw( 7) <<
"s-curve" <<
" "
887 << std::setw( 9) <<
"X(mm)" <<
" "
888 << std::setw( 9) <<
"Y(mm)" <<
" "
889 << std::setw( 9) <<
"Z(mm)" <<
" "
890 << std::setw( 8) <<
" N_x " <<
" "
891 << std::setw( 8) <<
" N_y " <<
" "
892 << std::setw( 8) <<
" N_z " <<
" "
893 << std::setw( 8) <<
" N^2-1 " <<
" "
894 << std::setw(10) <<
" N(0).N " <<
" "
895 << std::setw( 7) <<
"KinEner " <<
" "
896 << std::setw(12) <<
"Track-l" <<
" "
897 << std::setw(12) <<
"Step-len" <<
" "
898 << std::setw(12) <<
"Step-len" <<
" "
899 << std::setw( 9) <<
"ReqStep" <<
" "
903 if( (subStepNo <= 0) )
910 if( verboseLevel <= 3 )
912 G4cout.precision(noPrecision);
914 subStepNo, subStepSize, DotStartCurrentVeloc );
930 G4cout.precision(oldPrec);
948 G4cout << std::setw( 5) << subStepNo <<
" ";
952 G4cout << std::setw( 5) <<
"Start" <<
" ";
955 G4cout << std::setw( 7) << curveLen;
956 G4cout << std::setw( 9) << Position.
x() <<
" "
957 << std::setw( 9) << Position.
y() <<
" "
958 << std::setw( 9) << Position.
z() <<
" "
959 << std::setw( 8) << UnitVelocity.
x() <<
" "
960 << std::setw( 8) << UnitVelocity.
y() <<
" "
961 << std::setw( 8) << UnitVelocity.
z() <<
" ";
963 G4cout << std::setw( 8) << UnitVelocity.
mag2()-1.0 <<
" ";
965 G4cout << std::setw(10) << dotVeloc_StartCurr <<
" ";
966 G4cout.precision(oldprec);
968 G4cout << std::setw(12) << step_len <<
" ";
975 if( curveLen > oldCurveLength )
977 subStep_len= curveLen - oldCurveLength;
979 else if (subStepNo == oldSubStepNo)
981 subStep_len= oldSubStepLength;
983 oldCurveLength= curveLen;
984 oldSubStepLength= subStep_len;
986 G4cout << std::setw(12) << subStep_len <<
" ";
987 G4cout << std::setw(12) << subStepSize <<
" ";
988 if( requestStep != -1.0 )
990 G4cout << std::setw( 9) << requestStep <<
" ";
994 G4cout << std::setw( 9) <<
" InitialStep " <<
" ";
1006 G4cout <<
"G4FSALIntegrationDriver Statistics of steps undertaken. " <<
G4endl;
1007 G4cout <<
"G4FSALIntegrationDriver: Number of Steps: "
1008 <<
" Total= " << fNoTotalSteps
1009 <<
" Bad= " << fNoBadSteps
1010 <<
" Small= " << fNoSmallSteps
1011 <<
" Non-initial small= " << (fNoSmallSteps-fNoInitialSmallSteps)
1016 <<
" maximum= " << fDyerr_max
1017 <<
" Sum small= " << fDyerrPos_smTot
1018 <<
" std::sqrt(Sum large^2): pos= " << std::sqrt(fDyerrPos_lgTot)
1019 <<
" vel= " << std::sqrt( fDyerrVel_lgTot )
1020 <<
" Total h-distance: small= " << fSumH_sm
1021 <<
" large= " << fSumH_lg
1025 G4int noPrecSmall=4;
1027 G4cout.precision(noPrecSmall);
1028 G4cout <<
"MIDnums: " << fMinimumStep
1029 <<
" " << fNoTotalSteps
1030 <<
" " << fNoSmallSteps
1031 <<
" " << fNoSmallSteps-fNoInitialSmallSteps
1032 <<
" " << fNoBadSteps
1033 <<
" " << fDyerr_max
1034 <<
" " << fDyerr_mx2
1035 <<
" " << fDyerrPos_smTot
1037 <<
" " << fDyerrPos_lgTot
1038 <<
" " << fDyerrVel_lgTot
1044 G4cout.precision(oldPrec);
1051 if( (newFraction > 1.e-16) && (newFraction < 1e-8) )
1053 fSmallestFraction= newFraction;
1057 G4cerr <<
"Warning: SmallestFraction not changed. " <<
G4endl
1058 <<
" Proposed value was " << newFraction <<
G4endl
1059 <<
" Value must be between 1.e-8 and 1.e-16" <<
G4endl;
static constexpr double perMillion
void WarnEndPointTooFar(G4double endPointDist, G4double hStepSize, G4double epsilonRelative, G4int debugFlag)
G4double GetCurveLength() const
CLHEP::Hep3Vector G4ThreeVector
void WarnSmallStepSize(G4double hnext, G4double hstep, G4double h, G4double xDone, G4int noSteps)
void PrintStat_Aux(const G4FieldTrack &aFieldTrack, G4double requestStep, G4double actualStep, G4int subStepNo, G4double subStepSize, G4double dotVelocities)
G4double GetKineticEnergy() const
double dot(const Hep3Vector &) const
void SetCurveLength(G4double nCurve_s)
void PrintStatisticsReport()
G4double ComputeNewStepSize_WithinLimits(G4double errMaxNorm, G4double hstepCurrent)
G4double GetSurfaceTolerance() const
const G4ThreeVector & GetMomentumDir() const
static const G4double eps
G4bool AccurateAdvance(G4FieldTrack &y_current, G4double hstep, G4double eps, G4double hinitial=0.0)
void WarnTooManyStep(G4double x1start, G4double x2end, G4double xCurrent)
G4double GetPshrnk() const
G4ThreeVector GetPosition() const
G4GLOB_DLL std::ostream G4cout
G4FSALIntegrationDriver(G4double hminimum, G4VFSALIntegrationStepper *pItsStepper, G4int numberOfComponents=6, G4int statisticsVerbosity=1)
void RenewStepperAndAdjust(G4VFSALIntegrationStepper *pItsStepper)
void SetSmallestFraction(G4double val)
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *comments)
void OneGoodStep(G4double ystart[], G4double dydx[], G4double &x, G4double htry, G4double eps, G4double &hdid, G4double &hnext)
void DumpToArray(G4double valArr[ncompSVEC]) const
G4double ComputeNewStepSize(G4double errMaxNorm, G4double hstepCurrent)
T max(const T t1, const T t2)
brief Return the largest of the two arguments
virtual G4int IntegratorOrder() const =0
void LoadFromArray(const G4double valArr[ncompSVEC], G4int noVarsIntegrated)
~G4FSALIntegrationDriver()
G4bool QuickAdvance(G4FieldTrack &y_val, G4double dydx[], G4double hstep, G4double &dchord_step, G4double &dyerr)
static constexpr double perThousand
virtual void ComputeRightHandSide(const G4double y[], G4double dydx[])
G4double GetPgrow() const
void PrintStatus(const G4double *StartArr, G4double xstart, const G4double *CurrentArr, G4double xcurrent, G4double requestStep, G4int subStepNo)
static G4GeometryTolerance * GetInstance()
G4double GetSafety() const
G4GLOB_DLL std::ostream G4cerr