driftlet 0.1.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.
Files changed (47) hide show
  1. package/LICENSE +14 -0
  2. package/README.md +285 -0
  3. package/llms.txt +299 -0
  4. package/package.json +54 -0
  5. package/src/bernoulli.js +29 -0
  6. package/src/blockTridiagonal.js +492 -0
  7. package/src/constants.js +36 -0
  8. package/src/data.js +127 -0
  9. package/src/describe.js +190 -0
  10. package/src/device.js +954 -0
  11. package/src/equation.js +188 -0
  12. package/src/errors.js +8 -0
  13. package/src/fermi.js +106 -0
  14. package/src/grid.js +111 -0
  15. package/src/index.js +207 -0
  16. package/src/kit.js +76 -0
  17. package/src/live.js +217 -0
  18. package/src/merge.js +11 -0
  19. package/src/plot.js +267 -0
  20. package/src/solution.js +246 -0
  21. package/src/solver.js +2884 -0
  22. package/src/stack.js +172 -0
  23. package/src/statistics.js +593 -0
  24. package/src/traces.js +125 -0
  25. package/src/types.js +221 -0
  26. package/src/worker.js +24 -0
  27. package/types/bernoulli.d.ts +4 -0
  28. package/types/blockTridiagonal.d.ts +92 -0
  29. package/types/constants.d.ts +33 -0
  30. package/types/data.d.ts +73 -0
  31. package/types/describe.d.ts +15 -0
  32. package/types/device.d.ts +20 -0
  33. package/types/equation.d.ts +102 -0
  34. package/types/errors.d.ts +3 -0
  35. package/types/fermi.d.ts +3 -0
  36. package/types/grid.d.ts +28 -0
  37. package/types/index.d.ts +103 -0
  38. package/types/kit.d.ts +61 -0
  39. package/types/live.d.ts +101 -0
  40. package/types/merge.d.ts +1 -0
  41. package/types/plot.d.ts +60 -0
  42. package/types/solution.d.ts +18 -0
  43. package/types/solver.d.ts +342 -0
  44. package/types/stack.d.ts +59 -0
  45. package/types/statistics.d.ts +10 -0
  46. package/types/traces.d.ts +118 -0
  47. package/types/types.d.ts +574 -0
@@ -0,0 +1,102 @@
1
+ /**
2
+ * One participant of an equation as written.
3
+ * @typedef {object} Term
4
+ * @property {string} name the participant as written (with any trailing parenthesis)
5
+ * @property {number} nu signed coefficient (< 0 on the left of the equation)
6
+ */
7
+ /**
8
+ * Parse an equation into its terms, in order. The two sides are separated by `=` (or `⇌`, `<=>`,
9
+ * `->`, `→`), terms by ` + ` (spaces around the plus, which keeps it apart from charges), and a
10
+ * side with nothing on it is `0` or `∅`. A coefficient is an integer followed by a space
11
+ * (`2 e-`), so names may start with digits (`3He`).
12
+ * @param {string} text
13
+ * @param {string} [path] for error messages
14
+ * @returns {Term[]}
15
+ */
16
+ export function parseEquation(text: string, path?: string): Term[];
17
+ /**
18
+ * The signed stoichiometry `{ name: ν }` of a homogeneous reaction, as a bulk reaction's `nu`.
19
+ * A participant on both sides is an error: give the net reaction.
20
+ * @param {string} text
21
+ * @param {string} [path]
22
+ * @returns {Record<string, number>}
23
+ */
24
+ export function stoichiometry(text: string, path?: string): Record<string, number>;
25
+ /**
26
+ * Which side of a face each participant of an equation is on: the side whose material holds it
27
+ * (on a conductor's side, only its carrier). A species held on both sides is labelled with its
28
+ * side, 'Li+(left)', or its material, 'Li+(graphite)'. Participants in `fixed` (fixed-activity
29
+ * neutrals) go beside a conductor if there is one, else on the left (their side doesn't matter).
30
+ * @param {Term[]} terms
31
+ * @param {{ name: string, holds: (species: string) => boolean, conductor?: boolean }} left
32
+ * @param {{ name: string, holds: (species: string) => boolean, conductor?: boolean }} right
33
+ * @param {Record<string, number> | undefined} fixed
34
+ * @param {string} path
35
+ * @returns {{ left: Record<string, number>, right: Record<string, number> }}
36
+ */
37
+ export function faceSides(terms: Term[], left: {
38
+ name: string;
39
+ holds: (species: string) => boolean;
40
+ conductor?: boolean;
41
+ }, right: {
42
+ name: string;
43
+ holds: (species: string) => boolean;
44
+ conductor?: boolean;
45
+ }, fixed: Record<string, number> | undefined, path: string): {
46
+ left: Record<string, number>;
47
+ right: Record<string, number>;
48
+ };
49
+ /**
50
+ * A half-reaction: an equation with electrons `e-` on one side, and the μ (J/mol) of any
51
+ * participant that isn't a species (a fixed-activity neutral, such as a solid metal). It's plain
52
+ * data, `{ equation, fixed }`: spread it into a face reaction with its kinetics,
53
+ * `{ ...silver, k0: 1e-3 }`, or pass it to `level()`.
54
+ * @param {string} equation e.g. 'Ag+ + e- = Ag(s)'
55
+ * @param {Record<string, number>} [fixed] μ of the fixed participants, J/mol
56
+ * @returns {{ equation: string, fixed?: Record<string, number> }}
57
+ */
58
+ export function half(equation: string, fixed?: Record<string, number>): {
59
+ equation: string;
60
+ fixed?: Record<string, number>;
61
+ };
62
+ /**
63
+ * The electronic level a half-reaction implies at each node, as an electron voltage
64
+ * V = −μ̄_e/F: where an electrode exchanging electrons by that reaction would sit in equilibrium
65
+ * with the local composition (the couple's redox level). With `standard: true`, every
66
+ * species is taken at its reference concentration (its standard level μ° + zFφ), so it's the
67
+ * standard level: for `SHE`, V°_e⁻(SHE) = φ + μ°_H⁺/F. `NaN` where a participant is absent.
68
+ * @param {{ mu: Record<string, ArrayLike<number>>, muStd: Record<string, ArrayLike<number>> }} sol a solution
69
+ * @param {{ equation: string, fixed?: Record<string, number> }} halfReaction from `half()`
70
+ * @param {{ standard?: boolean }} [opts]
71
+ * @returns {Float64Array}
72
+ */
73
+ export function level(sol: {
74
+ mu: Record<string, ArrayLike<number>>;
75
+ muStd: Record<string, ArrayLike<number>>;
76
+ }, halfReaction: {
77
+ equation: string;
78
+ fixed?: Record<string, number>;
79
+ }, { standard }?: {
80
+ standard?: boolean;
81
+ }): Float64Array;
82
+ /**
83
+ * The standard hydrogen electrode, 2 H⁺ + 2 e⁻ ⇌ H₂, with μ(H₂) = 0 (the element in its standard
84
+ * state, on the usual table convention). Needs `H+` among the species.
85
+ */
86
+ export const SHE: Readonly<{
87
+ equation: string;
88
+ fixed?: Record<string, number>;
89
+ }>;
90
+ /**
91
+ * One participant of an equation as written.
92
+ */
93
+ export type Term = {
94
+ /**
95
+ * the participant as written (with any trailing parenthesis)
96
+ */
97
+ name: string;
98
+ /**
99
+ * signed coefficient (< 0 on the left of the equation)
100
+ */
101
+ nu: number;
102
+ };
@@ -0,0 +1,3 @@
1
+ export class DeviceError extends Error {
2
+ constructor(message: any);
3
+ }
@@ -0,0 +1,3 @@
1
+ export function fermiHalf(x: any): any;
2
+ export function fermiMinusHalf(x: any): any;
3
+ export function fermiQuadrature(j: any, x: any): number;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Cell widths for one region: fine at both ends, growing toward the middle.
3
+ * @param {number} length m
4
+ * @param {import('./types.js').GridOptions} [opts]
5
+ * @returns {number[]} widths summing to `length`
6
+ */
7
+ export function gradedCells(length: number, { hmin, hmax, ratio, minCells, hLeft, hRight }?: import("./types.js").GridOptions): number[];
8
+ /**
9
+ * Build the device grid.
10
+ * @param {{length: number, grid?: object, cells?: number[]}[]} regions in order, left to right
11
+ * @param {object} [opts] defaults for every region: { hmin, hmax, ratio, minCells }
12
+ */
13
+ export function buildGrid(regions: {
14
+ length: number;
15
+ grid?: object;
16
+ cells?: number[];
17
+ }[], opts?: object): {
18
+ nNodes: number;
19
+ x: Float64Array<ArrayBuffer>;
20
+ nodeRegion: Int32Array<ArrayBuffer>;
21
+ segLength: Float64Array<ArrayBuffer>;
22
+ segRegion: Int32Array<ArrayBuffer>;
23
+ segFace: Int32Array<ArrayBuffer>;
24
+ vol: Float64Array<ArrayBuffer>;
25
+ regionStart: Int32Array<ArrayBuffer>;
26
+ regionEnd: Int32Array<ArrayBuffer>;
27
+ length: number;
28
+ };
@@ -0,0 +1,103 @@
1
+ export { SolverError } from "./solver.js";
2
+ export { BlockTridiagonal } from "./blockTridiagonal.js";
3
+ export * from "./constants.js";
4
+ /** @typedef {import('./types.js').DeviceDefinition} DeviceDefinition */
5
+ /** @typedef {import('./types.js').Solution} Solution */
6
+ export class Device {
7
+ /** @param {DeviceDefinition} def plain, serialisable device definition (see docs/device.md) */
8
+ constructor(def: DeviceDefinition);
9
+ def: import("./types.js").DeviceDefinition;
10
+ model: any;
11
+ _solver: any;
12
+ /** The solver, built on first use (so construction only validates the definition). */
13
+ get solver(): any;
14
+ get grid(): any;
15
+ /**
16
+ * Change part of the definition (deep-merged). A change to the terminals' drives alone (V, I,
17
+ * R) is applied in place, cheaply. Otherwise the device is rebuilt, keeping the current state as
18
+ * the warm start when the grid and species are unchanged (else restarting from the regions' c0).
19
+ * @param {object} patch a partial device definition, merged into the current one
20
+ * @returns {this}
21
+ */
22
+ set(patch: object): this;
23
+ _redefineDrives(def: any): void;
24
+ /**
25
+ * Steady state (or equilibrium), warm-started from the current state. Doesn't advance time.
26
+ * @param {{ maxSteps?: number, tol?: number, continuation?: boolean }} [opts]
27
+ * @returns {Solution}
28
+ */
29
+ solve(opts?: {
30
+ maxSteps?: number;
31
+ tol?: number;
32
+ continuation?: boolean;
33
+ }): Solution;
34
+ /**
35
+ * Advance the transient by dt (s) with backward Euler. If Newton fails, the interval is
36
+ * split into smaller steps automatically; `substeps` in the result says how many.
37
+ * With `{ method: 'bdf2' }`, steps after the first use second-order BDF2.
38
+ * @param {number} dt s
39
+ * @param {{ method?: 'be' | 'bdf2' }} [opts]
40
+ * @returns {Solution}
41
+ */
42
+ step(dt: number, opts?: {
43
+ method?: "be" | "bdf2";
44
+ }): Solution;
45
+ /**
46
+ * Adaptive transient to time tEnd (s): variable-step BDF2 with local error control. With
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.
49
+ * @param {number} tEnd s
50
+ * @param {{ tol?: number, dt0?: number, dtMax?: number, budgetMs?: number, maxSteps?: number, method?: 'bdf2' | 'be' }} [opts]
51
+ * @returns {Solution}
52
+ */
53
+ advance(tEnd: number, opts?: {
54
+ tol?: number;
55
+ dt0?: number;
56
+ dtMax?: number;
57
+ budgetMs?: number;
58
+ maxSteps?: number;
59
+ method?: "bdf2" | "be";
60
+ }): Solution;
61
+ /**
62
+ * Small-signal impedance Z(f) about the steady state (solved first), at one terminal: its
63
+ * held voltage is perturbed (or its driven current), the others keep their drives.
64
+ * Z = δV/δI with I into the device (Ω·m²).
65
+ * @param {ArrayLike<number>} frequencies Hz
66
+ * @param {{ terminal?: string, profiles?: boolean }} [opts] the terminal (default 'right'), and
67
+ * whether to return complex profiles per frequency
68
+ * @returns {import('./types.js').ImpedanceResult}
69
+ */
70
+ impedance(frequencies: ArrayLike<number>, opts?: {
71
+ terminal?: string;
72
+ profiles?: boolean;
73
+ }): import("./types.js").ImpedanceResult;
74
+ /**
75
+ * A checkpoint of the definition and solver state, for `_rollback()` (the live wrapper keeps
76
+ * its last good state this way).
77
+ * @internal
78
+ */
79
+ _checkpoint(): {
80
+ def: import("./types.js").DeviceDefinition;
81
+ model: any;
82
+ solver: any;
83
+ snap: any;
84
+ solvedV: any;
85
+ referenceAmounts: any;
86
+ };
87
+ /**
88
+ * Back to a checkpoint taken on this device.
89
+ * @param {ReturnType<Device['_checkpoint']>} cp
90
+ * @internal
91
+ */
92
+ _rollback(cp: ReturnType<Device["_checkpoint"]>): void;
93
+ /**
94
+ * Snapshot of the current state.
95
+ * @returns {Solution}
96
+ */
97
+ solution(): Solution;
98
+ }
99
+ export type DeviceDefinition = import("./types.js").DeviceDefinition;
100
+ export type Solution = import("./types.js").Solution;
101
+ export { DeviceError, normalizeDevice } from "./device.js";
102
+ export { buildGrid, gradedCells } from "./grid.js";
103
+ export { bernoulli, bernoulliDerivative } from "./bernoulli.js";
package/types/kit.d.ts ADDED
@@ -0,0 +1,61 @@
1
+ /**
2
+ * One material seen from vacuum: a level inside it (the anchor) and how far above that level,
3
+ * in electron energy, the vacuum level just outside lies (the offset, V). So
4
+ * V_vac = V_anchor − offset.
5
+ * @typedef {object} VacuumSide
6
+ * @property {string} material material name in the definition
7
+ * @property {string} anchor a charged species present there (its standard level
8
+ * V°_i = φ + μ°_i/(z_i F): a band edge for e⁻ or h⁺), or 'phi' (the inner potential itself)
9
+ * @property {number} offset V: an electron affinity, ionisation energy, Trasatti's 4.44 V, …
10
+ */
11
+ /**
12
+ * A material's vacuum level relative to its own φ, V_vac − φ, in volts.
13
+ * @param {object} def device definition (its `species` and `materials` are read)
14
+ * @param {VacuumSide} side
15
+ * @param {string} [path] for error messages
16
+ */
17
+ export function vacuumLevel(def: object, side: VacuumSide, path?: string): number;
18
+ /**
19
+ * The vacuum-level (Anderson-type) estimate of a face's alignment: the two sides' vacuum levels
20
+ * are taken to coincide. Returns the face's `dipole`, φ_R − φ_L in volts.
21
+ * @param {object} def device definition
22
+ * @param {VacuumSide} left
23
+ * @param {VacuumSide} right
24
+ */
25
+ export function vacuumDipole(def: object, left: VacuumSide, right: VacuumSide): number;
26
+ /**
27
+ * The vacuum-level (Schottky–Mott-type) estimate of a `zeroCharge` where a conductor meets a
28
+ * material: at a conductor region's face, or a contact's capacitive or dipole law. The conductor's
29
+ * vacuum level sits its work function W beyond its Fermi level, so
30
+ * zeroCharge = V_F − φ_edge at zero charge = W + (V_vac − φ)_inside.
31
+ * @param {object} def device definition
32
+ * @param {number} workFunction V
33
+ * @param {VacuumSide} inside the material across the face
34
+ */
35
+ export function vacuumZeroCharge(def: object, workFunction: number, inside: VacuumSide): number;
36
+ export { live } from "./live.js";
37
+ /**
38
+ * One material seen from vacuum: a level inside it (the anchor) and how far above that level,
39
+ * in electron energy, the vacuum level just outside lies (the offset, V). So
40
+ * V_vac = V_anchor − offset.
41
+ */
42
+ export type VacuumSide = {
43
+ /**
44
+ * material name in the definition
45
+ */
46
+ material: string;
47
+ /**
48
+ * a charged species present there (its standard level
49
+ * V°_i = φ + μ°_i/(z_i F): a band edge for e⁻ or h⁺), or 'phi' (the inner potential itself)
50
+ */
51
+ anchor: string;
52
+ /**
53
+ * V: an electron affinity, ionisation energy, Trasatti's 4.44 V, …
54
+ */
55
+ offset: number;
56
+ };
57
+ export { build, combine, layer, ohmic, bath } from "./stack.js";
58
+ export { parseEquation, stoichiometry, half, SHE, level } from "./equation.js";
59
+ export { traces, speciesRole, typeset } from "./traces.js";
60
+ export { describe, unitWarnings } from "./describe.js";
61
+ export { IONS, H2O, WATER_EPSR, SEMICONDUCTORS, METALS, aqueous, semiconductor, metal } from "./data.js";
@@ -0,0 +1,101 @@
1
+ export function between(a: any, b: any, s: any): any;
2
+ /**
3
+ * A live device.
4
+ * @typedef {object} Live
5
+ * @property {(patch: object) => Promise<{ solution: object | null, info: object }>} set merge a change
6
+ * (as Device.set()) and solve it, after the solve under way; changes made meanwhile are merged
7
+ * and solved once, and all their promises resolve with that solution
8
+ * @property {Promise<{ solution: object | null, info: object }>} ready the first solve
9
+ * @property {object | null} solution the last good solution
10
+ * @property {() => void} close stop the worker, if any
11
+ */
12
+ /**
13
+ * A device for live demos: `live.set(patch)` as often as a slider moves, and draw what comes
14
+ * back (or in `onsolution`). Solves run one at a time, each warm from the last, letting the page
15
+ * paint in between; changes made during a solve are merged and solved together.
16
+ *
17
+ * On failure, the solution is the last good one, with `info.failed` (and `info.error` for an
18
+ * invalid change, `info.warnings` for one that didn't converge). `info.ramp` says how many steps
19
+ * a ramp from the last good state took (0: none needed), and `info.ms` the time.
20
+ *
21
+ * With `worker: true`, solving happens in a Web Worker (module workers are needed, as in every
22
+ * current browser). A function returning a Worker-like object can be given instead.
23
+ * @param {object} def device definition
24
+ * @param {{ worker?: boolean | (() => any), onsolution?: (solution: object, info: object) => void, maxRamp?: number }} [opts]
25
+ * @returns {Live}
26
+ */
27
+ export function live(def: object, { worker, onsolution, maxRamp }?: {
28
+ worker?: boolean | (() => any);
29
+ onsolution?: (solution: object, info: object) => void;
30
+ maxRamp?: number;
31
+ }): Live;
32
+ /**
33
+ * What a live device does with each change, on whichever thread solves it: apply, solve warm,
34
+ * ramp from the last good state if that fails, and fall back to the last good solution.
35
+ */
36
+ export class Session {
37
+ /** @param {object} def device definition */
38
+ constructor(def: object, { maxRamp }?: {
39
+ maxRamp?: number;
40
+ });
41
+ device: Device;
42
+ maxRamp: number;
43
+ good: {
44
+ cp: {
45
+ def: import("./types.js").DeviceDefinition;
46
+ model: any;
47
+ solver: any;
48
+ snap: any;
49
+ solvedV: any;
50
+ referenceAmounts: any;
51
+ };
52
+ sol: import("./types.js").Solution;
53
+ };
54
+ /**
55
+ * Apply changes in order, then solve once. Each change is applied on its own, so an invalid
56
+ * one is refused (its message in `errors`) without losing the others.
57
+ * @param {object[]} patches each merged into the definition, as by Device.set()
58
+ * @returns {{ solution: object | null, errors: (string | undefined)[], info: { ms: number, ramp: number, failed: boolean, error?: string, warnings?: string[] } }}
59
+ */
60
+ update(patches: object[]): {
61
+ solution: object | null;
62
+ errors: (string | undefined)[];
63
+ info: {
64
+ ms: number;
65
+ ramp: number;
66
+ failed: boolean;
67
+ error?: string;
68
+ warnings?: string[];
69
+ };
70
+ };
71
+ }
72
+ /**
73
+ * A live device.
74
+ */
75
+ export type Live = {
76
+ /**
77
+ * merge a change
78
+ * (as Device.set()) and solve it, after the solve under way; changes made meanwhile are merged
79
+ * and solved once, and all their promises resolve with that solution
80
+ */
81
+ set: (patch: object) => Promise<{
82
+ solution: object | null;
83
+ info: object;
84
+ }>;
85
+ /**
86
+ * the first solve
87
+ */
88
+ ready: Promise<{
89
+ solution: object | null;
90
+ info: object;
91
+ }>;
92
+ /**
93
+ * the last good solution
94
+ */
95
+ solution: object | null;
96
+ /**
97
+ * stop the worker, if any
98
+ */
99
+ close: () => void;
100
+ };
101
+ import { Device } from './index.js';
@@ -0,0 +1 @@
1
+ export function merge(base: any, patch: any): any;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * The colour of a trace's role and slot (a CSS colour), for drawing other charts in the same
3
+ * colours as the level diagrams.
4
+ * @param {'electron' | 'cation' | 'anion' | 'redox'} role
5
+ * @param {number} slot
6
+ * @param {{ dark?: boolean }} [opts]
7
+ */
8
+ export function themeColor(role: "electron" | "cation" | "anion" | "redox", slot: number, { dark }?: {
9
+ dark?: boolean;
10
+ }): string;
11
+ /**
12
+ * A label split into plain and subscript runs. Labels mark subscripts TeX-style: `V_{e⁻}`, or
13
+ * `C_ox` for a run of letters, digits and charge signs. Everything else is literal.
14
+ * @param {string} label
15
+ * @returns {{ text: string, sub: boolean }[]}
16
+ */
17
+ export function labelParts(label: string): {
18
+ text: string;
19
+ sub: boolean;
20
+ }[];
21
+ /**
22
+ * Line chart of level-diagram traces as an SVG string.
23
+ * @param {ReturnType<typeof traces>} tr from `traces()`
24
+ * @param {{ width?: number, height?: number, ylabel?: string, range?: [number, number], xlim?: [number, number], title?: string, ytick?: (v: number) => string }} [opts]
25
+ * `xlim` (m) zooms into part of the device; the range then fits what's shown. `ytick` writes
26
+ * the y axis's tick labels, say as powers of ten for lines that are log₁₀ of something
27
+ * @returns {string}
28
+ */
29
+ export function levelChart(tr: ReturnType<typeof traces>, { width, height, ylabel, range, xlim, title, ytick }?: {
30
+ width?: number;
31
+ height?: number;
32
+ ylabel?: string;
33
+ range?: [number, number];
34
+ xlim?: [number, number];
35
+ title?: string;
36
+ ytick?: (v: number) => string;
37
+ }): string;
38
+ /**
39
+ * A solution's level diagram as an SVG string: each charged species' voltage (thick) and
40
+ * standard level (thin), regions as bands. Options are those of `traces()` and `levelChart()`.
41
+ * @param {import('./types.js').Solution} sol
42
+ * @param {Parameters<typeof traces>[1] & Parameters<typeof levelChart>[1]} [opts]
43
+ * @returns {string}
44
+ */
45
+ export function bandDiagram(sol: import("./types.js").Solution, opts?: Parameters<typeof traces>[1] & Parameters<typeof levelChart>[1]): string;
46
+ export const THEME: Readonly<{
47
+ light: {
48
+ electron: string[];
49
+ cation: string[];
50
+ anion: string[];
51
+ redox: string[];
52
+ };
53
+ dark: {
54
+ electron: string[];
55
+ cation: string[];
56
+ anion: string[];
57
+ redox: string[];
58
+ };
59
+ }>;
60
+ import { traces } from './traces.js';
@@ -0,0 +1,18 @@
1
+ export function makeSolution(solver: any, result?: {}): {
2
+ x: Float64Array<ArrayBuffer>;
3
+ region: Int32Array<ArrayBuffer>;
4
+ species: any;
5
+ regions: any;
6
+ phi: Float64Array<any>;
7
+ c: {};
8
+ mu: {};
9
+ muStd: {};
10
+ V: {};
11
+ Vstd: {};
12
+ time: any;
13
+ converged: any;
14
+ iterations: any;
15
+ steps: any;
16
+ substeps: any;
17
+ history: any;
18
+ };