// // ******************************************************************** // * License and Disclaimer * // * * // * The Geant4 software is copyright of the Copyright Holders of * // * the Geant4 Collaboration. It is provided under the terms and * // * conditions of the Geant4 Software License, included in the file * // * LICENSE and available at http://cern.ch/geant4/license . These * // * include a list of copyright holders. * // * * // * Neither the authors of this software system, nor their employing * // * institutes,nor the agencies providing financial support for this * // * work make any representation or warranty, express or implied, * // * regarding this software system or assume any liability for its * // * use. Please see the license in the file LICENSE and URL above * // * for the full disclaimer and the limitation of liability. * // * * // * This code implementation is the result of the scientific and * // * technical work of the GEANT4 collaboration. * // * By using, copying, modifying or distributing the software (or * // * any work based on the software) you agree to acknowledge its * // * use in resulting scientific publications, and indicate your * // * acceptance of all terms of the Geant4 Software license. * // ******************************************************************** // // // $Id: G4MagIntegratorDriver.cc,v 1.49 2007/08/17 12:30:33 gcosmo Exp $ // GEANT4 tag $Name: geant4-09-02-cand-01 $ // // // // Implementation for class G4MagInt_Driver // Tracking in space dependent magnetic field // // History of major changes: // 8 Nov 01 J. Apostolakis: Respect minimum step in AccurateAdvance // 27 Jul 99 J. Apostolakis: Ensured that AccurateAdvance does not loop // due to very small eps & step size (precision) // 28 Jan 98 W. Wander: Added ability for low order integrators // 7 Oct 96 V. Grichine First version // -------------------------------------------------------------------- #include "globals.hh" #include "G4GeometryTolerance.hh" #include #include "G4MagIntegratorDriver.hh" #include "G4FieldTrack.hh" // Stepsize can increase by no more than 5.0 // and decrease by no more than 1/10. = 0.1 // const G4double G4MagInt_Driver::max_stepping_increase = 5.0; const G4double G4MagInt_Driver::max_stepping_decrease = 0.1; // The (default) maximum number of steps is Base divided by the order of Stepper // const G4int G4MagInt_Driver::fMaxStepBase = 250; // Was 5000 #ifndef G4NO_FIELD_STATISTICS #define G4FLD_STATS 1 #endif // Constructor // G4MagInt_Driver::G4MagInt_Driver( G4double hminimum, G4MagIntegratorStepper *pItsStepper, G4int numComponents, G4int statisticsVerbose) : fSmallestFraction( 1.0e-12 ), fNoIntegrationVariables(numComponents), fMinNoVars(12), fNoVars( std::max( fNoIntegrationVariables, fMinNoVars )), fVerboseLevel(0), fNoTotalSteps(0), fNoBadSteps(0), fNoSmallSteps(0), fNoInitialSmallSteps(0), fDyerr_max(0.0), fDyerr_mx2(0.0), fDyerrPos_smTot(0.0), fDyerrPos_lgTot(0.0), fDyerrVel_lgTot(0.0), fSumH_sm(0.0), fSumH_lg(0.0), fStatisticsVerboseLevel(statisticsVerbose) { // In order to accomodate "Laboratory Time", which is [7], fMinNoVars=8 is required. // For proper time of flight and spin, fMinNoVars must be 12 // fNoVars= std::max( fNoVars, fMinNoVars ); RenewStepperAndAdjust( pItsStepper ); fMinimumStep= hminimum; fMaxNoSteps = fMaxStepBase / pIntStepper->IntegratorOrder(); #ifdef G4DEBUG_FIELD fVerboseLevel=2; #endif if( (fVerboseLevel > 0) || (fStatisticsVerboseLevel > 1) ){ G4cout << "MagIntDriver version: Accur-Adv: invE_nS, QuickAdv-2sqrt with Statistics " #ifdef G4FLD_STATS << " enabled " #else << " disabled " #endif << G4endl; } } // Destructor // G4MagInt_Driver::~G4MagInt_Driver() { if( fStatisticsVerboseLevel > 1 ){ PrintStatisticsReport() ; } // Future: for default verbose level, print an understandable summary } // To add much printing for debugging purposes, uncomment this: // #define G4DEBUG_FIELD 1 // and set verbose level to 1 or higher value ! G4bool G4MagInt_Driver::AccurateAdvance(G4FieldTrack& y_current, G4double hstep, G4double eps, G4double hinitial ) // const G4double dydx[6], // We could may add this ?? // Runge-Kutta driver with adaptive stepsize control. Integrate starting // values at y_current over hstep x2 with accuracy eps. // On output ystart is replaced by values at the end of the integration // interval. // RightHandSide is the right-hand side of ODE system. // The source is similar to odeint routine from NRC p.721-722 . { G4int nstp, i, no_warnings=0;; G4double x, hnext, hdid, h ; #ifdef G4DEBUG_FIELD static G4int dbg=1; static G4int nStpPr=50; // For debug printing of long integrations G4double ySubStepStart[G4FieldTrack::ncompSVEC]; G4FieldTrack yFldTrkStart(y_current); #endif G4double y[G4FieldTrack::ncompSVEC], dydx[G4FieldTrack::ncompSVEC]; G4double ystart[G4FieldTrack::ncompSVEC], yEnd[G4FieldTrack::ncompSVEC]; G4double x1, x2; G4bool succeeded = true, lastStepSucceeded; G4double startCurveLength; G4int noFullIntegr=0, noSmallIntegr = 0 ; static G4int noGoodSteps =0 ; // Bad = chord > curve-len const int nvar= fNoVars; G4FieldTrack yStartFT(y_current); // Ensure that hstep > 0 if( hstep <= 0.0 ) { if(hstep==0.0) { G4cerr << "WARNING - G4MagIntegratorDriver::AccurateAdvance()" << G4endl << " Proposed step is zero; hstep = " << hstep << " !" << G4endl; return succeeded; } else { G4cerr << "ERROR - G4MagIntegratorDriver::AccurateAdvance()" << G4endl << " Proposed step is negative; hstep = " << hstep << " !" << G4endl; G4Exception("G4MagInt_Driver::AccurateAdvance()", "InvalidCall", EventMustBeAborted, "Requested step cannot be negative! Aborting event."); return false; } } y_current.DumpToArray( ystart ); startCurveLength= y_current.GetCurveLength(); x1= startCurveLength; x2= x1 + hstep; if( (hinitial > 0.0) && (hinitial < hstep) && (hinitial > perMillion * hstep) ){ h = hinitial; }else{ // Initial Step size "h" defaults to the full interval h = hstep; } x = x1; for(i=0;iRightHandSide( y, dydx ); fNoTotalSteps++; // Perform the Integration // if( h > fMinimumStep ){ OneGoodStep(y,dydx,x,h,eps,hdid,hnext) ; //-------------------------------------- lastStepSucceeded= (hdid == h); #ifdef G4DEBUG_FIELD if(dbg>2) PrintStatus( ySubStepStart, xSubStart, y, x, h, nstp); // Only #endif }else{ G4FieldTrack yFldTrk( G4ThreeVector(0,0,0), G4ThreeVector(0,0,0), 0., 0., 0., 0. ); G4double dchord_step, dyerr, dyerr_len; // Must figure what to do with these yFldTrk.LoadFromArray(y, fNoIntegrationVariables); yFldTrk.SetCurveLength( x ); QuickAdvance( yFldTrk, dydx, h, dchord_step, dyerr_len ); //----------------------------------------------------- // #ifdef G4DEBUG_FIELD // if(dbg>1) OneGoodStep(y,dydx,x,h,2*eps,hdid,hnext) ; // if(dbg>1) PrintStatus( ystart, x1, y, x, h, -nstp); yFldTrk.DumpToArray(y); #ifdef G4FLD_STATS fNoSmallSteps++; if( dyerr_len > fDyerr_max) fDyerr_max= dyerr_len; fDyerrPos_smTot += dyerr_len; fSumH_sm += h; // Length total for 'small' steps if(nstp<=1) fNoInitialSmallSteps++; #endif #ifdef G4DEBUG_FIELD if(dbg>1) { if(fNoSmallSteps<2) PrintStatus( ySubStepStart, x1, y, x, h, -nstp); G4cout << "Another sub-min step, no " << fNoSmallSteps << " of " << fNoTotalSteps << " this time " << nstp << G4endl; PrintStatus( ySubStepStart, x1, y, x, h, nstp); // Only this G4cout << " dyerr= " << dyerr_len << " relative = " << dyerr_len / h << " epsilon= " << eps << " hstep= " << hstep << " h= " << h << " hmin= " << fMinimumStep << G4endl; } #endif if( h == 0.0 ) { G4Exception("G4MagInt_Driver::AccurateAdvance()", "Integration Step became Zero", FatalException, "IntegrationStepUnderflow."); } dyerr = dyerr_len / h; hdid= h; x += hdid; // Compute suggested new step hnext= ComputeNewStepSize( dyerr/eps, h); // .. hnext= ComputeNewStepSize_WithinLimits( dyerr/eps, h); lastStepSucceeded= (dyerr<= eps); } if(lastStepSucceeded) noFullIntegr++ ; else noSmallIntegr++ ; G4ThreeVector EndPos( y[0], y[1], y[2] ); #ifdef G4DEBUG_FIELD if( (dbg>0) && (dbg<=2) && (nstp>nStpPr)) { if( nstp==nStpPr ) G4cout << "***** Many steps ****" << G4endl; G4cout << "hdid=" << std::setw(12) << hdid << " " << "hnext=" << std::setw(12) << hnext << " " << G4endl; PrintStatus( ystart, x1, y, x, h, (nstp==nStpPr) ? -nstp: nstp); } #endif // Check the endpoint G4double endPointDist= (EndPos-StartPos).mag(); if( endPointDist >= hdid*(1.+perMillion) ){ fNoBadSteps ++; // Issue a warning only for gross differences - // we understand how small difference occur. if( endPointDist >= hdid*(1.+perThousand) ){ #ifdef G4DEBUG_FIELD if(dbg){ WarnEndPointTooFar ( endPointDist, hdid, eps, dbg ); G4cerr << " Total steps: bad " << fNoBadSteps << " good " << noGoodSteps << " current h= " << hdid << G4endl; // G4cerr << "Mid:EndPtFar> "; PrintStatus( ystart, x1, y, x, hstep, no_warnings?nstp:-nstp); // Potentially add as arguments: - as Initial Force } #endif no_warnings++; } } else { // ie (!dbg) noGoodSteps ++; } // #endif // Avoid numerous small last steps if( (h < eps * hstep) || (h < fSmallestFraction * startCurveLength) ) { // No more integration -- the next step will not happen lastStep = true; // fNoLastStep++; } else { // Check the proposed next stepsize if(std::fabs(hnext) <= Hmin()) { #ifdef G4DEBUG_FIELD // If simply a very small interval is being integrated, do not warn if( (x < x2 * (1-eps) ) && // The last step can be small: it's OK (std::fabs(hstep) > Hmin()) // and if we are asked, it's OK // && (hnext < hstep * PerThousand ) ) { if(dbg>0){ // G4cerr << "Mid:SmallStep> "; WarnSmallStepSize( hnext, hstep, h, x-x1, nstp ); PrintStatus( ystart, x1, y, x, hstep, no_warnings?nstp:-nstp); } no_warnings++; } #endif // Make sure that the next step is at least Hmin. h = Hmin(); }else{ h = hnext ; } // Ensure that the next step does not overshoot if( x+h > x2 ) { h = x2 - x ; // When stepsize overshoots, decrease it! // Must cope with difficult rounding-error issues if hstep << x2 } // if( h < smallestFraction * startCurveLength ) if( h == 0.0 ){ // Cannot progress - accept this as last step - by default lastStep = true; #ifdef G4DEBUG_FIELD if(dbg){ G4cout << "Warning: G4MagIntegratorDriver::AccurateAdvance" << G4endl << " Integration step 'h' became " << h << " due to roundoff " << G4endl << " Forcing termination of advance." << G4endl; } #endif } } }while ( ((nstp++)<=fMaxNoSteps) && (x < x2) // Have we reached the end ? // --> a better test might be x-x2 > an_epsilon && (!lastStep) ); succeeded= (x>=x2); // If it was a "forced" last step for(i=0;i fMaxNoSteps){ no_warnings++; succeeded = false; #ifdef G4DEBUG_FIELD if(dbg){ WarnTooManyStep( x1, x2, x ); // Issue WARNING PrintStatus( yEnd, x1, y, x, hstep, -nstp); } #endif } #ifdef G4DEBUG_FIELD if( dbg && no_warnings ){ G4cerr << "G4MagIntegratorDriver exit status: no-steps " << nstp < 10 ){ G4cerr<< " Warning (G4MagIntegratorDriver::AccurateAdvance): The stepsize for the " << " next iteration=" << hnext << " is too small " << "- in Step number " << nstp << "." << G4endl; G4cerr << " The minimum for the driver is " << Hmin() << G4endl ; G4cerr << " Requested integr. length was " << hstep << " ." << G4endl ; G4cerr << " The size of this sub-step was " << h << " ." << G4endl ; G4cerr << " The integrations has already gone " << xDone << G4endl ; }else{ G4cerr<< " G4MagInt_Driver: Too small 'next' step " << hnext << " step-no " << nstp ; // << G4setw(4) G4cerr << " this sub-step " << h << " req_tot_len " << hstep << " done " << xDone << " min " << Hmin() << G4endl ; } noWarningsIssued++; } void G4MagInt_Driver::WarnTooManyStep( G4double x1start, G4double x2end, G4double xCurrent) { G4cerr << " Warning (G4MagIntegratorDriver): The number of steps " << "used in the Integration driver (Runge-Kutta) is too many. " << G4endl ; G4cerr << "Integration of the interval was not completed - only a " << (xCurrent-x1start)*100/(x2end-x1start) <<" % fraction of it was Done." << G4endl; } void G4MagInt_Driver::WarnEndPointTooFar (G4double endPointDist, G4double h , G4double eps, G4int dbg) { static G4double maxRelError= 0.0, maxRelError_last_printed=0.0; G4bool isNewMax, prNewMax; isNewMax = endPointDist > (1.0 + maxRelError) * h; prNewMax = endPointDist > (1.0 + 1.05 * maxRelError) * h; if( isNewMax ) maxRelError= endPointDist / h - 1.0; if( prNewMax ) maxRelError_last_printed = maxRelError; if( dbg && (h > G4GeometryTolerance::GetInstance()->GetSurfaceTolerance()) && ( (dbg>1) || prNewMax || (endPointDist >= h*(1.+eps) ) ) ){ static G4int noWarnings = 0; if( (noWarnings ++ < 10) || (dbg>2) ){ G4cerr << " Warning (G4MagIntegratorDriver): " << " The integration produced an endpoint which " << G4endl << " is further from the startpoint than the curve length." << G4endl; G4cerr << " Distance of endpoints = " << endPointDist << " curve length = " << h << " Difference (curveLen-endpDist)= " << (h - endPointDist) << " relative = " << (h-endPointDist) / h << " epsilon = " << eps << G4endl; }else{ G4cerr << " Warning:" << " dist_e= " << endPointDist << " h_step = " << h << " Diff (hs-ed)= " << (h - endPointDist) << " rel = " << (h-endPointDist) / h << " eps = " << eps << " (from G4MagInt_Driver)" << G4endl; } } } // --------------------------------------------------------- void G4MagInt_Driver::OneGoodStep( G4double y[], // InOut const G4double dydx[], G4double& x, // InOut G4double htry, G4double eps_rel_max, G4double& hdid, // Out G4double& hnext ) // Out // Driver for one Runge-Kutta Step with monitoring of local truncation error // to ensure accuracy and adjust stepsize. Input are dependent variable // array y[0,...,5] and its derivative dydx[0,...,5] at the // starting value of the independent variable x . Also input are stepsize // to be attempted htry, and the required accuracy eps. On output y and x // are replaced by their new values, hdid is the stepsize that was actually // accomplished, and hnext is the estimated next stepsize. // This is similar to the function rkqs from the book: // Numerical Recipes in C: The Art of Scientific Computing (NRC), Second // Edition, by William H. Press, Saul A. Teukolsky, William T. // Vetterling, and Brian P. Flannery (Cambridge University Press 1992), // 16.2 Adaptive StepSize Control for Runge-Kutta, p. 719 { // G4double errpos_rel_sq, errvel_rel_sq G4double errmax_sq; // G4double errmax; G4double h, htemp, xnew ; G4double yerr[G4FieldTrack::ncompSVEC], ytemp[G4FieldTrack::ncompSVEC]; h = htry ; // Set stepsize to the initial trial value // G4double inv_epspos_sq = 1.0 / eps * eps; G4double inv_eps_vel_sq = 1.0 / (eps_rel_max*eps_rel_max); G4double errpos_sq=0.0; // square of displacement error G4double errvel_sq=0.0; // square of momentum vector difference G4int iter; static G4int tot_no_trials=0; const G4int max_trials=100; for (iter=0; iter Stepper(y,dydx,h,ytemp,yerr); // ******* G4double eps_pos = eps_rel_max * std::max(h, fMinimumStep); G4double inv_eps_pos_sq = 1.0 / (eps_pos*eps_pos); // Evaluate accuracy // errpos_sq = sqr(yerr[0]) + sqr(yerr[1]) + sqr(yerr[2]) ; // errpos_sq /= eps_pos*eps_pos; // Scale to tolerance errpos_sq *= inv_eps_pos_sq; // Scale relative to required tolerance // Accuracy for momentum errvel_sq = (sqr(yerr[3]) + sqr(yerr[4]) + sqr(yerr[5]) ) / (sqr(y[3]) + sqr(y[4]) + sqr(y[5]) ); // errvel_sq /= eps_rel_max*eps_rel_max; errvel_sq *= inv_eps_vel_sq; errmax_sq = std::max( errpos_sq, errvel_sq ); // Square of maximum error // errmax = std::sqrt( errmax_sq ); if(errmax_sq <= 1.0 ) break ; // Step succeeded. // Step failed; compute the size of retrial Step. htemp = GetSafety()*h* std::pow( errmax_sq, 0.5*GetPshrnk() ); if(htemp >= 0.1*h) h = htemp ; // Truncation error too large, else h = 0.1*h ; // reduce stepsize, but no more // than a factor of 10 xnew = x + h ; if(xnew == x) { G4cerr<<"G4MagIntegratorDriver::OneGoodStep: Stepsize underflow in Stepper "< errcon*errcon) hnext = GetSafety()*h*std::pow(errmax_sq, 0.5*GetPgrow()) ; else hnext = max_stepping_increase*h ; // No more than a factor of 5 increase x += (hdid = h) ; int i; const int nvar= fNoIntegrationVariables; for(i=0;i Stepper(yarrin, dydx, hstep, yarrout, yerr_vec) ; // ******* // Estimate curve-chord distance dchord_step= pIntStepper-> DistChord(); // ********* // Put back the values. y_posvel.LoadFromArray( yarrout, fNoIntegrationVariables ); // yarrout ==> y_posvel y_posvel.SetCurveLength( s_start + hstep ); #ifdef G4DEBUG_FIELD if(fVerboseLevel>2) { G4cout << "G4MagIntDrv: Quick Advance" << G4endl; PrintStatus( yarrin, s_start, yarrout, s_start+hstep, hstep, 1); } #endif // A single measure of the error // TO-DO : account for energy, spin, ... ? vel_mag_sq = ( sqr(yarrout[3])+sqr(yarrout[4])+sqr(yarrout[5]) ); inv_vel_mag_sq = 1.0 / vel_mag_sq; dyerr_pos_sq = ( sqr(yerr_vec[0])+sqr(yerr_vec[1])+sqr(yerr_vec[2])); dyerr_mom_sq = ( sqr(yerr_vec[3])+sqr(yerr_vec[4])+sqr(yerr_vec[5])); dyerr_mom_rel_sq = dyerr_mom_sq * inv_vel_mag_sq; //// Calculate also the change in the momentum squared also ??? // G4double veloc_square = y_posvel.GetVelocity().mag2(); // ... #ifdef RETURN_A_NEW_STEP_LENGTH // The following step cannot be done here because "eps" is not known. dyerr_len = std::sqrt( dyerr_len_sq ); dyerr_len_sq /= eps ; // Look at the velocity deviation ? // sqr(yerr_vec[3])+sqr(yerr_vec[4])+sqr(yerr_vec[5])); // Set suggested new step hstep= ComputeNewStepSize( dyerr_len, hstep); #endif if( dyerr_pos_sq > ( dyerr_mom_rel_sq * sqr(hstep) ) ) { dyerr = std::sqrt(dyerr_pos_sq); }else{ // Scale it to the current step size - for now dyerr = std::sqrt(dyerr_mom_rel_sq) * hstep; } return true; } #ifdef QUICK_ADV_ARRAY_IN_AND_OUT G4bool G4MagInt_Driver::QuickAdvance( G4double yarrin[], // IN const G4double dydx[], G4double hstep, // In G4double yarrout[], G4double& dchord_step, G4double& dyerr ) // in length { G4Exception("G4MagInt_Driver::QuickAdvance()", "NotImplemented", FatalException, "Not yet implemented."); dyerr = dchord_step = hstep * yarrin[0] * dydx[0]; yarrout[0]= yarrin[0]; } #endif // -------------------------------------------------------------------------- // This method computes new step sizes - but does not limit changes to // within certain factors // G4double G4MagInt_Driver::ComputeNewStepSize( G4double errMaxNorm, // max error (normalised) G4double hstepCurrent) // current step size { G4double hnew; // Compute size of next Step for a failed step if(errMaxNorm > 1.0 ) { // Step failed; compute the size of retrial Step. hnew = GetSafety()*hstepCurrent*std::pow(errMaxNorm,GetPshrnk()) ; }else if(errMaxNorm > 0.0 ){ // Compute size of next Step for a successful step hnew = GetSafety()*hstepCurrent*std::pow(errMaxNorm,GetPgrow()) ; }else { // if error estimate is zero (possible) or negative (dubious) hnew = max_stepping_increase * hstepCurrent; } return hnew; } // ----------------------------------------------------------------------------- // This method computes new step sizes limiting changes within certain factors // // It shares its logic with AccurateAdvance. // They are kept separate currently for optimisation. G4double G4MagInt_Driver::ComputeNewStepSize_WithinLimits( G4double errMaxNorm, // max error (normalised) G4double hstepCurrent) // current step size { G4double hnew; // Compute size of next Step for a failed step if(errMaxNorm > 1.0 ) { // Step failed; compute the size of retrial Step. hnew = GetSafety()*hstepCurrent*std::pow(errMaxNorm,GetPshrnk()) ; if(hnew < max_stepping_decrease*hstepCurrent) hnew = max_stepping_decrease*hstepCurrent ; // reduce stepsize, but no more // than this factor (value= 1/10) }else{ // Compute size of next Step for a successful step if(errMaxNorm > errcon) hnew = GetSafety()*hstepCurrent*std::pow(errMaxNorm,GetPgrow()) ; else hnew = max_stepping_increase * hstepCurrent ; // No more than a factor of 5 increase } return hnew; } void G4MagInt_Driver::PrintStatus( const G4double* StartArr, G4double xstart, const G4double* CurrentArr, G4double xcurrent, G4double requestStep, G4int subStepNo) // Potentially add as arguments: // - as Initial Force // stepTaken(hdid) - last step taken // nextStep (hnext) - proposal for size { G4FieldTrack StartFT(G4ThreeVector(0,0,0), G4ThreeVector(0,0,0), 0., 0., 0., 0. ); G4FieldTrack CurrentFT (StartFT); StartFT.LoadFromArray( StartArr, fNoIntegrationVariables); StartFT.SetCurveLength( xstart); CurrentFT.LoadFromArray( CurrentArr, fNoIntegrationVariables); CurrentFT.SetCurveLength( xcurrent ); PrintStatus(StartFT, CurrentFT, requestStep, subStepNo ); } void G4MagInt_Driver::PrintStatus( const G4FieldTrack& StartFT, const G4FieldTrack& CurrentFT, G4double requestStep, // G4double safety, G4int subStepNo) { G4int verboseLevel= fVerboseLevel; static G4int noPrecision= 5; G4int oldPrec= G4cout.precision(noPrecision); // G4cout.setf(ios_base::fixed,ios_base::floatfield); const G4ThreeVector StartPosition= StartFT.GetPosition(); const G4ThreeVector StartUnitVelocity= StartFT.GetMomentumDir(); const G4ThreeVector CurrentPosition= CurrentFT.GetPosition(); const G4ThreeVector CurrentUnitVelocity= CurrentFT.GetMomentumDir(); G4double DotStartCurrentVeloc= StartUnitVelocity.dot(CurrentUnitVelocity); G4double step_len= CurrentFT.GetCurveLength() - StartFT.GetCurveLength(); G4double subStepSize = step_len; // G4cout << " G4MagInt_Driver: Current Position and Direction" << G4endl; if( (subStepNo <= 1) || (verboseLevel > 3) ) { subStepNo = - subStepNo; // To allow printing banner G4cout << std::setw( 6) << " " << std::setw( 25) << " G4MagInt_Driver: Current Position and Direction" << " " << G4endl; G4cout << std::setw( 5) << "Step#" << " " << std::setw( 7) << "s-curve" << " " << std::setw( 9) << "X(mm)" << " " << std::setw( 9) << "Y(mm)" << " " << std::setw( 9) << "Z(mm)" << " " << std::setw( 8) << " N_x " << " " << std::setw( 8) << " N_y " << " " << std::setw( 8) << " N_z " << " " << std::setw( 8) << " N^2-1 " << " " << std::setw(10) << " N(0).N " << " " << std::setw( 7) << "KinEner " << " " << std::setw(12) << "Track-l" << " " // Add the Sub-step ?? << std::setw(12) << "Step-len" << " " << std::setw(12) << "Step-len" << " " << std::setw( 9) << "ReqStep" << " " << G4endl; } if( (subStepNo <= 0) ){ PrintStat_Aux( StartFT, requestStep, 0., 0, 0.0, 1.0); //************* } if( verboseLevel <= 3 ) { G4cout.precision(noPrecision); PrintStat_Aux( CurrentFT, requestStep, step_len, subStepNo, subStepSize, DotStartCurrentVeloc ); //************* } else // if( verboseLevel > 3 ) { // Multi-line output // G4cout << "Current Position is " << CurrentPosition << G4endl // << " and UnitVelocity is " << CurrentUnitVelocity << G4endl; // G4cout << "Step taken was " << step_len // << " out of PhysicalStep= " << requestStep << G4endl; // G4cout << "Final safety is: " << safety << G4endl; // G4cout << "Chord length = " << (CurrentPosition-StartPosition).mag() << G4endl; // G4cout << G4endl; } G4cout.precision(oldPrec); } void G4MagInt_Driver::PrintStat_Aux( const G4FieldTrack& aFieldTrack, G4double requestStep, G4double step_len, G4int subStepNo, G4double subStepSize, G4double dotVeloc_StartCurr) { const G4ThreeVector Position= aFieldTrack.GetPosition(); const G4ThreeVector UnitVelocity= aFieldTrack.GetMomentumDir(); if( subStepNo >= 0) G4cout << std::setw( 5) << subStepNo << " "; else G4cout << std::setw( 5) << "Start" << " "; G4double curveLen= aFieldTrack.GetCurveLength(); G4cout << std::setw( 7) << curveLen; G4cout << std::setw( 9) << Position.x() << " " << std::setw( 9) << Position.y() << " " << std::setw( 9) << Position.z() << " " << std::setw( 8) << UnitVelocity.x() << " " << std::setw( 8) << UnitVelocity.y() << " " << std::setw( 8) << UnitVelocity.z() << " "; G4int oldprec= G4cout.precision(3); G4cout << std::setw( 8) << UnitVelocity.mag2()-1.0 << " "; G4cout.precision(6); G4cout << std::setw(10) << dotVeloc_StartCurr << " "; G4cout.precision(oldprec); G4cout << std::setw( 7) << aFieldTrack.GetKineticEnergy(); G4cout << std::setw(12) << step_len << " "; static G4double oldCurveLength= 0.0; static G4double oldSubStepLength= 0.0; static int oldSubStepNo= -1; G4double subStep_len=0.0; if( curveLen > oldCurveLength ) subStep_len= curveLen - oldCurveLength; else if (subStepNo == oldSubStepNo) subStep_len= oldSubStepLength; // else subStepLen_NotAvail; oldCurveLength= curveLen; oldSubStepLength= subStep_len; G4cout << std::setw(12) << subStep_len << " "; G4cout << std::setw(12) << subStepSize << " "; if( requestStep != -1.0 ) G4cout << std::setw( 9) << requestStep << " "; else G4cout << std::setw( 9) << " InitialStep " << " "; // G4cout << std::setw(12) << safety << " "; G4cout << G4endl; } void G4MagInt_Driver::PrintStatisticsReport() { G4int noPrecBig= 6; G4int oldPrec= G4cout.precision(noPrecBig); G4cout << "G4MagInt_Driver Statistics of steps undertaken. " << G4endl; G4cout << "G4MagInt_Driver: Number of Steps: " << " Total= " << fNoTotalSteps << " Bad= " << fNoBadSteps << " Small= " << fNoSmallSteps << " Non-initial small= " << (fNoSmallSteps-fNoInitialSmallSteps) << G4endl; #ifdef G4FLD_STATS G4cout << "MID dyerr: " << " maximum= " << fDyerr_max // << " 2nd max= " << fDyerr_mx2 << " Sum small= " << fDyerrPos_smTot << " std::sqrt(Sum large^2): pos= " << std::sqrt(fDyerrPos_lgTot) << " vel= " << std::sqrt( fDyerrVel_lgTot ) << " Total h-distance: small= " << fSumH_sm << " large= " << fSumH_lg << G4endl; #if 0 G4int noPrecSmall=4; // Single line precis of statistics ... optional G4cout.precision(noPrecSmall); G4cout << "MIDnums: " << fMinimumStep << " " << fNoTotalSteps << " " << fNoSmallSteps << " " << fNoSmallSteps-fNoInitialSmallSteps << " " << fNoBadSteps << " " << fDyerr_max << " " << fDyerr_mx2 << " " << fDyerrPos_smTot << " " << fSumH_sm << " " << fDyerrPos_lgTot << " " << fDyerrVel_lgTot << " " << fSumH_lg << G4endl; #endif #endif G4cout.precision(oldPrec); } void G4MagInt_Driver::SetSmallestFraction(G4double newFraction) { if( (newFraction > 1.e-16) && (newFraction < 1e-8) ) { fSmallestFraction= newFraction; }else{ G4cerr << "Warning: SmallestFraction not changed. " << G4endl << " Proposed value was " << newFraction << G4endl << " Value must be between 1.e-8 and 1.e-16" << G4endl; } }