File indexing completed on 2025-01-18 09:58:30
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032 #include "G4FieldUtils.hh"
0033
0034 #include <CLHEP/Units/SystemOfUnits.h>
0035
0036 template <class T>
0037 G4IntegrationDriver<T>::
0038 G4IntegrationDriver ( G4double hminimum, T* pStepper,
0039 G4int numComponents, G4int statisticsVerbose )
0040 : G4RKIntegrationDriver<T>(pStepper),
0041 fMinimumStep(hminimum),
0042 fVerboseLevel(statisticsVerbose)
0043 {
0044 if (numComponents != Base::GetStepper()->GetNumberOfVariables())
0045 {
0046 std::ostringstream message;
0047 message << "Driver's number of integrated components "
0048 << numComponents
0049 << " != Stepper's number of components "
0050 << pStepper->GetNumberOfVariables();
0051 G4Exception("G4IntegrationDriver","GeomField0002",
0052 FatalException, message);
0053 }
0054 }
0055
0056 template <class T>
0057 G4IntegrationDriver<T>::~G4IntegrationDriver()
0058 {
0059 #ifdef G4VERBOSE
0060 if (fVerboseLevel > 0)
0061 {
0062 G4cout << "G4Integration Driver Stats: "
0063 << "#QuickAdvance " << fNoQuickAvanceCalls
0064 << " - #AccurateAdvance " << fNoAccurateAdvanceCalls << " "
0065 << "#good steps " << fNoAccurateAdvanceGoodSteps << " "
0066 << "#bad steps " << fNoAccurateAdvanceBadSteps << G4endl;
0067 }
0068 #endif
0069 }
0070
0071 template <class T>
0072 G4double G4IntegrationDriver<T>::AdvanceChordLimited(G4FieldTrack& track,
0073 G4double stepMax,
0074 G4double epsStep,
0075 G4double chordDistance)
0076 {
0077 return ChordFinderDelegate::AdvanceChordLimitedImpl(track, stepMax, epsStep,
0078 chordDistance);
0079 }
0080
0081 template <class T>
0082 void G4IntegrationDriver<T>::OnStartTracking()
0083 {
0084 ChordFinderDelegate::ResetStepEstimate();
0085 }
0086
0087
0088
0089
0090
0091
0092
0093 template <class T>
0094 G4bool G4IntegrationDriver<T>::
0095 AccurateAdvance(G4FieldTrack& track, G4double hstep,
0096 G4double eps, G4double hinitial)
0097 {
0098 ++fNoAccurateAdvanceCalls;
0099
0100 if (hstep == 0.0)
0101 {
0102 std::ostringstream message;
0103 message << "Proposed step is zero; hstep = " << hstep << " !";
0104 G4Exception("G4IntegrationDriver::AccurateAdvance()",
0105 "GeomField1001", JustWarning, message);
0106 return true;
0107 }
0108
0109 if (hstep < 0)
0110 {
0111 std::ostringstream message;
0112 message << "Invalid run condition." << G4endl
0113 << "Proposed step is negative; hstep = " << hstep << "."
0114 << G4endl
0115 << "Requested step cannot be negative! Aborting event.";
0116 G4Exception("G4IntegrationDriver::AccurateAdvance()",
0117 "GeomField0003", EventMustBeAborted, message);
0118 return false;
0119 }
0120
0121 G4double hnext, hdid;
0122
0123 G4double dydx[G4FieldTrack::ncompSVEC];
0124 G4bool succeeded = true;
0125
0126 G4double y[G4FieldTrack::ncompSVEC];
0127 track.DumpToArray(y);
0128
0129 const G4double startCurveLength = track.GetCurveLength();
0130 const G4double endCurveLength = startCurveLength + hstep;
0131 const G4double hThreshold =
0132 std::min(eps * hstep, fSmallestFraction * startCurveLength);
0133
0134 G4double h = hstep;
0135 if (hinitial > CLHEP::perMillion * hstep && hinitial < hstep)
0136 {
0137 h = hinitial;
0138 }
0139
0140 G4double curveLength = startCurveLength;
0141
0142 for (G4int nstp = 0; nstp < Base::GetMaxNoSteps(); ++nstp)
0143 {
0144 const G4ThreeVector StartPos =
0145 field_utils::makeVector(y, field_utils::Value3D::Position);
0146
0147 Base::GetStepper()->RightHandSide(y, dydx);
0148
0149 if (h > GetMinimumStep())
0150 {
0151 OneGoodStep(y, dydx, curveLength, h, eps, hdid, hnext);
0152 }
0153 else
0154 {
0155 G4FieldTrack yFldTrk('0');
0156 G4double dchord_step, dyerr, dyerr_len;
0157 yFldTrk.LoadFromArray(y, Base::GetStepper()->GetNumberOfVariables());
0158 yFldTrk.SetCurveLength(curveLength);
0159
0160 QuickAdvance(yFldTrk, dydx, h, dchord_step, dyerr_len);
0161
0162 yFldTrk.DumpToArray(y);
0163
0164 if (h == 0.0)
0165 {
0166 G4Exception("G4IntegrationDriver::AccurateAdvance()",
0167 "GeomField0003", FatalException,
0168 "Integration Step became Zero!");
0169 }
0170 dyerr = dyerr_len / h;
0171 hdid = h;
0172 curveLength += hdid;
0173 hnext = Base::ComputeNewStepSize(dyerr / eps, h);
0174 }
0175
0176 const G4ThreeVector EndPos =
0177 field_utils::makeVector(y, field_utils::Value3D::Position);
0178
0179 CheckStep(EndPos, StartPos, hdid);
0180
0181
0182 if (h < hThreshold || curveLength >= endCurveLength)
0183 {
0184 break;
0185 }
0186
0187 h = std::max(hnext, GetMinimumStep());
0188 if (curveLength + h > endCurveLength)
0189 {
0190 h = endCurveLength - curveLength;
0191 }
0192 }
0193
0194
0195 succeeded = (curveLength >= endCurveLength);
0196
0197
0198 track.LoadFromArray(y, Base::GetStepper()->GetNumberOfVariables());
0199 track.SetCurveLength(curveLength);
0200
0201 return succeeded;
0202 }
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217 template <class T>
0218 void G4IntegrationDriver<T>::OneGoodStep(G4double y[],
0219 const G4double dydx[],
0220 G4double& curveLength,
0221 G4double htry,
0222 G4double eps_rel_max,
0223 G4double& hdid,
0224 G4double& hnext)
0225
0226 {
0227 G4double error2 = DBL_MAX;
0228
0229 G4double yerr[G4FieldTrack::ncompSVEC], ytemp[G4FieldTrack::ncompSVEC];
0230
0231 G4double h = htry;
0232
0233 const G4int max_trials = 100;
0234
0235 for (G4int iter = 0; iter < max_trials; ++iter)
0236 {
0237 Base::GetStepper()->Stepper(y, dydx, h, ytemp, yerr);
0238 error2 = field_utils::relativeError2(y, yerr, std::max(h, fMinimumStep),
0239 eps_rel_max);
0240 if (error2 <= 1.0)
0241 {
0242 break;
0243 }
0244
0245 h = Base::ShrinkStepSize2(h, error2);
0246
0247 G4double xnew = curveLength + h;
0248 if(xnew == curveLength)
0249 {
0250 std::ostringstream message;
0251 message << "Stepsize underflow in Stepper !" << G4endl
0252 << "- Step's start x=" << curveLength
0253 << " and end x= " << xnew
0254 << " are equal !! " << G4endl
0255 << " Due to step-size= " << h
0256 << ". Note that input step was " << htry;
0257 G4Exception("G4IntegrationDriver::OneGoodStep()",
0258 "GeomField1001", JustWarning, message);
0259 break;
0260 }
0261 }
0262
0263 hnext = Base::GrowStepSize2(h, error2);
0264 curveLength += (hdid = h);
0265
0266 field_utils::copy(y, ytemp, Base::GetStepper()->GetNumberOfVariables());
0267 }
0268
0269 template <class T>
0270 G4bool G4IntegrationDriver<T>::QuickAdvance(G4FieldTrack& track,
0271 const G4double dydx[],
0272 G4double hstep,
0273 G4double& dchord_step,
0274 G4double& dyerr)
0275 {
0276 ++fNoQuickAvanceCalls;
0277
0278 G4double yIn[G4FieldTrack::ncompSVEC],
0279 yOut[G4FieldTrack::ncompSVEC],
0280 yError[G4FieldTrack::ncompSVEC];
0281
0282 track.DumpToArray(yIn);
0283
0284 Base::GetStepper()->Stepper(yIn, dydx, hstep, yOut, yError);
0285
0286 dchord_step = Base::GetStepper()->DistChord();
0287 dyerr = field_utils::absoluteError(yOut, yError, hstep);
0288 track.LoadFromArray(yOut, Base::GetStepper()->GetNumberOfVariables());
0289 track.SetCurveLength(track.GetCurveLength() + hstep);
0290
0291 return true;
0292 }
0293
0294 template <class T>
0295 void G4IntegrationDriver<T>::SetSmallestFraction(G4double newFraction)
0296 {
0297 if (newFraction > 1.e-16 && newFraction < 1e-8)
0298 {
0299 fSmallestFraction = newFraction;
0300 }
0301 else
0302 {
0303 std::ostringstream message;
0304 message << "Smallest Fraction not changed. " << G4endl
0305 << " Proposed value was " << newFraction << G4endl
0306 << " Value must be between 1.e-8 and 1.e-16";
0307 G4Exception("G4IntegrationDriver::SetSmallestFraction()",
0308 "GeomField1001", JustWarning, message);
0309 }
0310 }
0311
0312 template <class T>
0313 void G4IntegrationDriver<T>::CheckStep(const G4ThreeVector& posIn,
0314 const G4ThreeVector& posOut,
0315 G4double hdid)
0316 {
0317 const G4double endPointDist = (posOut - posIn).mag();
0318 if (endPointDist >= hdid * (1. + CLHEP::perMillion))
0319 {
0320 ++fNoAccurateAdvanceBadSteps;
0321 #ifdef G4DEBUG_FIELD
0322
0323
0324 if (endPointDist >= hdid * (1. + perThousand))
0325 {
0326 G4Exception("G4IntegrationDriver::CheckStep()",
0327 "GeomField1002", JustWarning,
0328 "endPointDist >= hdid!");
0329 }
0330 #endif
0331 }
0332 else
0333 {
0334 ++fNoAccurateAdvanceGoodSteps;
0335 }
0336 }
0337
0338 template <class T>
0339 inline G4double G4IntegrationDriver<T>::GetMinimumStep() const
0340 {
0341 return fMinimumStep;
0342 }
0343
0344 template <class T>
0345 void G4IntegrationDriver<T>::SetMinimumStep(G4double minimumStepLength)
0346 {
0347 fMinimumStep = minimumStepLength;
0348 }
0349
0350 template <class T>
0351 G4int G4IntegrationDriver<T>::GetVerboseLevel() const
0352 {
0353 return fVerboseLevel;
0354 }
0355
0356 template <class T>
0357 void G4IntegrationDriver<T>::SetVerboseLevel(G4int newLevel)
0358 {
0359 fVerboseLevel = newLevel;
0360 }
0361
0362 template <class T>
0363 G4double G4IntegrationDriver<T>::GetSmallestFraction() const
0364 {
0365 return fSmallestFraction;
0366 }
0367
0368 template <class T>
0369 void G4IntegrationDriver<T>::IncrementQuickAdvanceCalls()
0370 {
0371 ++fNoQuickAvanceCalls;
0372 }
0373
0374 template <class T>
0375 void G4IntegrationDriver<T>::StreamInfo( std::ostream& os ) const
0376 {
0377
0378 os << "State of G4IntegrationDriver: " << std::endl;
0379 os << "--Base state (G4RKIntegrationDriver): " << std::endl;
0380 Base::StreamInfo( os );
0381 os << "--Own state (G4IntegrationDriver<>): " << std::endl;
0382 os << " fMinimumStep = " << fMinimumStep << std::endl;
0383 os << " Smallest Fraction = " << fSmallestFraction << std::endl;
0384
0385 os << " verbose level = " << fVerboseLevel << std::endl;
0386 os << " Reintegrates = " << DoesReIntegrate() << std::endl;
0387 os << "--Chord Finder Delegate state: " << std::endl;
0388 ChordFinderDelegate::StreamDelegateInfo( os );
0389 }