File indexing completed on 2026-09-17 09:14:11
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
0033
0034
0035
0036
0037
0038
0039 #ifndef G4TDORMAND_PRINCE_45_HH
0040 #define G4TDORMAND_PRINCE_45_HH
0041
0042 #include "G4MagIntegratorStepper.hh"
0043 #include "G4FieldUtils.hh"
0044 #include "G4LineSection.hh"
0045
0046 #include <cstring>
0047 #include <cassert>
0048
0049
0050
0051
0052
0053
0054 template <class T_Equation, unsigned int N = 6 >
0055 class G4TDormandPrince45 : public G4MagIntegratorStepper
0056 {
0057 public:
0058
0059 G4TDormandPrince45(T_Equation* equation );
0060 G4TDormandPrince45(T_Equation* equation, G4int numVar );
0061
0062 inline void StepWithError(const G4double yInput[],
0063 const G4double dydx[],
0064 G4double hstep,
0065 G4double yOutput[],
0066 G4double yError[] ) ;
0067
0068 void Stepper(const G4double yInput[],
0069 const G4double dydx[],
0070 G4double hstep,
0071 G4double yOutput[],
0072 G4double yError[]) final;
0073
0074 inline void StepWithFinalDerivate(const G4double yInput[],
0075 const G4double dydx[],
0076 G4double hstep,
0077 G4double yOutput[],
0078 G4double yError[],
0079 G4double dydxOutput[]);
0080
0081 inline void SetupInterpolation() {}
0082
0083 void Interpolate(G4double tau, G4double yOut[]) const
0084 {
0085 Interpolate4thOrder(yOut, tau);
0086 }
0087
0088
0089 G4double DistChord() const final;
0090
0091 inline G4int IntegratorOrder() const override { return 4; }
0092
0093 G4StepperType StepperType() const override { return kTDormandPrince45; }
0094
0095 inline const field_utils::ShortState<N>& GetYOut() const { return fyOut; }
0096
0097 void Interpolate4thOrder(G4double yOut[], G4double tau) const;
0098
0099 void SetupInterpolation5thOrder();
0100 void Interpolate5thOrder(G4double yOut[], G4double tau) const;
0101
0102
0103 inline void RightHandSideInl( const G4double y[],
0104 G4double dydx[] )
0105 {
0106 fEquation_Rhs->T_Equation::RightHandSide(y, dydx);
0107 }
0108
0109 inline void Stepper(const G4double yInput[],
0110 const G4double dydx[],
0111 G4double hstep, G4double yOutput[],
0112 G4double yError[], G4double dydxOutput[])
0113 {
0114 StepWithFinalDerivate(yInput, dydx, hstep, yOutput, yError, dydxOutput);
0115 }
0116
0117 T_Equation* GetSpecificEquation() { return fEquation_Rhs; }
0118
0119 static constexpr G4int N8 = N > 8 ? N : 8;
0120
0121 private:
0122
0123 field_utils::ShortState<N> ak2, ak3, ak4, ak5, ak6, ak7, ak8, ak9;
0124 field_utils::ShortState<N8> fyIn;
0125 field_utils::ShortState<N> fyOut, fdydxIn;
0126
0127
0128
0129
0130
0131 G4double fLastStepLength = -1.0;
0132 T_Equation* fEquation_Rhs;
0133 };
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163 template <class T_Equation, unsigned int N>
0164 G4TDormandPrince45<T_Equation,N>::G4TDormandPrince45(T_Equation* equation )
0165 : G4MagIntegratorStepper(dynamic_cast<G4EquationOfMotion*>(equation), N )
0166 , fEquation_Rhs(equation)
0167 {
0168
0169 if( dynamic_cast<G4EquationOfMotion*>(equation) == nullptr )
0170 {
0171 G4Exception("G4TDormandPrince745: constructor", "GeomField0001",
0172 FatalException, "T_Equation is not an G4EquationOfMotion.");
0173 }
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185 }
0186
0187 template <class T_Equation, unsigned int N>
0188 inline G4TDormandPrince45<T_Equation,N>::
0189 G4TDormandPrince45(T_Equation* equation, G4int numVar )
0190 : G4TDormandPrince45<T_Equation,N>(equation )
0191 {
0192 if( numVar != G4int(N))
0193 {
0194 G4ExceptionDescription msg;
0195 msg << "Equation has an incompatible number of variables." ;
0196 msg << " template N = " << N
0197 << " argument numVar = " << numVar ;
0198
0199 G4Exception("G4TCashKarpRKF45: constructor", "GeomField0001",
0200 FatalErrorInArgument, msg );
0201 }
0202 assert( numVar == N );
0203 }
0204
0205 template <class T_Equation, unsigned int N>
0206 inline void
0207 G4TDormandPrince45<T_Equation,N>::StepWithFinalDerivate(const G4double yInput[],
0208 const G4double dydx[],
0209 G4double hstep,
0210 G4double yOutput[],
0211 G4double yError[],
0212 G4double dydxOutput[])
0213 {
0214 StepWithError(yInput, dydx, hstep, yOutput, yError);
0215 field_utils::copy(dydxOutput, ak7, N);
0216 }
0217
0218
0219
0220
0221
0222
0223
0224 template <class T_Equation, unsigned int N>
0225 inline void
0226 G4TDormandPrince45<T_Equation,N>::StepWithError(const G4double yInput[],
0227 const G4double dydx[],
0228 G4double hstep,
0229 G4double yOut[],
0230 G4double yErr[] )
0231 {
0232
0233
0234 constexpr G4double b21 = 0.2,
0235 b31 = 3.0 / 40.0, b32 = 9.0 / 40.0,
0236 b41 = 44.0 / 45.0, b42 = -56.0 / 15.0, b43 = 32.0/9.0,
0237
0238 b51 = 19372.0 / 6561.0, b52 = -25360.0 / 2187.0, b53 = 64448.0 / 6561.0,
0239 b54 = -212.0 / 729.0,
0240
0241 b61 = 9017.0 / 3168.0 , b62 = -355.0 / 33.0,
0242 b63 = 46732.0 / 5247.0, b64 = 49.0 / 176.0,
0243 b65 = -5103.0 / 18656.0,
0244
0245 b71 = 35.0 / 384.0, b72 = 0.,
0246 b73 = 500.0 / 1113.0, b74 = 125.0 / 192.0,
0247 b75 = -2187.0 / 6784.0, b76 = 11.0 / 84.0,
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261 dc1 = -(b71 - 5179.0 / 57600.0),
0262 dc2 = -(b72 - .0),
0263 dc3 = -(b73 - 7571.0 / 16695.0),
0264 dc4 = -(b74 - 393.0 / 640.0),
0265 dc5 = -(b75 + 92097.0 / 339200.0),
0266 dc6 = -(b76 - 187.0 / 2100.0),
0267 dc7 = -(- 1.0 / 40.0);
0268
0269
0270
0271 field_utils::ShortState<N8> yTemp;
0272
0273 yOut[7] = yTemp[7] = fyIn[7] = yInput[7];
0274
0275
0276
0277 for(unsigned int i = 0; i < N; ++i)
0278 {
0279 fyIn[i] = yInput[i];
0280 yTemp[i] = yInput[i] + b21 * hstep * dydx[i];
0281 }
0282 RightHandSideInl(yTemp, ak2);
0283
0284 for(unsigned int i = 0; i < N; ++i)
0285 {
0286 yTemp[i] = fyIn[i] + hstep * (b31 * dydx[i] + b32 * ak2[i]);
0287 }
0288 RightHandSideInl(yTemp, ak3);
0289
0290 for(unsigned int i = 0; i < N; ++i)
0291 {
0292 yTemp[i] = fyIn[i] + hstep * (
0293 b41 * dydx[i] + b42 * ak2[i] + b43 * ak3[i]);
0294 }
0295 RightHandSideInl(yTemp, ak4);
0296
0297 for(unsigned int i = 0; i < N; ++i)
0298 {
0299 yTemp[i] = fyIn[i] + hstep * (
0300 b51 * dydx[i] + b52 * ak2[i] + b53 * ak3[i] + b54 * ak4[i]);
0301 }
0302 RightHandSideInl(yTemp, ak5);
0303
0304 for(unsigned int i = 0; i < N; ++i)
0305 {
0306 yTemp[i] = fyIn[i] + hstep * (
0307 b61 * dydx[i] + b62 * ak2[i] +
0308 b63 * ak3[i] + b64 * ak4[i] + b65 * ak5[i]);
0309 }
0310 RightHandSideInl(yTemp, ak6);
0311
0312 for(unsigned int i = 0; i < N; ++i)
0313 {
0314 yOut[i] = fyIn[i] + hstep * (
0315 b71 * dydx[i] + b72 * ak2[i] + b73 * ak3[i] +
0316 b74 * ak4[i] + b75 * ak5[i] + b76 * ak6[i]);
0317 }
0318 RightHandSideInl(yOut, ak7);
0319
0320 for(unsigned int i = 0; i < N; ++i)
0321 {
0322 yErr[i] = hstep * (
0323 dc1 * dydx[i] + dc2 * ak2[i] +
0324 dc3 * ak3[i] + dc4 * ak4[i] +
0325 dc5 * ak5[i] + dc6 * ak6[i] + dc7 * ak7[i]
0326 ) + 1.5e-18;
0327
0328
0329
0330 fyOut[i] = yOut[i];
0331 fdydxIn[i] = dydx[i];
0332 }
0333
0334 fLastStepLength = hstep;
0335 }
0336
0337 template <class T_Equation, unsigned int N >
0338 inline void
0339 G4TDormandPrince45<T_Equation,N>::Stepper(const G4double yInput[],
0340 const G4double dydx[],
0341 G4double Step,
0342 G4double yOutput[],
0343 G4double yError[])
0344 {
0345 assert( yOutput != yInput );
0346 assert( yError != yInput );
0347
0348 StepWithError( yInput, dydx, Step, yOutput, yError);
0349 }
0350
0351 template <class T_Equation, unsigned int N>
0352 inline G4double G4TDormandPrince45<T_Equation,N>::DistChord() const
0353 {
0354
0355
0356
0357 const G4double hf1 = 6025192743.0 / 30085553152.0,
0358 hf3 = 51252292925.0 / 65400821598.0,
0359 hf4 = - 2691868925.0 / 45128329728.0,
0360 hf5 = 187940372067.0 / 1594534317056.0,
0361 hf6 = - 1776094331.0 / 19743644256.0,
0362 hf7 = 11237099.0 / 235043384.0;
0363
0364 G4ThreeVector mid;
0365
0366 for(unsigned int i = 0; i < 3; ++i)
0367 {
0368 mid[i] = fyIn[i] + 0.5 * fLastStepLength * (
0369 hf1 * fdydxIn[i] + hf3 * ak3[i] +
0370 hf4 * ak4[i] + hf5 * ak5[i] + hf6 * ak6[i] + hf7 * ak7[i]);
0371 }
0372
0373 const G4ThreeVector begin = makeVector(fyIn, field_utils::Value3D::Position);
0374 const G4ThreeVector end = makeVector(fyOut, field_utils::Value3D::Position);
0375
0376 return G4LineSection::Distline(mid, begin, end);
0377 }
0378
0379
0380
0381
0382
0383
0384 template <class T_Equation, unsigned int N>
0385 inline void
0386 G4TDormandPrince45<T_Equation,N>::Interpolate4thOrder(G4double yOut[],
0387 G4double tau) const
0388 {
0389 const G4double tau2 = tau * tau,
0390 tau3 = tau * tau2,
0391 tau4 = tau2 * tau2;
0392
0393 const G4double bf1 = 1.0 / 11282082432.0 * (
0394 157015080.0 * tau4 - 13107642775.0 * tau3 + 34969693132.0 * tau2 -
0395 32272833064.0 * tau + 11282082432.0);
0396
0397 const G4double bf3 = - 100.0 / 32700410799.0 * tau * (
0398 15701508.0 * tau3 - 914128567.0 * tau2 + 2074956840.0 * tau -
0399 1323431896.0);
0400
0401 const G4double bf4 = 25.0 / 5641041216.0 * tau * (
0402 94209048.0 * tau3 - 1518414297.0 * tau2 + 2460397220.0 * tau -
0403 889289856.0);
0404
0405 const G4double bf5 = - 2187.0 / 199316789632.0 * tau * (
0406 52338360.0 * tau3 - 451824525.0 * tau2 + 687873124.0 * tau -
0407 259006536.0);
0408
0409 const G4double bf6 = 11.0 / 2467955532.0 * tau * (
0410 106151040.0 * tau3 - 661884105.0 * tau2 +
0411 946554244.0 * tau - 361440756.0);
0412
0413 const G4double bf7 = 1.0 / 29380423.0 * tau * (1.0 - tau) * (
0414 8293050.0 * tau2 - 82437520.0 * tau + 44764047.0);
0415
0416 for(unsigned int i = 0; i < N; ++i)
0417 {
0418 yOut[i] = fyIn[i] + fLastStepLength * tau * (
0419 bf1 * fdydxIn[i] + bf3 * ak3[i] + bf4 * ak4[i] +
0420 bf5 * ak5[i] + bf6 * ak6[i] + bf7 * ak7[i]);
0421 }
0422 }
0423
0424
0425
0426
0427
0428
0429
0430
0431 template <class T_Equation, unsigned int N>
0432 inline void G4TDormandPrince45<T_Equation,N>::SetupInterpolation5thOrder()
0433 {
0434
0435
0436 const G4double b81 = 6245.0 / 62208.0,
0437 b82 = 0.0,
0438 b83 = 8875.0 / 103032.0,
0439 b84 = -125.0 / 1728.0,
0440 b85 = 801.0 / 13568.0,
0441 b86 = -13519.0 / 368064.0,
0442 b87 = 11105.0 / 368064.0,
0443
0444 b91 = 632855.0 / 4478976.0,
0445 b92 = 0.0,
0446 b93 = 4146875.0 / 6491016.0,
0447 b94 = 5490625.0 /14183424.0,
0448 b95 = -15975.0 / 108544.0,
0449 b96 = 8295925.0 / 220286304.0,
0450 b97 = -1779595.0 / 62938944.0,
0451 b98 = -805.0 / 4104.0;
0452
0453 field_utils::ShortState<N> yTemp;
0454
0455
0456
0457 for(unsigned int i = 0; i < N; ++i)
0458 {
0459 yTemp[i] = fyIn[i] + fLastStepLength * (
0460 b81 * fdydxIn[i] + b82 * ak2[i] + b83 * ak3[i] +
0461 b84 * ak4[i] + b85 * ak5[i] + b86 * ak6[i] +
0462 b87 * ak7[i]
0463 );
0464 }
0465 RightHandSideInl(yTemp, ak8);
0466
0467 for(unsigned int i = 0; i < N; ++i)
0468 {
0469 yTemp[i] = fyIn[i] + fLastStepLength * (
0470 b91 * fdydxIn[i] + b92 * ak2[i] + b93 * ak3[i] +
0471 b94 * ak4[i] + b95 * ak5[i] + b96 * ak6[i] +
0472 b97 * ak7[i] + b98 * ak8[i]
0473 );
0474 }
0475 RightHandSideInl(yTemp, ak9);
0476 }
0477
0478
0479
0480 template <class T_Equation, unsigned int N>
0481 inline void G4TDormandPrince45<T_Equation,N>::
0482 Interpolate5thOrder(G4double yOut[], G4double tau) const
0483 {
0484
0485
0486 G4double bi[10][5];
0487
0488
0489 bi[1][0] = 1.0,
0490 bi[1][1] = -38039.0 / 7040.0,
0491 bi[1][2] = 125923.0 / 10560.0,
0492 bi[1][3] = -19683.0 / 1760.0,
0493 bi[1][4] = 3303.0 / 880.0,
0494
0495
0496
0497 bi[2][0] = 0.0,
0498 bi[2][1] = 0.0,
0499 bi[2][2] = 0.0,
0500 bi[2][3] = 0.0,
0501 bi[2][4] = 0.0,
0502
0503
0504
0505 bi[3][0] = 0.0,
0506 bi[3][1] = -12500.0 / 4081.0,
0507 bi[3][2] = 205000.0 / 12243.0,
0508 bi[3][3] = -90000.0 / 4081.0,
0509 bi[3][4] = 36000.0 / 4081.0,
0510
0511
0512
0513 bi[4][0] = 0.0,
0514 bi[4][1] = -3125.0 / 704.0,
0515 bi[4][2] = 25625.0 / 1056.0,
0516 bi[4][3] = -5625.0 / 176.0,
0517 bi[4][4] = 1125.0 / 88.0,
0518
0519
0520
0521 bi[5][0] = 0.0,
0522 bi[5][1] = 164025.0 / 74624.0,
0523 bi[5][2] = -448335.0 / 37312.0,
0524 bi[5][3] = 295245.0 / 18656.0,
0525 bi[5][4] = -59049.0 / 9328.0,
0526
0527
0528
0529 bi[6][0] = 0.0,
0530 bi[6][1] = -25.0 / 28.0,
0531 bi[6][2] = 205.0 / 42.0,
0532 bi[6][3] = -45.0 / 7.0,
0533 bi[6][4] = 18.0 / 7.0,
0534
0535
0536
0537 bi[7][0] = 0.0,
0538 bi[7][1] = -2.0 / 11.0,
0539 bi[7][2] = 73.0 / 55.0,
0540 bi[7][3] = -171.0 / 55.0,
0541 bi[7][4] = 108.0 / 55.0,
0542
0543
0544
0545 bi[8][0] = 0.0,
0546 bi[8][1] = 189.0 / 22.0,
0547 bi[8][2] = -1593.0 / 55.0,
0548 bi[8][3] = 3537.0 / 110.0,
0549 bi[8][4] = -648.0 / 55.0,
0550
0551
0552
0553 bi[9][0] = 0.0,
0554 bi[9][1] = 351.0 / 110.0,
0555 bi[9][2] = -999.0 / 55.0,
0556 bi[9][3] = 2943.0 / 110.0,
0557 bi[9][4] = -648.0 / 55.0;
0558
0559
0560
0561
0562 G4double b[10];
0563 std::memset(b, 0.0, sizeof(b));
0564
0565 G4double tauPower = 1.0;
0566 for(G4int j = 0; j <= 4; ++j)
0567 {
0568 for(G4int iStage = 1; iStage <= 9; ++iStage)
0569 {
0570 b[iStage] += bi[iStage][j] * tauPower;
0571 }
0572 tauPower *= tau;
0573 }
0574
0575 const G4double stepLen = fLastStepLength * tau;
0576 for(G4int i = 0; i < N; ++i)
0577 {
0578 yOut[i] = fyIn[i] + stepLen * (
0579 b[1] * fdydxIn[i] + b[2] * ak2[i] + b[3] * ak3[i] +
0580 b[4] * ak4[i] + b[5] * ak5[i] + b[6] * ak6[i] +
0581 b[7] * ak7[i] + b[8] * ak8[i] + b[9] * ak9[i]
0582 );
0583 }
0584 }
0585
0586 #endif