File indexing completed on 2026-10-05 09:14:01
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 template <class Driver>
0032 G4ChordFinderDelegate<Driver>::~G4ChordFinderDelegate()
0033 {
0034 #ifdef G4VERBOSE
0035 if (GetDriver().GetVerboseLevel() > 0)
0036 {
0037 PrintStatistics();
0038 }
0039 #endif
0040 }
0041
0042 template <class Driver>
0043 void G4ChordFinderDelegate<Driver>::ResetStepEstimate()
0044 {
0045 fLastStepEstimate_Unconstrained = DBL_MAX;
0046 }
0047
0048 template <class Driver>
0049 Driver& G4ChordFinderDelegate<Driver>::GetDriver()
0050 {
0051 return static_cast<Driver&>(*this);
0052 }
0053
0054 template <class Driver>
0055 G4double G4ChordFinderDelegate<Driver>::
0056 AdvanceChordLimitedImpl(G4FieldTrack& yCurrent, G4double stepMax,
0057 G4double epsStep, G4double chordDistance)
0058 {
0059 G4double dyErr;
0060 G4FieldTrack yEnd = yCurrent;
0061 G4double nextStep;
0062
0063 const G4double stepPossible = FindNextChord(yCurrent, stepMax,
0064 epsStep, chordDistance,
0065 yEnd, dyErr, nextStep);
0066 if (dyErr < epsStep * stepPossible)
0067 {
0068
0069
0070 yCurrent = yEnd;
0071 return stepPossible;
0072 }
0073
0074
0075
0076 const G4double startCurveLen = yCurrent.GetCurveLength();
0077 const G4bool goodAdvance =
0078 GetDriver().AccurateAdvance(yCurrent,stepPossible,epsStep,nextStep);
0079
0080 return goodAdvance ? stepPossible
0081 : yCurrent.GetCurveLength() - startCurveLen;
0082 }
0083
0084
0085
0086 template <class T>
0087 G4double G4ChordFinderDelegate<T>::
0088 FindNextChord(const G4FieldTrack& yStart,
0089 G4double stepMax,
0090 G4double epsStep,
0091 G4double chordDistance,
0092 G4FieldTrack& yEnd,
0093 G4double& dyErrPos,
0094 G4double& stepForAccuracy)
0095 {
0096
0097
0098
0099
0100 G4double dydx[G4FieldTrack::ncompSVEC];
0101
0102 G4bool validEndPoint = false;
0103 G4double dChordStep, lastStepLength;
0104
0105 GetDriver().GetDerivatives(yStart, dydx);
0106
0107 const G4double safetyFactor = fFirstFraction;
0108
0109 G4double stepTrial = std::min(stepMax,
0110 safetyFactor*fLastStepEstimate_Unconstrained);
0111
0112 G4double newStepEst_Uncons = 0.0;
0113 G4double stepForChord;
0114
0115 G4int noTrials = 1;
0116 constexpr G4int maxTrials = 75;
0117 for (; noTrials < maxTrials; ++noTrials)
0118 {
0119 yEnd = yStart;
0120 GetDriver().QuickAdvance(yEnd, dydx, stepTrial, dChordStep, dyErrPos);
0121 lastStepLength = stepTrial;
0122
0123 validEndPoint = dChordStep < chordDistance;
0124 stepForChord = NewStep(stepTrial, dChordStep,
0125 chordDistance, newStepEst_Uncons);
0126 if (validEndPoint)
0127 {
0128 break;
0129 }
0130
0131 if (stepTrial <= 0.0)
0132 {
0133 stepTrial = stepForChord;
0134 }
0135 else if (stepForChord <= stepTrial)
0136 {
0137
0138 stepTrial = std::min( stepForChord, fFractionLast * stepTrial);
0139 }
0140 else
0141 {
0142 stepTrial *= 0.1;
0143 }
0144 }
0145
0146 if (noTrials >= maxTrials)
0147 {
0148 std::ostringstream message;
0149 message << "Exceeded maximum number of trials= " << maxTrials << G4endl
0150 << "Current sagita dist= " << dChordStep << G4endl
0151 << "Max sagita dist= " << chordDistance << G4endl
0152 << "Step sizes (actual and proposed): " << G4endl
0153 << "Last trial = " << lastStepLength << G4endl
0154 << "Next trial = " << stepTrial << G4endl
0155 << "Proposed for chord = " << stepForChord << G4endl;
0156 G4Exception("G4ChordFinder::FindNextChord()", "GeomField0003",
0157 JustWarning, message);
0158 }
0159
0160 if (newStepEst_Uncons > 0.0)
0161 {
0162 fLastStepEstimate_Unconstrained = newStepEst_Uncons;
0163 }
0164
0165 AccumulateStatistics(noTrials);
0166
0167
0168
0169 G4double dyErr_relative = dyErrPos / (epsStep * lastStepLength);
0170 stepForAccuracy = dyErr_relative > 1 ?
0171 GetDriver().ComputeNewStepSize(dyErr_relative, lastStepLength) : 0;
0172
0173 return stepTrial;
0174 }
0175
0176
0177
0178
0179
0180 template <class T>
0181 G4double G4ChordFinderDelegate<T>::
0182 NewStep(G4double stepTrialOld,
0183 G4double dChordStep,
0184 G4double fDeltaChord,
0185 G4double& stepEstimate_Unconstrained)
0186 {
0187 G4double stepTrial;
0188
0189 if (dChordStep > 0.0)
0190 {
0191 stepEstimate_Unconstrained =
0192 stepTrialOld * std::sqrt(fDeltaChord / dChordStep);
0193 stepTrial = fFractionNextEstimate * stepEstimate_Unconstrained;
0194 }
0195 else
0196 {
0197
0198 stepTrial = stepTrialOld * 2.;
0199 }
0200
0201 if (stepTrial <= 0.001 * stepTrialOld)
0202 {
0203 if (dChordStep > 1000.0 * fDeltaChord)
0204 {
0205 stepTrial = stepTrialOld * 0.03;
0206 }
0207 else
0208 {
0209 if (dChordStep > 100. * fDeltaChord)
0210 {
0211 stepTrial = stepTrialOld * 0.1;
0212 }
0213 else
0214 {
0215 stepTrial = stepTrialOld * 0.5;
0216 }
0217 }
0218 }
0219 else if (stepTrial > 1000.0 * stepTrialOld)
0220 {
0221 stepTrial = 1000.0 * stepTrialOld;
0222 }
0223
0224 if (stepTrial == 0.0)
0225 {
0226 stepTrial= 0.000001;
0227 }
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238 return stepTrial;
0239 }
0240
0241 template <class T>
0242 void G4ChordFinderDelegate<T>::AccumulateStatistics(G4int noTrials)
0243 {
0244 fTotalNoTrials += noTrials;
0245 ++fNoCalls;
0246
0247 if (noTrials > fmaxTrials)
0248 {
0249 fmaxTrials = noTrials;
0250 }
0251 }
0252
0253 template <class T>
0254 void G4ChordFinderDelegate<T>::PrintStatistics()
0255 {
0256
0257 G4cout << "G4ChordFinder statistics report: \n"
0258 << " No trials: " << fTotalNoTrials
0259 << " No Calls: " << fNoCalls
0260 << " Max-trial: " << fmaxTrials << "\n"
0261 << " Parameters: "
0262 << " fFirstFraction " << fFirstFraction
0263 << " fFractionLast " << fFractionLast
0264 << " fFractionNextEstimate " << fFractionNextEstimate
0265 << G4endl;
0266 }
0267
0268 template <class T>
0269 G4int G4ChordFinderDelegate<T>::GetNoCalls()
0270 {
0271 return fNoCalls;
0272 }
0273
0274 template <class T>
0275 G4int G4ChordFinderDelegate<T>::GetNoTrials()
0276 {
0277 return fTotalNoTrials;
0278 }
0279
0280 template <class T>
0281 G4int G4ChordFinderDelegate<T>::GetNoMaxTrials()
0282 {
0283 return fmaxTrials;
0284 }
0285
0286 template <class T>
0287 void G4ChordFinderDelegate<T>::SetFractions_Last_Next(G4double fractLast,
0288 G4double fractNext)
0289 {
0290
0291 if (fractLast == -1.0) { fractLast = 1.0; }
0292 if (fractNext == -1.0) { fractNext = 0.98; }
0293
0294
0295 if (GetDriver().GetVerboseLevel() > 0)
0296 {
0297 G4cout << " ChordFnd> Trying to set fractions: "
0298 << " first " << fFirstFraction
0299 << " last " << fractLast
0300 << " next " << fractNext
0301 << G4endl;
0302 }
0303
0304 if (fractLast > 0 && fractLast <= 1)
0305 {
0306 fFractionLast = fractLast;
0307 } else
0308 {
0309 std::ostringstream message;
0310 message << "Invalid fraction Last = " << fractLast
0311 << "; must be 0 < fractionLast <= 1 ";
0312 G4Exception("G4ChordFinderDelegate::SetFractions_Last_Next()",
0313 "GeomField1001", JustWarning, message);
0314 }
0315 if (fractNext > 0. && fractNext < 1)
0316 {
0317 fFractionNextEstimate = fractNext;
0318 } else
0319 {
0320 std::ostringstream message;
0321 message << "Invalid fraction Next = " << fractNext
0322 << "; must be 0 < fractionNext < 1 ";
0323 G4Exception("G4ChordFinderDelegate::SetFractions_Last_Next()",
0324 "GeomField1001", JustWarning, message);
0325 }
0326 }
0327
0328 template <class T>
0329 void G4ChordFinderDelegate<T>::SetFirstFraction(G4double fractFirst)
0330 {
0331 fFirstFraction = fractFirst;
0332 }
0333
0334 template <class T>
0335 G4double G4ChordFinderDelegate<T>::GetFirstFraction()
0336 {
0337 return fFirstFraction;
0338 }
0339
0340 template <class T>
0341 G4double G4ChordFinderDelegate<T>::GetFractionLast()
0342 {
0343 return fFractionLast;
0344 }
0345
0346 template <class T>
0347 G4double G4ChordFinderDelegate<T>::GetFractionNextEstimate()
0348 {
0349 return fFractionNextEstimate;
0350 }
0351
0352 template <class T>
0353 G4double G4ChordFinderDelegate<T>::GetLastStepEstimateUnc()
0354 {
0355 return fLastStepEstimate_Unconstrained;
0356 }
0357
0358 template <class T>
0359 void G4ChordFinderDelegate<T>::SetLastStepEstimateUnc(G4double stepEst)
0360 {
0361 fLastStepEstimate_Unconstrained = stepEst;
0362 }
0363
0364 template <class T>
0365 void G4ChordFinderDelegate<T>::TestChordPrint(G4int noTrials,
0366 G4int lastStepTrial,
0367 G4double dChordStep,
0368 G4double fDeltaChord,
0369 G4double nextStepTrial)
0370 {
0371 G4int oldprec = G4cout.precision(5);
0372 G4cout << " ChF/fnc: notrial " << std::setw( 3) << noTrials
0373 << " this_step= " << std::setw(10) << lastStepTrial;
0374 if( std::fabs( (dChordStep / fDeltaChord) - 1.0 ) < 0.001 )
0375 {
0376 G4cout.precision(8);
0377 }
0378 else
0379 {
0380 G4cout.precision(6);
0381 }
0382 G4cout << " dChordStep= " << std::setw(12) << dChordStep;
0383 if( dChordStep > fDeltaChord ) { G4cout << " d+"; }
0384 else { G4cout << " d-"; }
0385 G4cout.precision(5);
0386 G4cout << " new_step= " << std::setw(10)
0387 << fLastStepEstimate_Unconstrained
0388 << " new_step_constr= " << std::setw(10)
0389 << lastStepTrial << G4endl;
0390 G4cout << " nextStepTrial = " << std::setw(10) << nextStepTrial << G4endl;
0391 G4cout.precision(oldprec);
0392 }
0393
0394 template <class T>
0395 void G4ChordFinderDelegate<T>::StreamDelegateInfo( std::ostream& os ) const
0396 {
0397
0398 os << "State of G4ChordFinderDelegate: " << std::endl;
0399 os << "--Parameters: " << std::endl;
0400 os << " First Fraction = " << fFirstFraction << std::endl;
0401 os << " Last Fraction = " << fFractionLast << std::endl;
0402 os << " Fract Next est = " << fFractionNextEstimate << std::endl;
0403
0404 os << "--State (fungible): " << std::endl;
0405 os << " Maximum No Trials (seen) = " << fmaxTrials << std::endl;
0406 os << " LastStepEstimate (Unconstrained) = " << fLastStepEstimate_Unconstrained
0407 << std::endl;
0408
0409 os << "--Statistics: trials= " << fTotalNoTrials
0410 << " calls= " << fNoCalls << std::endl;
0411 }
0412