@@ -1155,6 +1155,18 @@ impl ButcherTableau for RKF78 {
11551155// ┌─────────────────────────────────────────────────────────┐
11561156// Gauss-Legendre 4th order
11571157// └─────────────────────────────────────────────────────────┘
1158+
1159+ // Correct coefficients for 4th-order Gauss-Legendre method
1160+ const SQRT3 : f64 = 1.7320508075688772 ;
1161+ const C1 : f64 = 0.5 - SQRT3 / 6.0 ;
1162+ const C2 : f64 = 0.5 + SQRT3 / 6.0 ;
1163+ const A11 : f64 = 0.25 ;
1164+ const A12 : f64 = 0.25 - SQRT3 / 6.0 ;
1165+ const A21 : f64 = 0.25 + SQRT3 / 6.0 ;
1166+ const A22 : f64 = 0.25 ;
1167+ const B1 : f64 = 0.5 ;
1168+ const B2 : f64 = 0.5 ;
1169+
11581170/// Enum for implicit solvers.
11591171///
11601172/// This enum defines the available implicit solvers for the Gauss-Legendre 4th order integrator.
@@ -1198,7 +1210,7 @@ impl Default for GL4 {
11981210 fn default ( ) -> Self {
11991211 GL4 {
12001212 solver : ImplicitSolver :: FixedPoint ,
1201- tol : 1e-6 ,
1213+ tol : 1e-8 ,
12021214 max_step_iter : 100 ,
12031215 }
12041216 }
@@ -1219,41 +1231,40 @@ impl ODEIntegrator for GL4 {
12191231 #[ inline]
12201232 fn step < P : ODEProblem > ( & self , problem : & P , t : f64 , y : & mut [ f64 ] , dt : f64 ) -> Result < f64 > {
12211233 let n = y. len ( ) ;
1222- let sqrt3 = 3.0_f64 . sqrt ( ) ;
1223- let c = 0.5 * ( 3.0 - sqrt3) / 6.0 ;
1224- let d = 0.5 * ( 3.0 + sqrt3) / 6.0 ;
1234+ // let sqrt3 = 3.0_f64.sqrt();
1235+ // let c = 0.5 * (3.0 - sqrt3) / 6.0;
1236+ // let d = 0.5 * (3.0 + sqrt3) / 6.0;
12251237 let mut k1 = vec ! [ 0.0 ; n] ;
12261238 let mut k2 = vec ! [ 0.0 ; n] ;
1227- let mut y1 = vec ! [ 0.0 ; n] ;
1228- let mut y2 = vec ! [ 0.0 ; n] ;
1239+
1240+ // Initial guess for k1, k2.
1241+ problem. rhs ( t, y, & mut k1) ?;
1242+ k2. copy_from_slice ( & k1) ;
12291243
12301244 match self . solver {
12311245 ImplicitSolver :: FixedPoint => {
12321246 // Fixed-point iteration
1247+ let mut y1 = vec ! [ 0.0 ; n] ;
1248+ let mut y2 = vec ! [ 0.0 ; n] ;
1249+
12331250 for _ in 0 ..self . max_step_iter {
1251+ let k1_old = k1. clone ( ) ;
1252+ let k2_old = k2. clone ( ) ;
1253+
12341254 for i in 0 ..n {
1235- y1[ i] = y[ i] + dt * ( c * k1[ i] + d * k2[ i] - sqrt3 * ( k2 [ i ] - k1 [ i ] ) / 2.0 ) ;
1236- y2[ i] = y[ i] + dt * ( c * k1[ i] + d * k2[ i] + sqrt3 * ( k2 [ i ] - k1 [ i ] ) / 2.0 ) ;
1255+ y1[ i] = y[ i] + dt * ( A11 * k1[ i] + A12 * k2[ i] ) ;
1256+ y2[ i] = y[ i] + dt * ( A11 * k1[ i] + A12 * k2[ i] ) ;
12371257 }
12381258
1239- problem. rhs ( t + c * dt, & y1, & mut k1) ?;
1240- problem. rhs ( t + d * dt, & y2, & mut k2) ?;
1259+ // Compute new k1 and k2
1260+ problem. rhs ( t + C1 * dt, & y1, & mut k1) ?;
1261+ problem. rhs ( t + C2 * dt, & y2, & mut k2) ?;
12411262
1263+ // Check for convergence
12421264 let mut max_diff = 0f64 ;
12431265 for i in 0 ..n {
1244- max_diff = max_diff
1245- . max (
1246- ( y1[ i]
1247- - y[ i]
1248- - dt * ( c * k1[ i] + d * k2[ i] - sqrt3 * ( k2[ i] - k1[ i] ) / 2.0 ) )
1249- . abs ( ) ,
1250- )
1251- . max (
1252- ( y2[ i]
1253- - y[ i]
1254- - dt * ( c * k1[ i] + d * k2[ i] + sqrt3 * ( k2[ i] - k1[ i] ) / 2.0 ) )
1255- . abs ( ) ,
1256- ) ;
1266+ max_diff = max_diff. max ( ( k1[ i] - k1_old[ i] ) . abs ( ) ) ;
1267+ max_diff = max_diff. max ( ( k2[ i] - k2_old[ i] ) . abs ( ) ) ;
12571268 }
12581269
12591270 if max_diff < self . tol {
@@ -1264,43 +1275,28 @@ impl ODEIntegrator for GL4 {
12641275 ImplicitSolver :: Broyden => {
12651276 let m = 2 * n;
12661277 let mut U = vec ! [ 0.0 ; m] ;
1267-
1268- // Initial Guess via Fixed-Point Iteration
1269- {
1270- let mut k1 = vec ! [ 0.0 ; n] ;
1271- let mut k2 = vec ! [ 0.0 ; n] ;
1272- let mut y1 = vec ! [ 0.0 ; n] ;
1273- let mut y2 = vec ! [ 0.0 ; n] ;
1274-
1275- y1. copy_from_slice ( y) ;
1276- y2. copy_from_slice ( y) ;
1277- problem. rhs ( t + c * dt, & y1, & mut k1) ?;
1278- problem. rhs ( t + d * dt, & y2, & mut k2) ?;
1279- for i in 0 ..n {
1280- U [ i] = k1[ i] ;
1281- U [ n + i] = k2[ i] ;
1282- }
1283- }
1278+ U [ ..n] . copy_from_slice ( & k1) ;
1279+ U [ n..] . copy_from_slice ( & k2) ;
12841280
12851281 // F_vec = F(U)
12861282 let mut F_vec = vec ! [ 0.0 ; m] ;
1287- compute_F ( problem, t, y, dt, c , d , sqrt3 , & U , & mut F_vec ) ?;
1283+ compute_F ( problem, t, y, dt, & U , & mut F_vec ) ?;
12881284
12891285 // Initialize inverse Jacobian matrix
12901286 let mut J_inv = eye ( m) ;
12911287
12921288 // Repeat Broyden's method
12931289 for _ in 0 ..self . max_step_iter {
12941290 // delta = - J_inv * F_vec
1295- let mut delta = ( & J_inv * & F_vec ) . mul_scalar ( -1.0 ) ;
1291+ let delta = ( & J_inv * & F_vec ) . mul_scalar ( -1.0 ) ;
12961292
12971293 // U <- U + delta
12981294 U . iter_mut ( )
1299- . zip ( delta. iter_mut ( ) )
1295+ . zip ( delta. iter ( ) )
13001296 . for_each ( |( u, d) | * u += * d) ;
13011297
13021298 let mut F_new = vec ! [ 0.0 ; m] ;
1303- compute_F ( problem, t, y, dt, c , d , sqrt3 , & U , & mut F_new ) ?;
1299+ compute_F ( problem, t, y, dt, & U , & mut F_new ) ?;
13041300
13051301 // If infinity norm of F_new is less than tol, break
13061302 if F_new . norm ( Norm :: LInf ) < self . tol {
@@ -1312,12 +1308,13 @@ impl ODEIntegrator for GL4 {
13121308
13131309 // J_inv * delta_F
13141310 let J_inv_delta_F = & J_inv * & delta_F;
1311+
13151312 let denom = delta. dot ( & J_inv_delta_F ) ;
13161313 if denom. abs ( ) < 1e-12 {
13171314 break ;
13181315 }
13191316
1320- // Broyden "good" update
1317+ // Broyden's "good" update for the inverse Jacobian
13211318 // J_inv <- J_inv + ((delta - J_inv * delta_F) * delta^T * J_inv) / denom
13221319 let delta_minus_J_inv_delta_F = delta. sub_vec ( & J_inv_delta_F ) . to_col ( ) ;
13231320 let delta_T_J_inv = & delta. to_row ( ) * & J_inv ;
@@ -1326,57 +1323,87 @@ impl ODEIntegrator for GL4 {
13261323 F_vec = F_new ;
13271324 }
13281325
1329- // Extract k1 and k2
1330- for i in 0 ..n {
1331- k1[ i] = U [ i] ;
1332- k2[ i] = U [ n + i] ;
1333- }
1326+ k1. copy_from_slice ( & U [ ..n] ) ;
1327+ k2. copy_from_slice ( & U [ n..] ) ;
13341328 }
13351329 }
13361330
13371331 for i in 0 ..n {
1338- y[ i] += dt * 0.5 * ( k1[ i] + k2[ i] ) ;
1332+ y[ i] += dt * ( B1 * k1[ i] + B2 * k2[ i] ) ;
13391333 }
13401334
13411335 Ok ( dt)
13421336 }
13431337}
13441338
1345- // Helper function to compute the function F(U) for the implicit solver.
1346- // y1 = y + dt*(c*k1 + d*k2 - sqrt3/2*(k2-k1))
1347- // y2 = y + dt*(c*k1 + d*k2 + sqrt3/2*(k2-k1))
1339+ //// Helper function to compute the function F(U) for the implicit solver.
1340+ //// y1 = y + dt*(c*k1 + d*k2 - sqrt3/2*(k2-k1))
1341+ //// y2 = y + dt*(c*k1 + d*k2 + sqrt3/2*(k2-k1))
1342+ //#[allow(non_snake_case)]
1343+ //fn compute_F<P: ODEProblem>(
1344+ // problem: &P,
1345+ // t: f64,
1346+ // y: &[f64],
1347+ // dt: f64,
1348+ // c: f64,
1349+ // d: f64,
1350+ // sqrt3: f64,
1351+ // U: &[f64],
1352+ // F: &mut [f64],
1353+ //) -> Result<()> {
1354+ // let n = y.len();
1355+ // let mut y1 = vec![0.0; n];
1356+ // let mut y2 = vec![0.0; n];
1357+ //
1358+ // for i in 0..n {
1359+ // let k1 = U[i];
1360+ // let k2 = U[n + i];
1361+ // y1[i] = y[i] + dt * (c * k1 + d * k2 - sqrt3 * (k2 - k1) / 2.0);
1362+ // y2[i] = y[i] + dt * (c * k1 + d * k2 + sqrt3 * (k2 - k1) / 2.0);
1363+ // }
1364+ //
1365+ // let mut f1 = vec![0.0; n];
1366+ // let mut f2 = vec![0.0; n];
1367+ // problem.rhs(t + c * dt, &y1, &mut f1)?;
1368+ // problem.rhs(t + d * dt, &y2, &mut f2)?;
1369+ //
1370+ // // F = [ k1 - f1, k2 - f2 ]
1371+ // for i in 0..n {
1372+ // F[i] = U[i] - f1[i];
1373+ // F[n + i] = U[n + i] - f2[i];
1374+ // }
1375+ // Ok(())
1376+ //}
1377+ /// Helper function to compute the residual F(U) = U - f(y + dt*A*U)
13481378#[ allow( non_snake_case) ]
13491379fn compute_F < P : ODEProblem > (
13501380 problem : & P ,
13511381 t : f64 ,
13521382 y : & [ f64 ] ,
13531383 dt : f64 ,
1354- c : f64 ,
1355- d : f64 ,
1356- sqrt3 : f64 ,
1357- U : & [ f64 ] ,
1384+ U : & [ f64 ] , // U is a concatenated vector [k1, k2]
13581385 F : & mut [ f64 ] ,
13591386) -> Result < ( ) > {
13601387 let n = y. len ( ) ;
1388+ let ( k1_slice, k2_slice) = U . split_at ( n) ;
1389+
13611390 let mut y1 = vec ! [ 0.0 ; n] ;
13621391 let mut y2 = vec ! [ 0.0 ; n] ;
13631392
13641393 for i in 0 ..n {
1365- let k1 = U [ i] ;
1366- let k2 = U [ n + i] ;
1367- y1[ i] = y[ i] + dt * ( c * k1 + d * k2 - sqrt3 * ( k2 - k1) / 2.0 ) ;
1368- y2[ i] = y[ i] + dt * ( c * k1 + d * k2 + sqrt3 * ( k2 - k1) / 2.0 ) ;
1394+ y1[ i] = y[ i] + dt * ( A11 * k1_slice[ i] + A12 * k2_slice[ i] ) ;
1395+ y2[ i] = y[ i] + dt * ( A21 * k1_slice[ i] + A22 * k2_slice[ i] ) ;
13691396 }
1397+
1398+ // F is an output parameter, its parts f1 and f2 are stored temporarily
1399+ let ( f1, f2) = F . split_at_mut ( n) ;
1400+ problem. rhs ( t + C1 * dt, & y1, f1) ?;
1401+ problem. rhs ( t + C2 * dt, & y2, f2) ?;
13701402
1371- let mut f1 = vec ! [ 0.0 ; n] ;
1372- let mut f2 = vec ! [ 0.0 ; n] ;
1373- problem. rhs ( t + c * dt, & y1, & mut f1) ?;
1374- problem. rhs ( t + d * dt, & y2, & mut f2) ?;
1375-
1376- // F = [ k1 - f1, k2 - f2 ]
1403+ // Compute final residual F = [k1 - f1, k2 - f2]
13771404 for i in 0 ..n {
1378- F [ i] = U [ i] - f1[ i] ;
1379- F [ n + i] = U [ n + i] - f2[ i] ;
1405+ f1 [ i] = k1_slice [ i] - f1[ i] ;
1406+ f2 [ i] = k2_slice [ i] - f2[ i] ;
13801407 }
13811408 Ok ( ( ) )
13821409}
0 commit comments