driftlet 0.7.0 → 0.8.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/README.md +8 -4
- package/docs/device.md +79 -3
- package/docs/kit.md +26 -2
- package/docs/numerics.md +16 -0
- package/llms.txt +14 -9
- package/package.json +1 -1
- package/src/checks.js +10 -9
- package/src/describe.js +12 -1
- package/src/device.js +95 -13
- package/src/grid.js +73 -0
- package/src/kit.js +1 -0
- package/src/polarization.js +84 -0
- package/src/solution.js +12 -4
- package/src/solver.js +180 -41
- package/src/types.js +15 -4
- package/types/grid.d.ts +29 -0
- package/types/kit.d.ts +1 -0
- package/types/polarization.d.ts +31 -0
- package/types/solver.d.ts +6 -2
- package/types/types.d.ts +41 -4
package/types/grid.d.ts
CHANGED
|
@@ -26,3 +26,32 @@ export function buildGrid(regions: {
|
|
|
26
26
|
regionEnd: Int32Array<ArrayBuffer>;
|
|
27
27
|
length: number;
|
|
28
28
|
};
|
|
29
|
+
/**
|
|
30
|
+
* Give a grid its cross-section: `area` (A at each node, m²), `segArea` (each segment's
|
|
31
|
+
* effective area, its length over ∫dx/A, so that a flux D·segArea·Δc/h is exact for steady
|
|
32
|
+
* diffusion between the nodes; A at its middle where A vanishes at an end, as at a sphere's
|
|
33
|
+
* centre) and `vol` (each node's box, ∫A dx). Planar (no geometry): A = 1, and nothing changes.
|
|
34
|
+
* @param {ReturnType<typeof buildGrid>} grid
|
|
35
|
+
* @param {{ type: 'planar' } | { type: 'spherical' | 'cylindrical', r0: number } | { type: 'profile', x: ArrayLike<number>, values: ArrayLike<number> }} geometry
|
|
36
|
+
*/
|
|
37
|
+
export function applyGeometry(grid: ReturnType<typeof buildGrid>, geometry: {
|
|
38
|
+
type: "planar";
|
|
39
|
+
} | {
|
|
40
|
+
type: "spherical" | "cylindrical";
|
|
41
|
+
r0: number;
|
|
42
|
+
} | {
|
|
43
|
+
type: "profile";
|
|
44
|
+
x: ArrayLike<number>;
|
|
45
|
+
values: ArrayLike<number>;
|
|
46
|
+
}): {
|
|
47
|
+
nNodes: number;
|
|
48
|
+
x: Float64Array<ArrayBuffer>;
|
|
49
|
+
nodeRegion: Int32Array<ArrayBuffer>;
|
|
50
|
+
segLength: Float64Array<ArrayBuffer>;
|
|
51
|
+
segRegion: Int32Array<ArrayBuffer>;
|
|
52
|
+
segFace: Int32Array<ArrayBuffer>;
|
|
53
|
+
vol: Float64Array<ArrayBuffer>;
|
|
54
|
+
regionStart: Int32Array<ArrayBuffer>;
|
|
55
|
+
regionEnd: Int32Array<ArrayBuffer>;
|
|
56
|
+
length: number;
|
|
57
|
+
};
|
package/types/kit.d.ts
CHANGED
|
@@ -36,6 +36,7 @@ export function vacuumZeroCharge(def: object, workFunction: number, inside: Vacu
|
|
|
36
36
|
export { live } from "./live.js";
|
|
37
37
|
export { recorder } from "./recorder.js";
|
|
38
38
|
export { check } from "./checks.js";
|
|
39
|
+
export { polarization } from "./polarization.js";
|
|
39
40
|
/**
|
|
40
41
|
* One material seen from vacuum: a level inside it (the anchor) and how far above that level,
|
|
41
42
|
* in electron energy, the vacuum level just outside lies (the offset, V). So
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Each electrode reaction's rate at a face (a metal's) or at one spot of an electrode port, with
|
|
3
|
+
* the composition beside it as in `sol` and the metal's carrier at each level in `V` (in the
|
|
4
|
+
* terminals' convention, V = μ̄/(zF); against SHE, subtract φ for the usual tables' ions). The
|
|
5
|
+
* rates are the solver's own law, so at the electrode's actual level they are
|
|
6
|
+
* `sol.interfaces[f].rates` (or `sol.ports[k].rates` at that node).
|
|
7
|
+
* @param {import('./index.js').Device} device
|
|
8
|
+
* @param {object} sol a solution of it
|
|
9
|
+
* @param {{ face: number } | { port: string | number, x?: number }} where a face's index, or a port
|
|
10
|
+
* (name or index) and the position in its window (m, the device's x; default its first node)
|
|
11
|
+
* @param {number | ArrayLike<number>} V the metal's level(s), V
|
|
12
|
+
* @returns {{ V: Float64Array, current: Float64Array, reactions: { equation: string, level: number,
|
|
13
|
+
* rate: Float64Array, current: Float64Array }[] }} per reaction: its equilibrium level here (where
|
|
14
|
+
* its rate is zero), its rate (mol/(m²·s) of electrode, forward) and its current (A/m², anodic
|
|
15
|
+
* positive: into the solution); and their sum
|
|
16
|
+
*/
|
|
17
|
+
export function polarization(device: import("./index.js").Device, sol: object, where: {
|
|
18
|
+
face: number;
|
|
19
|
+
} | {
|
|
20
|
+
port: string | number;
|
|
21
|
+
x?: number;
|
|
22
|
+
}, V: number | ArrayLike<number>): {
|
|
23
|
+
V: Float64Array;
|
|
24
|
+
current: Float64Array;
|
|
25
|
+
reactions: {
|
|
26
|
+
equation: string;
|
|
27
|
+
level: number;
|
|
28
|
+
rate: Float64Array;
|
|
29
|
+
current: Float64Array;
|
|
30
|
+
}[];
|
|
31
|
+
};
|
package/types/solver.d.ts
CHANGED
|
@@ -77,6 +77,8 @@ export class Solver {
|
|
|
77
77
|
history: any[];
|
|
78
78
|
dtNext: any;
|
|
79
79
|
rxs: any;
|
|
80
|
+
portArea: any;
|
|
81
|
+
portRates: any;
|
|
80
82
|
strictlyNeutral: any;
|
|
81
83
|
generationScale: number;
|
|
82
84
|
hasGeneration: any;
|
|
@@ -119,7 +121,7 @@ export class Solver {
|
|
|
119
121
|
redrive(): void;
|
|
120
122
|
deltaV: Float64Array<any>;
|
|
121
123
|
_refreshSources(): void;
|
|
122
|
-
/** η_i (μ̄/RT) of a port's outside level for species i. */
|
|
124
|
+
/** η_i (μ̄/RT) of a port's outside level for species i (its electrode's carrier: at V itself). */
|
|
123
125
|
portEta(port: any, i: any): number;
|
|
124
126
|
/** η_i/RT that a fixed contact link imposes (or NaN if the link isn't fixed). */
|
|
125
127
|
contactEta(side: any, i: any): number;
|
|
@@ -129,6 +131,7 @@ export class Solver {
|
|
|
129
131
|
* profile varies), or continued across the interface dipole if nothing there responds.
|
|
130
132
|
*/
|
|
131
133
|
initFromComposition(): void;
|
|
134
|
+
_portRate(port: any, rx: any, g: any): number;
|
|
132
135
|
_materialAt(mat: any, background: any, eta: any, mode: any, cFix: any, ph: any, zeta: any, cc: any): void;
|
|
133
136
|
computeConcentrations(): void;
|
|
134
137
|
_work(md: any): any;
|
|
@@ -165,11 +168,12 @@ export class Solver {
|
|
|
165
168
|
Cp: number;
|
|
166
169
|
Ca: number;
|
|
167
170
|
};
|
|
168
|
-
_faceReaction(rx: any, k: any, f: any, bf: any, bL: any, bR: any): void;
|
|
171
|
+
_faceReaction(rx: any, k: any, f: any, bf: any, bL: any, bR: any, Af: any): void;
|
|
169
172
|
_terminals(dt: any): void;
|
|
170
173
|
_circuit(k: any): void;
|
|
171
174
|
_captureRow(b: any, s: any, w: any, into: any): number;
|
|
172
175
|
_port(port: any, flux: any, k: any): void;
|
|
176
|
+
_portReaction(port: any, rx: any, area: any, rates: any, flux: any, k: any): void;
|
|
173
177
|
_contact(side: any, dt: any): void;
|
|
174
178
|
_replaceRow(b: any, rs: any): void;
|
|
175
179
|
_equilibrate(): void;
|
package/types/types.d.ts
CHANGED
|
@@ -354,10 +354,10 @@ export type PortDef = {
|
|
|
354
354
|
*/
|
|
355
355
|
R?: number;
|
|
356
356
|
/**
|
|
357
|
-
* species whose offset defaults to 0
|
|
357
|
+
* species whose offset defaults to 0; with reactions, the electrode's carrier
|
|
358
358
|
*/
|
|
359
359
|
terminal?: string;
|
|
360
|
-
species
|
|
360
|
+
species?: Record<string, "blocked" | "equilibrium" | {
|
|
361
361
|
type: "equilibrium";
|
|
362
362
|
offset?: number;
|
|
363
363
|
mu?: number;
|
|
@@ -370,6 +370,25 @@ export type PortDef = {
|
|
|
370
370
|
k: number;
|
|
371
371
|
mu: number;
|
|
372
372
|
}>;
|
|
373
|
+
/**
|
|
374
|
+
* an
|
|
375
|
+
* electrode spread through the window: Butler–Volmer per area (k0 in mol/(m²·s)) between the region's
|
|
376
|
+
* species and the terminal species at the port's level
|
|
377
|
+
*/
|
|
378
|
+
reactions?: {
|
|
379
|
+
equation: string;
|
|
380
|
+
fixed?: Record<string, number>;
|
|
381
|
+
k0: number;
|
|
382
|
+
alpha: number;
|
|
383
|
+
}[];
|
|
384
|
+
/**
|
|
385
|
+
* with reactions: electrode area per volume,
|
|
386
|
+
* m²/m³ (1/h for a film of thickness h), or a profile against the device's x
|
|
387
|
+
*/
|
|
388
|
+
area?: number | {
|
|
389
|
+
x: number[];
|
|
390
|
+
values: number[];
|
|
391
|
+
};
|
|
373
392
|
};
|
|
374
393
|
/**
|
|
375
394
|
* A device definition: plain, serialisable data.
|
|
@@ -398,6 +417,20 @@ export type DeviceDefinition = {
|
|
|
398
417
|
* internal ports
|
|
399
418
|
*/
|
|
400
419
|
ports?: PortDef[];
|
|
420
|
+
/**
|
|
421
|
+
* the cross-section A(x): planar (A = 1 m², the
|
|
422
|
+
* default: currents read per m²), shells about a centre at r = r0 (m) left of x = 0 (cylindrical: per
|
|
423
|
+
* metre of length), or A in m² against x. Currents, fluxes, amounts and charges are then totals through A.
|
|
424
|
+
*/
|
|
425
|
+
geometry?: "planar" | "spherical" | "cylindrical" | {
|
|
426
|
+
type: "planar" | "spherical" | "cylindrical";
|
|
427
|
+
r0?: number;
|
|
428
|
+
} | {
|
|
429
|
+
area: {
|
|
430
|
+
x: number[];
|
|
431
|
+
values: number[];
|
|
432
|
+
};
|
|
433
|
+
};
|
|
401
434
|
grid?: GridOptions;
|
|
402
435
|
};
|
|
403
436
|
export type ContactResult = {
|
|
@@ -500,14 +533,18 @@ export type Solution = {
|
|
|
500
533
|
};
|
|
501
534
|
};
|
|
502
535
|
/**
|
|
503
|
-
* what each
|
|
504
|
-
*
|
|
536
|
+
* what each internal port brings into the device;
|
|
537
|
+
* with reactions, also its window's nodes (x, m), area per volume there, and each reaction's rate per area
|
|
538
|
+
* at each node (mol/(m²·s), forward)
|
|
505
539
|
*/
|
|
506
540
|
ports: {
|
|
507
541
|
name: string;
|
|
508
542
|
V: number;
|
|
509
543
|
flux: Record<string, number>;
|
|
510
544
|
current: number;
|
|
545
|
+
x?: Float64Array;
|
|
546
|
+
area?: Float64Array;
|
|
547
|
+
rates?: Float64Array[];
|
|
511
548
|
}[];
|
|
512
549
|
interfaces: {
|
|
513
550
|
left: string;
|