diff-grok 1.1.0 → 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/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 +10 -4
- package/LICENSE +1 -1
- package/README.MD +41 -23
- package/THIRD_PARTY_LICENSES +135 -0
- package/docs/.nojekyll +1 -0
- package/docs/assets/hierarchy.js +1 -0
- package/docs/assets/highlight.css +99 -0
- package/docs/assets/icons.js +18 -0
- package/docs/assets/icons.svg +1 -0
- package/docs/assets/main.js +60 -0
- package/docs/assets/navigation.js +1 -0
- package/docs/assets/search.js +1 -0
- package/docs/assets/style.css +1633 -0
- package/docs/classes/BasicModelPipelineCreator.html +10 -0
- package/docs/classes/Callback.html +7 -0
- package/docs/classes/CyclicModelPipelineCreator.html +10 -0
- package/docs/classes/IterCheckerCallback.html +8 -0
- package/docs/classes/PipelineCreator.html +6 -0
- package/docs/classes/TimeCheckerCallback.html +8 -0
- package/docs/classes/UpdatesModelPipelineCreator.html +10 -0
- package/docs/functions/ab4.html +8 -0
- package/docs/functions/ab5.html +8 -0
- package/docs/functions/applyPipeline.html +9 -0
- package/docs/functions/getCallback.html +3 -0
- package/docs/functions/getIVP.html +6 -0
- package/docs/functions/getInputVector.html +2 -0
- package/docs/functions/getIvp2WebWorker.html +6 -0
- package/docs/functions/getJScode.html +6 -0
- package/docs/functions/getOutputNames.html +4 -0
- package/docs/functions/getPipelineCreator.html +7 -0
- package/docs/functions/lsoda.html +8 -0
- package/docs/functions/mrt.html +11 -0
- package/docs/functions/printE5.html +76 -0
- package/docs/functions/printHires.html +76 -0
- package/docs/functions/printOrego.html +66 -0
- package/docs/functions/printPollution.html +163 -0
- package/docs/functions/printRobertson.html +60 -0
- package/docs/functions/printVdpol.html +66 -0
- 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 +8 -0
- package/docs/functions/ros3prw.html +8 -0
- package/docs/functions/solveIvp.html +5 -0
- package/docs/hierarchy.html +1 -0
- package/docs/index.html +768 -0
- package/docs/media/CONTRIBUTING.md +74 -0
- 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/POLL.png +0 -0
- package/docs/media/ROBER.png +0 -0
- package/docs/media/VDP0L.png +0 -0
- package/docs/media/VDPOL.png +0 -0
- package/docs/media/acid-prod.gif +0 -0
- package/docs/media/basic-use.js +40 -0
- package/docs/media/basic-use.js.map +1 -0
- package/docs/media/basic-use.ts +44 -0
- package/docs/media/check-methods.js +59 -0
- package/docs/media/check-methods.js.map +1 -0
- package/docs/media/check-methods.ts +81 -0
- package/docs/media/corr-probs.js +132 -0
- package/docs/media/corr-probs.js.map +1 -0
- package/docs/media/corr-probs.ts +155 -0
- package/docs/media/cyclic-model.js +102 -0
- package/docs/media/cyclic-model.js.map +1 -0
- package/docs/media/cyclic-model.ts +112 -0
- package/docs/media/e5.js +36 -0
- package/docs/media/e5.js.map +1 -0
- package/docs/media/e5.ts +36 -0
- package/docs/media/hires.js +39 -0
- package/docs/media/hires.js.map +1 -0
- package/docs/media/hires.ts +40 -0
- package/docs/media/model-updates.js +112 -0
- package/docs/media/model-updates.js.map +1 -0
- package/docs/media/model-updates.ts +122 -0
- package/docs/media/orego.js +24 -0
- package/docs/media/orego.js.map +1 -0
- package/docs/media/orego.ts +25 -0
- package/docs/media/pipeline-use.js +87 -0
- package/docs/media/pipeline-use.js.map +1 -0
- package/docs/media/pipeline-use.ts +98 -0
- package/docs/media/pollution.js +132 -0
- package/docs/media/pollution.js.map +1 -0
- package/docs/media/pollution.ts +133 -0
- package/docs/media/print-benchmark.js +581 -0
- package/docs/media/print-benchmark.js.map +1 -0
- package/docs/media/print-benchmark.ts +594 -0
- package/docs/media/robertson.js +19 -0
- package/docs/media/robertson.js.map +1 -0
- package/docs/media/robertson.ts +19 -0
- package/docs/media/scripting.js +30 -0
- package/docs/media/scripting.js.map +1 -0
- package/docs/media/scripting.ts +35 -0
- package/docs/media/vdpol.js +17 -0
- package/docs/media/vdpol.js.map +1 -0
- package/docs/media/vdpol.ts +17 -0
- package/docs/modules.html +1 -0
- package/docs/types/Arg.html +12 -0
- package/docs/types/DifEqs.html +8 -0
- package/docs/types/Func.html +7 -0
- package/docs/types/IVP.html +40 -0
- package/docs/types/IVP2WebWorker.html +12 -0
- package/docs/types/Input.html +8 -0
- package/docs/types/Loop.html +7 -0
- package/docs/types/ODEs.html +31 -0
- package/docs/types/Output.html +6 -0
- package/docs/types/Pipeline.html +6 -0
- package/docs/types/SolverOptions.html +8 -0
- package/docs/types/Update.html +9 -0
- package/docs/types/Wrapper.html +8 -0
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/index.ts +1 -1
- 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/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 +1 -0
- package/src/solver-tools/index.js.map +1 -1
- package/src/solver-tools/index.ts +1 -0
- package/src/solver-tools/lsoda/blas.js +11 -0
- package/src/solver-tools/lsoda/blas.js.map +1 -1
- package/src/solver-tools/lsoda/blas.ts +12 -0
- package/src/solver-tools/lsoda/cfode.js +11 -0
- package/src/solver-tools/lsoda/cfode.js.map +1 -1
- package/src/solver-tools/lsoda/cfode.ts +12 -0
- package/src/solver-tools/lsoda/corfailure.js +11 -0
- package/src/solver-tools/lsoda/corfailure.js.map +1 -1
- package/src/solver-tools/lsoda/corfailure.ts +12 -0
- package/src/solver-tools/lsoda/correction.js +11 -0
- package/src/solver-tools/lsoda/correction.js.map +1 -1
- package/src/solver-tools/lsoda/correction.ts +12 -0
- package/src/solver-tools/lsoda/dense.js +11 -0
- package/src/solver-tools/lsoda/dense.js.map +1 -1
- package/src/solver-tools/lsoda/dense.ts +12 -0
- package/src/solver-tools/lsoda/index.js +11 -0
- package/src/solver-tools/lsoda/index.js.map +1 -1
- package/src/solver-tools/lsoda/index.ts +12 -0
- package/src/solver-tools/lsoda/intdy.js +11 -0
- package/src/solver-tools/lsoda/intdy.js.map +1 -1
- package/src/solver-tools/lsoda/intdy.ts +12 -0
- package/src/solver-tools/lsoda/lsoda.js +11 -0
- package/src/solver-tools/lsoda/lsoda.js.map +1 -1
- package/src/solver-tools/lsoda/lsoda.ts +12 -0
- package/src/solver-tools/lsoda/methodswitch.js +11 -0
- package/src/solver-tools/lsoda/methodswitch.js.map +1 -1
- package/src/solver-tools/lsoda/methodswitch.ts +12 -0
- package/src/solver-tools/lsoda/orderswitch.js +11 -0
- package/src/solver-tools/lsoda/orderswitch.js.map +1 -1
- package/src/solver-tools/lsoda/orderswitch.ts +12 -0
- package/src/solver-tools/lsoda/prja.js +11 -0
- package/src/solver-tools/lsoda/prja.js.map +1 -1
- package/src/solver-tools/lsoda/prja.ts +12 -0
- package/src/solver-tools/lsoda/scaleh.js +11 -0
- package/src/solver-tools/lsoda/scaleh.js.map +1 -1
- package/src/solver-tools/lsoda/scaleh.ts +12 -0
- package/src/solver-tools/lsoda/solsy.js +11 -0
- package/src/solver-tools/lsoda/solsy.js.map +1 -1
- package/src/solver-tools/lsoda/solsy.ts +12 -0
- package/src/solver-tools/lsoda/stoda.js +11 -0
- package/src/solver-tools/lsoda/stoda.js.map +1 -1
- package/src/solver-tools/lsoda/stoda.ts +12 -0
- package/src/solver-tools/lsoda-method.js +23 -9
- package/src/solver-tools/lsoda-method.js.map +1 -1
- package/src/solver-tools/lsoda-method.ts +27 -9
- package/src/solver-tools/solver-defs.js +1 -0
- package/src/solver-tools/solver-defs.js.map +1 -1
- package/src/solver-tools/solver-defs.ts +1 -0
- 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/performance.test.js +4 -2
- package/src/tests/performance.test.js.map +1 -1
- package/src/tests/performance.test.ts +4 -2
- package/src/tests/test-defs.js +7 -1
- package/src/tests/test-defs.js.map +1 -1
- package/src/tests/test-defs.ts +8 -1
- package/src/worker-tools/solving.js +3 -1
- package/src/worker-tools/solving.js.map +1 -1
- package/src/worker-tools/solving.ts +4 -1
- package/src/examples/bioreactor.js +0 -125
- package/src/examples/bioreactor.js.map +0 -1
- package/src/examples/bioreactor.ts +0 -132
|
@@ -0,0 +1,1226 @@
|
|
|
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 - Main integration loop
|
|
16
|
+
// Ported from SUNDIALS CVODE v7.5.0 cvode.c
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
CvodeMem, CvodeRhsFn,
|
|
20
|
+
CV_ADAMS, CV_BDF,
|
|
21
|
+
CV_NORMAL, CV_ONE_STEP,
|
|
22
|
+
CV_SUCCESS, CV_TSTOP_RETURN, CV_ROOT_RETURN,
|
|
23
|
+
CV_TOO_MUCH_WORK, CV_TOO_MUCH_ACC, CV_ERR_FAILURE, CV_CONV_FAILURE,
|
|
24
|
+
CV_RHSFUNC_FAIL, CV_FIRST_RHSFUNC_ERR, CV_RTFUNC_FAIL, CV_TOO_CLOSE,
|
|
25
|
+
CV_LSETUP_FAIL, CV_LSOLVE_FAIL, CV_UNREC_RHSFUNC_ERR, CV_REPTD_RHSFUNC_ERR,
|
|
26
|
+
CV_LINIT_FAIL, CV_NLS_FAIL,
|
|
27
|
+
CV_NN, CV_SS, CV_SV,
|
|
28
|
+
ADAMS_Q_MAX, BDF_Q_MAX,
|
|
29
|
+
HMIN_DEFAULT, HMAX_INV_DEFAULT, MXSTEP_DEFAULT, MXHNIL_DEFAULT,
|
|
30
|
+
MSBP_DEFAULT, DGMAX_LSETUP_DEFAULT,
|
|
31
|
+
ETA_MIN_FX_DEFAULT, ETA_MAX_FX_DEFAULT, ETA_MAX_FS_DEFAULT,
|
|
32
|
+
ETA_MAX_ES_DEFAULT, ETA_MAX_GS_DEFAULT,
|
|
33
|
+
ETA_MIN_DEFAULT, ETA_MIN_EF_DEFAULT, ETA_MAX_EF_DEFAULT, ETA_CF_DEFAULT,
|
|
34
|
+
SMALL_NST_DEFAULT, SMALL_NEF_DEFAULT,
|
|
35
|
+
MXNEF, MXNCF, MXNEF1,
|
|
36
|
+
DO_ERROR_TEST, PREDICT_AGAIN, TRY_AGAIN, FIRST_CALL,
|
|
37
|
+
PREV_CONV_FAIL, PREV_ERR_FAIL,
|
|
38
|
+
RHSFUNC_RECVR, SUN_NLS_CONV_RECVR,
|
|
39
|
+
CV_NO_FAILURES,
|
|
40
|
+
FUZZ_FACTOR, UROUND, CORTES, ONEPSM, TINY,
|
|
41
|
+
ADDON, BIAS1, BIAS2, BIAS3, LONG_WAIT,
|
|
42
|
+
NUM_TESTS, L_MAX,
|
|
43
|
+
RTFOUND, CLOSERT,
|
|
44
|
+
wrmsNorm, vLinearSum, vScale, cvodeGetDky,
|
|
45
|
+
} from './common';
|
|
46
|
+
|
|
47
|
+
import {cvSetBDF, cvIncreaseBDF, cvDecreaseBDF} from './cvode_bdf';
|
|
48
|
+
import {cvSetAdams, cvAdjustAdams} from './cvode_adams';
|
|
49
|
+
import {cvHin} from './cvode_hin';
|
|
50
|
+
import {cvNls} from './cvode_nls';
|
|
51
|
+
import {cvRcheck1, cvRcheck2, cvRcheck3} from './cvode_root';
|
|
52
|
+
|
|
53
|
+
// ============================================================================
|
|
54
|
+
// PUBLIC EXPORTED FUNCTIONS
|
|
55
|
+
// ============================================================================
|
|
56
|
+
|
|
57
|
+
/** cvodeCreate - Create and initialize CvodeMem */
|
|
58
|
+
export function cvodeCreate(lmm: number): CvodeMem {
|
|
59
|
+
if (lmm !== CV_ADAMS && lmm !== CV_BDF)
|
|
60
|
+
throw new Error('cvodeCreate: bad lmm, must be CV_ADAMS or CV_BDF');
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
const maxord = (lmm === CV_ADAMS) ? ADAMS_Q_MAX : BDF_Q_MAX;
|
|
64
|
+
const mem = new CvodeMem();
|
|
65
|
+
|
|
66
|
+
mem.cv_lmm = lmm;
|
|
67
|
+
mem.cv_qmax = maxord;
|
|
68
|
+
mem.cv_qmax_alloc = maxord;
|
|
69
|
+
|
|
70
|
+
// Initialize ssdat as 6x4 array of zeros (1-based indexing: i=1..5, k=1..3)
|
|
71
|
+
mem.cv_ssdat = [];
|
|
72
|
+
for (let i = 0; i < 6; i++)
|
|
73
|
+
mem.cv_ssdat[i] = [0, 0, 0, 0];
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
mem.cv_nlscoef = CORTES;
|
|
77
|
+
|
|
78
|
+
return mem;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** cvodeInit - Initialize problem */
|
|
82
|
+
export function cvodeInit(mem: CvodeMem, f: CvodeRhsFn, t0: number, y0: Float64Array): number {
|
|
83
|
+
mem.cv_f = f;
|
|
84
|
+
mem.cv_tn = t0;
|
|
85
|
+
mem.cv_N = y0.length;
|
|
86
|
+
const N = mem.cv_N;
|
|
87
|
+
|
|
88
|
+
// Allocate Nordsieck history array: zn[0..qmax_alloc+1]
|
|
89
|
+
const allocQ = mem.cv_qmax_alloc;
|
|
90
|
+
mem.cv_zn = [];
|
|
91
|
+
for (let i = 0; i <= allocQ + 1; i++)
|
|
92
|
+
mem.cv_zn[i] = new Float64Array(N);
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
// Allocate work vectors
|
|
96
|
+
mem.cv_ewt = new Float64Array(N);
|
|
97
|
+
mem.cv_acor = new Float64Array(N);
|
|
98
|
+
mem.cv_tempv = new Float64Array(N);
|
|
99
|
+
mem.cv_ftemp = new Float64Array(N);
|
|
100
|
+
mem.cv_vtemp1 = new Float64Array(N);
|
|
101
|
+
mem.cv_vtemp2 = new Float64Array(N);
|
|
102
|
+
mem.cv_vtemp3 = new Float64Array(N);
|
|
103
|
+
mem.cv_y = new Float64Array(N);
|
|
104
|
+
|
|
105
|
+
// Copy y0 into zn[0]
|
|
106
|
+
mem.cv_zn[0].set(y0);
|
|
107
|
+
|
|
108
|
+
// Set step parameters
|
|
109
|
+
mem.cv_q = 1;
|
|
110
|
+
mem.cv_L = 2;
|
|
111
|
+
mem.cv_qwait = mem.cv_L;
|
|
112
|
+
mem.cv_etamax = mem.cv_eta_max_fs;
|
|
113
|
+
|
|
114
|
+
mem.cv_qu = 0;
|
|
115
|
+
mem.cv_hu = 0.0;
|
|
116
|
+
mem.cv_tolsf = 1.0;
|
|
117
|
+
|
|
118
|
+
// Reset all counters
|
|
119
|
+
mem.cv_nst = 0;
|
|
120
|
+
mem.cv_nfe = 0;
|
|
121
|
+
mem.cv_ncfn = 0;
|
|
122
|
+
mem.cv_netf = 0;
|
|
123
|
+
mem.cv_nni = 0;
|
|
124
|
+
mem.cv_nnf = 0;
|
|
125
|
+
mem.cv_nsetups = 0;
|
|
126
|
+
mem.cv_nhnil = 0;
|
|
127
|
+
mem.cv_nstlp = 0;
|
|
128
|
+
mem.cv_nscon = 0;
|
|
129
|
+
mem.cv_nge = 0;
|
|
130
|
+
mem.cv_irfnd = 0;
|
|
131
|
+
|
|
132
|
+
mem.cv_h0u = 0.0;
|
|
133
|
+
mem.cv_next_h = 0.0;
|
|
134
|
+
mem.cv_next_q = 0;
|
|
135
|
+
|
|
136
|
+
// Initialize stability limit detection data
|
|
137
|
+
mem.cv_nor = 0;
|
|
138
|
+
mem.cv_ssdat = [];
|
|
139
|
+
for (let i = 0; i < 6; i++)
|
|
140
|
+
mem.cv_ssdat[i] = [0, 0, 0, 0];
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
// Set indx_acor to qmax_alloc (the zn slot used to save acor)
|
|
144
|
+
mem.cv_indx_acor = mem.cv_qmax_alloc;
|
|
145
|
+
|
|
146
|
+
mem.cv_MallocDone = true;
|
|
147
|
+
|
|
148
|
+
return CV_SUCCESS;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** cvode - Main integration loop */
|
|
152
|
+
export function cvode(
|
|
153
|
+
mem: CvodeMem, tout: number, yout: Float64Array, itask: number,
|
|
154
|
+
): { flag: number; t: number } {
|
|
155
|
+
let istate: number;
|
|
156
|
+
let troundoff: number;
|
|
157
|
+
let retval: number;
|
|
158
|
+
let ier: number;
|
|
159
|
+
let tret = mem.cv_tn;
|
|
160
|
+
|
|
161
|
+
// Check itask
|
|
162
|
+
if (itask !== CV_NORMAL && itask !== CV_ONE_STEP)
|
|
163
|
+
return {flag: -99, t: mem.cv_tn};
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
if (itask === CV_NORMAL) mem.cv_toutc = tout;
|
|
167
|
+
mem.cv_taskc = itask;
|
|
168
|
+
|
|
169
|
+
// --- nst == 0: first step initialization ---
|
|
170
|
+
if (mem.cv_nst === 0) {
|
|
171
|
+
mem.cv_tretlast = tret = mem.cv_tn;
|
|
172
|
+
|
|
173
|
+
// Check inputs
|
|
174
|
+
ier = cvInitialSetup(mem);
|
|
175
|
+
if (ier !== CV_SUCCESS) return {flag: ier, t: tret};
|
|
176
|
+
|
|
177
|
+
// Call f at (t0, y0), set zn[1] = y'(t0)
|
|
178
|
+
retval = mem.cv_f!(mem.cv_tn, mem.cv_zn[0], mem.cv_zn[1], mem.cv_user_data);
|
|
179
|
+
mem.cv_nfe++;
|
|
180
|
+
if (retval < 0) return {flag: CV_RHSFUNC_FAIL, t: tret};
|
|
181
|
+
if (retval > 0) return {flag: CV_FIRST_RHSFUNC_ERR, t: tret};
|
|
182
|
+
|
|
183
|
+
// Test tstop legality
|
|
184
|
+
if (mem.cv_tstopset) {
|
|
185
|
+
if ((mem.cv_tstop - mem.cv_tn) * (tout - mem.cv_tn) <= 0.0)
|
|
186
|
+
return {flag: -99, t: tret}; // CV_ILL_INPUT
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Set initial h
|
|
190
|
+
mem.cv_h = mem.cv_hin;
|
|
191
|
+
if (mem.cv_h !== 0.0 && (tout - mem.cv_tn) * mem.cv_h < 0.0)
|
|
192
|
+
return {flag: -99, t: tret};
|
|
193
|
+
|
|
194
|
+
if (mem.cv_h === 0.0) {
|
|
195
|
+
let tout_hin = tout;
|
|
196
|
+
if (mem.cv_tstopset && (tout - mem.cv_tn) * (tout - mem.cv_tstop) > 0.0)
|
|
197
|
+
tout_hin = mem.cv_tstop;
|
|
198
|
+
|
|
199
|
+
const hflag = cvHin(mem, tout_hin);
|
|
200
|
+
if (hflag !== CV_SUCCESS) {
|
|
201
|
+
istate = cvHandleFailure(mem, hflag);
|
|
202
|
+
return {flag: istate, t: tret};
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Enforce hmax and hmin
|
|
207
|
+
const rh = Math.abs(mem.cv_h) * mem.cv_hmax_inv;
|
|
208
|
+
if (rh > 1.0) mem.cv_h /= rh;
|
|
209
|
+
if (Math.abs(mem.cv_h) < mem.cv_hmin)
|
|
210
|
+
mem.cv_h *= mem.cv_hmin / Math.abs(mem.cv_h);
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
// Check for approach to tstop
|
|
214
|
+
if (mem.cv_tstopset) {
|
|
215
|
+
if ((mem.cv_tn + mem.cv_h - mem.cv_tstop) * mem.cv_h > 0.0)
|
|
216
|
+
mem.cv_h = (mem.cv_tstop - mem.cv_tn) * (1.0 - 4.0 * UROUND);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Scale zn[1] by h
|
|
220
|
+
mem.cv_hscale = mem.cv_h;
|
|
221
|
+
mem.cv_h0u = mem.cv_h;
|
|
222
|
+
mem.cv_hprime = mem.cv_h;
|
|
223
|
+
vScale(mem.cv_h, mem.cv_zn[1], mem.cv_zn[1], mem.cv_N);
|
|
224
|
+
|
|
225
|
+
// Check for roots at/near t0
|
|
226
|
+
if (mem.cv_nrtfn > 0) {
|
|
227
|
+
retval = cvRcheck1(mem);
|
|
228
|
+
if (retval === CV_RTFUNC_FAIL)
|
|
229
|
+
return {flag: CV_RTFUNC_FAIL, t: tret};
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// --- nst > 0: stop tests ---
|
|
234
|
+
if (mem.cv_nst > 0) {
|
|
235
|
+
troundoff = FUZZ_FACTOR * UROUND *
|
|
236
|
+
(Math.abs(mem.cv_tn) + Math.abs(mem.cv_h));
|
|
237
|
+
|
|
238
|
+
// Root check from last step
|
|
239
|
+
if (mem.cv_nrtfn > 0) {
|
|
240
|
+
const irfndp = mem.cv_irfnd;
|
|
241
|
+
|
|
242
|
+
retval = cvRcheck2(mem);
|
|
243
|
+
|
|
244
|
+
if (retval === CLOSERT)
|
|
245
|
+
return {flag: -99, t: mem.cv_tlo};
|
|
246
|
+
else if (retval === CV_RTFUNC_FAIL)
|
|
247
|
+
return {flag: CV_RTFUNC_FAIL, t: mem.cv_tlo};
|
|
248
|
+
else if (retval === RTFOUND) {
|
|
249
|
+
mem.cv_tretlast = tret = mem.cv_tlo;
|
|
250
|
+
return {flag: CV_ROOT_RETURN, t: tret};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// If tn is distinct from tretlast, check remaining interval
|
|
254
|
+
if (Math.abs(mem.cv_tn - mem.cv_tretlast) > troundoff) {
|
|
255
|
+
retval = cvRcheck3(mem);
|
|
256
|
+
|
|
257
|
+
if (retval === CV_SUCCESS) {
|
|
258
|
+
mem.cv_irfnd = 0;
|
|
259
|
+
if (irfndp === 1 && itask === CV_ONE_STEP) {
|
|
260
|
+
mem.cv_tretlast = tret = mem.cv_tn;
|
|
261
|
+
yout.set(mem.cv_zn[0]);
|
|
262
|
+
return {flag: CV_SUCCESS, t: tret};
|
|
263
|
+
}
|
|
264
|
+
} else if (retval === RTFOUND) {
|
|
265
|
+
mem.cv_irfnd = 1;
|
|
266
|
+
mem.cv_tretlast = tret = mem.cv_tlo;
|
|
267
|
+
return {flag: CV_ROOT_RETURN, t: tret};
|
|
268
|
+
} else if (retval === CV_RTFUNC_FAIL)
|
|
269
|
+
return {flag: CV_RTFUNC_FAIL, t: mem.cv_tlo};
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Test for tn at tstop
|
|
274
|
+
if (mem.cv_tstopset) {
|
|
275
|
+
if (Math.abs(mem.cv_tn - mem.cv_tstop) <= troundoff) {
|
|
276
|
+
if ((tout - mem.cv_tstop) * mem.cv_h >= 0.0 ||
|
|
277
|
+
Math.abs(tout - mem.cv_tstop) <= troundoff) {
|
|
278
|
+
if (mem.cv_tstopinterp)
|
|
279
|
+
cvodeGetDky(mem, mem.cv_tstop, 0, yout);
|
|
280
|
+
else
|
|
281
|
+
yout.set(mem.cv_zn[0]);
|
|
282
|
+
|
|
283
|
+
mem.cv_tretlast = tret = mem.cv_tstop;
|
|
284
|
+
mem.cv_tstopset = false;
|
|
285
|
+
return {flag: CV_TSTOP_RETURN, t: tret};
|
|
286
|
+
}
|
|
287
|
+
} else if ((mem.cv_tn + mem.cv_hprime - mem.cv_tstop) * mem.cv_h > 0.0) {
|
|
288
|
+
mem.cv_hprime = (mem.cv_tstop - mem.cv_tn) * (1.0 - 4.0 * UROUND);
|
|
289
|
+
mem.cv_eta = mem.cv_hprime / mem.cv_h;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// In NORMAL mode, test if tout was reached
|
|
294
|
+
if (itask === CV_NORMAL && (mem.cv_tn - tout) * mem.cv_h >= 0.0) {
|
|
295
|
+
mem.cv_tretlast = tret = tout;
|
|
296
|
+
cvodeGetDky(mem, tout, 0, yout);
|
|
297
|
+
return {flag: CV_SUCCESS, t: tret};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// In ONE_STEP mode, test if tn was returned
|
|
301
|
+
if (itask === CV_ONE_STEP &&
|
|
302
|
+
Math.abs(mem.cv_tn - mem.cv_tretlast) > troundoff) {
|
|
303
|
+
mem.cv_tretlast = tret = mem.cv_tn;
|
|
304
|
+
yout.set(mem.cv_zn[0]);
|
|
305
|
+
return {flag: CV_SUCCESS, t: tret};
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// --- Main integration loop ---
|
|
310
|
+
let nstloc = 0;
|
|
311
|
+
istate = CV_SUCCESS; // will be overwritten
|
|
312
|
+
|
|
313
|
+
for (;;) {
|
|
314
|
+
mem.cv_next_h = mem.cv_h;
|
|
315
|
+
mem.cv_next_q = mem.cv_q;
|
|
316
|
+
|
|
317
|
+
// Reset and check ewt
|
|
318
|
+
if (mem.cv_nst > 0) {
|
|
319
|
+
const ewtsetOK = cvEwtSet(mem);
|
|
320
|
+
if (ewtsetOK !== 0) {
|
|
321
|
+
istate = -99; // CV_ILL_INPUT
|
|
322
|
+
mem.cv_tretlast = tret = mem.cv_tn;
|
|
323
|
+
yout.set(mem.cv_zn[0]);
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Check for too many steps
|
|
329
|
+
if (mem.cv_mxstep > 0 && nstloc >= mem.cv_mxstep) {
|
|
330
|
+
istate = CV_TOO_MUCH_WORK;
|
|
331
|
+
mem.cv_tretlast = tret = mem.cv_tn;
|
|
332
|
+
yout.set(mem.cv_zn[0]);
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Check for too much accuracy requested
|
|
337
|
+
const nrm = wrmsNorm(mem.cv_N, mem.cv_zn[0], mem.cv_ewt);
|
|
338
|
+
mem.cv_tolsf = UROUND * nrm;
|
|
339
|
+
if (mem.cv_tolsf > 1.0) {
|
|
340
|
+
istate = CV_TOO_MUCH_ACC;
|
|
341
|
+
mem.cv_tretlast = tret = mem.cv_tn;
|
|
342
|
+
yout.set(mem.cv_zn[0]);
|
|
343
|
+
mem.cv_tolsf *= 2.0;
|
|
344
|
+
break;
|
|
345
|
+
} else
|
|
346
|
+
mem.cv_tolsf = 1.0;
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
// Check for h below roundoff
|
|
350
|
+
if (mem.cv_tn + mem.cv_h === mem.cv_tn)
|
|
351
|
+
mem.cv_nhnil++;
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
// Take a step
|
|
355
|
+
const kflag = cvStep(mem);
|
|
356
|
+
|
|
357
|
+
// Process failed step
|
|
358
|
+
if (kflag !== CV_SUCCESS) {
|
|
359
|
+
istate = cvHandleFailure(mem, kflag);
|
|
360
|
+
mem.cv_tretlast = tret = mem.cv_tn;
|
|
361
|
+
yout.set(mem.cv_zn[0]);
|
|
362
|
+
break;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
nstloc++;
|
|
366
|
+
|
|
367
|
+
// If tstop was reached, reset tn
|
|
368
|
+
if (mem.cv_tstopset) {
|
|
369
|
+
troundoff = FUZZ_FACTOR * UROUND *
|
|
370
|
+
(Math.abs(mem.cv_tn) + Math.abs(mem.cv_h));
|
|
371
|
+
if (Math.abs(mem.cv_tn - mem.cv_tstop) <= troundoff)
|
|
372
|
+
mem.cv_tn = mem.cv_tstop;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Check for root in last step
|
|
376
|
+
if (mem.cv_nrtfn > 0) {
|
|
377
|
+
retval = cvRcheck3(mem);
|
|
378
|
+
|
|
379
|
+
if (retval === RTFOUND) {
|
|
380
|
+
mem.cv_irfnd = 1;
|
|
381
|
+
istate = CV_ROOT_RETURN;
|
|
382
|
+
mem.cv_tretlast = tret = mem.cv_tlo;
|
|
383
|
+
break;
|
|
384
|
+
} else if (retval === CV_RTFUNC_FAIL) {
|
|
385
|
+
istate = CV_RTFUNC_FAIL;
|
|
386
|
+
break;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Check tstop in loop
|
|
391
|
+
if (mem.cv_tstopset) {
|
|
392
|
+
troundoff = FUZZ_FACTOR * UROUND *
|
|
393
|
+
(Math.abs(mem.cv_tn) + Math.abs(mem.cv_h));
|
|
394
|
+
|
|
395
|
+
if (Math.abs(mem.cv_tn - mem.cv_tstop) <= troundoff) {
|
|
396
|
+
if ((tout - mem.cv_tstop) * mem.cv_h >= 0.0 ||
|
|
397
|
+
Math.abs(tout - mem.cv_tstop) <= troundoff) {
|
|
398
|
+
if (mem.cv_tstopinterp)
|
|
399
|
+
cvodeGetDky(mem, mem.cv_tstop, 0, yout);
|
|
400
|
+
else
|
|
401
|
+
yout.set(mem.cv_zn[0]);
|
|
402
|
+
|
|
403
|
+
mem.cv_tretlast = tret = mem.cv_tstop;
|
|
404
|
+
mem.cv_tstopset = false;
|
|
405
|
+
istate = CV_TSTOP_RETURN;
|
|
406
|
+
break;
|
|
407
|
+
}
|
|
408
|
+
} else if ((mem.cv_tn + mem.cv_hprime - mem.cv_tstop) * mem.cv_h > 0.0) {
|
|
409
|
+
mem.cv_hprime = (mem.cv_tstop - mem.cv_tn) * (1.0 - 4.0 * UROUND);
|
|
410
|
+
mem.cv_eta = mem.cv_hprime / mem.cv_h;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// In NORMAL mode, check if tout reached
|
|
415
|
+
if (itask === CV_NORMAL && (mem.cv_tn - tout) * mem.cv_h >= 0.0) {
|
|
416
|
+
istate = CV_SUCCESS;
|
|
417
|
+
mem.cv_tretlast = tret = tout;
|
|
418
|
+
cvodeGetDky(mem, tout, 0, yout);
|
|
419
|
+
mem.cv_next_q = mem.cv_qprime;
|
|
420
|
+
mem.cv_next_h = mem.cv_hprime;
|
|
421
|
+
break;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// In ONE_STEP mode, copy y and exit
|
|
425
|
+
if (itask === CV_ONE_STEP) {
|
|
426
|
+
istate = CV_SUCCESS;
|
|
427
|
+
mem.cv_tretlast = tret = mem.cv_tn;
|
|
428
|
+
yout.set(mem.cv_zn[0]);
|
|
429
|
+
mem.cv_next_q = mem.cv_qprime;
|
|
430
|
+
mem.cv_next_h = mem.cv_hprime;
|
|
431
|
+
break;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return {flag: istate, t: tret};
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// ============================================================================
|
|
439
|
+
// INTERNAL FUNCTIONS
|
|
440
|
+
// ============================================================================
|
|
441
|
+
|
|
442
|
+
/** cvInitialSetup - First-step checks */
|
|
443
|
+
function cvInitialSetup(mem: CvodeMem): number {
|
|
444
|
+
// Did the user specify tolerances?
|
|
445
|
+
if (mem.cv_itol === CV_NN) {
|
|
446
|
+
mem.cv_error = 'cvInitialSetup: no tolerances set';
|
|
447
|
+
return -99; // CV_ILL_INPUT
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// Load initial error weights
|
|
451
|
+
const ier = cvEwtSet(mem);
|
|
452
|
+
if (ier !== 0) {
|
|
453
|
+
mem.cv_error = 'cvInitialSetup: bad ewt';
|
|
454
|
+
return -99; // CV_ILL_INPUT
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Call linit function if it exists
|
|
458
|
+
if (mem.cv_linit !== null) {
|
|
459
|
+
const linit_ret = mem.cv_linit(mem);
|
|
460
|
+
if (linit_ret !== 0) {
|
|
461
|
+
mem.cv_error = 'cvInitialSetup: linear solver init failed';
|
|
462
|
+
return CV_LINIT_FAIL;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
return CV_SUCCESS;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/** cvEwtSet - Set error weights based on tolerance type */
|
|
470
|
+
function cvEwtSet(mem: CvodeMem): number {
|
|
471
|
+
switch (mem.cv_itol) {
|
|
472
|
+
case CV_SS: return cvEwtSetSS(mem);
|
|
473
|
+
case CV_SV: return cvEwtSetSV(mem);
|
|
474
|
+
default: return -1;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/** cvEwtSetSS - ewt[i] = 1/(reltol*|y[i]| + Sabstol) */
|
|
479
|
+
function cvEwtSetSS(mem: CvodeMem): number {
|
|
480
|
+
const N = mem.cv_N;
|
|
481
|
+
const rtol = mem.cv_reltol;
|
|
482
|
+
const atol = mem.cv_Sabstol;
|
|
483
|
+
const y = mem.cv_zn[0];
|
|
484
|
+
const ewt = mem.cv_ewt;
|
|
485
|
+
|
|
486
|
+
for (let i = 0; i < N; i++) {
|
|
487
|
+
const tol = rtol * Math.abs(y[i]) + atol;
|
|
488
|
+
if (mem.cv_atolmin0 && tol <= 0.0) return -1;
|
|
489
|
+
ewt[i] = 1.0 / tol;
|
|
490
|
+
}
|
|
491
|
+
return 0;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/** cvEwtSetSV - ewt[i] = 1/(reltol*|y[i]| + Vabstol[i]) */
|
|
495
|
+
function cvEwtSetSV(mem: CvodeMem): number {
|
|
496
|
+
const N = mem.cv_N;
|
|
497
|
+
const rtol = mem.cv_reltol;
|
|
498
|
+
const vatol = mem.cv_Vabstol;
|
|
499
|
+
const y = mem.cv_zn[0];
|
|
500
|
+
const ewt = mem.cv_ewt;
|
|
501
|
+
|
|
502
|
+
for (let i = 0; i < N; i++) {
|
|
503
|
+
const tol = rtol * Math.abs(y[i]) + vatol[i];
|
|
504
|
+
if (mem.cv_atolmin0 && tol <= 0.0) return -1;
|
|
505
|
+
ewt[i] = 1.0 / tol;
|
|
506
|
+
}
|
|
507
|
+
return 0;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/** cvStep - One internal step */
|
|
511
|
+
function cvStep(mem: CvodeMem): number {
|
|
512
|
+
let dsm = 0.0;
|
|
513
|
+
let ncf = 0;
|
|
514
|
+
let nef = 0;
|
|
515
|
+
let nflag: number;
|
|
516
|
+
let kflag: number;
|
|
517
|
+
let eflag: number;
|
|
518
|
+
|
|
519
|
+
// If step size changed, update history array
|
|
520
|
+
if (mem.cv_nst > 0 && mem.cv_hprime !== mem.cv_h)
|
|
521
|
+
cvAdjustParams(mem);
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
const saved_t = mem.cv_tn;
|
|
525
|
+
nflag = FIRST_CALL;
|
|
526
|
+
|
|
527
|
+
// Looping point for step attempts
|
|
528
|
+
for (;;) {
|
|
529
|
+
cvPredict(mem);
|
|
530
|
+
cvSet(mem);
|
|
531
|
+
|
|
532
|
+
nflag = cvNls(mem, nflag);
|
|
533
|
+
|
|
534
|
+
const nflagRef = {value: nflag};
|
|
535
|
+
const ncfRef = {value: ncf};
|
|
536
|
+
kflag = cvHandleNFlag(mem, nflagRef, saved_t, ncfRef);
|
|
537
|
+
nflag = nflagRef.value;
|
|
538
|
+
ncf = ncfRef.value;
|
|
539
|
+
|
|
540
|
+
// Go back if we need to predict again
|
|
541
|
+
if (kflag === PREDICT_AGAIN) continue;
|
|
542
|
+
|
|
543
|
+
// Return if nonlinear solve failed and recovery is not possible
|
|
544
|
+
if (kflag !== DO_ERROR_TEST) return kflag;
|
|
545
|
+
|
|
546
|
+
// Perform error test
|
|
547
|
+
const nflagRef2 = {value: nflag};
|
|
548
|
+
const nefRef = {value: nef};
|
|
549
|
+
const dsmRef = {value: dsm};
|
|
550
|
+
eflag = cvDoErrorTest(mem, nflagRef2, saved_t, nefRef, dsmRef);
|
|
551
|
+
nflag = nflagRef2.value;
|
|
552
|
+
nef = nefRef.value;
|
|
553
|
+
dsm = dsmRef.value;
|
|
554
|
+
|
|
555
|
+
// Go back if we need to try again
|
|
556
|
+
if (eflag === TRY_AGAIN) continue;
|
|
557
|
+
|
|
558
|
+
// Return if error test failed and recovery is not possible
|
|
559
|
+
if (eflag !== CV_SUCCESS) return eflag;
|
|
560
|
+
|
|
561
|
+
// Error test passed, break from loop
|
|
562
|
+
break;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// Step successful: update data and consider order/step changes
|
|
566
|
+
cvCompleteStep(mem);
|
|
567
|
+
cvPrepareNextStep(mem, dsm);
|
|
568
|
+
|
|
569
|
+
// BDF stability limit detection
|
|
570
|
+
if (mem.cv_sldeton) cvBDFStab(mem);
|
|
571
|
+
|
|
572
|
+
mem.cv_etamax = (mem.cv_nst <= mem.cv_small_nst) ?
|
|
573
|
+
mem.cv_eta_max_es :
|
|
574
|
+
mem.cv_eta_max_gs;
|
|
575
|
+
|
|
576
|
+
// Rescale acor to be the estimated local error vector
|
|
577
|
+
vScale(mem.cv_tq[2], mem.cv_acor, mem.cv_acor, mem.cv_N);
|
|
578
|
+
|
|
579
|
+
return CV_SUCCESS;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/** cvAdjustParams - adjust order and rescale when step size changes */
|
|
583
|
+
function cvAdjustParams(mem: CvodeMem): void {
|
|
584
|
+
if (mem.cv_qprime !== mem.cv_q) {
|
|
585
|
+
if (!mem.first_step_after_resize)
|
|
586
|
+
cvAdjustOrder(mem, mem.cv_qprime - mem.cv_q);
|
|
587
|
+
|
|
588
|
+
mem.cv_q = mem.cv_qprime;
|
|
589
|
+
mem.cv_L = mem.cv_q + 1;
|
|
590
|
+
mem.cv_qwait = mem.cv_L;
|
|
591
|
+
}
|
|
592
|
+
cvRescale(mem);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/** cvAdjustOrder - handle order change by deltaq */
|
|
596
|
+
function cvAdjustOrder(mem: CvodeMem, deltaq: number): void {
|
|
597
|
+
if (mem.cv_q === 2 && deltaq !== 1) return;
|
|
598
|
+
|
|
599
|
+
if (mem.cv_lmm === CV_ADAMS)
|
|
600
|
+
cvAdjustAdams(mem, deltaq);
|
|
601
|
+
else if (mem.cv_lmm === CV_BDF) {
|
|
602
|
+
if (deltaq === 1) cvIncreaseBDF(mem);
|
|
603
|
+
else if (deltaq === -1) cvDecreaseBDF(mem);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
/** cvRescale - multiply zn[j] by eta^j for j=1..q */
|
|
608
|
+
function cvRescale(mem: CvodeMem): void {
|
|
609
|
+
const N = mem.cv_N;
|
|
610
|
+
let factor = mem.cv_eta;
|
|
611
|
+
for (let j = 1; j <= mem.cv_q; j++) {
|
|
612
|
+
const znj = mem.cv_zn[j];
|
|
613
|
+
for (let i = 0; i < N; i++)
|
|
614
|
+
znj[i] *= factor;
|
|
615
|
+
|
|
616
|
+
factor *= mem.cv_eta;
|
|
617
|
+
}
|
|
618
|
+
mem.cv_h = mem.cv_hscale * mem.cv_eta;
|
|
619
|
+
mem.cv_next_h = mem.cv_h;
|
|
620
|
+
mem.cv_hscale = mem.cv_h;
|
|
621
|
+
mem.cv_nscon = 0;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/** cvPredict - advance tn and compute predicted Nordsieck array */
|
|
625
|
+
function cvPredict(mem: CvodeMem): void {
|
|
626
|
+
const N = mem.cv_N;
|
|
627
|
+
|
|
628
|
+
mem.cv_tn += mem.cv_h;
|
|
629
|
+
if (mem.cv_tstopset) {
|
|
630
|
+
if ((mem.cv_tn - mem.cv_tstop) * mem.cv_h > 0.0)
|
|
631
|
+
mem.cv_tn = mem.cv_tstop;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
for (let k = 1; k <= mem.cv_q; k++) {
|
|
635
|
+
for (let j = mem.cv_q; j >= k; j--) {
|
|
636
|
+
const znjm1 = mem.cv_zn[j - 1];
|
|
637
|
+
const znj = mem.cv_zn[j];
|
|
638
|
+
for (let i = 0; i < N; i++)
|
|
639
|
+
znjm1[i] += znj[i];
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/** cvSet - compute method coefficients l, tq, rl1, gamma, gamrat */
|
|
645
|
+
function cvSet(mem: CvodeMem): void {
|
|
646
|
+
if (mem.cv_lmm === CV_ADAMS) cvSetAdams(mem);
|
|
647
|
+
else cvSetBDF(mem);
|
|
648
|
+
|
|
649
|
+
mem.cv_rl1 = 1.0 / mem.cv_l[1];
|
|
650
|
+
mem.cv_gamma = mem.cv_h * mem.cv_rl1;
|
|
651
|
+
if (mem.cv_nst === 0) mem.cv_gammap = mem.cv_gamma;
|
|
652
|
+
mem.cv_gamrat = (mem.cv_nst > 0) ?
|
|
653
|
+
mem.cv_gamma / mem.cv_gammap :
|
|
654
|
+
1.0;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/** cvHandleNFlag - take action on nonlinear solver return */
|
|
658
|
+
function cvHandleNFlag(
|
|
659
|
+
mem: CvodeMem, nflagRef: { value: number }, saved_t: number, ncfRef: { value: number },
|
|
660
|
+
): number {
|
|
661
|
+
const nflag = nflagRef.value;
|
|
662
|
+
|
|
663
|
+
if (nflag === CV_SUCCESS) return DO_ERROR_TEST;
|
|
664
|
+
|
|
665
|
+
// Nonlinear solve failed; increment ncfn and restore zn
|
|
666
|
+
mem.cv_ncfn++;
|
|
667
|
+
cvRestore(mem, saved_t);
|
|
668
|
+
|
|
669
|
+
// Return if failed unrecoverably
|
|
670
|
+
if (nflag < 0) {
|
|
671
|
+
if (nflag === CV_LSETUP_FAIL) return CV_LSETUP_FAIL;
|
|
672
|
+
else if (nflag === CV_LSOLVE_FAIL) return CV_LSOLVE_FAIL;
|
|
673
|
+
else if (nflag === CV_RHSFUNC_FAIL) return CV_RHSFUNC_FAIL;
|
|
674
|
+
else return CV_NLS_FAIL;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
// Recoverable error
|
|
678
|
+
ncfRef.value++;
|
|
679
|
+
mem.cv_etamax = 1.0;
|
|
680
|
+
|
|
681
|
+
// If maxncf failures or |h| = hmin, return failure
|
|
682
|
+
if (Math.abs(mem.cv_h) <= mem.cv_hmin * ONEPSM ||
|
|
683
|
+
ncfRef.value === mem.cv_maxncf) {
|
|
684
|
+
if (nflag === SUN_NLS_CONV_RECVR) return CV_CONV_FAILURE;
|
|
685
|
+
if (nflag === RHSFUNC_RECVR) return CV_REPTD_RHSFUNC_ERR;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// Reduce step size; return to reattempt
|
|
689
|
+
mem.cv_eta = Math.max(mem.cv_eta_cf, mem.cv_hmin / Math.abs(mem.cv_h));
|
|
690
|
+
nflagRef.value = PREV_CONV_FAIL;
|
|
691
|
+
cvRescale(mem);
|
|
692
|
+
|
|
693
|
+
return PREDICT_AGAIN;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/** cvRestore - undo prediction, restore tn and zn */
|
|
697
|
+
function cvRestore(mem: CvodeMem, saved_t: number): void {
|
|
698
|
+
const N = mem.cv_N;
|
|
699
|
+
|
|
700
|
+
mem.cv_tn = saved_t;
|
|
701
|
+
for (let k = 1; k <= mem.cv_q; k++) {
|
|
702
|
+
for (let j = mem.cv_q; j >= k; j--) {
|
|
703
|
+
const znjm1 = mem.cv_zn[j - 1];
|
|
704
|
+
const znj = mem.cv_zn[j];
|
|
705
|
+
for (let i = 0; i < N; i++)
|
|
706
|
+
znjm1[i] -= znj[i];
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/** cvDoErrorTest - local error test */
|
|
712
|
+
function cvDoErrorTest(
|
|
713
|
+
mem: CvodeMem, nflagRef: { value: number }, saved_t: number,
|
|
714
|
+
nefRef: { value: number }, dsmRef: { value: number },
|
|
715
|
+
): number {
|
|
716
|
+
const dsm = mem.cv_acnrm * mem.cv_tq[2];
|
|
717
|
+
dsmRef.value = dsm;
|
|
718
|
+
|
|
719
|
+
// If dsm <= 1, test passed
|
|
720
|
+
if (dsm <= 1.0) return CV_SUCCESS;
|
|
721
|
+
|
|
722
|
+
// Test failed
|
|
723
|
+
nefRef.value++;
|
|
724
|
+
mem.cv_netf++;
|
|
725
|
+
nflagRef.value = PREV_ERR_FAIL;
|
|
726
|
+
cvRestore(mem, saved_t);
|
|
727
|
+
|
|
728
|
+
// At maxnef failures or |h| = hmin, return failure
|
|
729
|
+
if (Math.abs(mem.cv_h) <= mem.cv_hmin * ONEPSM ||
|
|
730
|
+
nefRef.value === mem.cv_maxnef)
|
|
731
|
+
return CV_ERR_FAILURE;
|
|
732
|
+
|
|
733
|
+
|
|
734
|
+
// Set etamax = 1 to prevent step size increase
|
|
735
|
+
mem.cv_etamax = 1.0;
|
|
736
|
+
|
|
737
|
+
// Compute eta from dsm and rescale
|
|
738
|
+
if (nefRef.value <= MXNEF1) {
|
|
739
|
+
mem.cv_eta = 1.0 / (Math.pow(BIAS2 * dsm, 1.0 / mem.cv_L) + ADDON);
|
|
740
|
+
mem.cv_eta = Math.max(mem.cv_eta_min_ef,
|
|
741
|
+
Math.max(mem.cv_eta, mem.cv_hmin / Math.abs(mem.cv_h)));
|
|
742
|
+
if (nefRef.value >= mem.cv_small_nef)
|
|
743
|
+
mem.cv_eta = Math.min(mem.cv_eta, mem.cv_eta_max_ef);
|
|
744
|
+
|
|
745
|
+
cvRescale(mem);
|
|
746
|
+
return TRY_AGAIN;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// After MXNEF1 failures, force order reduction
|
|
750
|
+
if (mem.cv_q > 1) {
|
|
751
|
+
mem.cv_eta = Math.max(mem.cv_eta_min_ef,
|
|
752
|
+
mem.cv_hmin / Math.abs(mem.cv_h));
|
|
753
|
+
cvAdjustOrder(mem, -1);
|
|
754
|
+
mem.cv_L = mem.cv_q;
|
|
755
|
+
mem.cv_q--;
|
|
756
|
+
mem.cv_qwait = mem.cv_L;
|
|
757
|
+
cvRescale(mem);
|
|
758
|
+
return TRY_AGAIN;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// Already at order 1: restart by reloading zn
|
|
762
|
+
mem.cv_eta = Math.max(mem.cv_eta_min_ef,
|
|
763
|
+
mem.cv_hmin / Math.abs(mem.cv_h));
|
|
764
|
+
mem.cv_h *= mem.cv_eta;
|
|
765
|
+
mem.cv_next_h = mem.cv_h;
|
|
766
|
+
mem.cv_hscale = mem.cv_h;
|
|
767
|
+
mem.cv_qwait = LONG_WAIT;
|
|
768
|
+
mem.cv_nscon = 0;
|
|
769
|
+
|
|
770
|
+
const retval = mem.cv_f!(mem.cv_tn, mem.cv_zn[0], mem.cv_tempv, mem.cv_user_data);
|
|
771
|
+
mem.cv_nfe++;
|
|
772
|
+
if (retval < 0) return CV_RHSFUNC_FAIL;
|
|
773
|
+
if (retval > 0) return CV_UNREC_RHSFUNC_ERR;
|
|
774
|
+
|
|
775
|
+
vScale(mem.cv_h, mem.cv_tempv, mem.cv_zn[1], mem.cv_N);
|
|
776
|
+
|
|
777
|
+
return TRY_AGAIN;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
/** cvCompleteStep - update state after successful step */
|
|
781
|
+
function cvCompleteStep(mem: CvodeMem): void {
|
|
782
|
+
const N = mem.cv_N;
|
|
783
|
+
|
|
784
|
+
mem.cv_nst++;
|
|
785
|
+
mem.cv_nscon++;
|
|
786
|
+
mem.cv_hu = mem.cv_h;
|
|
787
|
+
mem.cv_qu = mem.cv_q;
|
|
788
|
+
|
|
789
|
+
mem.first_step_after_resize = false;
|
|
790
|
+
|
|
791
|
+
// Shift tau array
|
|
792
|
+
for (let i = mem.cv_q; i >= 2; i--)
|
|
793
|
+
mem.cv_tau[i] = mem.cv_tau[i - 1];
|
|
794
|
+
|
|
795
|
+
if (mem.cv_q === 1 && mem.cv_nst > 1)
|
|
796
|
+
mem.cv_tau[2] = mem.cv_tau[1];
|
|
797
|
+
|
|
798
|
+
mem.cv_tau[1] = mem.cv_h;
|
|
799
|
+
|
|
800
|
+
// Apply corrections to zn: zn[j] += l[j] * acor
|
|
801
|
+
for (let j = 0; j <= mem.cv_q; j++) {
|
|
802
|
+
const lj = mem.cv_l[j];
|
|
803
|
+
const znj = mem.cv_zn[j];
|
|
804
|
+
const acor = mem.cv_acor;
|
|
805
|
+
for (let i = 0; i < N; i++)
|
|
806
|
+
znj[i] += lj * acor[i];
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
// Decrement qwait, save acor if qwait==1 and q < qmax
|
|
810
|
+
mem.cv_qwait--;
|
|
811
|
+
if (mem.cv_qwait === 1 && mem.cv_q !== mem.cv_qmax) {
|
|
812
|
+
mem.cv_zn[mem.cv_qmax].set(mem.cv_acor);
|
|
813
|
+
mem.cv_saved_tq5 = mem.cv_tq[5];
|
|
814
|
+
mem.cv_indx_acor = mem.cv_qmax;
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
/** cvPrepareNextStep - set stepsize and order for next step */
|
|
819
|
+
function cvPrepareNextStep(mem: CvodeMem, dsm: number): void {
|
|
820
|
+
if (mem.cv_etamax === 1.0) {
|
|
821
|
+
// Defer step size or order changes
|
|
822
|
+
mem.cv_qwait = Math.max(mem.cv_qwait, 2);
|
|
823
|
+
mem.cv_qprime = mem.cv_q;
|
|
824
|
+
mem.cv_hprime = mem.cv_h;
|
|
825
|
+
mem.cv_eta = 1.0;
|
|
826
|
+
} else {
|
|
827
|
+
// Compute etaq
|
|
828
|
+
mem.cv_etaq = 1.0 / (Math.pow(BIAS2 * dsm, 1.0 / mem.cv_L) + ADDON);
|
|
829
|
+
|
|
830
|
+
if (mem.cv_qwait !== 0) {
|
|
831
|
+
// No order change, just adjust eta
|
|
832
|
+
mem.cv_eta = mem.cv_etaq;
|
|
833
|
+
mem.cv_qprime = mem.cv_q;
|
|
834
|
+
cvSetEta(mem);
|
|
835
|
+
} else {
|
|
836
|
+
// Consider order change
|
|
837
|
+
mem.cv_qwait = 2;
|
|
838
|
+
mem.cv_etaqm1 = cvComputeEtaqm1(mem);
|
|
839
|
+
mem.cv_etaqp1 = cvComputeEtaqp1(mem);
|
|
840
|
+
cvChooseEta(mem);
|
|
841
|
+
cvSetEta(mem);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
/** cvSetEta - adjust eta by heuristic limits and hmax */
|
|
847
|
+
function cvSetEta(mem: CvodeMem): void {
|
|
848
|
+
if (mem.cv_eta > mem.cv_eta_min_fx && mem.cv_eta < mem.cv_eta_max_fx) {
|
|
849
|
+
// Eta within fixed-step bounds, retain step size
|
|
850
|
+
mem.cv_eta = 1.0;
|
|
851
|
+
mem.cv_hprime = mem.cv_h;
|
|
852
|
+
} else {
|
|
853
|
+
if (mem.cv_eta >= mem.cv_eta_max_fx) {
|
|
854
|
+
// Increase step size
|
|
855
|
+
mem.cv_eta = Math.min(mem.cv_eta, mem.cv_etamax);
|
|
856
|
+
mem.cv_eta /= Math.max(1.0,
|
|
857
|
+
Math.abs(mem.cv_h) * mem.cv_hmax_inv * mem.cv_eta);
|
|
858
|
+
} else {
|
|
859
|
+
// Reduce step size
|
|
860
|
+
mem.cv_eta = Math.max(mem.cv_eta, mem.cv_eta_min);
|
|
861
|
+
mem.cv_eta = Math.max(mem.cv_eta,
|
|
862
|
+
mem.cv_hmin / Math.abs(mem.cv_h));
|
|
863
|
+
}
|
|
864
|
+
mem.cv_hprime = mem.cv_h * mem.cv_eta;
|
|
865
|
+
if (mem.cv_qprime < mem.cv_q) mem.cv_nscon = 0;
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
/** cvComputeEtaqm1 - eta for possible order decrease */
|
|
870
|
+
function cvComputeEtaqm1(mem: CvodeMem): number {
|
|
871
|
+
mem.cv_etaqm1 = 0.0;
|
|
872
|
+
if (mem.cv_q > 1) {
|
|
873
|
+
const ddn = wrmsNorm(mem.cv_N, mem.cv_zn[mem.cv_q], mem.cv_ewt) * mem.cv_tq[1];
|
|
874
|
+
mem.cv_etaqm1 = 1.0 / (Math.pow(BIAS1 * ddn, 1.0 / mem.cv_q) + ADDON);
|
|
875
|
+
}
|
|
876
|
+
return mem.cv_etaqm1;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
/** cvComputeEtaqp1 - eta for possible order increase */
|
|
880
|
+
function cvComputeEtaqp1(mem: CvodeMem): number {
|
|
881
|
+
mem.cv_etaqp1 = 0.0;
|
|
882
|
+
if (mem.cv_q !== mem.cv_qmax) {
|
|
883
|
+
if (mem.cv_saved_tq5 === 0.0) return mem.cv_etaqp1;
|
|
884
|
+
const cquot = (mem.cv_tq[5] / mem.cv_saved_tq5) *
|
|
885
|
+
Math.pow(mem.cv_h / mem.cv_tau[2], mem.cv_L);
|
|
886
|
+
|
|
887
|
+
// tempv = acor - cquot * zn[qmax]
|
|
888
|
+
const N = mem.cv_N;
|
|
889
|
+
const tempv = mem.cv_tempv;
|
|
890
|
+
const znqmax = mem.cv_zn[mem.cv_qmax];
|
|
891
|
+
const acor = mem.cv_acor;
|
|
892
|
+
for (let i = 0; i < N; i++)
|
|
893
|
+
tempv[i] = acor[i] - cquot * znqmax[i];
|
|
894
|
+
|
|
895
|
+
|
|
896
|
+
const dup = wrmsNorm(N, tempv, mem.cv_ewt) * mem.cv_tq[3];
|
|
897
|
+
mem.cv_etaqp1 = 1.0 / (Math.pow(BIAS3 * dup, 1.0 / (mem.cv_L + 1)) + ADDON);
|
|
898
|
+
}
|
|
899
|
+
return mem.cv_etaqp1;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
/** cvChooseEta - choose max of etaqm1, etaq, etaqp1 */
|
|
903
|
+
function cvChooseEta(mem: CvodeMem): void {
|
|
904
|
+
const etam = Math.max(mem.cv_etaqm1, Math.max(mem.cv_etaq, mem.cv_etaqp1));
|
|
905
|
+
|
|
906
|
+
if (etam > mem.cv_eta_min_fx && etam < mem.cv_eta_max_fx) {
|
|
907
|
+
mem.cv_eta = 1.0;
|
|
908
|
+
mem.cv_qprime = mem.cv_q;
|
|
909
|
+
} else {
|
|
910
|
+
// Preference: keep > decrease > increase
|
|
911
|
+
if (etam === mem.cv_etaq) {
|
|
912
|
+
mem.cv_eta = mem.cv_etaq;
|
|
913
|
+
mem.cv_qprime = mem.cv_q;
|
|
914
|
+
} else if (etam === mem.cv_etaqm1) {
|
|
915
|
+
mem.cv_eta = mem.cv_etaqm1;
|
|
916
|
+
mem.cv_qprime = mem.cv_q - 1;
|
|
917
|
+
} else {
|
|
918
|
+
mem.cv_eta = mem.cv_etaqp1;
|
|
919
|
+
mem.cv_qprime = mem.cv_q + 1;
|
|
920
|
+
|
|
921
|
+
if (mem.cv_lmm === CV_BDF) {
|
|
922
|
+
// Store Delta_n in zn[qmax] for order increase
|
|
923
|
+
mem.cv_zn[mem.cv_qmax].set(mem.cv_acor);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
/** cvHandleFailure - set error and return flag */
|
|
930
|
+
function cvHandleFailure(mem: CvodeMem, flag: number): number {
|
|
931
|
+
switch (flag) {
|
|
932
|
+
case CV_ERR_FAILURE:
|
|
933
|
+
mem.cv_error = `Error test failures at t=${mem.cv_tn}, h=${mem.cv_h}`;
|
|
934
|
+
break;
|
|
935
|
+
case CV_CONV_FAILURE:
|
|
936
|
+
mem.cv_error = `Convergence failures at t=${mem.cv_tn}, h=${mem.cv_h}`;
|
|
937
|
+
break;
|
|
938
|
+
case CV_LSETUP_FAIL:
|
|
939
|
+
mem.cv_error = `Linear solver setup failed at t=${mem.cv_tn}`;
|
|
940
|
+
break;
|
|
941
|
+
case CV_LSOLVE_FAIL:
|
|
942
|
+
mem.cv_error = `Linear solver solve failed at t=${mem.cv_tn}`;
|
|
943
|
+
break;
|
|
944
|
+
case CV_RHSFUNC_FAIL:
|
|
945
|
+
mem.cv_error = `RHS function failed at t=${mem.cv_tn}`;
|
|
946
|
+
break;
|
|
947
|
+
case CV_UNREC_RHSFUNC_ERR:
|
|
948
|
+
mem.cv_error = `Unrecoverable RHS function error at t=${mem.cv_tn}`;
|
|
949
|
+
break;
|
|
950
|
+
case CV_REPTD_RHSFUNC_ERR:
|
|
951
|
+
mem.cv_error = `Repeated RHS function errors at t=${mem.cv_tn}`;
|
|
952
|
+
break;
|
|
953
|
+
case CV_RTFUNC_FAIL:
|
|
954
|
+
mem.cv_error = `Root function failed at t=${mem.cv_tn}`;
|
|
955
|
+
break;
|
|
956
|
+
case CV_TOO_CLOSE:
|
|
957
|
+
mem.cv_error = 'tout too close to t0';
|
|
958
|
+
break;
|
|
959
|
+
default:
|
|
960
|
+
mem.cv_error = `Unrecognized failure flag: ${flag}`;
|
|
961
|
+
break;
|
|
962
|
+
}
|
|
963
|
+
return flag;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
/** cvBDFStab - BDF stability limit detection (STALD) */
|
|
967
|
+
function cvBDFStab(mem: CvodeMem): void {
|
|
968
|
+
// If order >= 3, save scaled derivative data
|
|
969
|
+
if (mem.cv_q >= 3) {
|
|
970
|
+
for (let k = 1; k <= 3; k++) {
|
|
971
|
+
for (let i = 5; i >= 2; i--)
|
|
972
|
+
mem.cv_ssdat[i][k] = mem.cv_ssdat[i - 1][k];
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
let factorial = 1;
|
|
976
|
+
for (let i = 1; i <= mem.cv_q - 1; i++) factorial *= i;
|
|
977
|
+
|
|
978
|
+
const sq = factorial * mem.cv_q * (mem.cv_q + 1) * mem.cv_acnrm /
|
|
979
|
+
Math.max(mem.cv_tq[5], TINY);
|
|
980
|
+
const sqm1 = factorial * mem.cv_q *
|
|
981
|
+
wrmsNorm(mem.cv_N, mem.cv_zn[mem.cv_q], mem.cv_ewt);
|
|
982
|
+
const sqm2 = factorial *
|
|
983
|
+
wrmsNorm(mem.cv_N, mem.cv_zn[mem.cv_q - 1], mem.cv_ewt);
|
|
984
|
+
|
|
985
|
+
mem.cv_ssdat[1][1] = sqm2 * sqm2;
|
|
986
|
+
mem.cv_ssdat[1][2] = sqm1 * sqm1;
|
|
987
|
+
mem.cv_ssdat[1][3] = sq * sq;
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
if (mem.cv_qprime >= mem.cv_q) {
|
|
991
|
+
// If enough data, call stability limit detection
|
|
992
|
+
if (mem.cv_q >= 3 && mem.cv_nscon >= mem.cv_q + 5) {
|
|
993
|
+
const ldflag = cvSLdet(mem);
|
|
994
|
+
if (ldflag > 3) {
|
|
995
|
+
// Stability limit violation: reduce order
|
|
996
|
+
mem.cv_qprime = mem.cv_q - 1;
|
|
997
|
+
mem.cv_eta = mem.cv_etaqm1;
|
|
998
|
+
mem.cv_eta = Math.min(mem.cv_eta, mem.cv_etamax);
|
|
999
|
+
mem.cv_eta = mem.cv_eta /
|
|
1000
|
+
Math.max(1.0, Math.abs(mem.cv_h) * mem.cv_hmax_inv * mem.cv_eta);
|
|
1001
|
+
mem.cv_hprime = mem.cv_h * mem.cv_eta;
|
|
1002
|
+
mem.cv_nor = mem.cv_nor + 1;
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
} else {
|
|
1006
|
+
// Let order increase happen, reset nscon
|
|
1007
|
+
mem.cv_nscon = 0;
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
/** cvSLdet - Stability limit detection algorithm (~300 lines from C) */
|
|
1012
|
+
function cvSLdet(mem: CvodeMem): number {
|
|
1013
|
+
let kmin = 0;
|
|
1014
|
+
let kflag = 0;
|
|
1015
|
+
|
|
1016
|
+
// Allocate local arrays with 1-based indexing
|
|
1017
|
+
const rat: number[][] = [];
|
|
1018
|
+
for (let i = 0; i < 5; i++) rat[i] = [0, 0, 0, 0];
|
|
1019
|
+
const rav = [0, 0, 0, 0];
|
|
1020
|
+
const qkr = [0, 0, 0, 0];
|
|
1021
|
+
const sigsq = [0, 0, 0, 0];
|
|
1022
|
+
const smax = [0, 0, 0, 0];
|
|
1023
|
+
const ssmax = [0, 0, 0, 0];
|
|
1024
|
+
const drr = [0, 0, 0, 0];
|
|
1025
|
+
const rrc = [0, 0, 0, 0];
|
|
1026
|
+
const sqmx = [0, 0, 0, 0];
|
|
1027
|
+
const vrat = [0, 0, 0, 0, 0];
|
|
1028
|
+
|
|
1029
|
+
// qjk[j][k], qc[i][k], qco[i][k] - all 1-based
|
|
1030
|
+
const qjk: number[][] = [];
|
|
1031
|
+
for (let j = 0; j < 4; j++) qjk[j] = [0, 0, 0, 0];
|
|
1032
|
+
const qc: number[][] = [];
|
|
1033
|
+
for (let i = 0; i < 6; i++) qc[i] = [0, 0, 0, 0];
|
|
1034
|
+
const qco: number[][] = [];
|
|
1035
|
+
for (let i = 0; i < 6; i++) qco[i] = [0, 0, 0, 0];
|
|
1036
|
+
|
|
1037
|
+
// Cutoffs and tolerances
|
|
1038
|
+
const rrcut = 0.98;
|
|
1039
|
+
const vrrtol = 1.0e-4;
|
|
1040
|
+
const vrrt2 = 5.0e-4;
|
|
1041
|
+
const sqtol = 1.0e-3;
|
|
1042
|
+
const rrtol = 1.0e-2;
|
|
1043
|
+
|
|
1044
|
+
let rr = 0.0;
|
|
1045
|
+
|
|
1046
|
+
// Get maxima, minima, and variances, form quartic coefficients
|
|
1047
|
+
for (let k = 1; k <= 3; k++) {
|
|
1048
|
+
let smink = mem.cv_ssdat[1][k];
|
|
1049
|
+
let smaxk = 0.0;
|
|
1050
|
+
|
|
1051
|
+
for (let i = 1; i <= 5; i++) {
|
|
1052
|
+
smink = Math.min(smink, mem.cv_ssdat[i][k]);
|
|
1053
|
+
smaxk = Math.max(smaxk, mem.cv_ssdat[i][k]);
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
if (smink < TINY * smaxk) return -1;
|
|
1057
|
+
|
|
1058
|
+
smax[k] = smaxk;
|
|
1059
|
+
ssmax[k] = smaxk * smaxk;
|
|
1060
|
+
|
|
1061
|
+
let sumrat = 0.0;
|
|
1062
|
+
let sumrsq = 0.0;
|
|
1063
|
+
for (let i = 1; i <= 4; i++) {
|
|
1064
|
+
rat[i][k] = mem.cv_ssdat[i][k] / mem.cv_ssdat[i + 1][k];
|
|
1065
|
+
sumrat += rat[i][k];
|
|
1066
|
+
sumrsq += rat[i][k] * rat[i][k];
|
|
1067
|
+
}
|
|
1068
|
+
rav[k] = 0.25 * sumrat;
|
|
1069
|
+
vrat[k] = Math.abs(0.25 * sumrsq - rav[k] * rav[k]);
|
|
1070
|
+
|
|
1071
|
+
qc[5][k] = mem.cv_ssdat[1][k] * mem.cv_ssdat[3][k] -
|
|
1072
|
+
mem.cv_ssdat[2][k] * mem.cv_ssdat[2][k];
|
|
1073
|
+
qc[4][k] = mem.cv_ssdat[2][k] * mem.cv_ssdat[3][k] -
|
|
1074
|
+
mem.cv_ssdat[1][k] * mem.cv_ssdat[4][k];
|
|
1075
|
+
qc[3][k] = 0.0;
|
|
1076
|
+
qc[2][k] = mem.cv_ssdat[2][k] * mem.cv_ssdat[5][k] -
|
|
1077
|
+
mem.cv_ssdat[3][k] * mem.cv_ssdat[4][k];
|
|
1078
|
+
qc[1][k] = mem.cv_ssdat[4][k] * mem.cv_ssdat[4][k] -
|
|
1079
|
+
mem.cv_ssdat[3][k] * mem.cv_ssdat[5][k];
|
|
1080
|
+
|
|
1081
|
+
for (let i = 1; i <= 5; i++) qco[i][k] = qc[i][k];
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
// Isolate normal or nearly-normal matrix case
|
|
1085
|
+
const vmin = Math.min(vrat[1], Math.min(vrat[2], vrat[3]));
|
|
1086
|
+
const vmax = Math.max(vrat[1], Math.max(vrat[2], vrat[3]));
|
|
1087
|
+
|
|
1088
|
+
if (vmin < vrrtol * vrrtol) {
|
|
1089
|
+
if (vmax > vrrt2 * vrrt2) return -2;
|
|
1090
|
+
else {
|
|
1091
|
+
rr = (rav[1] + rav[2] + rav[3]) / 3.0;
|
|
1092
|
+
let drrmax = 0.0;
|
|
1093
|
+
for (let k = 1; k <= 3; k++) {
|
|
1094
|
+
const adrr = Math.abs(rav[k] - rr);
|
|
1095
|
+
drrmax = Math.max(drrmax, adrr);
|
|
1096
|
+
}
|
|
1097
|
+
if (drrmax > vrrt2) return -3;
|
|
1098
|
+
kflag = 1;
|
|
1099
|
+
}
|
|
1100
|
+
} else {
|
|
1101
|
+
// Use quartics to get rr
|
|
1102
|
+
if (Math.abs(qco[1][1]) < TINY * ssmax[1]) return -4;
|
|
1103
|
+
|
|
1104
|
+
let tem = qco[1][2] / qco[1][1];
|
|
1105
|
+
for (let i = 2; i <= 5; i++) qco[i][2] = qco[i][2] - tem * qco[i][1];
|
|
1106
|
+
qco[1][2] = 0.0;
|
|
1107
|
+
|
|
1108
|
+
tem = qco[1][3] / qco[1][1];
|
|
1109
|
+
for (let i = 2; i <= 5; i++) qco[i][3] = qco[i][3] - tem * qco[i][1];
|
|
1110
|
+
qco[1][3] = 0.0;
|
|
1111
|
+
|
|
1112
|
+
if (Math.abs(qco[2][2]) < TINY * ssmax[2]) return -4;
|
|
1113
|
+
|
|
1114
|
+
tem = qco[2][3] / qco[2][2];
|
|
1115
|
+
for (let i = 3; i <= 5; i++) qco[i][3] = qco[i][3] - tem * qco[i][2];
|
|
1116
|
+
|
|
1117
|
+
if (Math.abs(qco[4][3]) < TINY * ssmax[3]) return -4;
|
|
1118
|
+
|
|
1119
|
+
rr = -qco[5][3] / qco[4][3];
|
|
1120
|
+
|
|
1121
|
+
if (rr < TINY || rr > 100.0) return -5;
|
|
1122
|
+
|
|
1123
|
+
for (let k = 1; k <= 3; k++)
|
|
1124
|
+
qkr[k] = qc[5][k] + rr * (qc[4][k] + rr * rr * (qc[2][k] + rr * qc[1][k]));
|
|
1125
|
+
|
|
1126
|
+
|
|
1127
|
+
let sqmax = 0.0;
|
|
1128
|
+
for (let k = 1; k <= 3; k++) {
|
|
1129
|
+
const saqk = Math.abs(qkr[k]) / ssmax[k];
|
|
1130
|
+
if (saqk > sqmax) sqmax = saqk;
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
if (sqmax < sqtol)
|
|
1134
|
+
kflag = 2;
|
|
1135
|
+
else {
|
|
1136
|
+
// Newton corrections to improve rr
|
|
1137
|
+
for (let it = 1; it <= 3; it++) {
|
|
1138
|
+
for (let k = 1; k <= 3; k++) {
|
|
1139
|
+
const qp = qc[4][k] + rr * rr * (3.0 * qc[2][k] + rr * 4.0 * qc[1][k]);
|
|
1140
|
+
drr[k] = 0.0;
|
|
1141
|
+
if (Math.abs(qp) > TINY * ssmax[k]) drr[k] = -qkr[k] / qp;
|
|
1142
|
+
rrc[k] = rr + drr[k];
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
for (let k = 1; k <= 3; k++) {
|
|
1146
|
+
const s = rrc[k];
|
|
1147
|
+
let sqmaxk = 0.0;
|
|
1148
|
+
for (let j = 1; j <= 3; j++) {
|
|
1149
|
+
qjk[j][k] = qc[5][j] + s * (qc[4][j] + s * s * (qc[2][j] + s * qc[1][j]));
|
|
1150
|
+
const saqj = Math.abs(qjk[j][k]) / ssmax[j];
|
|
1151
|
+
if (saqj > sqmaxk) sqmaxk = saqj;
|
|
1152
|
+
}
|
|
1153
|
+
sqmx[k] = sqmaxk;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
let sqmin = sqmx[1] + 1.0;
|
|
1157
|
+
for (let k = 1; k <= 3; k++) {
|
|
1158
|
+
if (sqmx[k] < sqmin) {
|
|
1159
|
+
kmin = k;
|
|
1160
|
+
sqmin = sqmx[k];
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
rr = rrc[kmin];
|
|
1164
|
+
|
|
1165
|
+
if (sqmin < sqtol) {
|
|
1166
|
+
kflag = 3;
|
|
1167
|
+
break;
|
|
1168
|
+
} else
|
|
1169
|
+
for (let j = 1; j <= 3; j++) qkr[j] = qjk[j][kmin];
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
if (kflag !== 3) {
|
|
1173
|
+
// sqmin > sqtol after all Newton iterations
|
|
1174
|
+
return -6;
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
// Given rr, find sigsq[k] and verify rr
|
|
1180
|
+
for (let k = 1; k <= 3; k++) {
|
|
1181
|
+
const rsa = mem.cv_ssdat[1][k];
|
|
1182
|
+
const rsb = mem.cv_ssdat[2][k] * rr;
|
|
1183
|
+
const rsc = mem.cv_ssdat[3][k] * rr * rr;
|
|
1184
|
+
const rsd = mem.cv_ssdat[4][k] * rr * rr * rr;
|
|
1185
|
+
const rd1a = rsa - rsb;
|
|
1186
|
+
const rd1b = rsb - rsc;
|
|
1187
|
+
const rd1c = rsc - rsd;
|
|
1188
|
+
const rd2a = rd1a - rd1b;
|
|
1189
|
+
const rd2b = rd1b - rd1c;
|
|
1190
|
+
const rd3a = rd2a - rd2b;
|
|
1191
|
+
|
|
1192
|
+
if (Math.abs(rd1b) < TINY * smax[k]) return -7;
|
|
1193
|
+
|
|
1194
|
+
const cest1 = -rd3a / rd1b;
|
|
1195
|
+
if (cest1 < TINY || cest1 > 4.0) return -7;
|
|
1196
|
+
|
|
1197
|
+
const corr1 = (rd2b / cest1) / (rr * rr);
|
|
1198
|
+
sigsq[k] = mem.cv_ssdat[3][k] + corr1;
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
if (sigsq[2] < TINY) return -8;
|
|
1202
|
+
|
|
1203
|
+
const ratp = sigsq[3] / sigsq[2];
|
|
1204
|
+
const ratm = sigsq[1] / sigsq[2];
|
|
1205
|
+
const qfac1 = 0.25 * (mem.cv_q * mem.cv_q - 1);
|
|
1206
|
+
const qfac2 = 2.0 / (mem.cv_q - 1);
|
|
1207
|
+
const bb = ratp * ratm - 1.0 - qfac1 * ratp;
|
|
1208
|
+
const tem2 = 1.0 - qfac2 * bb;
|
|
1209
|
+
|
|
1210
|
+
if (Math.abs(tem2) < TINY) return -8;
|
|
1211
|
+
|
|
1212
|
+
const rrb = 1.0 / tem2;
|
|
1213
|
+
|
|
1214
|
+
if (Math.abs(rrb - rr) > rrtol) return -9;
|
|
1215
|
+
|
|
1216
|
+
// Check if rr is above cutoff
|
|
1217
|
+
if (rr > rrcut) {
|
|
1218
|
+
if (kflag === 1) kflag = 4;
|
|
1219
|
+
if (kflag === 2) kflag = 5;
|
|
1220
|
+
if (kflag === 3) kflag = 6;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
return kflag;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
// Rootfinding functions imported from cvode_root.ts (cvRcheck1, cvRcheck2, cvRcheck3)
|