@@ -1155,6 +1155,18 @@ impl ButcherTableau for RKF78 {
1155
1155
// ┌─────────────────────────────────────────────────────────┐
1156
1156
// Gauss-Legendre 4th order
1157
1157
// └─────────────────────────────────────────────────────────┘
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
+
1158
1170
/// Enum for implicit solvers.
1159
1171
///
1160
1172
/// This enum defines the available implicit solvers for the Gauss-Legendre 4th order integrator.
@@ -1198,7 +1210,7 @@ impl Default for GL4 {
1198
1210
fn default ( ) -> Self {
1199
1211
GL4 {
1200
1212
solver : ImplicitSolver :: FixedPoint ,
1201
- tol : 1e-6 ,
1213
+ tol : 1e-8 ,
1202
1214
max_step_iter : 100 ,
1203
1215
}
1204
1216
}
@@ -1219,41 +1231,40 @@ impl ODEIntegrator for GL4 {
1219
1231
#[ inline]
1220
1232
fn step < P : ODEProblem > ( & self , problem : & P , t : f64 , y : & mut [ f64 ] , dt : f64 ) -> Result < f64 > {
1221
1233
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;
1225
1237
let mut k1 = vec ! [ 0.0 ; n] ;
1226
1238
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) ;
1229
1243
1230
1244
match self . solver {
1231
1245
ImplicitSolver :: FixedPoint => {
1232
1246
// Fixed-point iteration
1247
+ let mut y1 = vec ! [ 0.0 ; n] ;
1248
+ let mut y2 = vec ! [ 0.0 ; n] ;
1249
+
1233
1250
for _ in 0 ..self . max_step_iter {
1251
+ let k1_old = k1. clone ( ) ;
1252
+ let k2_old = k2. clone ( ) ;
1253
+
1234
1254
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] ) ;
1237
1257
}
1238
1258
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) ?;
1241
1262
1263
+ // Check for convergence
1242
1264
let mut max_diff = 0f64 ;
1243
1265
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 ( ) ) ;
1257
1268
}
1258
1269
1259
1270
if max_diff < self . tol {
@@ -1264,43 +1275,28 @@ impl ODEIntegrator for GL4 {
1264
1275
ImplicitSolver :: Broyden => {
1265
1276
let m = 2 * n;
1266
1277
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) ;
1284
1280
1285
1281
// F_vec = F(U)
1286
1282
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 ) ?;
1288
1284
1289
1285
// Initialize inverse Jacobian matrix
1290
1286
let mut J_inv = eye ( m) ;
1291
1287
1292
1288
// Repeat Broyden's method
1293
1289
for _ in 0 ..self . max_step_iter {
1294
1290
// 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 ) ;
1296
1292
1297
1293
// U <- U + delta
1298
1294
U . iter_mut ( )
1299
- . zip ( delta. iter_mut ( ) )
1295
+ . zip ( delta. iter ( ) )
1300
1296
. for_each ( |( u, d) | * u += * d) ;
1301
1297
1302
1298
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 ) ?;
1304
1300
1305
1301
// If infinity norm of F_new is less than tol, break
1306
1302
if F_new . norm ( Norm :: LInf ) < self . tol {
@@ -1312,12 +1308,13 @@ impl ODEIntegrator for GL4 {
1312
1308
1313
1309
// J_inv * delta_F
1314
1310
let J_inv_delta_F = & J_inv * & delta_F;
1311
+
1315
1312
let denom = delta. dot ( & J_inv_delta_F ) ;
1316
1313
if denom. abs ( ) < 1e-12 {
1317
1314
break ;
1318
1315
}
1319
1316
1320
- // Broyden "good" update
1317
+ // Broyden's "good" update for the inverse Jacobian
1321
1318
// J_inv <- J_inv + ((delta - J_inv * delta_F) * delta^T * J_inv) / denom
1322
1319
let delta_minus_J_inv_delta_F = delta. sub_vec ( & J_inv_delta_F ) . to_col ( ) ;
1323
1320
let delta_T_J_inv = & delta. to_row ( ) * & J_inv ;
@@ -1326,57 +1323,87 @@ impl ODEIntegrator for GL4 {
1326
1323
F_vec = F_new ;
1327
1324
}
1328
1325
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..] ) ;
1334
1328
}
1335
1329
}
1336
1330
1337
1331
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] ) ;
1339
1333
}
1340
1334
1341
1335
Ok ( dt)
1342
1336
}
1343
1337
}
1344
1338
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)
1348
1378
#[ allow( non_snake_case) ]
1349
1379
fn compute_F < P : ODEProblem > (
1350
1380
problem : & P ,
1351
1381
t : f64 ,
1352
1382
y : & [ f64 ] ,
1353
1383
dt : f64 ,
1354
- c : f64 ,
1355
- d : f64 ,
1356
- sqrt3 : f64 ,
1357
- U : & [ f64 ] ,
1384
+ U : & [ f64 ] , // U is a concatenated vector [k1, k2]
1358
1385
F : & mut [ f64 ] ,
1359
1386
) -> Result < ( ) > {
1360
1387
let n = y. len ( ) ;
1388
+ let ( k1_slice, k2_slice) = U . split_at ( n) ;
1389
+
1361
1390
let mut y1 = vec ! [ 0.0 ; n] ;
1362
1391
let mut y2 = vec ! [ 0.0 ; n] ;
1363
1392
1364
1393
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] ) ;
1369
1396
}
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) ?;
1370
1402
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]
1377
1404
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] ;
1380
1407
}
1381
1408
Ok ( ( ) )
1382
1409
}
0 commit comments