File indexing completed on 2026-09-15 09:09:23
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 #include "G4Exception.hh"
0032 #include "G4FieldUtils.hh"
0033 #include "G4LineSection.hh"
0034
0035 #include <CLHEP/Units/SystemOfUnits.h>
0036
0037 #include <algorithm>
0038
0039 template <class T, G4bool StepperCachesDchord>
0040 G4InterpolationDriver<T, StepperCachesDchord>::G4InterpolationDriver(
0041 G4double hminimum, T* pStepper, G4int numComponents, G4int statisticsVerbose)
0042 : G4RKIntegrationDriver<T>(pStepper), fMinimumStep(hminimum), fVerboseLevel(statisticsVerbose)
0043 {
0044 if (numComponents != Base::GetStepper()->GetNumberOfVariables())
0045 {
0046 std::ostringstream message;
0047 message << "Driver's number of integrated components " << numComponents
0048 << " != Stepper's number of components " << pStepper->GetNumberOfVariables();
0049 G4Exception("G4InterpolationDriver", "GeomField0002", FatalException, message);
0050 }
0051
0052 for (G4int i = 0; i < Base::GetMaxNoSteps(); ++i)
0053 {
0054 fSteppers.push_back(
0055 {std::unique_ptr<T>(
0056 new T(pStepper->GetSpecificEquation(),
0057 pStepper->GetNumberOfVariables())),
0058 DBL_MAX, -DBL_MAX, 0.0});
0059 }
0060
0061 fLastStepper = fSteppers.end();
0062 }
0063
0064 template <class T, G4bool StepperCachesDchord>
0065 G4InterpolationDriver<T, StepperCachesDchord>::~G4InterpolationDriver()
0066 {
0067 #ifdef G4VERBOSE
0068 if (fVerboseLevel > 0)
0069 {
0070 G4cout << "G4ChordFinder statistics report: \n"
0071 << " No trials: " << fTotalNoTrials << " No Calls: " << fNoCalls
0072 << " Max-trial: " << fmaxTrials << G4endl;
0073 }
0074 #endif
0075 }
0076
0077 template <class T, G4bool StepperCachesDchord>
0078 void G4InterpolationDriver<T, StepperCachesDchord>::OnStartTracking()
0079 {
0080 fChordStepEstimate = DBL_MAX;
0081 fhnext = DBL_MAX;
0082 fTotalStepsForTrack = 0;
0083 }
0084
0085 template <class T, G4bool StepperCachesDchord>
0086 void G4InterpolationDriver<T, StepperCachesDchord>::OnComputeStep(const G4FieldTrack* )
0087 {
0088 fKeepLastStepper = false;
0089 fFirstStep = true;
0090 fLastStepper = fSteppers.end();
0091 }
0092
0093 template <class T, G4bool StepperCachesDchord>
0094 void G4InterpolationDriver<T, StepperCachesDchord>::SetVerboseLevel(G4int level)
0095 {
0096 fVerboseLevel = level;
0097 }
0098
0099 template <class T, G4bool StepperCachesDchord>
0100 G4int G4InterpolationDriver<T, StepperCachesDchord>::GetVerboseLevel() const
0101 {
0102 return fVerboseLevel;
0103 }
0104
0105 template <class T, G4bool StepperCachesDchord>
0106 void G4InterpolationDriver<T, StepperCachesDchord>::Interpolate(
0107 G4double curveLength, field_utils::State& y) const
0108 {
0109 if (fLastStepper == fSteppers.end())
0110 {
0111 std::ostringstream message;
0112 message << "LOGICK ERROR: fLastStepper == end";
0113 G4Exception("G4InterpolationDriver::Interpolate()", "GeomField1001", FatalException, message);
0114 return;
0115 }
0116
0117 ConstStepperIterator end = fLastStepper + 1;
0118
0119 auto it = std::lower_bound(fSteppers.cbegin(), end, curveLength,
0120 [](const InterpStepper& stepper, G4double value) { return stepper.end < value; });
0121 if (it == end)
0122 {
0123 if (curveLength - fLastStepper->end > CLHEP::perMillion)
0124 {
0125 std::ostringstream message;
0126 message << "curveLength = " << curveLength << " > " << fLastStepper->end;
0127 G4Exception("G4InterpolationDriver::Interpolate()", "GeomField1001", JustWarning, message);
0128 }
0129
0130 return fLastStepper->stepper->Interpolate(1, y);
0131 }
0132
0133 if (curveLength < it->begin)
0134 {
0135 if (it->begin - curveLength > CLHEP::perMillion)
0136 {
0137 std::ostringstream message;
0138 message << "curveLength = " << curveLength << " < " << it->begin;
0139 G4Exception("G4InterpolationDriver::Interpolate()", "GeomField1001", JustWarning, message);
0140 }
0141
0142 return it->stepper->Interpolate(0, y);
0143 }
0144
0145 return InterpolateImpl(curveLength, it, y);
0146 }
0147
0148 template <class T, G4bool StepperCachesDchord>
0149 void G4InterpolationDriver<T, StepperCachesDchord>::InterpolateImpl(
0150 G4double curveLength, ConstStepperIterator it, field_utils::State& y) const
0151 {
0152 const G4double tau = (curveLength - it->begin) * it->inverseLength;
0153 return it->stepper->Interpolate(field_utils::clamp(tau, 0., 1.), y);
0154 }
0155
0156 template <class T, G4bool StepperCachesDchord>
0157 G4double G4InterpolationDriver<T, StepperCachesDchord>::DistChord(const field_utils::State& yBegin,
0158 G4double curveLengthBegin, const field_utils::State& yEnd, G4double curveLengthEnd) const
0159 {
0160 if (StepperCachesDchord)
0161 {
0162
0163
0164 if (curveLengthBegin == fLastStepper->begin && curveLengthEnd == fLastStepper->end)
0165 {
0166 return fLastStepper->stepper
0167 ->DistChord();
0168 }
0169 }
0170
0171 const G4double curveLengthMid = 0.5 * (curveLengthBegin + curveLengthEnd);
0172 field_utils::State yMid;
0173
0174 Interpolate(curveLengthMid, yMid);
0175
0176 return G4LineSection::Distline(field_utils::makeVector(yMid, field_utils::Value3D::Position),
0177 field_utils::makeVector(yBegin, field_utils::Value3D::Position),
0178 field_utils::makeVector(yEnd, field_utils::Value3D::Position));
0179 }
0180
0181 template <class T, G4bool StepperCachesDchord>
0182 G4double G4InterpolationDriver<T, StepperCachesDchord>::AdvanceChordLimited(
0183 G4FieldTrack& track, G4double hstep, G4double epsStep, G4double chordDistance)
0184 {
0185 ++fTotalStepsForTrack;
0186
0187 const G4double curveLengthBegin = track.GetCurveLength();
0188 const G4double hend = std::min(hstep, fChordStepEstimate);
0189 G4double hdid = 0.0;
0190 auto it = fSteppers.begin();
0191 G4double dChordStep = 0.0;
0192
0193 field_utils::State yBegin, y;
0194 track.DumpToArray(yBegin);
0195 track.DumpToArray(y);
0196
0197 if (fFirstStep)
0198 {
0199 Base::GetEquationOfMotion()->RightHandSide(y, fdydx);
0200 fFirstStep = false;
0201 }
0202
0203 if (fKeepLastStepper)
0204 {
0205 std::swap(*fSteppers.begin(), *fLastStepper);
0206 it = fSteppers.begin();
0207 fLastStepper = it;
0208 hdid = it->end - curveLengthBegin;
0209 if (hdid > hend)
0210 {
0211 hdid = hend;
0212 InterpolateImpl(curveLengthBegin + hdid, it, y);
0213 }
0214 else
0215 {
0216 field_utils::copy(y, it->stepper->GetYOut());
0217 }
0218
0219 dChordStep = DistChord(yBegin, curveLengthBegin, y, curveLengthBegin + hdid);
0220
0221 ++it;
0222 }
0223
0224
0225 G4double h = fhnext;
0226 for (; hdid < hend && dChordStep < chordDistance && it != fSteppers.end(); ++it)
0227 {
0228 h = std::min(h, hstep - hdid);
0229
0230
0231 hdid += OneGoodStep(it, y, fdydx, h, epsStep, curveLengthBegin + hdid, &track);
0232
0233
0234 fLastStepper = it;
0235
0236
0237 dChordStep =
0238 std::max(dChordStep, DistChord(yBegin, curveLengthBegin, y, curveLengthBegin + hdid));
0239 }
0240
0241
0242
0243
0244
0245
0246
0247 if (h > fMinimumStep)
0248 {
0249 fhnext = h;
0250 }
0251
0252
0253
0254
0255
0256 hdid =
0257 FindNextChord(yBegin, curveLengthBegin, y, curveLengthBegin + hdid, dChordStep, chordDistance);
0258
0259 const G4double curveLengthEnd = curveLengthBegin + hdid;
0260 fKeepLastStepper = fLastStepper->end - curveLengthEnd > CLHEP::perMillion;
0261 track.LoadFromArray(y, fLastStepper->stepper->GetNumberOfVariables());
0262 track.SetCurveLength(curveLengthBegin + hdid);
0263
0264 return hdid;
0265 }
0266
0267 template <class T, G4bool StepperCachesDchord>
0268 G4double G4InterpolationDriver<T, StepperCachesDchord>::FindNextChord(
0269 const field_utils::State& yBegin, G4double curveLengthBegin, field_utils::State& yEnd,
0270 G4double curveLengthEnd, G4double dChord, G4double chordDistance)
0271 {
0272 G4double hstep = curveLengthEnd - curveLengthBegin;
0273 G4double curveLength = curveLengthEnd;
0274
0275 G4int i = 1;
0276 for (; i < fMaxTrials && dChord > chordDistance && curveLength > fLastStepper->begin; ++i)
0277 {
0278
0279 hstep = CalcChordStep(hstep, dChord, chordDistance);
0280
0281
0282 hstep = std::max(hstep, fLastStepper->begin - curveLengthBegin);
0283 curveLength = curveLengthBegin + hstep;
0284
0285
0286 InterpolateImpl(curveLength, fLastStepper, yEnd);
0287
0288
0289 dChord = DistChord(yBegin, curveLengthBegin, yEnd, curveLength);
0290 }
0291
0292
0293
0294 if (dChord > 0.0)
0295 {
0296 fChordStepEstimate = hstep * std::sqrt(chordDistance / dChord);
0297 }
0298
0299 if (i == fMaxTrials)
0300 {
0301 G4Exception(
0302 "G4InterpolationDriver::FindNextChord()", "GeomField1001", JustWarning, "cannot converge");
0303 }
0304
0305 AccumulateStatistics(i);
0306
0307 return hstep;
0308 }
0309
0310
0311
0312
0313
0314 template <class T, G4bool StepperCachesDchord>
0315 G4double G4InterpolationDriver<T, StepperCachesDchord>::CalcChordStep(
0316 G4double stepTrialOld, G4double dChordStep, G4double chordDistance)
0317 {
0318 const G4double chordStepEstimate = stepTrialOld * std::sqrt(chordDistance / dChordStep);
0319 G4double stepTrial = fFractionNextEstimate * chordStepEstimate;
0320
0321 if (stepTrial <= 0.001 * stepTrialOld)
0322 {
0323 if (dChordStep > 1000.0 * chordDistance)
0324 {
0325 stepTrial = stepTrialOld * 0.03;
0326 }
0327 else
0328 {
0329 if (dChordStep > 100. * chordDistance)
0330 {
0331 stepTrial = stepTrialOld * 0.1;
0332 }
0333 else
0334 {
0335 stepTrial = stepTrialOld * 0.5;
0336 }
0337 }
0338 }
0339 else if (stepTrial > 1000.0 * stepTrialOld)
0340 {
0341 stepTrial = 1000.0 * stepTrialOld;
0342 }
0343
0344 if (stepTrial == 0.0)
0345 {
0346 stepTrial = 0.000001;
0347 }
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358 return stepTrial;
0359 }
0360
0361 template <class T, G4bool StepperCachesDchord>
0362 G4bool G4InterpolationDriver<T, StepperCachesDchord>::AccurateAdvance(
0363 G4FieldTrack& track, G4double hstep, G4double , G4double
0364 )
0365 {
0366 if (hstep == 0.0)
0367 {
0368 std::ostringstream message;
0369 message << "Proposed step is zero; hstep = " << hstep << " !";
0370 G4Exception("G4InterpolationDriver::AccurateAdvance()", "GeomField1001", JustWarning, message);
0371 return true;
0372 }
0373
0374 if (hstep < 0)
0375 {
0376 std::ostringstream message;
0377 message << "Invalid run condition." << G4endl << "Proposed step is negative; hstep = " << hstep
0378 << "." << G4endl << "Requested step cannot be negative! Aborting event.";
0379 G4Exception(
0380 "G4InterpolationDriver::AccurateAdvance()", "GeomField0003", EventMustBeAborted, message);
0381 return false;
0382 }
0383
0384 const G4double curveLength = track.GetCurveLength();
0385 const G4double curveLengthEnd = curveLength + hstep;
0386
0387 field_utils::State y;
0388 Interpolate(curveLengthEnd, y);
0389
0390 track.LoadFromArray(y, Base::GetStepper()->GetNumberOfVariables());
0391 track.SetCurveLength(curveLengthEnd);
0392
0393 return true;
0394 }
0395
0396
0397
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409 template <class T, G4bool StepperCachesDchord>
0410 G4double G4InterpolationDriver<T, StepperCachesDchord>::OneGoodStep(StepperIterator it,
0411 field_utils::State& y, field_utils::State& dydx, G4double& hstep, G4double epsStep,
0412 G4double curveLength, G4FieldTrack* )
0413
0414 {
0415 G4double error2 = DBL_MAX;
0416 field_utils::State yerr, ytemp, dydxtemp;
0417 G4double h = hstep;
0418
0419 G4int i = 0;
0420 for (; i < fMaxTrials; ++i)
0421 {
0422 it->stepper->Stepper(y, dydx, h, ytemp, yerr, dydxtemp);
0423 error2 = field_utils::relativeError2(y, yerr, h, epsStep);
0424
0425 if (error2 <= 1.0)
0426 {
0427 hstep = std::max(Base::GrowStepSize2(h, error2), fMinimumStep);
0428 break;
0429 }
0430
0431
0432 if (h <= fMinimumStep)
0433 {
0434 hstep = fMinimumStep;
0435 break;
0436 }
0437
0438 h = std::max(Base::ShrinkStepSize2(h, error2), fMinimumStep);
0439 }
0440
0441 if (i == fMaxTrials)
0442 {
0443 G4Exception(
0444 "G4InterpolationDriver::OneGoodStep()", "GeomField1001", JustWarning, "cannot converge");
0445 hstep = std::max(Base::ShrinkStepSize2(h, error2), fMinimumStep);
0446 }
0447
0448
0449 it->begin = curveLength;
0450 it->end = curveLength + h;
0451 it->inverseLength = 1. / h;
0452
0453
0454 it->stepper->SetupInterpolation();
0455
0456 field_utils::copy(dydx, dydxtemp);
0457 field_utils::copy(y, ytemp);
0458
0459 return h;
0460 }
0461
0462 template <class T, G4bool StepperCachesDchord>
0463 void G4InterpolationDriver<T, StepperCachesDchord>::PrintState() const
0464 {
0465 using namespace field_utils;
0466 State prevEnd, currBegin;
0467 auto prev = fSteppers.begin();
0468
0469 G4cout << "====== curr state ========" << G4endl;
0470 for (auto i = fSteppers.begin(); i <= fLastStepper; ++i)
0471 {
0472 i->stepper->Interpolate(0, currBegin);
0473
0474 G4cout << "cl_begin: " << i->begin << " "
0475 << "cl_end: " << i->end << " ";
0476
0477 if (prev != i)
0478 {
0479 prev->stepper->Interpolate(1, prevEnd);
0480 auto prevPos = makeVector(prevEnd, Value3D::Position);
0481 auto currPos = makeVector(currBegin, Value3D::Position);
0482 G4cout << "diff_begin: " << (prevPos - currPos).mag();
0483 }
0484
0485 G4cout << G4endl;
0486 prev = i;
0487 }
0488
0489 const G4double clBegin = fSteppers.begin()->begin;
0490 const G4double clEnd = fLastStepper->end;
0491 const G4double hstep = (clEnd - clBegin) / 10.;
0492 State yBegin, yCurr;
0493 Interpolate(0, yBegin);
0494 for (G4double cl = clBegin; cl <= clEnd + 1e-12; cl += hstep)
0495 {
0496 Interpolate(cl, yCurr);
0497 auto d = DistChord(yBegin, clBegin, yCurr, cl);
0498 G4cout << "cl: " << cl << " chord_distance: " << d << G4endl;
0499 }
0500
0501 G4cout << "==========================" << G4endl;
0502 }
0503
0504 template <class T, G4bool StepperCachesDchord>
0505 void G4InterpolationDriver<T, StepperCachesDchord>::CheckState() const
0506 {
0507 G4int smallSteps = 0;
0508 for (auto i = fSteppers.begin(); i <= fLastStepper; ++i)
0509 {
0510 G4double stepLength = i->end - i->begin;
0511 if (stepLength < fMinimumStep)
0512 {
0513 ++smallSteps;
0514 }
0515 }
0516
0517 if (smallSteps > 1)
0518 {
0519 std::ostringstream message;
0520 message << "====== curr state ========\n";
0521 for (auto i = fSteppers.begin(); i <= fLastStepper; ++i)
0522 {
0523 message << "cl_begin: " << i->begin << " "
0524 << "cl_end: " << i->end << "\n";
0525 }
0526
0527 G4Exception("G4InterpolationDriver::CheckState()", "GeomField0003", FatalException, message);
0528 }
0529 }
0530
0531 template <class T, G4bool StepperCachesDchord>
0532 void G4InterpolationDriver<T, StepperCachesDchord>::AccumulateStatistics(G4int noTrials)
0533 {
0534 fTotalNoTrials += noTrials;
0535 ++fNoCalls;
0536
0537 if (noTrials > fmaxTrials)
0538 {
0539 fmaxTrials = noTrials;
0540 }
0541 }
0542
0543 template <class T, G4bool StepperCachesDchord>
0544 void G4InterpolationDriver<T, StepperCachesDchord>::StreamInfo(std::ostream& os) const
0545 {
0546 os << "State of G4InterpolationDriver: " << std::endl;
0547 os << "--Base state (G4RKIntegrationDriver): " << std::endl;
0548 Base::StreamInfo(os);
0549 os << " fMinimumStep = " << fMinimumStep << std::endl;
0550
0551
0552
0553
0554
0555
0556
0557 os << " Max num of Trials = " << fMaxTrials << std::endl;
0558 os << " Fract Next Estimate = " << fFractionNextEstimate << std::endl;
0559 os << " Smallest Curve Fract= " << fSmallestCurveFraction << std::endl;
0560
0561 os << " VerboseLevel = " << fVerboseLevel << std::endl;
0562 os << " KeepLastStepper = " << fKeepLastStepper << std::endl;
0563 }