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
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript port of SUNDIALS CVODE v7.5.0 (https://github.com/LLNL/sundials)
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2025, Lawrence Livermore National Security, University of
|
|
5
|
+
* Maryland Baltimore County, and the SUNDIALS contributors.
|
|
6
|
+
* Copyright (c) 2013-2025, Lawrence Livermore National Security and
|
|
7
|
+
* Southern Methodist University.
|
|
8
|
+
* Copyright (c) 2002-2013, Lawrence Livermore National Security.
|
|
9
|
+
* Copyright (c) 2026 Datagrok.
|
|
10
|
+
*
|
|
11
|
+
* Licensed under the BSD-3-Clause License. See THIRD_PARTY_LICENSES
|
|
12
|
+
* for the full license text and provenance chain of the original code.
|
|
13
|
+
*/
|
|
14
|
+
// CVODE TypeScript port - Dense linear solver interface
|
|
15
|
+
// Translated from SUNDIALS cvode_ls.c
|
|
16
|
+
//
|
|
17
|
+
// Instead of SUNDIALS' SUNLinearSolver / SUNMatrix abstraction, we use
|
|
18
|
+
// direct Float64Array[] matrices and dgefa / dgesl from dense_linalg.ts.
|
|
19
|
+
import { CvLsMem, wrmsNorm, CV_SUCCESS, CV_FAIL_BAD_J, CVLS_MSBJ, CVLS_DGMAX } from './common';
|
|
20
|
+
import { dgefa, dgesl } from './dense_linalg';
|
|
21
|
+
/**
|
|
22
|
+
* cvodeSetLinearSolver - Initialize the dense linear solver.
|
|
23
|
+
* Sets up CvLsMem, allocates matrix, sets function pointers on CvodeMem.
|
|
24
|
+
*/
|
|
25
|
+
export function cvodeSetLinearSolver(mem) {
|
|
26
|
+
const N = mem.cv_N;
|
|
27
|
+
const lmem = new CvLsMem();
|
|
28
|
+
// Allocate dense matrix A (N x N, row-major)
|
|
29
|
+
lmem.A = new Array(N);
|
|
30
|
+
lmem.savedJ = new Array(N);
|
|
31
|
+
for (let i = 0; i < N; i++) {
|
|
32
|
+
lmem.A[i] = new Float64Array(N);
|
|
33
|
+
lmem.savedJ[i] = new Float64Array(N);
|
|
34
|
+
}
|
|
35
|
+
lmem.pivots = new Int32Array(N);
|
|
36
|
+
// Set defaults
|
|
37
|
+
lmem.jacDQ = true;
|
|
38
|
+
lmem.jacFn = null;
|
|
39
|
+
lmem.jbad = true;
|
|
40
|
+
lmem.nje = 0;
|
|
41
|
+
lmem.nfeDQ = 0;
|
|
42
|
+
lmem.nstlj = 0;
|
|
43
|
+
lmem.tnlj = 0;
|
|
44
|
+
lmem.msbj = CVLS_MSBJ;
|
|
45
|
+
lmem.dgmax_jbad = CVLS_DGMAX;
|
|
46
|
+
// Attach to CvodeMem
|
|
47
|
+
mem.cv_lmem = lmem;
|
|
48
|
+
mem.cv_linit = cvLsInitialize;
|
|
49
|
+
mem.cv_lsetup = cvLsSetup;
|
|
50
|
+
mem.cv_lsolve = cvLsSolve;
|
|
51
|
+
mem.cv_lfree = cvLsFree;
|
|
52
|
+
return CV_SUCCESS;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* cvodeSetJacFn - Set a user-supplied Jacobian function.
|
|
56
|
+
*/
|
|
57
|
+
export function cvodeSetJacFn(mem, jac) {
|
|
58
|
+
const lmem = mem.cv_lmem;
|
|
59
|
+
if (!lmem)
|
|
60
|
+
return -1;
|
|
61
|
+
if (jac) {
|
|
62
|
+
lmem.jacDQ = false;
|
|
63
|
+
lmem.jacFn = jac;
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
lmem.jacDQ = true;
|
|
67
|
+
lmem.jacFn = null;
|
|
68
|
+
}
|
|
69
|
+
return CV_SUCCESS;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* cvLsInitialize - Initialize linear solver counters.
|
|
73
|
+
*/
|
|
74
|
+
function cvLsInitialize(mem) {
|
|
75
|
+
const lmem = mem.cv_lmem;
|
|
76
|
+
lmem.nje = 0;
|
|
77
|
+
lmem.nfeDQ = 0;
|
|
78
|
+
lmem.nstlj = 0;
|
|
79
|
+
lmem.jbad = true;
|
|
80
|
+
return CV_SUCCESS;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* cvLsSetup - Compute Jacobian and form/factor the linear system matrix A = I - gamma*J.
|
|
84
|
+
*
|
|
85
|
+
* Heuristic for when to recompute Jacobian:
|
|
86
|
+
* - On first call (nstlj == 0)
|
|
87
|
+
* - If convfail is CV_FAIL_BAD_J (NLS flagged Jacobian as bad)
|
|
88
|
+
* - If enough steps since last eval (nst >= nstlj + msbj)
|
|
89
|
+
* - If gamma changed significantly (|gamrat - 1| > dgmax_jbad)
|
|
90
|
+
*/
|
|
91
|
+
function cvLsSetup(mem, convfail, ypred, fpred, jcurPtr, tmp1, tmp2, tmp3) {
|
|
92
|
+
const lmem = mem.cv_lmem;
|
|
93
|
+
const N = mem.cv_N;
|
|
94
|
+
let retval;
|
|
95
|
+
// Determine if Jacobian needs updating
|
|
96
|
+
const jbad = lmem.jbad;
|
|
97
|
+
let jok = !jbad;
|
|
98
|
+
if (!jbad) {
|
|
99
|
+
// Check gamma ratio
|
|
100
|
+
if (Math.abs(mem.cv_gamrat - 1.0) > lmem.dgmax_jbad)
|
|
101
|
+
jok = false;
|
|
102
|
+
// Check steps since last Jacobian
|
|
103
|
+
if (mem.cv_nst >= lmem.nstlj + lmem.msbj)
|
|
104
|
+
jok = false;
|
|
105
|
+
// Check convfail
|
|
106
|
+
if (convfail === CV_FAIL_BAD_J)
|
|
107
|
+
jok = false;
|
|
108
|
+
}
|
|
109
|
+
if (jok) {
|
|
110
|
+
// Reuse saved Jacobian, just form A = I - gamma*J
|
|
111
|
+
jcurPtr.value = false;
|
|
112
|
+
// Copy savedJ to A and form I - gamma*J
|
|
113
|
+
for (let i = 0; i < N; i++) {
|
|
114
|
+
for (let j = 0; j < N; j++)
|
|
115
|
+
lmem.A[i][j] = -mem.cv_gamma * lmem.savedJ[i][j];
|
|
116
|
+
lmem.A[i][i] += 1.0;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
// Recompute Jacobian
|
|
121
|
+
lmem.nje++;
|
|
122
|
+
lmem.nstlj = mem.cv_nst;
|
|
123
|
+
lmem.jbad = false;
|
|
124
|
+
jcurPtr.value = true;
|
|
125
|
+
// Evaluate Jacobian
|
|
126
|
+
if (lmem.jacDQ)
|
|
127
|
+
retval = cvLsDQJac(mem, mem.cv_tn, ypred, fpred, lmem.savedJ, tmp1, tmp2);
|
|
128
|
+
else
|
|
129
|
+
retval = lmem.jacFn(mem.cv_tn, ypred, fpred, lmem.savedJ, mem.cv_user_data);
|
|
130
|
+
if (retval < 0) {
|
|
131
|
+
lmem.jbad = true;
|
|
132
|
+
return -1;
|
|
133
|
+
}
|
|
134
|
+
if (retval > 0) {
|
|
135
|
+
lmem.jbad = true;
|
|
136
|
+
return 1;
|
|
137
|
+
}
|
|
138
|
+
// Form A = I - gamma*J
|
|
139
|
+
for (let i = 0; i < N; i++) {
|
|
140
|
+
for (let j = 0; j < N; j++)
|
|
141
|
+
lmem.A[i][j] = -mem.cv_gamma * lmem.savedJ[i][j];
|
|
142
|
+
lmem.A[i][i] += 1.0;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// Factor A using LU decomposition
|
|
146
|
+
const info = dgefa(lmem.A, N, lmem.pivots);
|
|
147
|
+
if (info !== 0) {
|
|
148
|
+
lmem.jbad = true;
|
|
149
|
+
return 1; // recoverable
|
|
150
|
+
}
|
|
151
|
+
return CV_SUCCESS;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* cvLsSolve - Solve the linear system A*x = b using LU factors.
|
|
155
|
+
*/
|
|
156
|
+
function cvLsSolve(mem, b, weight, ycur, fcur) {
|
|
157
|
+
const lmem = mem.cv_lmem;
|
|
158
|
+
const N = mem.cv_N;
|
|
159
|
+
dgesl(lmem.A, N, lmem.pivots, b);
|
|
160
|
+
// Apply gamma/gammap correction if gamma has changed since last setup
|
|
161
|
+
if (mem.cv_gamrat !== 1.0) {
|
|
162
|
+
const factor = 2.0 / (1.0 + mem.cv_gamrat);
|
|
163
|
+
for (let i = 0; i < N; i++)
|
|
164
|
+
b[i] *= factor;
|
|
165
|
+
}
|
|
166
|
+
return CV_SUCCESS;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* cvLsDQJac - Compute difference-quotient Jacobian approximation.
|
|
170
|
+
*
|
|
171
|
+
* For each column j:
|
|
172
|
+
* sigma_j = max(|y_j|, 1/ewt_j) * sqrt(uround)
|
|
173
|
+
* J[:,j] = (f(t, y + sigma_j*e_j) - f(t, y)) / sigma_j
|
|
174
|
+
*/
|
|
175
|
+
function cvLsDQJac(mem, t, y, fy, J, tmp1, tmp2) {
|
|
176
|
+
const N = mem.cv_N;
|
|
177
|
+
const lmem = mem.cv_lmem;
|
|
178
|
+
const uround = 2.2204460492503131e-16;
|
|
179
|
+
const srur = Math.sqrt(uround);
|
|
180
|
+
const fnorm_val = wrmsNorm(N, fy, mem.cv_ewt);
|
|
181
|
+
const minInc = (fnorm_val !== 0.0) ? (1000.0 * Math.abs(mem.cv_h) * uround * N * fnorm_val) : 1.0;
|
|
182
|
+
// Use tmp1 as perturbed y, tmp2 as perturbed f
|
|
183
|
+
for (let j = 0; j < N; j++) {
|
|
184
|
+
const yjsaved = y[j];
|
|
185
|
+
let inc = Math.max(srur * Math.abs(yjsaved), minInc / mem.cv_ewt[j]);
|
|
186
|
+
// Ensure inc has same sign (positive since we want to increase)
|
|
187
|
+
// Perturb y[j]
|
|
188
|
+
tmp1.set(y);
|
|
189
|
+
tmp1[j] = yjsaved + inc;
|
|
190
|
+
inc = tmp1[j] - yjsaved; // exact increment after rounding
|
|
191
|
+
// Evaluate f(t, y + inc*e_j)
|
|
192
|
+
const retval = mem.cv_f(t, tmp1, tmp2, mem.cv_user_data);
|
|
193
|
+
lmem.nfeDQ++;
|
|
194
|
+
mem.cv_nfe++;
|
|
195
|
+
if (retval !== 0)
|
|
196
|
+
return retval;
|
|
197
|
+
// Compute column j of Jacobian: (f_perturbed - f) / inc
|
|
198
|
+
const inc_inv = 1.0 / inc;
|
|
199
|
+
for (let i = 0; i < N; i++)
|
|
200
|
+
J[i][j] = (tmp2[i] - fy[i]) * inc_inv;
|
|
201
|
+
}
|
|
202
|
+
return CV_SUCCESS;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* cvLsFree - Free linear solver memory (no-op in TS, GC handles it).
|
|
206
|
+
*/
|
|
207
|
+
function cvLsFree(mem) {
|
|
208
|
+
mem.cv_lmem = null;
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=cvode_ls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cvode_ls.js","sourceRoot":"","sources":["cvode_ls.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript port of SUNDIALS CVODE v7.5.0 (https://github.com/LLNL/sundials)
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2025, Lawrence Livermore National Security, University of
|
|
5
|
+
* Maryland Baltimore County, and the SUNDIALS contributors.
|
|
6
|
+
* Copyright (c) 2013-2025, Lawrence Livermore National Security and
|
|
7
|
+
* Southern Methodist University.
|
|
8
|
+
* Copyright (c) 2002-2013, Lawrence Livermore National Security.
|
|
9
|
+
* Copyright (c) 2026 Datagrok.
|
|
10
|
+
*
|
|
11
|
+
* Licensed under the BSD-3-Clause License. See THIRD_PARTY_LICENSES
|
|
12
|
+
* for the full license text and provenance chain of the original code.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
// CVODE TypeScript port - Dense linear solver interface
|
|
16
|
+
// Translated from SUNDIALS cvode_ls.c
|
|
17
|
+
//
|
|
18
|
+
// Instead of SUNDIALS' SUNLinearSolver / SUNMatrix abstraction, we use
|
|
19
|
+
// direct Float64Array[] matrices and dgefa / dgesl from dense_linalg.ts.
|
|
20
|
+
|
|
21
|
+
import {CvodeMem, CvLsMem, CvodeJacFn, wrmsNorm,
|
|
22
|
+
CV_SUCCESS, CV_RHSFUNC_FAIL, RHSFUNC_RECVR,
|
|
23
|
+
CV_NO_FAILURES, CV_FAIL_BAD_J, CV_FAIL_OTHER,
|
|
24
|
+
CVLS_MSBJ, CVLS_DGMAX, ONEPSM} from './common';
|
|
25
|
+
import {dgefa, dgesl} from './dense_linalg';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* cvodeSetLinearSolver - Initialize the dense linear solver.
|
|
29
|
+
* Sets up CvLsMem, allocates matrix, sets function pointers on CvodeMem.
|
|
30
|
+
*/
|
|
31
|
+
export function cvodeSetLinearSolver(mem: CvodeMem): number {
|
|
32
|
+
const N = mem.cv_N;
|
|
33
|
+
const lmem = new CvLsMem();
|
|
34
|
+
|
|
35
|
+
// Allocate dense matrix A (N x N, row-major)
|
|
36
|
+
lmem.A = new Array(N);
|
|
37
|
+
lmem.savedJ = new Array(N);
|
|
38
|
+
for (let i = 0; i < N; i++) {
|
|
39
|
+
lmem.A[i] = new Float64Array(N);
|
|
40
|
+
lmem.savedJ[i] = new Float64Array(N);
|
|
41
|
+
}
|
|
42
|
+
lmem.pivots = new Int32Array(N);
|
|
43
|
+
|
|
44
|
+
// Set defaults
|
|
45
|
+
lmem.jacDQ = true;
|
|
46
|
+
lmem.jacFn = null;
|
|
47
|
+
lmem.jbad = true;
|
|
48
|
+
lmem.nje = 0;
|
|
49
|
+
lmem.nfeDQ = 0;
|
|
50
|
+
lmem.nstlj = 0;
|
|
51
|
+
lmem.tnlj = 0;
|
|
52
|
+
lmem.msbj = CVLS_MSBJ;
|
|
53
|
+
lmem.dgmax_jbad = CVLS_DGMAX;
|
|
54
|
+
|
|
55
|
+
// Attach to CvodeMem
|
|
56
|
+
mem.cv_lmem = lmem;
|
|
57
|
+
mem.cv_linit = cvLsInitialize;
|
|
58
|
+
mem.cv_lsetup = cvLsSetup;
|
|
59
|
+
mem.cv_lsolve = cvLsSolve;
|
|
60
|
+
mem.cv_lfree = cvLsFree;
|
|
61
|
+
|
|
62
|
+
return CV_SUCCESS;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* cvodeSetJacFn - Set a user-supplied Jacobian function.
|
|
67
|
+
*/
|
|
68
|
+
export function cvodeSetJacFn(mem: CvodeMem, jac: CvodeJacFn | null): number {
|
|
69
|
+
const lmem = mem.cv_lmem;
|
|
70
|
+
if (!lmem) return -1;
|
|
71
|
+
|
|
72
|
+
if (jac) {
|
|
73
|
+
lmem.jacDQ = false;
|
|
74
|
+
lmem.jacFn = jac;
|
|
75
|
+
} else {
|
|
76
|
+
lmem.jacDQ = true;
|
|
77
|
+
lmem.jacFn = null;
|
|
78
|
+
}
|
|
79
|
+
return CV_SUCCESS;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* cvLsInitialize - Initialize linear solver counters.
|
|
84
|
+
*/
|
|
85
|
+
function cvLsInitialize(mem: CvodeMem): number {
|
|
86
|
+
const lmem = mem.cv_lmem!;
|
|
87
|
+
lmem.nje = 0;
|
|
88
|
+
lmem.nfeDQ = 0;
|
|
89
|
+
lmem.nstlj = 0;
|
|
90
|
+
lmem.jbad = true;
|
|
91
|
+
return CV_SUCCESS;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* cvLsSetup - Compute Jacobian and form/factor the linear system matrix A = I - gamma*J.
|
|
96
|
+
*
|
|
97
|
+
* Heuristic for when to recompute Jacobian:
|
|
98
|
+
* - On first call (nstlj == 0)
|
|
99
|
+
* - If convfail is CV_FAIL_BAD_J (NLS flagged Jacobian as bad)
|
|
100
|
+
* - If enough steps since last eval (nst >= nstlj + msbj)
|
|
101
|
+
* - If gamma changed significantly (|gamrat - 1| > dgmax_jbad)
|
|
102
|
+
*/
|
|
103
|
+
function cvLsSetup(mem: CvodeMem, convfail: number, ypred: Float64Array,
|
|
104
|
+
fpred: Float64Array, jcurPtr: { value: boolean },
|
|
105
|
+
tmp1: Float64Array, tmp2: Float64Array,
|
|
106
|
+
tmp3: Float64Array): number {
|
|
107
|
+
const lmem = mem.cv_lmem!;
|
|
108
|
+
const N = mem.cv_N;
|
|
109
|
+
let retval: number;
|
|
110
|
+
|
|
111
|
+
// Determine if Jacobian needs updating
|
|
112
|
+
const jbad = lmem.jbad;
|
|
113
|
+
let jok = !jbad;
|
|
114
|
+
|
|
115
|
+
if (!jbad) {
|
|
116
|
+
// Check gamma ratio
|
|
117
|
+
if (Math.abs(mem.cv_gamrat - 1.0) > lmem.dgmax_jbad)
|
|
118
|
+
jok = false;
|
|
119
|
+
|
|
120
|
+
// Check steps since last Jacobian
|
|
121
|
+
if (mem.cv_nst >= lmem.nstlj + lmem.msbj)
|
|
122
|
+
jok = false;
|
|
123
|
+
|
|
124
|
+
// Check convfail
|
|
125
|
+
if (convfail === CV_FAIL_BAD_J)
|
|
126
|
+
jok = false;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (jok) {
|
|
130
|
+
// Reuse saved Jacobian, just form A = I - gamma*J
|
|
131
|
+
jcurPtr.value = false;
|
|
132
|
+
|
|
133
|
+
// Copy savedJ to A and form I - gamma*J
|
|
134
|
+
for (let i = 0; i < N; i++) {
|
|
135
|
+
for (let j = 0; j < N; j++)
|
|
136
|
+
lmem.A[i][j] = -mem.cv_gamma * lmem.savedJ[i][j];
|
|
137
|
+
|
|
138
|
+
lmem.A[i][i] += 1.0;
|
|
139
|
+
}
|
|
140
|
+
} else {
|
|
141
|
+
// Recompute Jacobian
|
|
142
|
+
lmem.nje++;
|
|
143
|
+
lmem.nstlj = mem.cv_nst;
|
|
144
|
+
lmem.jbad = false;
|
|
145
|
+
jcurPtr.value = true;
|
|
146
|
+
|
|
147
|
+
// Evaluate Jacobian
|
|
148
|
+
if (lmem.jacDQ)
|
|
149
|
+
retval = cvLsDQJac(mem, mem.cv_tn, ypred, fpred, lmem.savedJ, tmp1, tmp2);
|
|
150
|
+
else
|
|
151
|
+
retval = lmem.jacFn!(mem.cv_tn, ypred, fpred, lmem.savedJ, mem.cv_user_data);
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
if (retval < 0) {
|
|
155
|
+
lmem.jbad = true;
|
|
156
|
+
return -1;
|
|
157
|
+
}
|
|
158
|
+
if (retval > 0) {
|
|
159
|
+
lmem.jbad = true;
|
|
160
|
+
return 1;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Form A = I - gamma*J
|
|
164
|
+
for (let i = 0; i < N; i++) {
|
|
165
|
+
for (let j = 0; j < N; j++)
|
|
166
|
+
lmem.A[i][j] = -mem.cv_gamma * lmem.savedJ[i][j];
|
|
167
|
+
|
|
168
|
+
lmem.A[i][i] += 1.0;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Factor A using LU decomposition
|
|
173
|
+
const info = dgefa(lmem.A, N, lmem.pivots);
|
|
174
|
+
if (info !== 0) {
|
|
175
|
+
lmem.jbad = true;
|
|
176
|
+
return 1; // recoverable
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return CV_SUCCESS;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* cvLsSolve - Solve the linear system A*x = b using LU factors.
|
|
184
|
+
*/
|
|
185
|
+
function cvLsSolve(mem: CvodeMem, b: Float64Array, weight: Float64Array,
|
|
186
|
+
ycur: Float64Array, fcur: Float64Array): number {
|
|
187
|
+
const lmem = mem.cv_lmem!;
|
|
188
|
+
const N = mem.cv_N;
|
|
189
|
+
|
|
190
|
+
dgesl(lmem.A, N, lmem.pivots, b);
|
|
191
|
+
|
|
192
|
+
// Apply gamma/gammap correction if gamma has changed since last setup
|
|
193
|
+
if (mem.cv_gamrat !== 1.0) {
|
|
194
|
+
const factor = 2.0 / (1.0 + mem.cv_gamrat);
|
|
195
|
+
for (let i = 0; i < N; i++)
|
|
196
|
+
b[i] *= factor;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return CV_SUCCESS;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* cvLsDQJac - Compute difference-quotient Jacobian approximation.
|
|
204
|
+
*
|
|
205
|
+
* For each column j:
|
|
206
|
+
* sigma_j = max(|y_j|, 1/ewt_j) * sqrt(uround)
|
|
207
|
+
* J[:,j] = (f(t, y + sigma_j*e_j) - f(t, y)) / sigma_j
|
|
208
|
+
*/
|
|
209
|
+
function cvLsDQJac(mem: CvodeMem, t: number, y: Float64Array, fy: Float64Array,
|
|
210
|
+
J: Float64Array[], tmp1: Float64Array, tmp2: Float64Array): number {
|
|
211
|
+
const N = mem.cv_N;
|
|
212
|
+
const lmem = mem.cv_lmem!;
|
|
213
|
+
const uround = 2.2204460492503131e-16;
|
|
214
|
+
const srur = Math.sqrt(uround);
|
|
215
|
+
const fnorm_val = wrmsNorm(N, fy, mem.cv_ewt);
|
|
216
|
+
const minInc = (fnorm_val !== 0.0) ? (1000.0 * Math.abs(mem.cv_h) * uround * N * fnorm_val) : 1.0;
|
|
217
|
+
|
|
218
|
+
// Use tmp1 as perturbed y, tmp2 as perturbed f
|
|
219
|
+
for (let j = 0; j < N; j++) {
|
|
220
|
+
const yjsaved = y[j];
|
|
221
|
+
let inc = Math.max(srur * Math.abs(yjsaved), minInc / mem.cv_ewt[j]);
|
|
222
|
+
// Ensure inc has same sign (positive since we want to increase)
|
|
223
|
+
|
|
224
|
+
// Perturb y[j]
|
|
225
|
+
tmp1.set(y);
|
|
226
|
+
tmp1[j] = yjsaved + inc;
|
|
227
|
+
inc = tmp1[j] - yjsaved; // exact increment after rounding
|
|
228
|
+
|
|
229
|
+
// Evaluate f(t, y + inc*e_j)
|
|
230
|
+
const retval = mem.cv_f!(t, tmp1, tmp2, mem.cv_user_data);
|
|
231
|
+
lmem.nfeDQ++;
|
|
232
|
+
mem.cv_nfe++;
|
|
233
|
+
if (retval !== 0) return retval;
|
|
234
|
+
|
|
235
|
+
// Compute column j of Jacobian: (f_perturbed - f) / inc
|
|
236
|
+
const inc_inv = 1.0 / inc;
|
|
237
|
+
for (let i = 0; i < N; i++)
|
|
238
|
+
J[i][j] = (tmp2[i] - fy[i]) * inc_inv;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return CV_SUCCESS;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* cvLsFree - Free linear solver memory (no-op in TS, GC handles it).
|
|
246
|
+
*/
|
|
247
|
+
function cvLsFree(mem: CvodeMem): void {
|
|
248
|
+
mem.cv_lmem = null;
|
|
249
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript port of SUNDIALS CVODE v7.5.0 (https://github.com/LLNL/sundials)
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2025, Lawrence Livermore National Security, University of
|
|
5
|
+
* Maryland Baltimore County, and the SUNDIALS contributors.
|
|
6
|
+
* Copyright (c) 2013-2025, Lawrence Livermore National Security and
|
|
7
|
+
* Southern Methodist University.
|
|
8
|
+
* Copyright (c) 2002-2013, Lawrence Livermore National Security.
|
|
9
|
+
* Copyright (c) 2026 Datagrok.
|
|
10
|
+
*
|
|
11
|
+
* Licensed under the BSD-3-Clause License. See THIRD_PARTY_LICENSES
|
|
12
|
+
* for the full license text and provenance chain of the original code.
|
|
13
|
+
*/
|
|
14
|
+
import { wrmsNorm, vLinearSum, vScale, vConst, CV_SUCCESS, CV_BDF, CV_RHSFUNC_FAIL, CV_LSETUP_FAIL, CV_LSOLVE_FAIL, RHSFUNC_RECVR, SUN_NLS_CONV_RECVR, SUN_NLS_CONTINUE, CV_NO_FAILURES, CV_FAIL_OTHER, FIRST_CALL, PREV_CONV_FAIL, PREV_ERR_FAIL, NLS_MAXCOR, CRDOWN, RDIV } from './common';
|
|
15
|
+
/**
|
|
16
|
+
* cvNls - Solve the nonlinear system for one step.
|
|
17
|
+
*
|
|
18
|
+
* For BDF: Newton iteration solving G(ycor) = 0 where
|
|
19
|
+
* G(ycor) = rl1*zn[1] + ycor - gamma*f(tn, zn[0]+ycor)
|
|
20
|
+
* The Newton update is: (I - gamma*J) * delta = -G(ycor)
|
|
21
|
+
*
|
|
22
|
+
* For Adams: Fixed-point iteration
|
|
23
|
+
* ycor_new = h * rl1 * f(tn, zn[0]+ycor) - rl1*zn[1]
|
|
24
|
+
*/
|
|
25
|
+
export function cvNls(mem, nflag) {
|
|
26
|
+
const N = mem.cv_N;
|
|
27
|
+
let callSetup;
|
|
28
|
+
// Decide whether to call linear solver setup
|
|
29
|
+
if (mem.cv_lsetup) {
|
|
30
|
+
mem.convfail = (nflag === FIRST_CALL || nflag === PREV_ERR_FAIL) ?
|
|
31
|
+
CV_NO_FAILURES :
|
|
32
|
+
CV_FAIL_OTHER;
|
|
33
|
+
callSetup = (nflag === PREV_CONV_FAIL) || (nflag === PREV_ERR_FAIL) ||
|
|
34
|
+
(mem.cv_nst === 0) || (mem.first_step_after_resize) ||
|
|
35
|
+
(mem.cv_nst >= mem.cv_nstlp + mem.cv_msbp) ||
|
|
36
|
+
(Math.abs(mem.cv_gamrat - 1.0) > mem.cv_dgmax_lsetup);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
mem.cv_crate = 1.0;
|
|
40
|
+
callSetup = false;
|
|
41
|
+
}
|
|
42
|
+
// Initial guess for correction: acor = 0
|
|
43
|
+
vConst(0.0, mem.cv_acor, N);
|
|
44
|
+
// Set acnrmcur to false
|
|
45
|
+
mem.cv_acnrmcur = false;
|
|
46
|
+
// Dispatch to Newton or fixed-point
|
|
47
|
+
let flag;
|
|
48
|
+
if (mem.cv_lmm === CV_BDF)
|
|
49
|
+
flag = cvNewtonIteration(mem, callSetup);
|
|
50
|
+
else
|
|
51
|
+
flag = cvFixedPointIteration(mem);
|
|
52
|
+
if (flag !== CV_SUCCESS)
|
|
53
|
+
return flag;
|
|
54
|
+
// Solve successful - update y = zn[0] + acor
|
|
55
|
+
vLinearSum(1.0, mem.cv_zn[0], 1.0, mem.cv_acor, mem.cv_y, N);
|
|
56
|
+
// Compute acnrm if not already done
|
|
57
|
+
if (!mem.cv_acnrmcur)
|
|
58
|
+
mem.cv_acnrm = wrmsNorm(N, mem.cv_acor, mem.cv_ewt);
|
|
59
|
+
// Update Jacobian status
|
|
60
|
+
mem.cv_jcur = false;
|
|
61
|
+
return CV_SUCCESS;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Newton iteration for BDF method.
|
|
65
|
+
* Solves: (I - gamma*J) * delta = -G(ycor)
|
|
66
|
+
* where G(ycor) = rl1*zn[1] + ycor - gamma*f(tn, zn[0]+ycor)
|
|
67
|
+
*/
|
|
68
|
+
function cvNewtonIteration(mem, callSetup) {
|
|
69
|
+
const N = mem.cv_N;
|
|
70
|
+
let retval;
|
|
71
|
+
// Call linear solver setup if needed
|
|
72
|
+
if (callSetup && mem.cv_lsetup) {
|
|
73
|
+
// y = zn[0] + acor (current approximation)
|
|
74
|
+
vLinearSum(1.0, mem.cv_zn[0], 1.0, mem.cv_acor, mem.cv_y, N);
|
|
75
|
+
// Evaluate f at current approximation
|
|
76
|
+
retval = mem.cv_f(mem.cv_tn, mem.cv_y, mem.cv_ftemp, mem.cv_user_data);
|
|
77
|
+
mem.cv_nfe++;
|
|
78
|
+
if (retval < 0)
|
|
79
|
+
return CV_RHSFUNC_FAIL;
|
|
80
|
+
if (retval > 0)
|
|
81
|
+
return RHSFUNC_RECVR;
|
|
82
|
+
// Call lsetup
|
|
83
|
+
const jcurPtr = { value: false };
|
|
84
|
+
retval = mem.cv_lsetup(mem, mem.convfail, mem.cv_y, mem.cv_ftemp, jcurPtr, mem.cv_vtemp1, mem.cv_vtemp2, mem.cv_vtemp3);
|
|
85
|
+
mem.cv_nsetups++;
|
|
86
|
+
mem.cv_jcur = jcurPtr.value;
|
|
87
|
+
mem.cv_gamrat = 1.0;
|
|
88
|
+
mem.cv_gammap = mem.cv_gamma;
|
|
89
|
+
mem.cv_crate = 1.0;
|
|
90
|
+
mem.cv_nstlp = mem.cv_nst;
|
|
91
|
+
if (retval < 0)
|
|
92
|
+
return CV_LSETUP_FAIL;
|
|
93
|
+
if (retval > 0)
|
|
94
|
+
return SUN_NLS_CONV_RECVR;
|
|
95
|
+
}
|
|
96
|
+
// Newton iteration loop
|
|
97
|
+
for (let m = 0; m < NLS_MAXCOR; m++) {
|
|
98
|
+
mem.cv_nni++;
|
|
99
|
+
// y = zn[0] + acor
|
|
100
|
+
vLinearSum(1.0, mem.cv_zn[0], 1.0, mem.cv_acor, mem.cv_y, N);
|
|
101
|
+
// Evaluate f(tn, y)
|
|
102
|
+
retval = mem.cv_f(mem.cv_tn, mem.cv_y, mem.cv_ftemp, mem.cv_user_data);
|
|
103
|
+
mem.cv_nfe++;
|
|
104
|
+
if (retval < 0)
|
|
105
|
+
return CV_RHSFUNC_FAIL;
|
|
106
|
+
if (retval > 0)
|
|
107
|
+
return RHSFUNC_RECVR;
|
|
108
|
+
// Compute residual: b = rl1*zn[1] + acor - gamma*ftemp
|
|
109
|
+
// Store in tempv as the RHS for the linear solve
|
|
110
|
+
const b = mem.cv_tempv;
|
|
111
|
+
for (let i = 0; i < N; i++)
|
|
112
|
+
b[i] = mem.cv_rl1 * mem.cv_zn[1][i] + mem.cv_acor[i] - mem.cv_gamma * mem.cv_ftemp[i];
|
|
113
|
+
// Solve: (I - gamma*J) * delta = -b, so pass b (which is G, so we negate)
|
|
114
|
+
// Actually the convention is lsolve solves (I-gamma*J)*x = b
|
|
115
|
+
// and b here is -G so we negate
|
|
116
|
+
for (let i = 0; i < N; i++)
|
|
117
|
+
b[i] = -b[i];
|
|
118
|
+
retval = mem.cv_lsolve(mem, b, mem.cv_ewt, mem.cv_y, mem.cv_ftemp);
|
|
119
|
+
if (retval < 0)
|
|
120
|
+
return CV_LSOLVE_FAIL;
|
|
121
|
+
if (retval > 0)
|
|
122
|
+
return SUN_NLS_CONV_RECVR;
|
|
123
|
+
// Update acor += delta (delta is in b after solve)
|
|
124
|
+
for (let i = 0; i < N; i++)
|
|
125
|
+
mem.cv_acor[i] += b[i];
|
|
126
|
+
// Convergence test
|
|
127
|
+
const del = wrmsNorm(N, b, mem.cv_ewt);
|
|
128
|
+
const convTestResult = cvNlsConvTest(mem, del, m, mem.cv_tq[4]);
|
|
129
|
+
if (convTestResult === CV_SUCCESS)
|
|
130
|
+
return CV_SUCCESS;
|
|
131
|
+
if (convTestResult === SUN_NLS_CONV_RECVR) {
|
|
132
|
+
mem.cv_nnf++;
|
|
133
|
+
return SUN_NLS_CONV_RECVR;
|
|
134
|
+
}
|
|
135
|
+
// SUN_NLS_CONTINUE: continue iterating
|
|
136
|
+
}
|
|
137
|
+
// Max iterations reached without convergence
|
|
138
|
+
mem.cv_nnf++;
|
|
139
|
+
return SUN_NLS_CONV_RECVR;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Fixed-point iteration for Adams method.
|
|
143
|
+
* ycor = rl1 * (h * f(tn, zn[0]+ycor) - zn[1])
|
|
144
|
+
*/
|
|
145
|
+
function cvFixedPointIteration(mem) {
|
|
146
|
+
const N = mem.cv_N;
|
|
147
|
+
let retval;
|
|
148
|
+
for (let m = 0; m < NLS_MAXCOR; m++) {
|
|
149
|
+
mem.cv_nni++;
|
|
150
|
+
// y = zn[0] + acor
|
|
151
|
+
vLinearSum(1.0, mem.cv_zn[0], 1.0, mem.cv_acor, mem.cv_y, N);
|
|
152
|
+
// Evaluate f(tn, y) -> store in tempv
|
|
153
|
+
retval = mem.cv_f(mem.cv_tn, mem.cv_y, mem.cv_tempv, mem.cv_user_data);
|
|
154
|
+
mem.cv_nfe++;
|
|
155
|
+
if (retval < 0)
|
|
156
|
+
return CV_RHSFUNC_FAIL;
|
|
157
|
+
if (retval > 0)
|
|
158
|
+
return RHSFUNC_RECVR;
|
|
159
|
+
// Compute new ycor: rl1 * (h * f - zn[1])
|
|
160
|
+
// First: tempv = h * tempv - zn[1]
|
|
161
|
+
for (let i = 0; i < N; i++)
|
|
162
|
+
mem.cv_tempv[i] = mem.cv_h * mem.cv_tempv[i] - mem.cv_zn[1][i];
|
|
163
|
+
// Then scale by rl1
|
|
164
|
+
const newAcor = mem.cv_vtemp1;
|
|
165
|
+
vScale(mem.cv_rl1, mem.cv_tempv, newAcor, N);
|
|
166
|
+
// Compute delta = newAcor - acor
|
|
167
|
+
const delta = mem.cv_tempv;
|
|
168
|
+
for (let i = 0; i < N; i++)
|
|
169
|
+
delta[i] = newAcor[i] - mem.cv_acor[i];
|
|
170
|
+
// Update acor
|
|
171
|
+
for (let i = 0; i < N; i++)
|
|
172
|
+
mem.cv_acor[i] = newAcor[i];
|
|
173
|
+
// Convergence test
|
|
174
|
+
const del = wrmsNorm(N, delta, mem.cv_ewt);
|
|
175
|
+
const convTestResult = cvNlsConvTest(mem, del, m, mem.cv_tq[4]);
|
|
176
|
+
if (convTestResult === CV_SUCCESS)
|
|
177
|
+
return CV_SUCCESS;
|
|
178
|
+
if (convTestResult === SUN_NLS_CONV_RECVR) {
|
|
179
|
+
mem.cv_nnf++;
|
|
180
|
+
return SUN_NLS_CONV_RECVR;
|
|
181
|
+
}
|
|
182
|
+
// SUN_NLS_CONTINUE: continue iterating
|
|
183
|
+
}
|
|
184
|
+
// Max iterations reached
|
|
185
|
+
mem.cv_nnf++;
|
|
186
|
+
return SUN_NLS_CONV_RECVR;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* cvNlsConvTest - Test for convergence of the nonlinear iteration.
|
|
190
|
+
*
|
|
191
|
+
* del: WRMS norm of the current update
|
|
192
|
+
* m: iteration count (0-based)
|
|
193
|
+
* tol: tolerance (tq[4])
|
|
194
|
+
*
|
|
195
|
+
* Returns: CV_SUCCESS if converged, SUN_NLS_CONV_RECVR if diverging,
|
|
196
|
+
* SUN_NLS_CONTINUE if not yet converged
|
|
197
|
+
*/
|
|
198
|
+
function cvNlsConvTest(mem, del, m, tol) {
|
|
199
|
+
// Update convergence rate estimate
|
|
200
|
+
if (m > 0)
|
|
201
|
+
mem.cv_crate = Math.max(CRDOWN * mem.cv_crate, del / mem.cv_delp);
|
|
202
|
+
// Test for convergence
|
|
203
|
+
const dcon = del * Math.min(1.0, mem.cv_crate) / tol;
|
|
204
|
+
if (dcon <= 1.0) {
|
|
205
|
+
// Converged
|
|
206
|
+
if (m === 0)
|
|
207
|
+
mem.cv_acnrm = del;
|
|
208
|
+
else
|
|
209
|
+
mem.cv_acnrm = wrmsNorm(mem.cv_N, mem.cv_acor, mem.cv_ewt);
|
|
210
|
+
mem.cv_acnrmcur = true;
|
|
211
|
+
return CV_SUCCESS;
|
|
212
|
+
}
|
|
213
|
+
// Check for divergence
|
|
214
|
+
if (m >= 1 && del > RDIV * mem.cv_delp)
|
|
215
|
+
return SUN_NLS_CONV_RECVR;
|
|
216
|
+
// Save del and continue
|
|
217
|
+
mem.cv_delp = del;
|
|
218
|
+
return SUN_NLS_CONTINUE;
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=cvode_nls.js.map
|