driftlet 0.1.1 → 0.3.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/types/index.d.ts CHANGED
@@ -45,9 +45,12 @@ export class Device {
45
45
  /**
46
46
  * Adaptive transient to time tEnd (s): variable-step BDF2 with local error control. With
47
47
  * `budgetMs`, it returns after that much wall time even if tEnd isn't reached (`done` says
48
- * which), so an animation can call it once per frame; the step size carries over.
48
+ * which), so an animation can call it once per frame; the step size carries over. `probes`
49
+ * read a species at points inside the device after every accepted step, into `trace.probes`
50
+ * (one array per probe, alongside `trace.t`): what a detector at x sees.
49
51
  * @param {number} tEnd s
50
- * @param {{ tol?: number, dt0?: number, dtMax?: number, budgetMs?: number, maxSteps?: number, method?: 'bdf2' | 'be' }} [opts]
52
+ * @param {{ tol?: number, dt0?: number, dtMax?: number, budgetMs?: number, maxSteps?: number, method?: 'bdf2' | 'be',
53
+ * probes?: { x: number, species: string, quantity?: 'c' | 'V', region?: string | number }[] }} [opts]
51
54
  * @returns {Solution}
52
55
  */
53
56
  advance(tEnd: number, opts?: {
@@ -57,6 +60,12 @@ export class Device {
57
60
  budgetMs?: number;
58
61
  maxSteps?: number;
59
62
  method?: "bdf2" | "be";
63
+ probes?: {
64
+ x: number;
65
+ species: string;
66
+ quantity?: "c" | "V";
67
+ region?: string | number;
68
+ }[];
60
69
  }): Solution;
61
70
  /**
62
71
  * Small-signal impedance Z(f) about the steady state (solved first), at one terminal: its
package/types/kit.d.ts CHANGED
@@ -57,5 +57,6 @@ export type VacuumSide = {
57
57
  export { build, combine, layer, ohmic, bath } from "./stack.js";
58
58
  export { parseEquation, stoichiometry, half, SHE, level } from "./equation.js";
59
59
  export { traces, speciesRole, typeset } from "./traces.js";
60
+ export { pulse, square, triangle, ramp, injector, recombination } from "./sources.js";
60
61
  export { describe, unitWarnings } from "./describe.js";
61
62
  export { IONS, H2O, WATER_EPSR, SEMICONDUCTORS, METALS, aqueous, semiconductor, metal } from "./data.js";
package/types/pow.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ /** x^n for an integer n. */
2
+ export function powi(x: any, n: any): any;
3
+ /** x^y for x ≥ 0 and any real y. */
4
+ export function powr(x: any, y: any): any;
package/types/solver.d.ts CHANGED
@@ -120,9 +120,9 @@ export class Solver {
120
120
  /** η_i/RT that a fixed contact link imposes (or NaN if the link isn't fixed). */
121
121
  contactEta(side: any, i: any): number;
122
122
  /**
123
- * Cold start. Species connected to a contact take that contact's level; spectators take
124
- * their region's c0 (which fixes their conserved amount). φ in each region is then chosen
125
- * for local neutrality, or continued across the interface dipole if nothing there responds.
123
+ * Cold start. Each species takes its region's c0 where one is given (for a spectator, it fixes
124
+ * the conserved amount), else its contact's level. φ in each region is then chosen for local neutrality (node by node where a
125
+ * profile varies), or continued across the interface dipole if nothing there responds.
126
126
  */
127
127
  initFromComposition(): void;
128
128
  _materialAt(mat: any, background: any, eta: any, mode: any, cFix: any, ph: any, zeta: any, cc: any): void;
@@ -216,6 +216,7 @@ export class Solver {
216
216
  rejected: number;
217
217
  iterations: number;
218
218
  trace: {
219
+ probes?: any;
219
220
  t: any[];
220
221
  current: any[];
221
222
  voltage: any[];
@@ -227,6 +228,11 @@ export class Solver {
227
228
  scale: number;
228
229
  order: number;
229
230
  };
231
+ _probes(probes: any): {
232
+ out: any;
233
+ read: () => any;
234
+ push: (values: any) => any;
235
+ };
230
236
  _errorNorm(ref: any): number;
231
237
  _snapshot(): {
232
238
  u: Float64Array<ArrayBuffer>;
@@ -0,0 +1,102 @@
1
+ /**
2
+ * A rectangular pulse, as a waveform for a terminal's `V` or `I`: `base` until `start`, then
3
+ * `base + amplitude` for `width`, then `base` again. With a `rise` > 0 its edges are ramps of
4
+ * that length, placed so the area stays `amplitude · width`; without one they're jumps, which
5
+ * the time stepping handles exactly (so a pulse with no rise must start after t = 0, the time a
6
+ * device starts at and solve() reads: it's off then).
7
+ * @param {{ start?: number, width: number, amplitude: number, rise?: number, base?: number }} opts s, s, V or A/m², s, V or A/m²
8
+ * @returns {{ t: number[], values: number[] }}
9
+ */
10
+ export function pulse({ start, width, amplitude, rise, base }?: {
11
+ start?: number;
12
+ width: number;
13
+ amplitude: number;
14
+ rise?: number;
15
+ base?: number;
16
+ }): {
17
+ t: number[];
18
+ values: number[];
19
+ };
20
+ /**
21
+ * A square wave, repeating: `high` for `duty · period`, then `low`, from t = 0.
22
+ * @param {{ high: number, low: number, period: number, duty?: number }} opts
23
+ * @returns {{ t: number[], values: number[], repeat: true }}
24
+ */
25
+ export function square({ high, low, period, duty }?: {
26
+ high: number;
27
+ low: number;
28
+ period: number;
29
+ duty?: number;
30
+ }): {
31
+ t: number[];
32
+ values: number[];
33
+ repeat: true;
34
+ };
35
+ /**
36
+ * A triangle wave, repeating: from `from` to `to` and back in each `period`, from t = 0 (a
37
+ * cyclic voltammogram's sweep, from its starting potential).
38
+ * @param {{ from: number, to: number, period: number }} opts
39
+ * @returns {{ t: number[], values: number[], repeat: true }}
40
+ */
41
+ export function triangle({ from, to, period }?: {
42
+ from: number;
43
+ to: number;
44
+ period: number;
45
+ }): {
46
+ t: number[];
47
+ values: number[];
48
+ repeat: true;
49
+ };
50
+ /**
51
+ * A ramp from `from` to `to` over `duration`, starting at `start`, constant on either side.
52
+ * @param {{ from: number, to: number, duration: number, start?: number }} opts
53
+ * @returns {{ t: number[], values: number[] }}
54
+ */
55
+ export function ramp({ from, to, duration, start }?: {
56
+ from: number;
57
+ to: number;
58
+ duration: number;
59
+ start?: number;
60
+ }): {
61
+ t: number[];
62
+ values: number[];
63
+ };
64
+ /**
65
+ * A port that injects a species into a window of a region at a driven current `I` (A/m², a
66
+ * number or a waveform), spread evenly over the window. It's an ordinary port: driven by `I`,
67
+ * its terminal the species, linked by a conductance small enough that at the peak current the
68
+ * port sits `headroom` volts above the window's level of that species, so every node of the
69
+ * window takes the same share (like a current source). At I = 0 it still links the window,
70
+ * weakly.
71
+ * @param {{ name?: string, region: string | number, from: number, to: number, species: string,
72
+ * I: number | { t: number[], values: number[], repeat?: boolean }, headroom?: number }} opts
73
+ * @returns {object} a port, for the definition's `ports`
74
+ */
75
+ export function injector({ name, region, from, to, species, I, headroom }?: {
76
+ name?: string;
77
+ region: string | number;
78
+ from: number;
79
+ to: number;
80
+ species: string;
81
+ I: number | {
82
+ t: number[];
83
+ values: number[];
84
+ repeat?: boolean;
85
+ };
86
+ headroom?: number;
87
+ }): object;
88
+ /**
89
+ * Band-to-band recombination e⁻ + h⁺ ⇌ 0 in a material, from the minority-carrier lifetime it
90
+ * should give at a majority density: kf = 1/(τ · majority). (The rate is kf (np − n_i²), so τ is
91
+ * the low-injection lifetime of whichever carrier is the minority.)
92
+ * @param {{ material: string, tau: number, majority: number }} opts material name, s, mol/m³
93
+ * @returns {{ equation: string, kf: Record<string, number> }} a bulk reaction
94
+ */
95
+ export function recombination({ material, tau, majority }?: {
96
+ material: string;
97
+ tau: number;
98
+ majority: number;
99
+ }): {
100
+ equation: string;
101
+ kf: Record<string, number>;
102
+ };
package/types/types.d.ts CHANGED
@@ -130,10 +130,14 @@ export type RegionDef = {
130
130
  */
131
131
  fixedCharge?: number;
132
132
  /**
133
- * initial concentrations, mol/m³ (required for species
134
- * not connected to a contact: it fixes the amount they conserve)
133
+ * initial concentrations,
134
+ * mol/m³ (required for species not connected to a contact: it fixes the amount they conserve);
135
+ * or a profile against the device's x (m), piecewise linear; either is the starting state
135
136
  */
136
- c0?: Record<string, number>;
137
+ c0?: Record<string, number | {
138
+ x: number[];
139
+ c: number[];
140
+ }>;
137
141
  /**
138
142
  * imposed flow toward +x, m/s, carrying every mobile species
139
143
  */
@@ -538,13 +542,15 @@ export type Solution = {
538
542
  */
539
543
  rejected?: number;
540
544
  /**
541
- * advance(): terminal
542
- * current (A/m², toward +x) and voltage after each accepted step
545
+ * advance():
546
+ * terminal current (A/m², toward +x) and voltage after each accepted step, and each probe's
547
+ * reading (mol/m³, or V for quantity 'V'), interpolated between the nodes around its x
543
548
  */
544
549
  trace?: {
545
550
  t: number[];
546
551
  current: number[];
547
552
  voltage: number[];
553
+ probes?: number[][];
548
554
  };
549
555
  };
550
556
  export type ImpedanceResult = {