diff-grok 1.0.10 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +11 -0
- package/.claude/skills/license-updater/SKILL.md +149 -0
- package/.claude/skills/license-updater/references/compatibility.md +68 -0
- package/.claude/skills/license-updater/references/templates.md +151 -0
- package/.claude/skills/license-updater/scripts/generate_license_files.py +467 -0
- package/CLAUDE.md +104 -0
- package/LICENSE +1 -1
- package/README.MD +121 -27
- package/THIRD_PARTY_LICENSES +135 -0
- package/docs/assets/hierarchy.js +1 -1
- package/docs/assets/navigation.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/classes/BasicModelPipelineCreator.html +4 -4
- package/docs/classes/Callback.html +5 -5
- package/docs/classes/CyclicModelPipelineCreator.html +4 -4
- package/docs/classes/IterCheckerCallback.html +5 -5
- package/docs/classes/PipelineCreator.html +4 -4
- package/docs/classes/TimeCheckerCallback.html +5 -5
- package/docs/classes/UpdatesModelPipelineCreator.html +4 -4
- package/docs/functions/ab4.html +8 -0
- package/docs/functions/ab5.html +8 -0
- package/docs/functions/applyPipeline.html +2 -2
- package/docs/functions/getCallback.html +2 -2
- package/docs/functions/getIVP.html +2 -2
- package/docs/functions/getInputVector.html +2 -2
- package/docs/functions/getIvp2WebWorker.html +2 -2
- package/docs/functions/getJScode.html +2 -2
- package/docs/functions/getOutputNames.html +2 -2
- package/docs/functions/getPipelineCreator.html +2 -2
- package/docs/functions/lsoda.html +8 -0
- package/docs/functions/mrt.html +2 -2
- package/docs/functions/printE5.html +2 -2
- package/docs/functions/printHires.html +2 -2
- package/docs/functions/printOrego.html +2 -2
- package/docs/functions/printPollution.html +2 -2
- package/docs/functions/printRobertson.html +2 -2
- package/docs/functions/printVdpol.html +2 -2
- package/docs/functions/rk3.html +8 -0
- package/docs/functions/rk4.html +8 -0
- package/docs/functions/rkdp.html +8 -0
- package/docs/functions/ros34prw.html +2 -2
- package/docs/functions/ros3prw.html +2 -2
- package/docs/functions/solveIvp.html +2 -2
- package/docs/hierarchy.html +1 -1
- package/docs/index.html +100 -15
- package/docs/media/E5.png +0 -0
- package/docs/media/HIRES.png +0 -0
- package/docs/media/OREGO.png +0 -0
- package/docs/media/POLL-full.png +0 -0
- package/docs/media/ROBER.png +0 -0
- package/docs/media/VDP0L.png +0 -0
- package/docs/media/cyclic-model.js +3 -1
- package/docs/media/cyclic-model.js.map +1 -1
- package/docs/media/cyclic-model.ts +3 -1
- package/docs/modules.html +1 -1
- package/docs/types/Arg.html +7 -7
- package/docs/types/DifEqs.html +4 -4
- package/docs/types/Func.html +2 -2
- package/docs/types/IVP.html +20 -20
- package/docs/types/IVP2WebWorker.html +7 -7
- package/docs/types/Input.html +4 -4
- package/docs/types/Loop.html +4 -4
- package/docs/types/ODEs.html +8 -8
- package/docs/types/Output.html +4 -4
- package/docs/types/Pipeline.html +4 -4
- package/docs/types/SolverOptions.html +5 -5
- package/docs/types/Update.html +5 -5
- package/docs/types/Wrapper.html +5 -5
- package/images/E5.png +0 -0
- package/images/HIRES.png +0 -0
- package/images/OREGO.png +0 -0
- package/images/POLL-full.png +0 -0
- package/images/ROBER.png +0 -0
- package/images/VDP0L.png +0 -0
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/index.ts +2 -1
- package/jest.config.js +1 -0
- package/package.json +4 -2
- package/src/examples/check-methods.js +15 -3
- package/src/examples/check-methods.js.map +1 -1
- package/src/examples/check-methods.ts +18 -3
- package/src/examples/cyclic-model.js +3 -1
- package/src/examples/cyclic-model.js.map +1 -1
- package/src/examples/cyclic-model.ts +3 -1
- package/src/solver-tools/ab4-method.js +332 -0
- package/src/solver-tools/ab4-method.js.map +1 -0
- package/src/solver-tools/ab4-method.ts +395 -0
- package/src/solver-tools/ab5-method.js +334 -0
- package/src/solver-tools/ab5-method.js.map +1 -0
- package/src/solver-tools/ab5-method.ts +397 -0
- package/src/solver-tools/cvode/common.js +487 -0
- package/src/solver-tools/cvode/common.js.map +1 -0
- package/src/solver-tools/cvode/common.ts +549 -0
- package/src/solver-tools/cvode/cvode.js +1062 -0
- package/src/solver-tools/cvode/cvode.js.map +1 -0
- package/src/solver-tools/cvode/cvode.ts +1226 -0
- package/src/solver-tools/cvode/cvode_adams.js +124 -0
- package/src/solver-tools/cvode/cvode_adams.js.map +1 -0
- package/src/solver-tools/cvode/cvode_adams.ts +142 -0
- package/src/solver-tools/cvode/cvode_bdf.js +153 -0
- package/src/solver-tools/cvode/cvode_bdf.js.map +1 -0
- package/src/solver-tools/cvode/cvode_bdf.ts +164 -0
- package/src/solver-tools/cvode/cvode_class.js +158 -0
- package/src/solver-tools/cvode/cvode_class.js.map +1 -0
- package/src/solver-tools/cvode/cvode_class.ts +271 -0
- package/src/solver-tools/cvode/cvode_hin.js +119 -0
- package/src/solver-tools/cvode/cvode_hin.js.map +1 -0
- package/src/solver-tools/cvode/cvode_hin.ts +150 -0
- package/src/solver-tools/cvode/cvode_io.js +203 -0
- package/src/solver-tools/cvode/cvode_io.js.map +1 -0
- package/src/solver-tools/cvode/cvode_io.ts +258 -0
- package/src/solver-tools/cvode/cvode_ls.js +210 -0
- package/src/solver-tools/cvode/cvode_ls.js.map +1 -0
- package/src/solver-tools/cvode/cvode_ls.ts +249 -0
- package/src/solver-tools/cvode/cvode_nls.js +220 -0
- package/src/solver-tools/cvode/cvode_nls.js.map +1 -0
- package/src/solver-tools/cvode/cvode_nls.ts +259 -0
- package/src/solver-tools/cvode/cvode_root.js +415 -0
- package/src/solver-tools/cvode/cvode_root.js.map +1 -0
- package/src/solver-tools/cvode/cvode_root.ts +503 -0
- package/src/solver-tools/cvode/dense_linalg.js +131 -0
- package/src/solver-tools/cvode/dense_linalg.js.map +1 -0
- package/src/solver-tools/cvode/dense_linalg.ts +144 -0
- package/src/solver-tools/cvode/index.js +26 -0
- package/src/solver-tools/cvode/index.js.map +1 -0
- package/src/solver-tools/cvode/index.ts +64 -0
- package/src/solver-tools/cvode-method.js +114 -0
- package/src/solver-tools/cvode-method.js.map +1 -0
- package/src/solver-tools/cvode-method.ts +129 -0
- package/src/solver-tools/index.js +7 -0
- package/src/solver-tools/index.js.map +1 -1
- package/src/solver-tools/index.ts +7 -0
- package/src/solver-tools/lsoda/blas.js +257 -0
- package/src/solver-tools/lsoda/blas.js.map +1 -0
- package/src/solver-tools/lsoda/blas.ts +279 -0
- package/src/solver-tools/lsoda/cfode.js +84 -0
- package/src/solver-tools/lsoda/cfode.js.map +1 -0
- package/src/solver-tools/lsoda/cfode.ts +95 -0
- package/src/solver-tools/lsoda/common.js +94 -0
- package/src/solver-tools/lsoda/common.js.map +1 -0
- package/src/solver-tools/lsoda/common.ts +135 -0
- package/src/solver-tools/lsoda/corfailure.js +36 -0
- package/src/solver-tools/lsoda/corfailure.js.map +1 -0
- package/src/solver-tools/lsoda/corfailure.ts +42 -0
- package/src/solver-tools/lsoda/correction.js +112 -0
- package/src/solver-tools/lsoda/correction.js.map +1 -0
- package/src/solver-tools/lsoda/correction.ts +131 -0
- package/src/solver-tools/lsoda/dense.js +121 -0
- package/src/solver-tools/lsoda/dense.js.map +1 -0
- package/src/solver-tools/lsoda/dense.ts +141 -0
- package/src/solver-tools/lsoda/index.js +15 -0
- package/src/solver-tools/lsoda/index.js.map +1 -0
- package/src/solver-tools/lsoda/index.ts +17 -0
- package/src/solver-tools/lsoda/intdy.js +54 -0
- package/src/solver-tools/lsoda/intdy.js.map +1 -0
- package/src/solver-tools/lsoda/intdy.ts +62 -0
- package/src/solver-tools/lsoda/lsoda.js +578 -0
- package/src/solver-tools/lsoda/lsoda.js.map +1 -0
- package/src/solver-tools/lsoda/lsoda.ts +644 -0
- package/src/solver-tools/lsoda/methodswitch.js +108 -0
- package/src/solver-tools/lsoda/methodswitch.js.map +1 -0
- package/src/solver-tools/lsoda/methodswitch.ts +119 -0
- package/src/solver-tools/lsoda/orderswitch.js +97 -0
- package/src/solver-tools/lsoda/orderswitch.js.map +1 -0
- package/src/solver-tools/lsoda/orderswitch.ts +107 -0
- package/src/solver-tools/lsoda/prja.js +54 -0
- package/src/solver-tools/lsoda/prja.js.map +1 -0
- package/src/solver-tools/lsoda/prja.ts +61 -0
- package/src/solver-tools/lsoda/scaleh.js +41 -0
- package/src/solver-tools/lsoda/scaleh.js.map +1 -0
- package/src/solver-tools/lsoda/scaleh.ts +45 -0
- package/src/solver-tools/lsoda/solsy.js +25 -0
- package/src/solver-tools/lsoda/solsy.js.map +1 -0
- package/src/solver-tools/lsoda/solsy.ts +30 -0
- package/src/solver-tools/lsoda/stoda.js +270 -0
- package/src/solver-tools/lsoda/stoda.js.map +1 -0
- package/src/solver-tools/lsoda/stoda.ts +298 -0
- package/src/solver-tools/lsoda-method.js +134 -0
- package/src/solver-tools/lsoda-method.js.map +1 -0
- package/src/solver-tools/lsoda-method.ts +154 -0
- package/src/solver-tools/mrt-method.js +81 -18
- package/src/solver-tools/mrt-method.js.map +1 -1
- package/src/solver-tools/mrt-method.ts +111 -21
- package/src/solver-tools/rk3-method.js +210 -0
- package/src/solver-tools/rk3-method.js.map +1 -0
- package/src/solver-tools/rk3-method.ts +257 -0
- package/src/solver-tools/rk4-method.js +236 -0
- package/src/solver-tools/rk4-method.js.map +1 -0
- package/src/solver-tools/rk4-method.ts +286 -0
- package/src/solver-tools/rkdp-method.js +247 -0
- package/src/solver-tools/rkdp-method.js.map +1 -0
- package/src/solver-tools/rkdp-method.ts +300 -0
- package/src/solver-tools/ros34prw-method.js +1 -1
- package/src/solver-tools/ros34prw-method.js.map +1 -1
- package/src/solver-tools/ros34prw-method.ts +1 -1
- package/src/solver-tools/ros3prw-method.js +1 -1
- package/src/solver-tools/ros3prw-method.js.map +1 -1
- package/src/solver-tools/ros3prw-method.ts +1 -1
- package/src/solver-tools/solver-defs.js +7 -0
- package/src/solver-tools/solver-defs.js.map +1 -1
- package/src/solver-tools/solver-defs.ts +7 -0
- package/src/tests/correctness.test.js +6 -4
- package/src/tests/correctness.test.js.map +1 -1
- package/src/tests/correctness.test.ts +6 -4
- package/src/tests/cvode-lib-correctness.test.js +404 -0
- package/src/tests/cvode-lib-correctness.test.js.map +1 -0
- package/src/tests/cvode-lib-correctness.test.ts +505 -0
- package/src/tests/cvode-lib-performance.test.js +103 -0
- package/src/tests/cvode-lib-performance.test.js.map +1 -0
- package/src/tests/cvode-lib-performance.test.ts +128 -0
- package/src/tests/lsoda-lib-correctness.test.js +223 -0
- package/src/tests/lsoda-lib-correctness.test.js.map +1 -0
- package/src/tests/lsoda-lib-correctness.test.ts +283 -0
- package/src/tests/lsoda-lib-performance.test.js +95 -0
- package/src/tests/lsoda-lib-performance.test.js.map +1 -0
- package/src/tests/lsoda-lib-performance.test.ts +126 -0
- package/src/tests/performance.test.js +12 -8
- package/src/tests/performance.test.js.map +1 -1
- package/src/tests/performance.test.ts +12 -8
- package/src/tests/test-defs.js +20 -1
- package/src/tests/test-defs.js.map +1 -1
- package/src/tests/test-defs.ts +22 -1
- package/src/worker-tools/solving.js +15 -1
- package/src/worker-tools/solving.js.map +1 -1
- package/src/worker-tools/solving.ts +23 -1
|
@@ -5,14 +5,102 @@
|
|
|
5
5
|
[2] https://doi.org/10.1016/S0898-1221(00)00175-9
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {ODEs, max, abs, SAFETY,
|
|
9
|
-
ERR_CONTR, TINY, EPS, tDerivative, jacobian, ERROR_MSG} from './solver-defs';
|
|
8
|
+
import {ODEs, max, min, abs, SAFETY, TINY, EPS, tDerivative, jacobian, ERROR_MSG} from './solver-defs';
|
|
10
9
|
import {Callback} from './callbacks/callback-base';
|
|
11
10
|
import {luDecomp, luSolve, solve1d2d} from './lin-alg-tools';
|
|
12
11
|
|
|
13
12
|
// Quantities used in Rosenbrock method (see [1], [2] for more details)
|
|
14
13
|
const D = 1.0 - Math.sqrt(2.0) / 2.0;
|
|
15
14
|
const E32 = 6.0 + Math.sqrt(2.0);
|
|
15
|
+
const TWO_D = 2.0 * D;
|
|
16
|
+
const ONE_MINUS_2D = 1.0 - TWO_D;
|
|
17
|
+
|
|
18
|
+
// Adaptive step size control bounds (see MRT.md, Section 6)
|
|
19
|
+
const ALPHA_MAX = 5;
|
|
20
|
+
const ALPHA_MIN = 0.2;
|
|
21
|
+
|
|
22
|
+
/** Compute the initial step size using the Hairer-Norsett-Wanner algorithm.
|
|
23
|
+
* @param t0 initial time
|
|
24
|
+
* @param y0 initial state vector
|
|
25
|
+
* @param f right-hand side function
|
|
26
|
+
* @param tol scalar tolerance (plays the role of rtol)
|
|
27
|
+
* @param dim dimension of the system
|
|
28
|
+
* @param p order of the method (p = 2 for MRT)
|
|
29
|
+
* @param tEnd end of the integration interval (used to cap h0)
|
|
30
|
+
* @returns estimated initial step size
|
|
31
|
+
*/
|
|
32
|
+
function initialStepSize(
|
|
33
|
+
t0: number,
|
|
34
|
+
y0: Float64Array,
|
|
35
|
+
f: (t: number, y: Float64Array, out: Float64Array) => void,
|
|
36
|
+
tol: number,
|
|
37
|
+
dim: number,
|
|
38
|
+
p: number,
|
|
39
|
+
tEnd: number,
|
|
40
|
+
): number {
|
|
41
|
+
const f0 = new Float64Array(dim);
|
|
42
|
+
const f1 = new Float64Array(dim);
|
|
43
|
+
const y1 = new Float64Array(dim);
|
|
44
|
+
const sc = new Float64Array(dim);
|
|
45
|
+
|
|
46
|
+
// Step 1: scale vector (sc[i] = |y0[i]| + TINY)
|
|
47
|
+
for (let i = 0; i < dim; ++i)
|
|
48
|
+
sc[i] = Math.abs(y0[i]) + TINY;
|
|
49
|
+
|
|
50
|
+
// Step 2: evaluate the right-hand side at the initial point
|
|
51
|
+
f(t0, y0, f0);
|
|
52
|
+
|
|
53
|
+
// Step 3: compute scaled norms d0 = ||y0/sc||, d1 = ||f0/sc||
|
|
54
|
+
let d0 = 0.0;
|
|
55
|
+
let d1 = 0.0;
|
|
56
|
+
|
|
57
|
+
for (let i = 0; i < dim; ++i) {
|
|
58
|
+
d0 = Math.max(d0, Math.abs(y0[i]) / sc[i]);
|
|
59
|
+
d1 = Math.max(d1, Math.abs(f0[i]) / sc[i]);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Step 4: first guess
|
|
63
|
+
let h0: number;
|
|
64
|
+
|
|
65
|
+
if (d0 < 1e-5 || d1 < 1e-5)
|
|
66
|
+
h0 = 1e-6;
|
|
67
|
+
else
|
|
68
|
+
h0 = 0.01 * d0 / d1;
|
|
69
|
+
|
|
70
|
+
// Cap h0 to the integration interval
|
|
71
|
+
h0 = Math.min(h0, Math.abs(tEnd - t0));
|
|
72
|
+
|
|
73
|
+
// Step 5: explicit Euler probe to estimate the second derivative
|
|
74
|
+
for (let i = 0; i < dim; ++i)
|
|
75
|
+
y1[i] = y0[i] + h0 * f0[i];
|
|
76
|
+
|
|
77
|
+
f(t0 + h0, y1, f1);
|
|
78
|
+
|
|
79
|
+
let d2 = 0.0;
|
|
80
|
+
|
|
81
|
+
for (let i = 0; i < dim; ++i)
|
|
82
|
+
d2 = Math.max(d2, Math.abs(f1[i] - f0[i]) / sc[i]);
|
|
83
|
+
|
|
84
|
+
d2 /= h0;
|
|
85
|
+
|
|
86
|
+
// Step 6: refine using the method order
|
|
87
|
+
// h1 = (tol / max(d1, d2))^(1/(p+1))
|
|
88
|
+
const maxD = Math.max(d1, d2);
|
|
89
|
+
let h1: number;
|
|
90
|
+
|
|
91
|
+
if (maxD <= 1e-15)
|
|
92
|
+
h1 = Math.max(1e-6, h0 * 1e-3);
|
|
93
|
+
else
|
|
94
|
+
h1 = Math.pow(tol / maxD, 1.0 / (p + 1));
|
|
95
|
+
|
|
96
|
+
// Step 7: final initial step size
|
|
97
|
+
h0 = Math.min(100.0 * h0, h1);
|
|
98
|
+
|
|
99
|
+
// Safety: clip to the integration interval
|
|
100
|
+
h0 = Math.min(h0, Math.abs(tEnd - t0));
|
|
101
|
+
|
|
102
|
+
return h0;
|
|
103
|
+
}
|
|
16
104
|
|
|
17
105
|
/** Solve initial value problem the modified Rosenbrock triple (MRT) method
|
|
18
106
|
* @param odes initial value problem for ordinary differential equations
|
|
@@ -61,19 +149,22 @@ const E32 = 6.0 + Math.sqrt(2.0);
|
|
|
61
149
|
export function mrt(odes: ODEs, callback?: Callback): Float64Array[] {
|
|
62
150
|
/** right-hand side of the IVP solved */
|
|
63
151
|
const f = odes.func;
|
|
64
|
-
|
|
65
152
|
// operating variables
|
|
66
153
|
const t0 = odes.arg.start;
|
|
67
154
|
const t1 = odes.arg.finish;
|
|
68
|
-
|
|
69
|
-
const hDataframe = h;
|
|
155
|
+
const hDataframe = odes.arg.step;
|
|
70
156
|
const tolerance = odes.tolerance;
|
|
71
157
|
|
|
72
|
-
/** number of solution dataframe rows */
|
|
73
|
-
const rowCount = Math.trunc((t1 - t0) / h) + 1;
|
|
74
|
-
|
|
75
158
|
/** dimension of the problem */
|
|
76
159
|
const dim = odes.initial.length;
|
|
160
|
+
|
|
161
|
+
// compute the initial step size automatically
|
|
162
|
+
let h = initialStepSize(t0, new Float64Array(odes.initial), f, tolerance, dim, 2, t1);
|
|
163
|
+
|
|
164
|
+
//console.log(`MRT, the problem "${odes.name}", grid step: ${hDataframe}, initial step size: ${h}.`);
|
|
165
|
+
|
|
166
|
+
/** number of solution dataframe rows */
|
|
167
|
+
const rowCount = Math.trunc((t1 - t0) / hDataframe) + 1;
|
|
77
168
|
const dimSquared = dim * dim;
|
|
78
169
|
|
|
79
170
|
/** independent variable values */
|
|
@@ -93,7 +184,6 @@ export function mrt(odes: ODEs, callback?: Callback): Float64Array[] {
|
|
|
93
184
|
let flag = true;
|
|
94
185
|
let index = 1;
|
|
95
186
|
let errmax = 0;
|
|
96
|
-
let hTemp = 0;
|
|
97
187
|
let tNew = 0;
|
|
98
188
|
|
|
99
189
|
// 0 BUFFERS & TEMP STRUCTURES
|
|
@@ -241,18 +331,16 @@ export function mrt(odes: ODEs, callback?: Callback): Float64Array[] {
|
|
|
241
331
|
errmax = max(errmax, abs(yErr[i] / yScale[i]));
|
|
242
332
|
errmax /= tolerance;
|
|
243
333
|
|
|
244
|
-
//
|
|
334
|
+
// adaptive step size control (see MRT.md, Section 6)
|
|
245
335
|
if (errmax > 1) {
|
|
246
|
-
|
|
247
|
-
h = max(
|
|
336
|
+
// step rejected: reduce step size, but not below ALPHA_MIN factor
|
|
337
|
+
h = h * max(ALPHA_MIN, SAFETY * errmax ** (-1 / 3));
|
|
248
338
|
tNew = t + h;
|
|
249
339
|
if (tNew == t)
|
|
250
340
|
throw new Error(ERROR_MSG.MRT_FAILS);
|
|
251
341
|
} else {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
else
|
|
255
|
-
hNext = GROW_COEF * h;
|
|
342
|
+
// step accepted: grow step size, but not above ALPHA_MAX factor
|
|
343
|
+
hNext = h * min(ALPHA_MAX, SAFETY * errmax ** (-1 / 3));
|
|
256
344
|
t = t + h;
|
|
257
345
|
|
|
258
346
|
for (let i = 0; i < dim; ++i)
|
|
@@ -262,15 +350,17 @@ export function mrt(odes: ODEs, callback?: Callback): Float64Array[] {
|
|
|
262
350
|
}
|
|
263
351
|
} // while (true)
|
|
264
352
|
|
|
265
|
-
// compute
|
|
353
|
+
// compute dense output using Shampine-Reichelt continuous extension
|
|
354
|
+
const hStep = t - tPrev;
|
|
266
355
|
while (timeDataframe < t) {
|
|
267
|
-
const
|
|
268
|
-
const
|
|
356
|
+
const s = (timeDataframe - tPrev) / hStep;
|
|
357
|
+
const b1 = s * (1.0 - s) / ONE_MINUS_2D;
|
|
358
|
+
const b2 = s * (s - TWO_D) / ONE_MINUS_2D;
|
|
269
359
|
|
|
270
360
|
tArr[index] = timeDataframe;
|
|
271
361
|
|
|
272
362
|
for (let j = 0; j < dim; ++j)
|
|
273
|
-
yArrs[j][index] =
|
|
363
|
+
yArrs[j][index] = yPrev[j] + hStep * (b1 * k1[j] + b2 * k2[j]);
|
|
274
364
|
|
|
275
365
|
timeDataframe += hDataframe;
|
|
276
366
|
++index;
|
|
@@ -294,7 +384,7 @@ export function mrt(odes: ODEs, callback?: Callback): Float64Array[] {
|
|
|
294
384
|
yArrs[i][rowCount - 1] = y[i];
|
|
295
385
|
|
|
296
386
|
// 4. prepare output
|
|
297
|
-
const solution = Array<Float64Array>(dim);
|
|
387
|
+
const solution = Array<Float64Array>(dim + 1);
|
|
298
388
|
|
|
299
389
|
// independent variable
|
|
300
390
|
solution[0] = tArr;
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/* The Bogacki-Shampine 3(2) method (RK3).
|
|
2
|
+
|
|
3
|
+
An explicit adaptive Runge-Kutta method of order 3 with an embedded
|
|
4
|
+
2nd-order error estimate for step size control. Uses the FSAL (First
|
|
5
|
+
Same As Last) property for efficiency.
|
|
6
|
+
|
|
7
|
+
Reference:
|
|
8
|
+
[1] P. Bogacki and L.F. Shampine, "A 3(2) pair of Runge-Kutta formulas",
|
|
9
|
+
Applied Mathematics Letters, 2(4):321-325, 1989.
|
|
10
|
+
*/
|
|
11
|
+
import { max, abs, SAFETY, REDUCE_COEF, GROW_COEF, ERR_CONTR, TINY, ERROR_MSG } from './solver-defs';
|
|
12
|
+
// Step size control exponents for a 3rd-order method
|
|
13
|
+
const PSHRNK = -1.0 / 3.0; // -1/p = -1/3
|
|
14
|
+
const PSGROW = -0.25; // -1/(p+1) = -1/4
|
|
15
|
+
// Bogacki-Shampine 3(2) Butcher tableau coefficients
|
|
16
|
+
// Nodes (c_i)
|
|
17
|
+
const C2 = 1.0 / 2.0;
|
|
18
|
+
const C3 = 3.0 / 4.0;
|
|
19
|
+
// C4 = 1 (FSAL)
|
|
20
|
+
// Matrix coefficients (a_ij)
|
|
21
|
+
const A21 = 1.0 / 2.0;
|
|
22
|
+
const A32 = 3.0 / 4.0;
|
|
23
|
+
// A4i = Bi (FSAL property: 4th-stage coefficients equal the 3rd-order weights)
|
|
24
|
+
// 3rd-order weights (b_i) — used to advance the solution
|
|
25
|
+
const B1 = 2.0 / 9.0;
|
|
26
|
+
const B2 = 1.0 / 3.0;
|
|
27
|
+
const B3 = 4.0 / 9.0;
|
|
28
|
+
// B4 = 0
|
|
29
|
+
// Error coefficients: (b_i - bHat_i), where bHat are the 2nd-order weights
|
|
30
|
+
const E1 = -5.0 / 72.0;
|
|
31
|
+
const E2 = 1.0 / 12.0;
|
|
32
|
+
const E3 = 1.0 / 9.0;
|
|
33
|
+
const E4 = -1.0 / 8.0;
|
|
34
|
+
/** Solve initial value problem using the Bogacki-Shampine 3(2) method
|
|
35
|
+
* @param odes initial value problem for ordinary differential equations
|
|
36
|
+
* @param callback computations control callback
|
|
37
|
+
* @returns solution of the problem
|
|
38
|
+
* @example
|
|
39
|
+
* // Example. Solve the following initial value problem using the RK3 method:
|
|
40
|
+
* // dx/dt = x + y - t
|
|
41
|
+
* // dy/dt = x * y + t
|
|
42
|
+
* // x(0) = 1
|
|
43
|
+
* // y(0) = -1
|
|
44
|
+
* // on [0, 2] with the step 0.01.
|
|
45
|
+
* import { ODEs, rk3 } from 'diff-grok';
|
|
46
|
+
*
|
|
47
|
+
* const task: ODEs = {
|
|
48
|
+
* name: 'Example', // name of your model
|
|
49
|
+
* arg: {
|
|
50
|
+
* name: 't', // name of the argument
|
|
51
|
+
* start: 0, // initial value of the argument
|
|
52
|
+
* finish: 2, // final value of the argument
|
|
53
|
+
* step: 0.01, // solution grid step
|
|
54
|
+
* },
|
|
55
|
+
* initial: [1, -1], // initial values
|
|
56
|
+
* func: (t: number, y: Float64Array, output: Float64Array) => { // right-hand side of the system
|
|
57
|
+
* output[0] = y[0] + y[1] - t; // 1-st equation
|
|
58
|
+
* output[1] = y[0] * y[1] + t; // 2-nd equation
|
|
59
|
+
* },
|
|
60
|
+
* tolerance: 1e-7, // tolerance
|
|
61
|
+
* solutionColNames: ['x', 'y'], // names of solution functions
|
|
62
|
+
* };
|
|
63
|
+
*
|
|
64
|
+
* try {
|
|
65
|
+
* // Solve the problem using the RK3 method
|
|
66
|
+
* const solution = rk3(task);
|
|
67
|
+
*
|
|
68
|
+
* // Print a table with the results
|
|
69
|
+
* console.log(task.arg.name, task.solutionColNames[0], task.solutionColNames[1]);
|
|
70
|
+
* const length = solution[0].length;
|
|
71
|
+
* for (let i = 0; i < length; ++i)
|
|
72
|
+
* console.log(solution[0][i], solution[1][i], solution[2][i]);
|
|
73
|
+
* } catch (err) {
|
|
74
|
+
* console.log('Solver failed: ', err instanceof Error ? err.message : 'Unknown problem!');
|
|
75
|
+
* }
|
|
76
|
+
*/
|
|
77
|
+
export function rk3(odes, callback) {
|
|
78
|
+
const f = odes.func;
|
|
79
|
+
// operating variables
|
|
80
|
+
const t0 = odes.arg.start;
|
|
81
|
+
const t1 = odes.arg.finish;
|
|
82
|
+
let h = odes.arg.step;
|
|
83
|
+
const hDataframe = h;
|
|
84
|
+
const hMax = hDataframe * 10;
|
|
85
|
+
const tolerance = odes.tolerance;
|
|
86
|
+
const rowCount = Math.trunc((t1 - t0) / h) + 1;
|
|
87
|
+
const dim = odes.initial.length;
|
|
88
|
+
// result arrays
|
|
89
|
+
const tArr = new Float64Array(rowCount);
|
|
90
|
+
const yArrs = Array(dim);
|
|
91
|
+
for (let i = 0; i < dim; ++i)
|
|
92
|
+
yArrs[i] = new Float64Array(rowCount);
|
|
93
|
+
// method routine
|
|
94
|
+
let timeDataframe = t0 + hDataframe;
|
|
95
|
+
let t = t0;
|
|
96
|
+
let tPrev = t0;
|
|
97
|
+
let hNext = 0.0;
|
|
98
|
+
let flag = true;
|
|
99
|
+
let index = 1;
|
|
100
|
+
let errmax = 0;
|
|
101
|
+
let hTemp = 0;
|
|
102
|
+
let tNew = 0;
|
|
103
|
+
// buffers
|
|
104
|
+
const y = new Float64Array(odes.initial);
|
|
105
|
+
const yPrev = new Float64Array(odes.initial);
|
|
106
|
+
const dydt = new Float64Array(dim);
|
|
107
|
+
const yScale = new Float64Array(dim);
|
|
108
|
+
const yTemp = new Float64Array(dim);
|
|
109
|
+
const yErr = new Float64Array(dim);
|
|
110
|
+
const k1 = new Float64Array(dim);
|
|
111
|
+
const k2 = new Float64Array(dim);
|
|
112
|
+
const k3 = new Float64Array(dim);
|
|
113
|
+
const k4 = new Float64Array(dim);
|
|
114
|
+
// 1. SOLUTION AT THE POINT t0
|
|
115
|
+
tArr[0] = t0;
|
|
116
|
+
for (let i = 0; i < dim; ++i)
|
|
117
|
+
yArrs[i][0] = y[i];
|
|
118
|
+
// 2. COMPUTE NUMERICAL SOLUTION FOR THE POINTS FROM THE INTERVAL (t0, t1)
|
|
119
|
+
while (flag) {
|
|
120
|
+
// compute derivative
|
|
121
|
+
f(t, y, dydt);
|
|
122
|
+
// check whether to go on computations
|
|
123
|
+
if (callback)
|
|
124
|
+
callback.onIterationStart();
|
|
125
|
+
// compute scale vector
|
|
126
|
+
for (let i = 0; i < dim; ++i)
|
|
127
|
+
yScale[i] = abs(y[i]) + h * abs(dydt[i]) + TINY;
|
|
128
|
+
// check end point
|
|
129
|
+
if (t + h > t1) {
|
|
130
|
+
h = t1 - t;
|
|
131
|
+
flag = false;
|
|
132
|
+
}
|
|
133
|
+
// adaptive step loop
|
|
134
|
+
while (true) {
|
|
135
|
+
// Stage 1: k1 = f(t, y)
|
|
136
|
+
f(t, y, k1);
|
|
137
|
+
// Stage 2: k2 = f(t + C2*h, y + h*A21*k1)
|
|
138
|
+
for (let i = 0; i < dim; ++i)
|
|
139
|
+
yTemp[i] = y[i] + h * A21 * k1[i];
|
|
140
|
+
f(t + C2 * h, yTemp, k2);
|
|
141
|
+
// Stage 3: k3 = f(t + C3*h, y + h*A32*k2)
|
|
142
|
+
for (let i = 0; i < dim; ++i)
|
|
143
|
+
yTemp[i] = y[i] + h * A32 * k2[i];
|
|
144
|
+
f(t + C3 * h, yTemp, k3);
|
|
145
|
+
// 3rd-order solution
|
|
146
|
+
for (let i = 0; i < dim; ++i)
|
|
147
|
+
yTemp[i] = y[i] + h * (B1 * k1[i] + B2 * k2[i] + B3 * k3[i]);
|
|
148
|
+
// Stage 4: k4 = f(t + h, yTemp) — needed for error estimate (FSAL)
|
|
149
|
+
f(t + h, yTemp, k4);
|
|
150
|
+
// Error estimate: difference between 3rd and 2nd order solutions
|
|
151
|
+
for (let i = 0; i < dim; ++i)
|
|
152
|
+
yErr[i] = h * (E1 * k1[i] + E2 * k2[i] + E3 * k3[i] + E4 * k4[i]);
|
|
153
|
+
// estimating error
|
|
154
|
+
errmax = 0;
|
|
155
|
+
for (let i = 0; i < dim; ++i)
|
|
156
|
+
errmax = max(errmax, abs(yErr[i] / yScale[i]));
|
|
157
|
+
errmax /= tolerance;
|
|
158
|
+
// processing the error obtained
|
|
159
|
+
if (errmax > 1) {
|
|
160
|
+
hTemp = SAFETY * h * Math.pow(errmax, PSHRNK);
|
|
161
|
+
h = max(hTemp, REDUCE_COEF * h);
|
|
162
|
+
tNew = t + h;
|
|
163
|
+
if (tNew == t)
|
|
164
|
+
throw new Error(ERROR_MSG.RK3_FAILS);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
if (errmax > ERR_CONTR)
|
|
168
|
+
hNext = SAFETY * h * Math.pow(errmax, PSGROW);
|
|
169
|
+
else
|
|
170
|
+
hNext = GROW_COEF * h;
|
|
171
|
+
if (hNext > hMax)
|
|
172
|
+
hNext = hMax;
|
|
173
|
+
t = t + h;
|
|
174
|
+
for (let i = 0; i < dim; ++i)
|
|
175
|
+
y[i] = yTemp[i];
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
} // while (true)
|
|
179
|
+
// compute linearly interpolated results and store them in dataframe
|
|
180
|
+
while (timeDataframe < t) {
|
|
181
|
+
const cLeft = (t - timeDataframe) / (t - tPrev);
|
|
182
|
+
const cRight = 1.0 - cLeft;
|
|
183
|
+
tArr[index] = timeDataframe;
|
|
184
|
+
for (let j = 0; j < dim; ++j)
|
|
185
|
+
yArrs[j][index] = cRight * y[j] + cLeft * yPrev[j];
|
|
186
|
+
timeDataframe += hDataframe;
|
|
187
|
+
++index;
|
|
188
|
+
}
|
|
189
|
+
h = hNext;
|
|
190
|
+
tPrev = t;
|
|
191
|
+
for (let i = 0; i < dim; ++i)
|
|
192
|
+
yPrev[i] = y[i];
|
|
193
|
+
} // while (flag)
|
|
194
|
+
// perform final callback actions
|
|
195
|
+
if (callback)
|
|
196
|
+
callback.onComputationsCompleted();
|
|
197
|
+
// 3. solution at the point t1
|
|
198
|
+
tArr[rowCount - 1] = t1;
|
|
199
|
+
for (let i = 0; i < dim; ++i)
|
|
200
|
+
yArrs[i][rowCount - 1] = y[i];
|
|
201
|
+
// 4. prepare output
|
|
202
|
+
const solution = Array(dim + 1);
|
|
203
|
+
// independent variable
|
|
204
|
+
solution[0] = tArr;
|
|
205
|
+
// functions
|
|
206
|
+
for (let i = 0; i < dim; ++i)
|
|
207
|
+
solution[i + 1] = yArrs[i];
|
|
208
|
+
return solution;
|
|
209
|
+
} // rk3
|
|
210
|
+
//# sourceMappingURL=rk3-method.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rk3-method.js","sourceRoot":"","sources":["rk3-method.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/* The Bogacki-Shampine 3(2) method (RK3).
|
|
2
|
+
|
|
3
|
+
An explicit adaptive Runge-Kutta method of order 3 with an embedded
|
|
4
|
+
2nd-order error estimate for step size control. Uses the FSAL (First
|
|
5
|
+
Same As Last) property for efficiency.
|
|
6
|
+
|
|
7
|
+
Reference:
|
|
8
|
+
[1] P. Bogacki and L.F. Shampine, "A 3(2) pair of Runge-Kutta formulas",
|
|
9
|
+
Applied Mathematics Letters, 2(4):321-325, 1989.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import {ODEs, max, abs, SAFETY, REDUCE_COEF, GROW_COEF,
|
|
13
|
+
ERR_CONTR, TINY, ERROR_MSG} from './solver-defs';
|
|
14
|
+
import {Callback} from './callbacks/callback-base';
|
|
15
|
+
|
|
16
|
+
// Step size control exponents for a 3rd-order method
|
|
17
|
+
const PSHRNK = -1.0 / 3.0; // -1/p = -1/3
|
|
18
|
+
const PSGROW = -0.25; // -1/(p+1) = -1/4
|
|
19
|
+
|
|
20
|
+
// Bogacki-Shampine 3(2) Butcher tableau coefficients
|
|
21
|
+
|
|
22
|
+
// Nodes (c_i)
|
|
23
|
+
const C2 = 1.0 / 2.0;
|
|
24
|
+
const C3 = 3.0 / 4.0;
|
|
25
|
+
// C4 = 1 (FSAL)
|
|
26
|
+
|
|
27
|
+
// Matrix coefficients (a_ij)
|
|
28
|
+
const A21 = 1.0 / 2.0;
|
|
29
|
+
|
|
30
|
+
const A32 = 3.0 / 4.0;
|
|
31
|
+
|
|
32
|
+
// A4i = Bi (FSAL property: 4th-stage coefficients equal the 3rd-order weights)
|
|
33
|
+
|
|
34
|
+
// 3rd-order weights (b_i) — used to advance the solution
|
|
35
|
+
const B1 = 2.0 / 9.0;
|
|
36
|
+
const B2 = 1.0 / 3.0;
|
|
37
|
+
const B3 = 4.0 / 9.0;
|
|
38
|
+
// B4 = 0
|
|
39
|
+
|
|
40
|
+
// Error coefficients: (b_i - bHat_i), where bHat are the 2nd-order weights
|
|
41
|
+
const E1 = -5.0 / 72.0;
|
|
42
|
+
const E2 = 1.0 / 12.0;
|
|
43
|
+
const E3 = 1.0 / 9.0;
|
|
44
|
+
const E4 = -1.0 / 8.0;
|
|
45
|
+
|
|
46
|
+
/** Solve initial value problem using the Bogacki-Shampine 3(2) method
|
|
47
|
+
* @param odes initial value problem for ordinary differential equations
|
|
48
|
+
* @param callback computations control callback
|
|
49
|
+
* @returns solution of the problem
|
|
50
|
+
* @example
|
|
51
|
+
* // Example. Solve the following initial value problem using the RK3 method:
|
|
52
|
+
* // dx/dt = x + y - t
|
|
53
|
+
* // dy/dt = x * y + t
|
|
54
|
+
* // x(0) = 1
|
|
55
|
+
* // y(0) = -1
|
|
56
|
+
* // on [0, 2] with the step 0.01.
|
|
57
|
+
* import { ODEs, rk3 } from 'diff-grok';
|
|
58
|
+
*
|
|
59
|
+
* const task: ODEs = {
|
|
60
|
+
* name: 'Example', // name of your model
|
|
61
|
+
* arg: {
|
|
62
|
+
* name: 't', // name of the argument
|
|
63
|
+
* start: 0, // initial value of the argument
|
|
64
|
+
* finish: 2, // final value of the argument
|
|
65
|
+
* step: 0.01, // solution grid step
|
|
66
|
+
* },
|
|
67
|
+
* initial: [1, -1], // initial values
|
|
68
|
+
* func: (t: number, y: Float64Array, output: Float64Array) => { // right-hand side of the system
|
|
69
|
+
* output[0] = y[0] + y[1] - t; // 1-st equation
|
|
70
|
+
* output[1] = y[0] * y[1] + t; // 2-nd equation
|
|
71
|
+
* },
|
|
72
|
+
* tolerance: 1e-7, // tolerance
|
|
73
|
+
* solutionColNames: ['x', 'y'], // names of solution functions
|
|
74
|
+
* };
|
|
75
|
+
*
|
|
76
|
+
* try {
|
|
77
|
+
* // Solve the problem using the RK3 method
|
|
78
|
+
* const solution = rk3(task);
|
|
79
|
+
*
|
|
80
|
+
* // Print a table with the results
|
|
81
|
+
* console.log(task.arg.name, task.solutionColNames[0], task.solutionColNames[1]);
|
|
82
|
+
* const length = solution[0].length;
|
|
83
|
+
* for (let i = 0; i < length; ++i)
|
|
84
|
+
* console.log(solution[0][i], solution[1][i], solution[2][i]);
|
|
85
|
+
* } catch (err) {
|
|
86
|
+
* console.log('Solver failed: ', err instanceof Error ? err.message : 'Unknown problem!');
|
|
87
|
+
* }
|
|
88
|
+
*/
|
|
89
|
+
export function rk3(odes: ODEs, callback?: Callback): Float64Array[] {
|
|
90
|
+
const f = odes.func;
|
|
91
|
+
|
|
92
|
+
// operating variables
|
|
93
|
+
const t0 = odes.arg.start;
|
|
94
|
+
const t1 = odes.arg.finish;
|
|
95
|
+
let h = odes.arg.step;
|
|
96
|
+
const hDataframe = h;
|
|
97
|
+
const hMax = hDataframe * 10;
|
|
98
|
+
const tolerance = odes.tolerance;
|
|
99
|
+
|
|
100
|
+
const rowCount = Math.trunc((t1 - t0) / h) + 1;
|
|
101
|
+
const dim = odes.initial.length;
|
|
102
|
+
|
|
103
|
+
// result arrays
|
|
104
|
+
const tArr = new Float64Array(rowCount);
|
|
105
|
+
const yArrs = Array<Float64Array>(dim);
|
|
106
|
+
|
|
107
|
+
for (let i = 0; i < dim; ++i)
|
|
108
|
+
yArrs[i] = new Float64Array(rowCount);
|
|
109
|
+
|
|
110
|
+
// method routine
|
|
111
|
+
let timeDataframe = t0 + hDataframe;
|
|
112
|
+
let t = t0;
|
|
113
|
+
let tPrev = t0;
|
|
114
|
+
let hNext = 0.0;
|
|
115
|
+
let flag = true;
|
|
116
|
+
let index = 1;
|
|
117
|
+
let errmax = 0;
|
|
118
|
+
let hTemp = 0;
|
|
119
|
+
let tNew = 0;
|
|
120
|
+
|
|
121
|
+
// buffers
|
|
122
|
+
const y = new Float64Array(odes.initial);
|
|
123
|
+
const yPrev = new Float64Array(odes.initial);
|
|
124
|
+
const dydt = new Float64Array(dim);
|
|
125
|
+
const yScale = new Float64Array(dim);
|
|
126
|
+
const yTemp = new Float64Array(dim);
|
|
127
|
+
const yErr = new Float64Array(dim);
|
|
128
|
+
|
|
129
|
+
const k1 = new Float64Array(dim);
|
|
130
|
+
const k2 = new Float64Array(dim);
|
|
131
|
+
const k3 = new Float64Array(dim);
|
|
132
|
+
const k4 = new Float64Array(dim);
|
|
133
|
+
|
|
134
|
+
// 1. SOLUTION AT THE POINT t0
|
|
135
|
+
tArr[0] = t0;
|
|
136
|
+
for (let i = 0; i < dim; ++i)
|
|
137
|
+
yArrs[i][0] = y[i];
|
|
138
|
+
|
|
139
|
+
// 2. COMPUTE NUMERICAL SOLUTION FOR THE POINTS FROM THE INTERVAL (t0, t1)
|
|
140
|
+
while (flag) {
|
|
141
|
+
// compute derivative
|
|
142
|
+
f(t, y, dydt);
|
|
143
|
+
|
|
144
|
+
// check whether to go on computations
|
|
145
|
+
if (callback)
|
|
146
|
+
callback.onIterationStart();
|
|
147
|
+
|
|
148
|
+
// compute scale vector
|
|
149
|
+
for (let i = 0; i < dim; ++i)
|
|
150
|
+
yScale[i] = abs(y[i]) + h * abs(dydt[i]) + TINY;
|
|
151
|
+
|
|
152
|
+
// check end point
|
|
153
|
+
if (t + h > t1) {
|
|
154
|
+
h = t1 - t;
|
|
155
|
+
flag = false;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// adaptive step loop
|
|
159
|
+
while (true) {
|
|
160
|
+
// Stage 1: k1 = f(t, y)
|
|
161
|
+
f(t, y, k1);
|
|
162
|
+
|
|
163
|
+
// Stage 2: k2 = f(t + C2*h, y + h*A21*k1)
|
|
164
|
+
for (let i = 0; i < dim; ++i)
|
|
165
|
+
yTemp[i] = y[i] + h * A21 * k1[i];
|
|
166
|
+
f(t + C2 * h, yTemp, k2);
|
|
167
|
+
|
|
168
|
+
// Stage 3: k3 = f(t + C3*h, y + h*A32*k2)
|
|
169
|
+
for (let i = 0; i < dim; ++i)
|
|
170
|
+
yTemp[i] = y[i] + h * A32 * k2[i];
|
|
171
|
+
f(t + C3 * h, yTemp, k3);
|
|
172
|
+
|
|
173
|
+
// 3rd-order solution
|
|
174
|
+
for (let i = 0; i < dim; ++i)
|
|
175
|
+
yTemp[i] = y[i] + h * (B1 * k1[i] + B2 * k2[i] + B3 * k3[i]);
|
|
176
|
+
|
|
177
|
+
// Stage 4: k4 = f(t + h, yTemp) — needed for error estimate (FSAL)
|
|
178
|
+
f(t + h, yTemp, k4);
|
|
179
|
+
|
|
180
|
+
// Error estimate: difference between 3rd and 2nd order solutions
|
|
181
|
+
for (let i = 0; i < dim; ++i)
|
|
182
|
+
yErr[i] = h * (E1 * k1[i] + E2 * k2[i] + E3 * k3[i] + E4 * k4[i]);
|
|
183
|
+
|
|
184
|
+
// estimating error
|
|
185
|
+
errmax = 0;
|
|
186
|
+
for (let i = 0; i < dim; ++i)
|
|
187
|
+
errmax = max(errmax, abs(yErr[i] / yScale[i]));
|
|
188
|
+
errmax /= tolerance;
|
|
189
|
+
|
|
190
|
+
// processing the error obtained
|
|
191
|
+
if (errmax > 1) {
|
|
192
|
+
hTemp = SAFETY * h * errmax**PSHRNK;
|
|
193
|
+
h = max(hTemp, REDUCE_COEF * h);
|
|
194
|
+
tNew = t + h;
|
|
195
|
+
if (tNew == t)
|
|
196
|
+
throw new Error(ERROR_MSG.RK3_FAILS);
|
|
197
|
+
} else {
|
|
198
|
+
if (errmax > ERR_CONTR)
|
|
199
|
+
hNext = SAFETY * h * errmax**PSGROW;
|
|
200
|
+
else
|
|
201
|
+
hNext = GROW_COEF * h;
|
|
202
|
+
|
|
203
|
+
if (hNext > hMax)
|
|
204
|
+
hNext = hMax;
|
|
205
|
+
|
|
206
|
+
t = t + h;
|
|
207
|
+
|
|
208
|
+
for (let i = 0; i < dim; ++i)
|
|
209
|
+
y[i] = yTemp[i];
|
|
210
|
+
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
} // while (true)
|
|
214
|
+
|
|
215
|
+
// compute linearly interpolated results and store them in dataframe
|
|
216
|
+
while (timeDataframe < t) {
|
|
217
|
+
const cLeft = (t - timeDataframe) / (t - tPrev);
|
|
218
|
+
const cRight = 1.0 - cLeft;
|
|
219
|
+
|
|
220
|
+
tArr[index] = timeDataframe;
|
|
221
|
+
|
|
222
|
+
for (let j = 0; j < dim; ++j)
|
|
223
|
+
yArrs[j][index] = cRight * y[j] + cLeft * yPrev[j];
|
|
224
|
+
|
|
225
|
+
timeDataframe += hDataframe;
|
|
226
|
+
++index;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
h = hNext;
|
|
230
|
+
tPrev = t;
|
|
231
|
+
|
|
232
|
+
for (let i = 0; i < dim; ++i)
|
|
233
|
+
yPrev[i] = y[i];
|
|
234
|
+
} // while (flag)
|
|
235
|
+
|
|
236
|
+
// perform final callback actions
|
|
237
|
+
if (callback)
|
|
238
|
+
callback.onComputationsCompleted();
|
|
239
|
+
|
|
240
|
+
// 3. solution at the point t1
|
|
241
|
+
tArr[rowCount - 1] = t1;
|
|
242
|
+
|
|
243
|
+
for (let i = 0; i < dim; ++i)
|
|
244
|
+
yArrs[i][rowCount - 1] = y[i];
|
|
245
|
+
|
|
246
|
+
// 4. prepare output
|
|
247
|
+
const solution = Array<Float64Array>(dim + 1);
|
|
248
|
+
|
|
249
|
+
// independent variable
|
|
250
|
+
solution[0] = tArr;
|
|
251
|
+
|
|
252
|
+
// functions
|
|
253
|
+
for (let i = 0; i < dim; ++i)
|
|
254
|
+
solution[i + 1] = yArrs[i];
|
|
255
|
+
|
|
256
|
+
return solution;
|
|
257
|
+
} // rk3
|