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.
Files changed (226) hide show
  1. package/.claude/settings.local.json +11 -0
  2. package/.claude/skills/license-updater/SKILL.md +149 -0
  3. package/.claude/skills/license-updater/references/compatibility.md +68 -0
  4. package/.claude/skills/license-updater/references/templates.md +151 -0
  5. package/.claude/skills/license-updater/scripts/generate_license_files.py +467 -0
  6. package/CLAUDE.md +104 -0
  7. package/LICENSE +1 -1
  8. package/README.MD +121 -27
  9. package/THIRD_PARTY_LICENSES +135 -0
  10. package/docs/assets/hierarchy.js +1 -1
  11. package/docs/assets/navigation.js +1 -1
  12. package/docs/assets/search.js +1 -1
  13. package/docs/classes/BasicModelPipelineCreator.html +4 -4
  14. package/docs/classes/Callback.html +5 -5
  15. package/docs/classes/CyclicModelPipelineCreator.html +4 -4
  16. package/docs/classes/IterCheckerCallback.html +5 -5
  17. package/docs/classes/PipelineCreator.html +4 -4
  18. package/docs/classes/TimeCheckerCallback.html +5 -5
  19. package/docs/classes/UpdatesModelPipelineCreator.html +4 -4
  20. package/docs/functions/ab4.html +8 -0
  21. package/docs/functions/ab5.html +8 -0
  22. package/docs/functions/applyPipeline.html +2 -2
  23. package/docs/functions/getCallback.html +2 -2
  24. package/docs/functions/getIVP.html +2 -2
  25. package/docs/functions/getInputVector.html +2 -2
  26. package/docs/functions/getIvp2WebWorker.html +2 -2
  27. package/docs/functions/getJScode.html +2 -2
  28. package/docs/functions/getOutputNames.html +2 -2
  29. package/docs/functions/getPipelineCreator.html +2 -2
  30. package/docs/functions/lsoda.html +8 -0
  31. package/docs/functions/mrt.html +2 -2
  32. package/docs/functions/printE5.html +2 -2
  33. package/docs/functions/printHires.html +2 -2
  34. package/docs/functions/printOrego.html +2 -2
  35. package/docs/functions/printPollution.html +2 -2
  36. package/docs/functions/printRobertson.html +2 -2
  37. package/docs/functions/printVdpol.html +2 -2
  38. package/docs/functions/rk3.html +8 -0
  39. package/docs/functions/rk4.html +8 -0
  40. package/docs/functions/rkdp.html +8 -0
  41. package/docs/functions/ros34prw.html +2 -2
  42. package/docs/functions/ros3prw.html +2 -2
  43. package/docs/functions/solveIvp.html +2 -2
  44. package/docs/hierarchy.html +1 -1
  45. package/docs/index.html +100 -15
  46. package/docs/media/E5.png +0 -0
  47. package/docs/media/HIRES.png +0 -0
  48. package/docs/media/OREGO.png +0 -0
  49. package/docs/media/POLL-full.png +0 -0
  50. package/docs/media/ROBER.png +0 -0
  51. package/docs/media/VDP0L.png +0 -0
  52. package/docs/media/cyclic-model.js +3 -1
  53. package/docs/media/cyclic-model.js.map +1 -1
  54. package/docs/media/cyclic-model.ts +3 -1
  55. package/docs/modules.html +1 -1
  56. package/docs/types/Arg.html +7 -7
  57. package/docs/types/DifEqs.html +4 -4
  58. package/docs/types/Func.html +2 -2
  59. package/docs/types/IVP.html +20 -20
  60. package/docs/types/IVP2WebWorker.html +7 -7
  61. package/docs/types/Input.html +4 -4
  62. package/docs/types/Loop.html +4 -4
  63. package/docs/types/ODEs.html +8 -8
  64. package/docs/types/Output.html +4 -4
  65. package/docs/types/Pipeline.html +4 -4
  66. package/docs/types/SolverOptions.html +5 -5
  67. package/docs/types/Update.html +5 -5
  68. package/docs/types/Wrapper.html +5 -5
  69. package/images/E5.png +0 -0
  70. package/images/HIRES.png +0 -0
  71. package/images/OREGO.png +0 -0
  72. package/images/POLL-full.png +0 -0
  73. package/images/ROBER.png +0 -0
  74. package/images/VDP0L.png +0 -0
  75. package/index.js +1 -1
  76. package/index.js.map +1 -1
  77. package/index.ts +2 -1
  78. package/jest.config.js +1 -0
  79. package/package.json +4 -2
  80. package/src/examples/check-methods.js +15 -3
  81. package/src/examples/check-methods.js.map +1 -1
  82. package/src/examples/check-methods.ts +18 -3
  83. package/src/examples/cyclic-model.js +3 -1
  84. package/src/examples/cyclic-model.js.map +1 -1
  85. package/src/examples/cyclic-model.ts +3 -1
  86. package/src/solver-tools/ab4-method.js +332 -0
  87. package/src/solver-tools/ab4-method.js.map +1 -0
  88. package/src/solver-tools/ab4-method.ts +395 -0
  89. package/src/solver-tools/ab5-method.js +334 -0
  90. package/src/solver-tools/ab5-method.js.map +1 -0
  91. package/src/solver-tools/ab5-method.ts +397 -0
  92. package/src/solver-tools/cvode/common.js +487 -0
  93. package/src/solver-tools/cvode/common.js.map +1 -0
  94. package/src/solver-tools/cvode/common.ts +549 -0
  95. package/src/solver-tools/cvode/cvode.js +1062 -0
  96. package/src/solver-tools/cvode/cvode.js.map +1 -0
  97. package/src/solver-tools/cvode/cvode.ts +1226 -0
  98. package/src/solver-tools/cvode/cvode_adams.js +124 -0
  99. package/src/solver-tools/cvode/cvode_adams.js.map +1 -0
  100. package/src/solver-tools/cvode/cvode_adams.ts +142 -0
  101. package/src/solver-tools/cvode/cvode_bdf.js +153 -0
  102. package/src/solver-tools/cvode/cvode_bdf.js.map +1 -0
  103. package/src/solver-tools/cvode/cvode_bdf.ts +164 -0
  104. package/src/solver-tools/cvode/cvode_class.js +158 -0
  105. package/src/solver-tools/cvode/cvode_class.js.map +1 -0
  106. package/src/solver-tools/cvode/cvode_class.ts +271 -0
  107. package/src/solver-tools/cvode/cvode_hin.js +119 -0
  108. package/src/solver-tools/cvode/cvode_hin.js.map +1 -0
  109. package/src/solver-tools/cvode/cvode_hin.ts +150 -0
  110. package/src/solver-tools/cvode/cvode_io.js +203 -0
  111. package/src/solver-tools/cvode/cvode_io.js.map +1 -0
  112. package/src/solver-tools/cvode/cvode_io.ts +258 -0
  113. package/src/solver-tools/cvode/cvode_ls.js +210 -0
  114. package/src/solver-tools/cvode/cvode_ls.js.map +1 -0
  115. package/src/solver-tools/cvode/cvode_ls.ts +249 -0
  116. package/src/solver-tools/cvode/cvode_nls.js +220 -0
  117. package/src/solver-tools/cvode/cvode_nls.js.map +1 -0
  118. package/src/solver-tools/cvode/cvode_nls.ts +259 -0
  119. package/src/solver-tools/cvode/cvode_root.js +415 -0
  120. package/src/solver-tools/cvode/cvode_root.js.map +1 -0
  121. package/src/solver-tools/cvode/cvode_root.ts +503 -0
  122. package/src/solver-tools/cvode/dense_linalg.js +131 -0
  123. package/src/solver-tools/cvode/dense_linalg.js.map +1 -0
  124. package/src/solver-tools/cvode/dense_linalg.ts +144 -0
  125. package/src/solver-tools/cvode/index.js +26 -0
  126. package/src/solver-tools/cvode/index.js.map +1 -0
  127. package/src/solver-tools/cvode/index.ts +64 -0
  128. package/src/solver-tools/cvode-method.js +114 -0
  129. package/src/solver-tools/cvode-method.js.map +1 -0
  130. package/src/solver-tools/cvode-method.ts +129 -0
  131. package/src/solver-tools/index.js +7 -0
  132. package/src/solver-tools/index.js.map +1 -1
  133. package/src/solver-tools/index.ts +7 -0
  134. package/src/solver-tools/lsoda/blas.js +257 -0
  135. package/src/solver-tools/lsoda/blas.js.map +1 -0
  136. package/src/solver-tools/lsoda/blas.ts +279 -0
  137. package/src/solver-tools/lsoda/cfode.js +84 -0
  138. package/src/solver-tools/lsoda/cfode.js.map +1 -0
  139. package/src/solver-tools/lsoda/cfode.ts +95 -0
  140. package/src/solver-tools/lsoda/common.js +94 -0
  141. package/src/solver-tools/lsoda/common.js.map +1 -0
  142. package/src/solver-tools/lsoda/common.ts +135 -0
  143. package/src/solver-tools/lsoda/corfailure.js +36 -0
  144. package/src/solver-tools/lsoda/corfailure.js.map +1 -0
  145. package/src/solver-tools/lsoda/corfailure.ts +42 -0
  146. package/src/solver-tools/lsoda/correction.js +112 -0
  147. package/src/solver-tools/lsoda/correction.js.map +1 -0
  148. package/src/solver-tools/lsoda/correction.ts +131 -0
  149. package/src/solver-tools/lsoda/dense.js +121 -0
  150. package/src/solver-tools/lsoda/dense.js.map +1 -0
  151. package/src/solver-tools/lsoda/dense.ts +141 -0
  152. package/src/solver-tools/lsoda/index.js +15 -0
  153. package/src/solver-tools/lsoda/index.js.map +1 -0
  154. package/src/solver-tools/lsoda/index.ts +17 -0
  155. package/src/solver-tools/lsoda/intdy.js +54 -0
  156. package/src/solver-tools/lsoda/intdy.js.map +1 -0
  157. package/src/solver-tools/lsoda/intdy.ts +62 -0
  158. package/src/solver-tools/lsoda/lsoda.js +578 -0
  159. package/src/solver-tools/lsoda/lsoda.js.map +1 -0
  160. package/src/solver-tools/lsoda/lsoda.ts +644 -0
  161. package/src/solver-tools/lsoda/methodswitch.js +108 -0
  162. package/src/solver-tools/lsoda/methodswitch.js.map +1 -0
  163. package/src/solver-tools/lsoda/methodswitch.ts +119 -0
  164. package/src/solver-tools/lsoda/orderswitch.js +97 -0
  165. package/src/solver-tools/lsoda/orderswitch.js.map +1 -0
  166. package/src/solver-tools/lsoda/orderswitch.ts +107 -0
  167. package/src/solver-tools/lsoda/prja.js +54 -0
  168. package/src/solver-tools/lsoda/prja.js.map +1 -0
  169. package/src/solver-tools/lsoda/prja.ts +61 -0
  170. package/src/solver-tools/lsoda/scaleh.js +41 -0
  171. package/src/solver-tools/lsoda/scaleh.js.map +1 -0
  172. package/src/solver-tools/lsoda/scaleh.ts +45 -0
  173. package/src/solver-tools/lsoda/solsy.js +25 -0
  174. package/src/solver-tools/lsoda/solsy.js.map +1 -0
  175. package/src/solver-tools/lsoda/solsy.ts +30 -0
  176. package/src/solver-tools/lsoda/stoda.js +270 -0
  177. package/src/solver-tools/lsoda/stoda.js.map +1 -0
  178. package/src/solver-tools/lsoda/stoda.ts +298 -0
  179. package/src/solver-tools/lsoda-method.js +134 -0
  180. package/src/solver-tools/lsoda-method.js.map +1 -0
  181. package/src/solver-tools/lsoda-method.ts +154 -0
  182. package/src/solver-tools/mrt-method.js +81 -18
  183. package/src/solver-tools/mrt-method.js.map +1 -1
  184. package/src/solver-tools/mrt-method.ts +111 -21
  185. package/src/solver-tools/rk3-method.js +210 -0
  186. package/src/solver-tools/rk3-method.js.map +1 -0
  187. package/src/solver-tools/rk3-method.ts +257 -0
  188. package/src/solver-tools/rk4-method.js +236 -0
  189. package/src/solver-tools/rk4-method.js.map +1 -0
  190. package/src/solver-tools/rk4-method.ts +286 -0
  191. package/src/solver-tools/rkdp-method.js +247 -0
  192. package/src/solver-tools/rkdp-method.js.map +1 -0
  193. package/src/solver-tools/rkdp-method.ts +300 -0
  194. package/src/solver-tools/ros34prw-method.js +1 -1
  195. package/src/solver-tools/ros34prw-method.js.map +1 -1
  196. package/src/solver-tools/ros34prw-method.ts +1 -1
  197. package/src/solver-tools/ros3prw-method.js +1 -1
  198. package/src/solver-tools/ros3prw-method.js.map +1 -1
  199. package/src/solver-tools/ros3prw-method.ts +1 -1
  200. package/src/solver-tools/solver-defs.js +7 -0
  201. package/src/solver-tools/solver-defs.js.map +1 -1
  202. package/src/solver-tools/solver-defs.ts +7 -0
  203. package/src/tests/correctness.test.js +6 -4
  204. package/src/tests/correctness.test.js.map +1 -1
  205. package/src/tests/correctness.test.ts +6 -4
  206. package/src/tests/cvode-lib-correctness.test.js +404 -0
  207. package/src/tests/cvode-lib-correctness.test.js.map +1 -0
  208. package/src/tests/cvode-lib-correctness.test.ts +505 -0
  209. package/src/tests/cvode-lib-performance.test.js +103 -0
  210. package/src/tests/cvode-lib-performance.test.js.map +1 -0
  211. package/src/tests/cvode-lib-performance.test.ts +128 -0
  212. package/src/tests/lsoda-lib-correctness.test.js +223 -0
  213. package/src/tests/lsoda-lib-correctness.test.js.map +1 -0
  214. package/src/tests/lsoda-lib-correctness.test.ts +283 -0
  215. package/src/tests/lsoda-lib-performance.test.js +95 -0
  216. package/src/tests/lsoda-lib-performance.test.js.map +1 -0
  217. package/src/tests/lsoda-lib-performance.test.ts +126 -0
  218. package/src/tests/performance.test.js +12 -8
  219. package/src/tests/performance.test.js.map +1 -1
  220. package/src/tests/performance.test.ts +12 -8
  221. package/src/tests/test-defs.js +20 -1
  222. package/src/tests/test-defs.js.map +1 -1
  223. package/src/tests/test-defs.ts +22 -1
  224. package/src/worker-tools/solving.js +15 -1
  225. package/src/worker-tools/solving.js.map +1 -1
  226. 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, PSHRNK, PSGROW, REDUCE_COEF, GROW_COEF,
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
- let h = odes.arg.step;
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
- // processing the error obtained
334
+ // adaptive step size control (see MRT.md, Section 6)
245
335
  if (errmax > 1) {
246
- hTemp = SAFETY * h * errmax**PSHRNK;
247
- h = max(hTemp, REDUCE_COEF * h);
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
- if (errmax > ERR_CONTR)
253
- hNext = SAFETY * h * errmax**PSGROW;
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 lineraly interpolated results and store them in dataframe
353
+ // compute dense output using Shampine-Reichelt continuous extension
354
+ const hStep = t - tPrev;
266
355
  while (timeDataframe < t) {
267
- const cLeft = (t - timeDataframe) / (t - tPrev);
268
- const cRight = 1.0 - cLeft;
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] = cRight * y[j] + cLeft * yPrev[j];
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