driftlet 1.2.4 → 1.3.2
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/README.md +1 -1
- package/docs/conventions.md +8 -3
- package/docs/device.md +38 -9
- package/docs/internals.md +33 -14
- package/docs/numerics.md +65 -15
- package/docs/reliability.md +25 -16
- package/docs/statistics.md +13 -0
- package/llms.txt +11 -8
- package/package.json +1 -1
- package/src/assemble.js +206 -0
- package/src/bernoulli.js +32 -0
- package/src/boundaries.js +795 -0
- package/src/describe.js +2 -0
- package/src/device.js +32 -6
- package/src/impedance.js +857 -0
- package/src/index.js +25 -1
- package/src/newton.js +605 -0
- package/src/regions.js +1009 -0
- package/src/solution.js +24 -2
- package/src/solver.js +178 -3643
- package/src/start.js +508 -0
- package/src/steady.js +817 -0
- package/src/timeSteps.js +17 -2
- package/src/types.js +3 -0
- package/types/assemble.d.ts +18 -0
- package/types/bernoulli.d.ts +9 -0
- package/types/boundaries.d.ts +24 -0
- package/types/impedance.d.ts +53 -0
- package/types/newton.d.ts +7 -0
- package/types/regions.d.ts +61 -0
- package/types/solver.d.ts +14 -220
- package/types/start.d.ts +14 -0
- package/types/steady.d.ts +81 -0
- package/types/types.d.ts +6 -0
package/src/timeSteps.js
CHANGED
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
// (ports' charges) }: what BDF2 and the predictor need.
|
|
22
22
|
//
|
|
23
23
|
// step(s, dt, opts) → newton's result (+ bdf)
|
|
24
|
+
// From a cold start (s.coldStart, outside a steady solve), the faces between strictly neutral
|
|
25
|
+
// regions first set to their t = 0⁺ equilibrium (equilibrateFaces, src/start.js).
|
|
24
26
|
// One step from s.time to tEnd = s.time + dt (or s.landing exactly, where it's within 1e-9·dt
|
|
25
27
|
// of that). Backward Euler; BDF2 when opts.method is 'bdf2', a previous step exists and the
|
|
26
28
|
// ratio ω = dt/dt_prev ≤ 2: then c* = b1·c_n − b2·c_{n−1} (b1 = (1+ω)/a0, b2 = ω²/((1+ω)a0),
|
|
@@ -85,6 +87,7 @@
|
|
|
85
87
|
|
|
86
88
|
import { nextBreakpoint } from './device.js';
|
|
87
89
|
import { SolverError } from './solver.js';
|
|
90
|
+
import { equilibrateFaces } from './start.js';
|
|
88
91
|
|
|
89
92
|
// Lagrange weights at x through the points s0, s1, s2.
|
|
90
93
|
function lagrange3(x, s0, s1, s2) {
|
|
@@ -120,6 +123,8 @@ export function advance(s, dt, opts, depth = 0) {
|
|
|
120
123
|
* the start-of-step values, and dt/a0 replaces dt.
|
|
121
124
|
*/
|
|
122
125
|
export function step(s, dt, opts = {}) {
|
|
126
|
+
// A transient's first step from a cold start begins at its t = 0⁺ (see equilibrateFaces).
|
|
127
|
+
if (s.coldStart && !s.steady) equilibrateFaces(s);
|
|
123
128
|
// What the step overwrites before Newton runs, for a failed one to put back: the Solution read
|
|
124
129
|
// after it takes its contacts' fluxes against the start-of-step values (a host emptied by its
|
|
125
130
|
// current read its contact's Li⁺ flux 8× off at the same state).
|
|
@@ -262,6 +267,7 @@ export function integrate(s, tEnd, opts = {}) {
|
|
|
262
267
|
const sample = s._probes(opts.probes);
|
|
263
268
|
const trace = { t: [], current: [], voltage: [], ...(sample ? { probes: sample.out } : {}) };
|
|
264
269
|
let steps = 0, rejected = 0, iterations = 0, failed = false;
|
|
270
|
+
s.modelError = null; // (a statistics model's refusal, for the failure: see newton)
|
|
265
271
|
// Already there (an animation frame with no time to add): nothing to do, and the step size
|
|
266
272
|
// carried to the next call stays as it was. A time already passed, or reached again outside
|
|
267
273
|
// an animation, is most likely advance(dt) read as a duration: say so.
|
|
@@ -269,7 +275,7 @@ export function integrate(s, tEnd, opts = {}) {
|
|
|
269
275
|
const relative = tEnd < s.time || (s.time > 0 && opts.budgetMs === undefined);
|
|
270
276
|
return { converged: true, done: true, steps: 0, rejected: 0, iterations: 0, trace, ...(relative ? { stopped: `advance(${tEnd}) did nothing: ${absolute}. To run for a further dt, advance(sol.time + dt)` } : {}) };
|
|
271
277
|
}
|
|
272
|
-
const t0 = s.time;
|
|
278
|
+
const t0 = s.time, fromLayout = s.history.length === 0 && !s.stepped && !s.atSteady; // (c0's layout, not a solution)
|
|
273
279
|
// A cold start whose floating double layers start uncharged far from the equilibrium of an ion
|
|
274
280
|
// link beside them (a capacitive contact or port passing K⁺, its outside level set for the
|
|
275
281
|
// charged steady state): the link closes the gap in the first instant, which can be far below
|
|
@@ -390,8 +396,17 @@ export function integrate(s, tEnd, opts = {}) {
|
|
|
390
396
|
// (What usually does it, most likely first. Round 11's agents read the old list, which led
|
|
391
397
|
// with a drive's jump, as blaming a modest current pulse: a host emptied at its surface, and
|
|
392
398
|
// an electrode at open circuit with no double layer, held only by a slow reaction.)
|
|
393
|
-
|
|
399
|
+
const unbalanced = s.history.length === 0 && s.time === t0 ? (s.unbalanced ?? []).map((r) => s.model.regions[r].name ?? `regions[${r}]`) : [];
|
|
400
|
+
if (failed && unbalanced.length > 0 && s.time === t0)
|
|
401
|
+
stopped = `${at}: the start can't be neutral in ${unbalanced.join(', ')}, strictly neutral (ε = 0): the amounts its c0 gives leave a net charge that no species held at a contact's level can balance, and a step can't move a stored amount at once. Give c0 that balances (with any fixed charge), or leave out of c0 the species a contact feeds, so that they start at its level.`;
|
|
402
|
+
else if (failed && violent.length > 0)
|
|
394
403
|
stopped = `${at}: a step did not converge even when shortened to ${dt.toExponential(1)} s. The start is violent: ${violent.join('; ')}. A double layer starts uncharged, and what passes beside it closes such a gap in the first instant, faster than any step can follow. For a start in equilibrium, solve() first (the steady state at the starting drives), then change what the experiment changes, then advance(). Where solve() fails from there too, hold that terminal at a voltage, solve(), then let it float (set its I: 0): it keeps the state the held one gave it.`;
|
|
404
|
+
else if (failed && s.modelError)
|
|
405
|
+
stopped = `${at}: a step did not converge even when shortened to ${dt.toExponential(1)} s, the state it reached refused by a statistics model: ${s.modelError}. The model doesn't hold there: a smaller concentration or drive, or a model for it (lattice for crowding).`;
|
|
406
|
+
else if (failed && fromLayout && steps === 0)
|
|
407
|
+
// (round 15's fuzzer: the pn template advanced from its c0, a step of 3e-24 s failing, 23 of 62
|
|
408
|
+
// plain diodes; nothing said to solve first)
|
|
409
|
+
stopped = `${at}: the first step did not converge even when shortened to ${dt.toExponential(1)} s, from the starting state, which is c0's layout rather than a solution (a junction's depletion not yet formed, say). For a transient from equilibrium, solve() first at the starting drives, then change what the experiment changes, then advance().`;
|
|
395
410
|
else if (failed) stopped = `${at}: a step did not converge even when shortened to ${dt.toExponential(1)} s. Look for: a host or surface driven to its limit (emptied or filled at its surface by a current it can no longer pass); an electrode at open circuit held only by a slow reaction, with no double-layer capacitance to keep its level (give its face one: phi capacitive); a drive's jump too big for one step (ramp it); a driven current the device cannot keep passing (a diode's reverse recovery past its storage time: stop there); or a device the steady solves also find hard.`;
|
|
396
411
|
else if (s.time < tEnd && steps + rejected >= maxSteps) stopped = `${at}: maxSteps (${maxSteps}) used up (${rejected} of them rejected). Call again to go on, or loosen tol.`;
|
|
397
412
|
return { converged: !failed, done: s.time >= tEnd, steps, rejected, iterations, trace, ...(stopped ? { stopped } : {}) };
|
package/src/types.js
CHANGED
|
@@ -317,6 +317,9 @@
|
|
|
317
317
|
* @typedef {object} ImpedanceResult
|
|
318
318
|
* @property {Float64Array} f frequencies, Hz
|
|
319
319
|
* @property {{ re: Float64Array, im: Float64Array }} Z impedance δV/δI at the terminal, I into the device, Ω·m²
|
|
320
|
+
* @property {Float64Array} relError each Z's estimated error, relative to |Z| (on Re Z and Im Z alike): the current's round-off
|
|
321
|
+
* and the solves' residuals; cautious (it can exceed the true error many times). Over 1%, or over 10·|Re Z|/|Z|,
|
|
322
|
+
* a warning says so
|
|
320
323
|
* @property {{ phi: ComplexProfile, mu: Record<string, ComplexProfile>, c: Record<string, ComplexProfile> }[]} [profiles]
|
|
321
324
|
* per frequency, per unit excitation (volt, or A/m² in current mode)
|
|
322
325
|
* @property {string[]} warnings the steady state's warnings, which hold for its impedance too
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export class Assembly {
|
|
2
|
+
_j(rb: any, rs: any, cb: any, cs: any, v: any): void;
|
|
3
|
+
/** Assemble residual and Jacobian for a backward-Euler step of size dt. */
|
|
4
|
+
assemble(dt: any): void;
|
|
5
|
+
dtNow: any;
|
|
6
|
+
transformed: boolean;
|
|
7
|
+
_replaceRow(b: any, rs: any): void;
|
|
8
|
+
_assembleDifference(dt: any): {
|
|
9
|
+
rest: any;
|
|
10
|
+
lin: DifferenceTerms;
|
|
11
|
+
};
|
|
12
|
+
sysRest: any;
|
|
13
|
+
diffTerms: DifferenceTerms;
|
|
14
|
+
sys: any;
|
|
15
|
+
lin: DifferenceTerms;
|
|
16
|
+
_assembleBookkeeping(dt: any): void;
|
|
17
|
+
}
|
|
18
|
+
import { DifferenceTerms } from './difference.js';
|
package/types/bernoulli.d.ts
CHANGED
|
@@ -2,3 +2,12 @@
|
|
|
2
2
|
export function bernoulli(x: any): number;
|
|
3
3
|
/** dB/dx, with B'(0) = −1/2. */
|
|
4
4
|
export function bernoulliDerivative(x: any): number;
|
|
5
|
+
/**
|
|
6
|
+
* A Scharfetter–Gummel flux N = −g·B(d)·c_L·expm1(Δη) and its derivatives, into `out`: [N, ∂N/∂d,
|
|
7
|
+
* g·B(d)·c_L (= ∂N/∂η_L), g·B(d)·c_L·e^{Δη} (= −∂N/∂η_R), −g·expm1(Δη)·(B(d) + B′(d)) (the
|
|
8
|
+
* non-ideal kernel's ∂N/∂ζ_L per unit K_L)]. d is the drift, Δη the difference of levels, so
|
|
9
|
+
* that c_R = c_L e^{Δη−d}. From d = SG_FAR on, the same flux from the downstream end, N =
|
|
10
|
+
* g·B(−d)·c_R·expm1(−Δη), whose factors stay finite; ∂N/∂d = N·B′(d)/B(d).
|
|
11
|
+
*/
|
|
12
|
+
export function sgFlux(g: any, d: any, deta: any, cL: any, cR: any, out: any): any;
|
|
13
|
+
export const SG_FAR: 300;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export function gateRate(law: any, V: any): number[];
|
|
2
|
+
export class BoundaryTerms {
|
|
3
|
+
_portRate(port: any, rx: any, g: any): number;
|
|
4
|
+
_face(f: any): void;
|
|
5
|
+
_gateSlot(f: any, q: any): any;
|
|
6
|
+
_gateVoltage(gt: any): number;
|
|
7
|
+
_portVoltage(k: any, g: any): number;
|
|
8
|
+
_faceVoltage(f: any): number;
|
|
9
|
+
_faceGates(f: any, bf: any, bL: any, bR: any): void;
|
|
10
|
+
_faceReaction(rx: any, k: any, f: any, bf: any, bL: any, bR: any, Af: any): void;
|
|
11
|
+
_liveTerms(): any;
|
|
12
|
+
_allTerms: any;
|
|
13
|
+
_terminals(dt: any): void;
|
|
14
|
+
_circuit(k: any): void;
|
|
15
|
+
_captureRow(b: any, s: any, w: any, into: any, k?: number): any;
|
|
16
|
+
_port(port: any, flux: any, k: any, dt: any, holds: any): void;
|
|
17
|
+
_portReaction(port: any, rx: any, area: any, rates: any, flux: any, k: any): void;
|
|
18
|
+
_portGates(port: any, k: any, dt: any): void;
|
|
19
|
+
_open(gated: any, x: any): number;
|
|
20
|
+
_dOpen(gated: any, q: any, p: any, x: any): number;
|
|
21
|
+
_portCapacitance(port: any, k: any, dt: any): void;
|
|
22
|
+
_surfaceStorage(port: any, dt: any): void;
|
|
23
|
+
_contact(side: any, dt: any): void;
|
|
24
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export class SmallSignal {
|
|
2
|
+
/**
|
|
3
|
+
* Small-signal impedance about the current (steady) state, seen at one terminal. Linearising
|
|
4
|
+
* gives (J + iωM)·δx + Σ B_k δV_k = rhs for the grid's rows, and (C_k + iωC′_k)·δx +
|
|
5
|
+
* (∂I_k/∂V_k)·δV_k = δI_set,k for each floating terminal's circuit row, with J the steady
|
|
6
|
+
* Jacobian and M the storage part (from J(dt) = J + M/dt), B_k = ∂res/∂V_k and C_k = ∂I_k/∂x.
|
|
7
|
+
* At the measured terminal, its voltage is perturbed (rhs = −B δV) and its current read, held
|
|
8
|
+
* or driven by a current alike (one input impedance; see the contract). The other terminals
|
|
9
|
+
* keep their drives: held ones at AC ground, driven ones at AC open circuit.
|
|
10
|
+
* Z = δV/δI with I into the device (positive real part for a passive device).
|
|
11
|
+
* @param {ArrayLike<number>} frequencies Hz
|
|
12
|
+
*/
|
|
13
|
+
impedance(frequencies: ArrayLike<number>, opts: any): {
|
|
14
|
+
f: Float64Array<ArrayBuffer>;
|
|
15
|
+
Z: {
|
|
16
|
+
re: Float64Array<any>;
|
|
17
|
+
im: Float64Array<any>;
|
|
18
|
+
};
|
|
19
|
+
relError: Float64Array<any>;
|
|
20
|
+
};
|
|
21
|
+
allTerminals: any;
|
|
22
|
+
_impedance(frequencies: any, { profiles, terminal }?: {
|
|
23
|
+
profiles?: boolean;
|
|
24
|
+
terminal?: string;
|
|
25
|
+
}): {
|
|
26
|
+
f: Float64Array<ArrayBuffer>;
|
|
27
|
+
Z: {
|
|
28
|
+
re: Float64Array<any>;
|
|
29
|
+
im: Float64Array<any>;
|
|
30
|
+
};
|
|
31
|
+
relError: Float64Array<any>;
|
|
32
|
+
};
|
|
33
|
+
sourceTime: any;
|
|
34
|
+
contactDStart: any;
|
|
35
|
+
portQStart: Float64Array<ArrayBuffer>;
|
|
36
|
+
lawForm: Map<any, boolean>;
|
|
37
|
+
_regionShift(yr: any, yi: any): Float64Array<any>[];
|
|
38
|
+
_regionEdgeRows(): Uint8Array<any>;
|
|
39
|
+
_currentCuts(): {
|
|
40
|
+
s: any;
|
|
41
|
+
idx: any[];
|
|
42
|
+
g: any[];
|
|
43
|
+
d: any[];
|
|
44
|
+
}[];
|
|
45
|
+
_smallSignalProfiles(xr: any, xi: any): {
|
|
46
|
+
phi: {
|
|
47
|
+
re: Float64Array<any>;
|
|
48
|
+
im: Float64Array<any>;
|
|
49
|
+
};
|
|
50
|
+
mu: {};
|
|
51
|
+
c: {};
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export class RegionTerms {
|
|
2
|
+
_coverages(): void;
|
|
3
|
+
computeConcentrations(): void;
|
|
4
|
+
_work(md: any): any;
|
|
5
|
+
_nodeStatistics(g: any, b: any, phiHat: any): void;
|
|
6
|
+
_statSlopes(g: any, mat: any): void;
|
|
7
|
+
_Kz(g: any, i: any): number;
|
|
8
|
+
/** zᵀKz at node g (per RT): the charge response that sets the screening length. */
|
|
9
|
+
screening(g: any): number;
|
|
10
|
+
_dlnc(g: any, i: any, w: any, d: any): void;
|
|
11
|
+
_nodeConductor(g: any, dt: any): void;
|
|
12
|
+
_portHeldAt(g: any, i: any): boolean;
|
|
13
|
+
_nodesDilute(g0: any, g1: any, dt: any): void;
|
|
14
|
+
_nodeConcentrated(g: any, dt: any): void;
|
|
15
|
+
_storage(g: any, i: any, dt: any, Kz?: number): void;
|
|
16
|
+
_chargeRows(dt: any): void;
|
|
17
|
+
_untransform(delta: any): void;
|
|
18
|
+
_bulkReactions(g: any, rxs: any): void;
|
|
19
|
+
_segmentDisplacement(s: any, bL: any, bR: any, mat: any, h: any): any;
|
|
20
|
+
_segmentsDilute(g0: any, g1: any, region: any, mat: any, vel: any): void;
|
|
21
|
+
_segmentConcentrated(s: any, bL: any, bR: any, mat: any, h: any, vel: any): void;
|
|
22
|
+
_fluxConcentrated(s: any, bL: any, bR: any, mat: any, h: any, vel: any, i: any): {
|
|
23
|
+
N: any;
|
|
24
|
+
gBcE1: any;
|
|
25
|
+
dNdd: any;
|
|
26
|
+
fL: any;
|
|
27
|
+
cR: any;
|
|
28
|
+
};
|
|
29
|
+
_segmentConductor(s: any, bL: any, bR: any, mat: any, h: any): void;
|
|
30
|
+
_segmentMixing(s: any, bL: any, bR: any, Dm: any, h: any, mat: any): void;
|
|
31
|
+
mixWork: Float64Array<any>[];
|
|
32
|
+
_mixCrowded(gL: any, gR: any, bL: any, bR: any, on: any, k0: any): void;
|
|
33
|
+
_dKslot(g: any, i: any, j: any, t: any): any;
|
|
34
|
+
_mixBase(gL: any, gR: any, bL: any, bR: any, on: any): {
|
|
35
|
+
Jl: Float64Array<ArrayBuffer>;
|
|
36
|
+
Jr: Float64Array<ArrayBuffer>;
|
|
37
|
+
dcs: Float64Array<ArrayBuffer>;
|
|
38
|
+
};
|
|
39
|
+
mixCrowd: {
|
|
40
|
+
Jl: Float64Array<ArrayBuffer>;
|
|
41
|
+
Jr: Float64Array<ArrayBuffer>;
|
|
42
|
+
dcs: Float64Array<ArrayBuffer>;
|
|
43
|
+
};
|
|
44
|
+
_Kat(g: any, i: any, j: any): any;
|
|
45
|
+
_dc(g: any, k: any, d: any): void;
|
|
46
|
+
bulkRate(rx: any, g: any): number;
|
|
47
|
+
bulkForward(rx: any, g: any): any;
|
|
48
|
+
bulkOneWay(rx: any, g: any): number;
|
|
49
|
+
_srhRate(law: any, cn: any, cp: any, a: any, xn?: number, xp?: number): {
|
|
50
|
+
rate: number;
|
|
51
|
+
forward: number;
|
|
52
|
+
oneWay: number;
|
|
53
|
+
Cn: number;
|
|
54
|
+
Cp: number;
|
|
55
|
+
Ca: number;
|
|
56
|
+
Cxn: number;
|
|
57
|
+
Cxp: number;
|
|
58
|
+
};
|
|
59
|
+
_srhDegen(gn: any, gq: any, law: any): any[];
|
|
60
|
+
_srhInto(g: any, i: any, C: any, Cx: any, d: any): void;
|
|
61
|
+
}
|
package/types/solver.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
export function profileAt({ x, values: c }: {
|
|
2
|
+
x: any;
|
|
3
|
+
values: any;
|
|
4
|
+
}, at: any): any;
|
|
1
5
|
export class SolverError extends Error {
|
|
2
6
|
constructor(message: any, details: any);
|
|
3
7
|
details: any;
|
|
@@ -49,6 +53,8 @@ export class Solver {
|
|
|
49
53
|
sheetSign: Int8Array<any>;
|
|
50
54
|
conductorLast: Uint8Array<any>;
|
|
51
55
|
K: Float64Array<ArrayBuffer>;
|
|
56
|
+
nodeDK: Uint8Array<any>;
|
|
57
|
+
dK: Float64Array<ArrayBuffer>;
|
|
52
58
|
ex: Float64Array<ArrayBuffer>;
|
|
53
59
|
zeta: Float64Array<any>;
|
|
54
60
|
scratch: Map<any, any>;
|
|
@@ -56,10 +62,11 @@ export class Solver {
|
|
|
56
62
|
dB: Float64Array<any>;
|
|
57
63
|
jL: Float64Array<any>;
|
|
58
64
|
jR: Float64Array<any>;
|
|
65
|
+
sg: Float64Array<ArrayBuffer>;
|
|
59
66
|
time: number;
|
|
60
67
|
lastDt: number;
|
|
61
68
|
atSteady: boolean;
|
|
62
|
-
lin:
|
|
69
|
+
lin: any;
|
|
63
70
|
contactFlux: {
|
|
64
71
|
left: Float64Array<any>;
|
|
65
72
|
right: Float64Array<any>;
|
|
@@ -126,7 +133,7 @@ export class Solver {
|
|
|
126
133
|
_activeSlots(): void;
|
|
127
134
|
active: Uint8Array<ArrayBuffer>;
|
|
128
135
|
loc: Int32Array<ArrayBuffer>;
|
|
129
|
-
sys:
|
|
136
|
+
sys: BlockTridiagonal;
|
|
130
137
|
SINK: number;
|
|
131
138
|
rix: Int32Array<ArrayBuffer>;
|
|
132
139
|
fullOf: Int32Array<ArrayBuffer>;
|
|
@@ -224,136 +231,26 @@ export class Solver {
|
|
|
224
231
|
nodeMaterial: Int32Array<any>;
|
|
225
232
|
phiUndefined: Uint8Array<any>;
|
|
226
233
|
};
|
|
227
|
-
_directSteady(): boolean;
|
|
228
234
|
_surfaceStart(g: any): void;
|
|
229
235
|
/** Amount (mol per unit area) of surface column j's species, Γ Σ v·a·θ, in the current state. */
|
|
230
236
|
surfaceAmount(j: any): number;
|
|
231
237
|
/** Total amount (mol per unit area) of a stretch's species in the current state. */
|
|
232
238
|
amount(stretch: any): number;
|
|
233
239
|
redrive(): void;
|
|
234
|
-
deltaV:
|
|
235
|
-
stuckReactions(): any[];
|
|
240
|
+
deltaV: any;
|
|
236
241
|
_drivenKey(): any;
|
|
237
242
|
_refreshSources(): void;
|
|
238
243
|
/** η_i (μ̄/RT) of a port's outside level for species i (its electrode's carrier: at V itself). */
|
|
239
244
|
portEta(port: any, i: any): number;
|
|
240
245
|
/** η_i/RT that a fixed contact link imposes (or NaN if the link isn't fixed). */
|
|
241
246
|
contactEta(side: any, i: any): number;
|
|
242
|
-
/**
|
|
243
|
-
* Cold start. Each species takes its region's c0 where one is given (for a spectator, it fixes
|
|
244
|
-
* the conserved amount), else its contact's level. φ in each region is then chosen for local neutrality (node by node where a
|
|
245
|
-
* profile varies), or continued across the interface dipole if nothing there responds.
|
|
246
|
-
*/
|
|
247
247
|
initFromComposition(): void;
|
|
248
|
-
|
|
249
|
-
_materialAt(mat: any, background: any, eta: any, mode: any, cFix: any, ph: any, zeta: any, cc: any): void;
|
|
250
|
-
_coverages(): void;
|
|
251
|
-
computeConcentrations(): void;
|
|
252
|
-
_work(md: any): any;
|
|
253
|
-
_nodeStatistics(g: any, b: any, phiHat: any): void;
|
|
254
|
-
_Kz(g: any, i: any): number;
|
|
255
|
-
/** zᵀKz at node g (per RT): the charge response that sets the screening length. */
|
|
256
|
-
screening(g: any): number;
|
|
257
|
-
_dlnc(g: any, i: any, w: any, d: any): void;
|
|
258
|
-
_j(rb: any, rs: any, cb: any, cs: any, v: any): void;
|
|
259
|
-
/** Assemble residual and Jacobian for a backward-Euler step of size dt. */
|
|
260
|
-
assemble(dt: any): void;
|
|
261
|
-
dtNow: any;
|
|
262
|
-
transformed: any;
|
|
263
|
-
_nodeConductor(g: any, dt: any): void;
|
|
264
|
-
_portHeldAt(g: any, i: any): boolean;
|
|
265
|
-
_nodesDilute(g0: any, g1: any, dt: any): void;
|
|
266
|
-
_nodeConcentrated(g: any, dt: any): void;
|
|
267
|
-
_storage(g: any, i: any, dt: any, Kz?: number): void;
|
|
268
|
-
_chargeRows(dt: any): void;
|
|
269
|
-
_untransform(delta: any): void;
|
|
270
|
-
_bulkReactions(g: any, rxs: any): void;
|
|
271
|
-
_segmentDisplacement(s: any, bL: any, bR: any, mat: any, h: any): void;
|
|
272
|
-
_segmentsDilute(g0: any, g1: any, region: any, mat: any, vel: any): void;
|
|
273
|
-
_face(f: any): void;
|
|
274
|
-
_gateSlot(f: any, q: any): any;
|
|
275
|
-
_gateVoltage(gt: any): number;
|
|
276
|
-
_portVoltage(k: any, g: any): number;
|
|
277
|
-
_faceVoltage(f: any): number;
|
|
278
|
-
_faceGates(f: any, bf: any, bL: any, bR: any): void;
|
|
279
|
-
_segmentConcentrated(s: any, bL: any, bR: any, mat: any, h: any, vel: any): void;
|
|
280
|
-
_fluxConcentrated(s: any, bL: any, bR: any, mat: any, h: any, vel: any, i: any): {
|
|
281
|
-
N: number;
|
|
282
|
-
E: number;
|
|
283
|
-
gBc: number;
|
|
284
|
-
dNdd: number;
|
|
285
|
-
fL: number;
|
|
286
|
-
cR: number;
|
|
287
|
-
};
|
|
288
|
-
_segmentConductor(s: any, bL: any, bR: any, mat: any, h: any): void;
|
|
289
|
-
_segmentMixing(s: any, bL: any, bR: any, Dm: any, h: any, mat: any): void;
|
|
290
|
-
mixWork: Float64Array<any>[];
|
|
291
|
-
_dc(g: any, k: any, d: any): void;
|
|
292
|
-
bulkRate(rx: any, g: any): number;
|
|
293
|
-
bulkForward(rx: any, g: any): any;
|
|
294
|
-
bulkOneWay(rx: any, g: any): number;
|
|
295
|
-
_srhRate(law: any, cn: any, cp: any, a: any, xn?: number, xp?: number, sn?: number, sp?: number): {
|
|
296
|
-
rate: number;
|
|
297
|
-
forward: number;
|
|
298
|
-
oneWay: number;
|
|
299
|
-
Cn: number;
|
|
300
|
-
Cp: number;
|
|
301
|
-
Ca: number;
|
|
302
|
-
};
|
|
303
|
-
_srhDegen(gn: any, gq: any, law: any): number[];
|
|
304
|
-
_degen(g: any, i: any): number[];
|
|
305
|
-
_faceReaction(rx: any, k: any, f: any, bf: any, bL: any, bR: any, Af: any): void;
|
|
306
|
-
_liveTerms(): any;
|
|
307
|
-
_allTerms: any;
|
|
308
|
-
_terminals(dt: any): void;
|
|
309
|
-
_circuit(k: any): void;
|
|
310
|
-
_captureRow(b: any, s: any, w: any, into: any): any;
|
|
311
|
-
_port(port: any, flux: any, k: any, dt: any, holds: any): void;
|
|
312
|
-
_portReaction(port: any, rx: any, area: any, rates: any, flux: any, k: any): void;
|
|
313
|
-
_portGates(port: any, k: any, dt: any): void;
|
|
314
|
-
_open(gated: any, x: any): number;
|
|
315
|
-
_dOpen(gated: any, q: any, p: any, x: any): number;
|
|
316
|
-
_portCapacitance(port: any, k: any, dt: any): void;
|
|
317
|
-
_surfaceStorage(port: any, dt: any): void;
|
|
318
|
-
_contact(side: any, dt: any): void;
|
|
319
|
-
_replaceRow(b: any, rs: any): void;
|
|
320
|
-
_equilibrate(): void;
|
|
321
|
-
_assembleDifference(dt: any): {
|
|
322
|
-
rest: any;
|
|
323
|
-
lin: DifferenceTerms;
|
|
324
|
-
};
|
|
325
|
-
sysRest: any;
|
|
326
|
-
diffTerms: DifferenceTerms;
|
|
327
|
-
_refine(dt: any, delta: any, deltaV: any): boolean;
|
|
328
|
-
_maxPotentialStep(delta: any, deltaV?: Float64Array<any>): number;
|
|
329
|
-
/**
|
|
330
|
-
* Newton iteration for one backward-Euler step from the current cOld.
|
|
331
|
-
* @returns {{converged: boolean, iterations: number, history: number[]}}
|
|
332
|
-
*/
|
|
333
|
-
newton(dt: any, { maxIter, tol, maxStep, islands }?: {
|
|
334
|
-
maxIter?: number;
|
|
335
|
-
tol?: number;
|
|
336
|
-
maxStep?: number;
|
|
337
|
-
islands?: boolean;
|
|
338
|
-
}): {
|
|
339
|
-
converged: boolean;
|
|
340
|
-
iterations: number;
|
|
341
|
-
history: number[];
|
|
342
|
-
};
|
|
343
|
-
_kirchhoff(): number;
|
|
344
|
-
_noteConditioning(): void;
|
|
345
|
-
conditioning: {
|
|
346
|
-
digits: any;
|
|
347
|
-
x: number;
|
|
348
|
-
where: string;
|
|
349
|
-
nodes: any[];
|
|
350
|
-
};
|
|
248
|
+
newton(dt: any, opts: any): any;
|
|
351
249
|
/**
|
|
352
250
|
* Advance by dt, splitting the interval into halves (recursively) wherever Newton fails.
|
|
353
251
|
* The end time is always t + dt; the result reports the substeps taken.
|
|
354
252
|
*/
|
|
355
253
|
advance(dt: any, opts: any, depth?: number): any;
|
|
356
|
-
_addToState(d: any, scale: any): void;
|
|
357
254
|
step(dt: any, opts?: {}): any;
|
|
358
255
|
integrate(tEnd: any, opts?: {}): {
|
|
359
256
|
stopped?: string;
|
|
@@ -376,6 +273,7 @@ export class Solver {
|
|
|
376
273
|
};
|
|
377
274
|
_warmFrom(src: any): void;
|
|
378
275
|
solvedV: any;
|
|
276
|
+
coldStart: any;
|
|
379
277
|
_snapshot(): {
|
|
380
278
|
u: Float64Array<ArrayBuffer>;
|
|
381
279
|
uLo: Float64Array<ArrayBuffer>;
|
|
@@ -402,118 +300,14 @@ export class Solver {
|
|
|
402
300
|
history: any[];
|
|
403
301
|
termV: Float64Array<ArrayBuffer>;
|
|
404
302
|
sourceTime: number;
|
|
303
|
+
coldStart: any;
|
|
405
304
|
};
|
|
406
305
|
_restore(s: any): void;
|
|
407
306
|
contactDEnd: any;
|
|
408
307
|
passedCurrent(k: any): any;
|
|
409
308
|
_terminalCurrent(): number;
|
|
410
|
-
/**
|
|
411
|
-
* Small-signal impedance about the current (steady) state, seen at one terminal. Linearising
|
|
412
|
-
* gives (J + iωM)·δx + Σ B_k δV_k = rhs for the grid's rows, and (C_k + iωC′_k)·δx +
|
|
413
|
-
* (∂I_k/∂V_k)·δV_k = δI_set,k for each floating terminal's circuit row, with J the steady
|
|
414
|
-
* Jacobian and M the storage part (from J(dt) = J + M/dt), B_k = ∂res/∂V_k and C_k = ∂I_k/∂x.
|
|
415
|
-
* At the measured terminal, a held voltage is perturbed (rhs = −B δV) and its current read
|
|
416
|
-
* from C, or a driven current is perturbed and its voltage solved for. The other terminals
|
|
417
|
-
* keep their drives: held ones at AC ground, driven ones at AC open circuit.
|
|
418
|
-
* Z = δV/δI with I into the device (positive real part for a passive device).
|
|
419
|
-
* @param {ArrayLike<number>} frequencies Hz
|
|
420
|
-
*/
|
|
421
|
-
impedance(frequencies: ArrayLike<number>, opts: any): {
|
|
422
|
-
f: Float64Array<ArrayBuffer>;
|
|
423
|
-
Z: {
|
|
424
|
-
re: Float64Array<any>;
|
|
425
|
-
im: Float64Array<any>;
|
|
426
|
-
};
|
|
427
|
-
};
|
|
428
|
-
allTerminals: any;
|
|
429
|
-
_impedance(frequencies: any, { profiles, terminal }?: {
|
|
430
|
-
profiles?: boolean;
|
|
431
|
-
terminal?: string;
|
|
432
|
-
}): {
|
|
433
|
-
f: Float64Array<ArrayBuffer>;
|
|
434
|
-
Z: {
|
|
435
|
-
re: Float64Array<any>;
|
|
436
|
-
im: Float64Array<any>;
|
|
437
|
-
};
|
|
438
|
-
};
|
|
439
|
-
_regionShift(yr: any, yi: any): Float64Array<any>[];
|
|
440
|
-
_regionEdgeRows(): Uint8Array<any>;
|
|
441
|
-
_currentCuts(): {
|
|
442
|
-
s: any;
|
|
443
|
-
idx: any[];
|
|
444
|
-
g: any[];
|
|
445
|
-
d: any[];
|
|
446
|
-
}[];
|
|
447
309
|
segmentFluxes(): Float64Array<ArrayBuffer>[];
|
|
448
310
|
faceOneWay(f: any): any;
|
|
449
|
-
_smallSignalProfiles(xr: any, xi: any): {
|
|
450
|
-
phi: {
|
|
451
|
-
re: Float64Array<any>;
|
|
452
|
-
im: Float64Array<any>;
|
|
453
|
-
};
|
|
454
|
-
mu: {};
|
|
455
|
-
c: {};
|
|
456
|
-
};
|
|
457
|
-
_assembleBookkeeping(dt: any): void;
|
|
458
311
|
_accumulateBoundaryIntake(dt: any, cN: any): void;
|
|
459
|
-
slowestTime(): number;
|
|
460
|
-
fastestTime(): number;
|
|
461
|
-
/**
|
|
462
|
-
* Steady state: where a transient from the present state ends, found as the solution of the
|
|
463
|
-
* steady equations (dt = ∞, no storage term), with no slow modes to wait out, however slow the
|
|
464
|
-
* physics (e.g. exponentially scarce minority carriers). What the storage term held is held by
|
|
465
|
-
* the steady system's own rows instead (see src/laws.js): each conserved amount in place of a balance
|
|
466
|
-
* row that says nothing new, levels that carry nothing held flat, islands' summed balances.
|
|
467
|
-
* Where Newton from here fails: continuation along the drives, then the pseudo-transient ramp.
|
|
468
|
-
* The clock is not advanced, and open-system conservation bookkeeping restarts here.
|
|
469
|
-
*/
|
|
470
|
-
solveSteady(opts?: {}): any;
|
|
471
|
-
violent: any[];
|
|
472
|
-
unreached: {
|
|
473
|
-
terminal: any;
|
|
474
|
-
target: any;
|
|
475
|
-
low: any;
|
|
476
|
-
high: any;
|
|
477
|
-
};
|
|
478
|
-
charging: {
|
|
479
|
-
terminal: any;
|
|
480
|
-
current: any;
|
|
481
|
-
what: any[];
|
|
482
|
-
};
|
|
483
|
-
steadyAt: number;
|
|
484
|
-
_solveSteadyAll(opts: any): any;
|
|
485
|
-
_steadyFromHere(opts: any): any;
|
|
486
|
-
stepped: boolean;
|
|
487
|
-
dimmer: boolean;
|
|
488
|
-
_bound(k: any): boolean;
|
|
489
|
-
_floatingContinuation(opts: any, r: any): any;
|
|
490
|
-
_generationContinuation(opts: any, r: any): {
|
|
491
|
-
converged: boolean;
|
|
492
|
-
steps: any;
|
|
493
|
-
iterations: any;
|
|
494
|
-
history: any;
|
|
495
|
-
};
|
|
496
|
-
_continuation(opts: any, k: any, level: any, target: any, r: any, warm: any, hold: any): any;
|
|
497
|
-
_steadySteps({ maxSteps, tol }?: {
|
|
498
|
-
maxSteps?: number;
|
|
499
|
-
tol?: number;
|
|
500
|
-
}): {
|
|
501
|
-
converged: boolean;
|
|
502
|
-
steps: number;
|
|
503
|
-
iterations: number;
|
|
504
|
-
history: ({
|
|
505
|
-
dt: number;
|
|
506
|
-
converged: any;
|
|
507
|
-
iterations: any;
|
|
508
|
-
maxStep?: undefined;
|
|
509
|
-
} | {
|
|
510
|
-
dt: number;
|
|
511
|
-
converged: any;
|
|
512
|
-
iterations: any;
|
|
513
|
-
maxStep: number;
|
|
514
|
-
})[];
|
|
515
|
-
};
|
|
516
|
-
_renormalizeSpectators(): void;
|
|
517
|
-
_diff(): Float64Array<ArrayBuffer>;
|
|
518
312
|
}
|
|
519
|
-
import {
|
|
313
|
+
import { BlockTridiagonal } from './blockTridiagonal.js';
|
package/types/start.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cold start. Each species takes its region's c0 where one is given (for a spectator, it fixes
|
|
3
|
+
* the conserved amount), else its contact's level. φ in each region is then chosen for local neutrality (node by node where a
|
|
4
|
+
* profile varies), or continued across the interface dipole if nothing there responds.
|
|
5
|
+
*/
|
|
6
|
+
export function initFromComposition(s: any): void;
|
|
7
|
+
/**
|
|
8
|
+
* The t = 0⁺ state at the faces between strictly neutral regions, taken by the first time step
|
|
9
|
+
* from a cold start (src/timeSteps.js) and not by a steady solve, which needs no t = 0⁺: there it
|
|
10
|
+
* was the worse start, its face nodes moved while the rest of a region stayed (a stack whose
|
|
11
|
+
* middle region started 2.2 V from its neighbour's level failed every steady solve, where the
|
|
12
|
+
* cold start converged in one).
|
|
13
|
+
*/
|
|
14
|
+
export function equilibrateFaces(s: any): void;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export class SteadySolves {
|
|
2
|
+
slowestTime(): number;
|
|
3
|
+
_usedMaterials(): any[];
|
|
4
|
+
fastestTime(): number;
|
|
5
|
+
/**
|
|
6
|
+
* Steady state: where a transient from the present state ends, found as the solution of the
|
|
7
|
+
* steady equations (dt = ∞, no storage term), with no slow transport to wait out (e.g.
|
|
8
|
+
* exponentially scarce minority carriers); but a slow reaction that alone settles a closed
|
|
9
|
+
* combination is waited out by time steps, to ~1e12 of the slowest diffusion time (invariant
|
|
10
|
+
* 5). What the storage term held is held by
|
|
11
|
+
* the steady system's own rows instead (see src/laws.js): each conserved amount in place of a balance
|
|
12
|
+
* row that says nothing new, levels that carry nothing held flat, islands' summed balances.
|
|
13
|
+
* Where Newton from here fails: continuation along the drives, then the pseudo-transient ramp.
|
|
14
|
+
* The clock is not advanced, and open-system conservation bookkeeping restarts here.
|
|
15
|
+
*/
|
|
16
|
+
solveSteady(opts?: {}): any;
|
|
17
|
+
violent: any[];
|
|
18
|
+
unreached: {
|
|
19
|
+
terminal: any;
|
|
20
|
+
target: any;
|
|
21
|
+
low: any;
|
|
22
|
+
high: any;
|
|
23
|
+
};
|
|
24
|
+
charging: {
|
|
25
|
+
terminal: any;
|
|
26
|
+
current: any;
|
|
27
|
+
what: any;
|
|
28
|
+
};
|
|
29
|
+
steady: boolean;
|
|
30
|
+
steadyAt: any;
|
|
31
|
+
drifted: any;
|
|
32
|
+
modelError: any;
|
|
33
|
+
_solveSteadyAll(opts: any): any;
|
|
34
|
+
atSteady: any;
|
|
35
|
+
_steadyFromHere(opts: any): any;
|
|
36
|
+
conditioning: any;
|
|
37
|
+
sourceTime: any;
|
|
38
|
+
solvedV: any[];
|
|
39
|
+
stepped: boolean;
|
|
40
|
+
coldStart: boolean;
|
|
41
|
+
dimmer: boolean;
|
|
42
|
+
_bound(k: any): any;
|
|
43
|
+
_floatingContinuation(opts: any, r: any, k?: any, line?: any): any;
|
|
44
|
+
_resistanceContinuation(opts: any, r: any): any;
|
|
45
|
+
_generationContinuation(opts: any, r: any): {
|
|
46
|
+
converged: boolean;
|
|
47
|
+
steps: any;
|
|
48
|
+
iterations: any;
|
|
49
|
+
history: any;
|
|
50
|
+
};
|
|
51
|
+
generationScale: number;
|
|
52
|
+
_continuation(opts: any, k: any, level: any, target: any, r: any, warm: any, hold: any): any;
|
|
53
|
+
_steadySteps({ maxSteps, tol }?: {
|
|
54
|
+
maxSteps?: number;
|
|
55
|
+
tol?: number;
|
|
56
|
+
}): {
|
|
57
|
+
converged: boolean;
|
|
58
|
+
steps: number;
|
|
59
|
+
iterations: number;
|
|
60
|
+
history: ({
|
|
61
|
+
drifted?: boolean;
|
|
62
|
+
dt: number;
|
|
63
|
+
converged: any;
|
|
64
|
+
iterations: any;
|
|
65
|
+
maxStep?: undefined;
|
|
66
|
+
} | {
|
|
67
|
+
dt: number;
|
|
68
|
+
converged: any;
|
|
69
|
+
iterations: any;
|
|
70
|
+
maxStep: number;
|
|
71
|
+
})[];
|
|
72
|
+
};
|
|
73
|
+
time: any;
|
|
74
|
+
history: any[];
|
|
75
|
+
dtNext: any;
|
|
76
|
+
_unkeptAmounts(): any;
|
|
77
|
+
_renormalizeSpectators(): void;
|
|
78
|
+
_diff(): any;
|
|
79
|
+
_directSteady(): any;
|
|
80
|
+
stuckReactions(): any[];
|
|
81
|
+
}
|
package/types/types.d.ts
CHANGED
|
@@ -820,6 +820,12 @@ export type ImpedanceResult = {
|
|
|
820
820
|
re: Float64Array;
|
|
821
821
|
im: Float64Array;
|
|
822
822
|
};
|
|
823
|
+
/**
|
|
824
|
+
* each Z's estimated error, relative to |Z| (on Re Z and Im Z alike): the current's round-off
|
|
825
|
+
* and the solves' residuals; cautious (it can exceed the true error many times). Over 1%, or over 10·|Re Z|/|Z|,
|
|
826
|
+
* a warning says so
|
|
827
|
+
*/
|
|
828
|
+
relError: Float64Array;
|
|
823
829
|
/**
|
|
824
830
|
* per frequency, per unit excitation (volt, or A/m² in current mode)
|
|
825
831
|
*/
|