driftlet 0.8.0 → 0.10.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/src/stack.js CHANGED
@@ -100,7 +100,7 @@ export function bath(c, reference, d = 0, { offset } = {}) {
100
100
  return { ...drive(d, 'bath'), bath: { c: { ...c }, reference, ...(offset === undefined ? {} : { offset }) } };
101
101
  }
102
102
 
103
- const STACK_FIELDS = ['T', 'library', 'species', 'materials', 'stack', 'bulkReactions', 'ports', 'grid'];
103
+ const STACK_FIELDS = ['T', 'library', 'species', 'materials', 'stack', 'bulkReactions', 'ports', 'grid', 'geometry'];
104
104
 
105
105
  /**
106
106
  * Build a plain device definition from a stack:
@@ -112,7 +112,7 @@ const STACK_FIELDS = ['T', 'library', 'species', 'materials', 'stack', 'bulkReac
112
112
  * between them get the default face. Nested lists are flattened.
113
113
  * - Layers may give doping as `donors` and `acceptors` (mol/m³) in place of `fixedCharge`.
114
114
  * - `library`: pieces with species and materials, merged with `species` and `materials`.
115
- * - `T`, `grid`, `ports` pass through.
115
+ * - `T`, `grid`, `ports`, `geometry` pass through.
116
116
  * @param {object} def
117
117
  * @returns {object} a device definition for `new Device`
118
118
  */
@@ -168,5 +168,6 @@ export function build(def) {
168
168
  if (def.bulkReactions !== undefined) out.bulkReactions = def.bulkReactions;
169
169
  if (def.ports !== undefined) out.ports = def.ports;
170
170
  if (def.grid !== undefined) out.grid = def.grid;
171
+ if (def.geometry !== undefined) out.geometry = def.geometry;
171
172
  return out;
172
173
  }
package/src/types.js CHANGED
@@ -157,10 +157,16 @@
157
157
  * @property {string} [terminal] species whose offset defaults to 0; with reactions, the electrode's carrier
158
158
  * @property {Record<string, 'blocked' | 'equilibrium' | { type: 'equilibrium', offset?: number, mu?: number }
159
159
  * | { type: 'conductance', G: number, offset?: number } | { type: 'exchange', k: number, mu: number }>} [species]
160
- * @property {{ equation: string, fixed?: Record<string, number>, k0: number, alpha: number }[]} [reactions] an
160
+ * @property {{ equation: string, fixed?: Record<string, number>, k0: number, alpha: number, bare?: boolean }[]} [reactions] an
161
161
  * electrode spread through the window: Butler–Volmer per area (k0 in mol/(m²·s)) between the region's
162
162
  * species and the terminal species at the port's level
163
- * @property {number | { x: number[], values: number[] }} [area] with reactions: electrode area per volume,
163
+ * @property {Record<string, { mu0: number, capacity: number, theta0?: number }>} [surface] with reactions: species
164
+ * on the electrode's sites, Langmuir (μ = μ° + RT ln(θ/θ₀)), capacity in mol of sites per m² of electrode,
165
+ * shared; a reaction with `bare: true` runs only on the bare fraction θ₀ = 1 − Σθ
166
+ * @property {{ C: number, zeroCharge?: number }} [capacitance] a capacitance spread through the window (F/m² of
167
+ * electrode): σ = C (V − zeroCharge − φ) on the port's side, aσ in each node's charge balance; a gate
168
+ * along a channel, a double layer
169
+ * @property {number | { x: number[], values: number[] }} [area] with reactions or a capacitance: electrode area per volume,
164
170
  * m²/m³ (1/h for a film of thickness h), or a profile against the device's x
165
171
  */
166
172
 
@@ -191,6 +197,10 @@
191
197
  */
192
198
 
193
199
  /**
200
+ * The device's totals through its cross-section (currents, fluxes through contacts and ports,
201
+ * charges, amounts, reaction totals, impedance) are per m² of a planar device, as below, and
202
+ * whole (A, mol/s, C, mol, Ω; per metre of a cylinder) for one with a `geometry`. Rates at a
203
+ * face or an electrode are always per m² of it.
194
204
  * @typedef {object} Solution
195
205
  * @property {Float64Array} x node positions, m (interface positions appear twice)
196
206
  * @property {Int32Array} region region index per node
@@ -209,7 +219,8 @@
209
219
  * @property {{ left: ContactResult, right: ContactResult }} contacts
210
220
  * @property {{ left?: { V: number, D: number, charge: number }, right?: { V: number, D: number, charge: number } }} gates
211
221
  * @property {{ name: string, V: number, flux: Record<string, number>, current: number, x?: Float64Array,
212
- * area?: Float64Array, rates?: Float64Array[] }[]} ports what each internal port brings into the device;
222
+ * area?: Float64Array, rates?: Float64Array[], coverage?: Record<string, Float64Array>, bare?: Float64Array,
223
+ * sigma?: Float64Array, charge?: number }[]} ports what each internal port brings into the device;
213
224
  * with reactions, also its window's nodes (x, m), area per volume there, and each reaction's rate per area
214
225
  * at each node (mol/(m²·s), forward)
215
226
  * @property {{ left: string, right: string, dipole: number, sheetCharge: number, D: number, N: Record<string, number>, rates: number[] }[]} interfaces
package/types/checks.d.ts CHANGED
@@ -13,9 +13,9 @@
13
13
  * - **warnings**: the solution's warnings (unresolved double layers, steep profiles, weakly held
14
14
  * parts) and the definition's likely unit slips.
15
15
  * - **balance** (a steady state): each species' ledger, what comes in through each terminal and
16
- * what each reaction (bulk or at a face) makes or uses, in mol/(m²·s) and, for a charged
17
- * species, as a current F·|z|·rate. The terms must sum to zero; under light it's J = F(G − R),
18
- * and it says where every carrier went.
16
+ * what each reaction (bulk or at a face) makes or uses, in mol/(m²·s) (mol/s if the device
17
+ * isn't planar) and, for a charged species, as a current F·|z|·rate. The terms must sum to
18
+ * zero; under light it's J = F(G − R), and it says where every carrier went.
19
19
  * - **conservation** (a transient): every closed, unreacting stretch keeps what it held plus
20
20
  * what came in.
21
21
  * - **grid** (a steady state, with `refine`, the default): the device solved again on a grid
package/types/index.d.ts CHANGED
@@ -93,6 +93,7 @@ export class Device {
93
93
  snap: any;
94
94
  solvedV: any;
95
95
  referenceAmounts: any;
96
+ surfaceRef: any;
96
97
  };
97
98
  /**
98
99
  * Back to a checkpoint taken on this device.
package/types/live.d.ts CHANGED
@@ -48,6 +48,7 @@ export class Session {
48
48
  snap: any;
49
49
  solvedV: any;
50
50
  referenceAmounts: any;
51
+ surfaceRef: any;
51
52
  };
52
53
  sol: import("./types.js").Solution;
53
54
  };
@@ -9,7 +9,10 @@
9
9
  * @param {{ face: number } | { port: string | number, x?: number }} where a face's index, or a port
10
10
  * (name or index) and the position in its window (m, the device's x; default its first node)
11
11
  * @param {number | ArrayLike<number>} V the metal's level(s), V
12
- * @returns {{ V: Float64Array, current: Float64Array, reactions: { equation: string, level: number,
12
+ * @param {{ surface?: 'held' | 'equilibrium' }} [opts] an electrode port's surface coverages: held as
13
+ * in `sol` (the default: this instant's curves), or in equilibrium at each V (the steady-state
14
+ * curve, with a passive film's active–passive peak), each species by the reaction that makes it
15
+ * @returns {{ V: Float64Array, current: Float64Array, bare?: Float64Array, reactions: { equation: string, level: number,
13
16
  * rate: Float64Array, current: Float64Array }[] }} per reaction: its equilibrium level here (where
14
17
  * its rate is zero), its rate (mol/(m²·s) of electrode, forward) and its current (A/m², anodic
15
18
  * positive: into the solution); and their sum
@@ -19,9 +22,12 @@ export function polarization(device: import("./index.js").Device, sol: object, w
19
22
  } | {
20
23
  port: string | number;
21
24
  x?: number;
22
- }, V: number | ArrayLike<number>): {
25
+ }, V: number | ArrayLike<number>, opts?: {
26
+ surface?: "held" | "equilibrium";
27
+ }): {
23
28
  V: Float64Array;
24
29
  current: Float64Array;
30
+ bare?: Float64Array;
25
31
  reactions: {
26
32
  equation: string;
27
33
  level: number;
package/types/solver.d.ts CHANGED
@@ -8,12 +8,21 @@ export class Solver {
8
8
  n: any;
9
9
  M: any;
10
10
  nRx: any;
11
+ nSurf: any;
11
12
  nNodes: any;
12
13
  nFaces: number;
13
14
  nB: any;
14
15
  VT: number;
15
16
  blockOfNode: Int32Array<any>;
16
17
  blockOfFace: Int32Array<ArrayBuffer>;
18
+ surfPort: Int32Array<any>;
19
+ surfW: Int32Array<any>;
20
+ surfCols: any;
21
+ surfColOf: any;
22
+ th: Float64Array<ArrayBuffer>;
23
+ thOld: Float64Array<ArrayBuffer>;
24
+ th0: Float64Array<any>;
25
+ th0Old: Float64Array<any>;
17
26
  present: Uint8Array<ArrayBuffer>;
18
27
  cRef: Float64Array<ArrayBuffer>;
19
28
  mu0hat: Float64Array<ArrayBuffer>;
@@ -54,6 +63,13 @@ export class Solver {
54
63
  left: number;
55
64
  right: number;
56
65
  };
66
+ portQ: Float64Array<any>;
67
+ portQStart: Float64Array<any>;
68
+ portQOld: Float64Array<any>;
69
+ portQEnd: any;
70
+ qg: Float64Array<any>;
71
+ qgSlope: Float64Array<any>;
72
+ qgTerms: any[][];
57
73
  contactDOld: {
58
74
  left: number;
59
75
  right: number;
@@ -83,12 +99,17 @@ export class Solver {
83
99
  generationScale: number;
84
100
  hasGeneration: any;
85
101
  rxsIn: any;
102
+ closedEnd: {
103
+ left: any;
104
+ right: any;
105
+ };
86
106
  chargeNode: Uint8Array<any>;
87
107
  chargeNodes: Int32Array<ArrayBuffer>;
88
108
  combining: boolean;
89
109
  bookkeeping: any;
90
110
  bookkeepingFaces: number[];
91
111
  referenceAmounts: number[];
112
+ surfaceRef: Float64Array<ArrayBuffer>;
92
113
  boundaryIntake: Float64Array<ArrayBuffer>;
93
114
  _activeSlots(): void;
94
115
  active: Uint8Array<ArrayBuffer>;
@@ -104,18 +125,20 @@ export class Solver {
104
125
  _findStretches(): void;
105
126
  stretches: any[];
106
127
  stretchOf: Int32Array<ArrayBuffer>;
107
- moieties: Float64Array<ArrayBuffer>[];
128
+ moieties: Float64Array<any>[];
108
129
  constraints: any[];
109
130
  localConstraints: any[];
110
131
  constrained: boolean;
111
132
  _captureLocal(): void;
112
133
  _applyLocalConstraints(): void;
113
- _conservedMoieties(): Float64Array<ArrayBuffer>[];
134
+ _conservedMoieties(): Float64Array<any>[];
114
135
  _directSteady(): boolean;
115
136
  _applyConstraints(): void;
116
137
  _solveBordered(rhs: any, delta: any, deltaV: any, pins: any): void;
117
138
  dWork: Float64Array<ArrayBuffer>;
118
139
  borderCols: any[];
140
+ /** Amount (mol per unit area) of surface column j's species, Γ Σ v·a·θ, in the current state. */
141
+ surfaceAmount(j: any): number;
119
142
  /** Total amount (mol per unit area) of a stretch's species in the current state. */
120
143
  amount(stretch: any): number;
121
144
  redrive(): void;
@@ -133,6 +156,7 @@ export class Solver {
133
156
  initFromComposition(): void;
134
157
  _portRate(port: any, rx: any, g: any): number;
135
158
  _materialAt(mat: any, background: any, eta: any, mode: any, cFix: any, ph: any, zeta: any, cc: any): void;
159
+ _coverages(): void;
136
160
  computeConcentrations(): void;
137
161
  _work(md: any): any;
138
162
  _nodeStatistics(g: any, b: any, phiHat: any): void;
@@ -172,8 +196,10 @@ export class Solver {
172
196
  _terminals(dt: any): void;
173
197
  _circuit(k: any): void;
174
198
  _captureRow(b: any, s: any, w: any, into: any): number;
175
- _port(port: any, flux: any, k: any): void;
199
+ _port(port: any, flux: any, k: any, dt: any, holds: any): void;
176
200
  _portReaction(port: any, rx: any, area: any, rates: any, flux: any, k: any): void;
201
+ _portCapacitance(port: any, k: any, dt: any): void;
202
+ _surfaceStorage(port: any, dt: any): void;
177
203
  _contact(side: any, dt: any): void;
178
204
  _replaceRow(b: any, rs: any): void;
179
205
  _equilibrate(): void;
@@ -222,7 +248,7 @@ export class Solver {
222
248
  /**
223
249
  * Adaptive time stepping to tEnd: variable-step BDF2 (or backward Euler), with the local error
224
250
  * estimated against an explicit predictor through the previous states, and controlled to
225
- * `tol` thermal units per step in every potential (φ̂, each η, a floating terminal). The first
251
+ * `tol` thermal units per step in every potential (φ̂, each η, a surface's coverages as η). The first
226
252
  * step is checked by step doubling. Stops early when `budgetMs` of wall time is used, so an
227
253
  * animation can call it once per frame; the step size carries over between calls.
228
254
  */
@@ -257,6 +283,8 @@ export class Solver {
257
283
  u: Float64Array<ArrayBuffer>;
258
284
  uLo: Float64Array<ArrayBuffer>;
259
285
  cOld: Float64Array<ArrayBuffer>;
286
+ thOld: Float64Array<ArrayBuffer>;
287
+ th0Old: Float64Array<ArrayBuffer>;
260
288
  time: number;
261
289
  lastDt: number;
262
290
  atSteady: boolean;
@@ -269,6 +297,9 @@ export class Solver {
269
297
  right: number;
270
298
  };
271
299
  contactDEnd: any;
300
+ portQStart: Float64Array<any>;
301
+ portQOld: Float64Array<any>;
302
+ portQEnd: any;
272
303
  boundaryIntake: Float64Array<ArrayBuffer>;
273
304
  history: any[];
274
305
  termV: Float64Array<ArrayBuffer>;
package/types/stack.d.ts CHANGED
@@ -53,7 +53,7 @@ export function bath(c: Record<string, number>, reference: string, d?: number, {
53
53
  * between them get the default face. Nested lists are flattened.
54
54
  * - Layers may give doping as `donors` and `acceptors` (mol/m³) in place of `fixedCharge`.
55
55
  * - `library`: pieces with species and materials, merged with `species` and `materials`.
56
- * - `T`, `grid`, `ports` pass through.
56
+ * - `T`, `grid`, `ports`, `geometry` pass through.
57
57
  * @param {object} def
58
58
  * @returns {object} a device definition for `new Device`
59
59
  */
package/types/types.d.ts CHANGED
@@ -380,9 +380,29 @@ export type PortDef = {
380
380
  fixed?: Record<string, number>;
381
381
  k0: number;
382
382
  alpha: number;
383
+ bare?: boolean;
383
384
  }[];
384
385
  /**
385
- * with reactions: electrode area per volume,
386
+ * with reactions: species
387
+ * on the electrode's sites, Langmuir (μ = μ° + RT ln(θ/θ₀)), capacity in mol of sites per m² of electrode,
388
+ * shared; a reaction with `bare: true` runs only on the bare fraction θ₀ = 1 − Σθ
389
+ */
390
+ surface?: Record<string, {
391
+ mu0: number;
392
+ capacity: number;
393
+ theta0?: number;
394
+ }>;
395
+ /**
396
+ * a capacitance spread through the window (F/m² of
397
+ * electrode): σ = C (V − zeroCharge − φ) on the port's side, aσ in each node's charge balance; a gate
398
+ * along a channel, a double layer
399
+ */
400
+ capacitance?: {
401
+ C: number;
402
+ zeroCharge?: number;
403
+ };
404
+ /**
405
+ * with reactions or a capacitance: electrode area per volume,
386
406
  * m²/m³ (1/h for a film of thickness h), or a profile against the device's x
387
407
  */
388
408
  area?: number | {
@@ -451,6 +471,12 @@ export type ContactResult = {
451
471
  */
452
472
  current: number;
453
473
  };
474
+ /**
475
+ * The device's totals through its cross-section (currents, fluxes through contacts and ports,
476
+ * charges, amounts, reaction totals, impedance) are per m² of a planar device, as below, and
477
+ * whole (A, mol/s, C, mol, Ω; per metre of a cylinder) for one with a `geometry`. Rates at a
478
+ * face or an electrode are always per m² of it.
479
+ */
454
480
  export type Solution = {
455
481
  /**
456
482
  * node positions, m (interface positions appear twice)
@@ -545,6 +571,10 @@ export type Solution = {
545
571
  x?: Float64Array;
546
572
  area?: Float64Array;
547
573
  rates?: Float64Array[];
574
+ coverage?: Record<string, Float64Array>;
575
+ bare?: Float64Array;
576
+ sigma?: Float64Array;
577
+ charge?: number;
548
578
  }[];
549
579
  interfaces: {
550
580
  left: string;