|
24 | 24 | //! - Runge-Kutta-Fehlberg 4/5th order (RKF45) |
25 | 25 | //! - Dormand-Prince 4/5th order (DP45) |
26 | 26 | //! - Tsitouras 4/5th order (TSIT45) |
| 27 | +//! - Runge-Kutta-Fehlberg 7/8th order (RKF78) |
27 | 28 | //! - **Implicit** |
28 | 29 | //! - Gauss-Legendre 4th order (GL4) |
29 | 30 | //! |
@@ -895,6 +896,211 @@ impl ButcherTableau for TSIT45 { |
895 | 896 | } |
896 | 897 | } |
897 | 898 |
|
| 899 | +/// Runge-Kutta-Fehlberg 7/8th order integrator. |
| 900 | +/// |
| 901 | +/// This integrator uses the Runge-Kutta-Fehlberg 7(8) method, an adaptive step size integrator. |
| 902 | +/// It evaluates f(x,y) thirteen times per step, using embedded 7th and 8th order |
| 903 | +/// Runge-Kutta estimates to estimate the solution and the error. |
| 904 | +/// The 7th order solution is propagated, and the difference between the 8th and 7th |
| 905 | +/// order solutions is used for error estimation and step size control. |
| 906 | +/// |
| 907 | +/// # Member variables |
| 908 | +/// |
| 909 | +/// - `tol`: The tolerance for the estimated error. |
| 910 | +/// - `safety_factor`: The safety factor for the step size adjustment. |
| 911 | +/// - `min_step_size`: The minimum step size. |
| 912 | +/// - `max_step_size`: The maximum step size. |
| 913 | +/// - `max_step_iter`: The maximum number of iterations per step. |
| 914 | +/// |
| 915 | +/// # References |
| 916 | +/// - Meysam Mahooti (2025). [Runge-Kutta-Fehlberg (RKF78)](https://www.mathworks.com/matlabcentral/fileexchange/61130-runge-kutta-fehlberg-rkf78), MATLAB Central File Exchange. |
| 917 | +#[derive(Debug, Clone, Copy)] |
| 918 | +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| 919 | +#[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] |
| 920 | +pub struct RKF78 { |
| 921 | + pub tol: f64, |
| 922 | + pub safety_factor: f64, |
| 923 | + pub min_step_size: f64, |
| 924 | + pub max_step_size: f64, |
| 925 | + pub max_step_iter: usize, |
| 926 | +} |
| 927 | + |
| 928 | +impl Default for RKF78 { |
| 929 | + fn default() -> Self { |
| 930 | + Self { |
| 931 | + tol: 1e-7, // Higher precision default for a higher-order method |
| 932 | + safety_factor: 0.9, |
| 933 | + min_step_size: 1e-10, // Smaller min step for higher order |
| 934 | + max_step_size: 1e-1, |
| 935 | + max_step_iter: 100, |
| 936 | + } |
| 937 | + } |
| 938 | +} |
| 939 | + |
| 940 | +impl RKF78 { |
| 941 | + pub fn new( |
| 942 | + tol: f64, |
| 943 | + safety_factor: f64, |
| 944 | + min_step_size: f64, |
| 945 | + max_step_size: f64, |
| 946 | + max_step_iter: usize, |
| 947 | + ) -> Self { |
| 948 | + Self { |
| 949 | + tol, |
| 950 | + safety_factor, |
| 951 | + min_step_size, |
| 952 | + max_step_size, |
| 953 | + max_step_iter, |
| 954 | + } |
| 955 | + } |
| 956 | +} |
| 957 | + |
| 958 | +impl ButcherTableau for RKF78 { |
| 959 | + const C: &'static [f64] = &[ |
| 960 | + 0.0, |
| 961 | + 2.0 / 27.0, |
| 962 | + 1.0 / 9.0, |
| 963 | + 1.0 / 6.0, |
| 964 | + 5.0 / 12.0, |
| 965 | + 1.0 / 2.0, |
| 966 | + 5.0 / 6.0, |
| 967 | + 1.0 / 6.0, |
| 968 | + 2.0 / 3.0, |
| 969 | + 1.0 / 3.0, |
| 970 | + 1.0, |
| 971 | + 0.0, // k12 is evaluated at x[i] |
| 972 | + 1.0, // k13 is evaluated at x[i]+h |
| 973 | + ]; |
| 974 | + |
| 975 | + const A: &'static [&'static [f64]] = &[ |
| 976 | + // k1 |
| 977 | + &[], |
| 978 | + // k2 |
| 979 | + &[2.0 / 27.0], |
| 980 | + // k3 |
| 981 | + &[1.0 / 36.0, 3.0 / 36.0], |
| 982 | + // k4 |
| 983 | + &[1.0 / 24.0, 0.0, 3.0 / 24.0], |
| 984 | + // k5 |
| 985 | + &[20.0 / 48.0, 0.0, -75.0 / 48.0, 75.0 / 48.0], |
| 986 | + // k6 |
| 987 | + &[1.0 / 20.0, 0.0, 0.0, 5.0 / 20.0, 4.0 / 20.0], |
| 988 | + // k7 |
| 989 | + &[-25.0 / 108.0, 0.0, 0.0, 125.0 / 108.0, -260.0 / 108.0, 250.0 / 108.0], |
| 990 | + // k8 |
| 991 | + &[31.0 / 300.0, 0.0, 0.0, 0.0, 61.0 / 225.0, -2.0 / 9.0, 13.0 / 900.0], |
| 992 | + // k9 |
| 993 | + &[2.0, 0.0, 0.0, -53.0 / 6.0, 704.0 / 45.0, -107.0 / 9.0, 67.0 / 90.0, 3.0], |
| 994 | + // k10 |
| 995 | + &[ |
| 996 | + -91.0 / 108.0, |
| 997 | + 0.0, |
| 998 | + 0.0, |
| 999 | + 23.0 / 108.0, |
| 1000 | + -976.0 / 135.0, |
| 1001 | + 311.0 / 54.0, |
| 1002 | + -19.0 / 60.0, |
| 1003 | + 17.0 / 6.0, |
| 1004 | + -1.0 / 12.0, |
| 1005 | + ], |
| 1006 | + // k11 |
| 1007 | + &[ |
| 1008 | + 2383.0 / 4100.0, |
| 1009 | + 0.0, |
| 1010 | + 0.0, |
| 1011 | + -341.0 / 164.0, |
| 1012 | + 4496.0 / 1025.0, |
| 1013 | + -301.0 / 82.0, |
| 1014 | + 2133.0 / 4100.0, |
| 1015 | + 45.0 / 82.0, |
| 1016 | + 45.0 / 164.0, |
| 1017 | + 18.0 / 41.0, |
| 1018 | + ], |
| 1019 | + // k12 |
| 1020 | + &[ |
| 1021 | + 3.0 / 205.0, |
| 1022 | + 0.0, |
| 1023 | + 0.0, |
| 1024 | + 0.0, |
| 1025 | + 0.0, |
| 1026 | + -6.0 / 41.0, |
| 1027 | + -3.0 / 205.0, |
| 1028 | + -3.0 / 41.0, |
| 1029 | + 3.0 / 41.0, |
| 1030 | + 6.0 / 41.0, |
| 1031 | + 0.0, |
| 1032 | + ], |
| 1033 | + // k13 |
| 1034 | + &[ |
| 1035 | + -1777.0 / 4100.0, |
| 1036 | + 0.0, |
| 1037 | + 0.0, |
| 1038 | + -341.0 / 164.0, |
| 1039 | + 4496.0 / 1025.0, |
| 1040 | + -289.0 / 82.0, |
| 1041 | + 2193.0 / 4100.0, |
| 1042 | + 51.0 / 82.0, |
| 1043 | + 33.0 / 164.0, |
| 1044 | + 12.0 / 41.0, |
| 1045 | + 0.0, |
| 1046 | + 1.0, |
| 1047 | + ], |
| 1048 | + ]; |
| 1049 | + |
| 1050 | + // Coefficients for the 7th order solution (propagated solution) |
| 1051 | + // BU_i = BE_i (8th order) - ErrorCoeff_i |
| 1052 | + // ErrorCoeff_i = [-41/840, 0, ..., 0, -41/840 (for k11), 41/840 (for k12), 41/840 (for k13)] |
| 1053 | + const BU: &'static [f64] = &[ |
| 1054 | + 41.0 / 420.0, // 41/840 - (-41/840) |
| 1055 | + 0.0, |
| 1056 | + 0.0, |
| 1057 | + 0.0, |
| 1058 | + 0.0, |
| 1059 | + 34.0 / 105.0, |
| 1060 | + 9.0 / 35.0, |
| 1061 | + 9.0 / 35.0, |
| 1062 | + 9.0 / 280.0, |
| 1063 | + 9.0 / 280.0, |
| 1064 | + 41.0 / 420.0, // 41/840 - (-41/840) |
| 1065 | + -41.0 / 840.0, // 0.0 - (41/840) |
| 1066 | + -41.0 / 840.0, // 0.0 - (41/840) |
| 1067 | + ]; |
| 1068 | + |
| 1069 | + // Coefficients for the 8th order solution (used for error estimation) |
| 1070 | + // These are from the y[i+1] formula in the MATLAB description |
| 1071 | + const BE: &'static [f64] = &[ |
| 1072 | + 41.0 / 840.0, |
| 1073 | + 0.0, |
| 1074 | + 0.0, |
| 1075 | + 0.0, |
| 1076 | + 0.0, |
| 1077 | + 34.0 / 105.0, |
| 1078 | + 9.0 / 35.0, |
| 1079 | + 9.0 / 35.0, |
| 1080 | + 9.0 / 280.0, |
| 1081 | + 9.0 / 280.0, |
| 1082 | + 41.0 / 840.0, |
| 1083 | + 0.0, |
| 1084 | + 0.0, |
| 1085 | + ]; |
| 1086 | + |
| 1087 | + fn tol(&self) -> f64 { |
| 1088 | + self.tol |
| 1089 | + } |
| 1090 | + fn safety_factor(&self) -> f64 { |
| 1091 | + self.safety_factor |
| 1092 | + } |
| 1093 | + fn min_step_size(&self) -> f64 { |
| 1094 | + self.min_step_size |
| 1095 | + } |
| 1096 | + fn max_step_size(&self) -> f64 { |
| 1097 | + self.max_step_size |
| 1098 | + } |
| 1099 | + fn max_step_iter(&self) -> usize { |
| 1100 | + self.max_step_iter |
| 1101 | + } |
| 1102 | +} |
| 1103 | + |
898 | 1104 | // ┌─────────────────────────────────────────────────────────┐ |
899 | 1105 | // Gauss-Legendre 4th order |
900 | 1106 | // └─────────────────────────────────────────────────────────┘ |
|
0 commit comments