driftlet 1.0.1 → 1.1.1
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 +2 -2
- package/docs/data.md +131 -10
- package/docs/device.md +20 -4
- package/docs/kit.md +19 -3
- package/docs/numerics.md +10 -5
- package/docs/reliability.md +1 -3
- package/docs/templates.md +1 -1
- package/llms.txt +31 -16
- package/package.json +1 -1
- package/src/checks.js +7 -2
- package/src/data.js +104 -13
- package/src/describe.js +1 -1
- package/src/device.js +36 -15
- package/src/difference.js +42 -7
- package/src/errors.js +18 -0
- package/src/index.js +3 -1
- package/src/kit.js +1 -1
- package/src/solution.js +14 -7
- package/src/solver.js +164 -68
- package/src/stack.js +2 -1
- package/src/types.js +2 -0
- package/types/data.d.ts +44 -6
- package/types/difference.d.ts +8 -2
- package/types/errors.d.ts +8 -0
- package/types/kit.d.ts +1 -1
- package/types/solver.d.ts +13 -2
- package/types/types.d.ts +5 -0
package/src/solver.js
CHANGED
|
@@ -661,7 +661,7 @@ export class Solver {
|
|
|
661
661
|
}
|
|
662
662
|
this.res = new Float64Array(N + 1);
|
|
663
663
|
this.delta = new Float64Array(N + 1);
|
|
664
|
-
this.
|
|
664
|
+
this.rowDiv = new Float64Array(N + 1).fill(1); // what each row is divided by in the factorised system
|
|
665
665
|
}
|
|
666
666
|
|
|
667
667
|
_factor() {
|
|
@@ -801,6 +801,19 @@ export class Solver {
|
|
|
801
801
|
this._laws();
|
|
802
802
|
}
|
|
803
803
|
|
|
804
|
+
// A stretch's amount from its regions' starting concentrations (c0), per unit area, before
|
|
805
|
+
// any state exists: Infinity where one isn't given (set by a level, or doping), to order it last.
|
|
806
|
+
_roughAmount(st) {
|
|
807
|
+
const { regions, grid } = this.model;
|
|
808
|
+
let t = 0;
|
|
809
|
+
for (let q = st.regions[0]; q <= st.regions[1]; q++) {
|
|
810
|
+
const reg = regions[q], c0 = reg.c0Profile[st.species] ? profileAt(reg.c0Profile[st.species], grid.x[grid.regionStart[q]]) : reg.c0[st.species];
|
|
811
|
+
if (!(c0 >= 0)) return Infinity;
|
|
812
|
+
t += c0 * (grid.x[grid.regionEnd[q]] - grid.x[grid.regionStart[q]]);
|
|
813
|
+
}
|
|
814
|
+
return t;
|
|
815
|
+
}
|
|
816
|
+
|
|
804
817
|
// Whether a stretch's species moves through it (mobile in every region, or a metal's carrier),
|
|
805
818
|
// or stays still in every region (D = 0: trap states, conserved node by node).
|
|
806
819
|
_moves(st) {
|
|
@@ -1305,7 +1318,18 @@ export class Solver {
|
|
|
1305
1318
|
// Reduced row echelon form; the free columns give the null space. Immobile stretches' columns
|
|
1306
1319
|
// go first, so that a combination of them alone (trap states, X⁰ + X⁻) comes out on its own,
|
|
1307
1320
|
// to be kept node by node, apart from any that moves (e⁻ − X⁰, the electrons the traps hold).
|
|
1308
|
-
|
|
1321
|
+
// Then the stretches by their starting amounts, least first, and by name: a trace species
|
|
1322
|
+
// pivoted after an abundant one comes out added to it (A + B ⇌ C with B at 1 M and A at 1e-14
|
|
1323
|
+
// gave B + C and A − B, where A + C was lost to round-off), and the basis followed the listing.
|
|
1324
|
+
const still = (k) => (k < S && this._still(this.stretches[k]) ? 1 : 0);
|
|
1325
|
+
const rough = this.stretches.map((st) => this._roughAmount(st)), name = (k) => model.species[this.stretches[k].species].name;
|
|
1326
|
+
const order = [...Array(C).keys()].sort((a, b) => {
|
|
1327
|
+
if (still(a) !== still(b)) return still(b) - still(a);
|
|
1328
|
+
if (a >= S || b >= S) return a - b;
|
|
1329
|
+
if (rough[a] !== rough[b]) return rough[a] - rough[b];
|
|
1330
|
+
const na = name(a), nb = name(b);
|
|
1331
|
+
return na < nb ? -1 : na > nb ? 1 : a - b;
|
|
1332
|
+
});
|
|
1309
1333
|
const pivots = [];
|
|
1310
1334
|
let r = 0;
|
|
1311
1335
|
for (const col of order) {
|
|
@@ -2270,10 +2294,23 @@ export class Solver {
|
|
|
2270
2294
|
return;
|
|
2271
2295
|
}
|
|
2272
2296
|
let q = this.rhoFixed[g], dq = 0;
|
|
2297
|
+
const lin = this.lin;
|
|
2273
2298
|
for (let i = 0; i < n; i++) {
|
|
2274
2299
|
const k = g * n + i, r = 1 + i;
|
|
2275
2300
|
if (!this.present[k]) continue;
|
|
2276
2301
|
const Kz = this._Kz(g, i);
|
|
2302
|
+
if (lin) {
|
|
2303
|
+
// In difference form (see DifferenceTerms): storage of i and its charge, in each
|
|
2304
|
+
// δη_j − z_j δφ̂ through K_ij.
|
|
2305
|
+
res[R[b * M + r]] += (v * (c[k] - this.cOld[k])) / dt;
|
|
2306
|
+
q += F * z[i] * c[k];
|
|
2307
|
+
const Kg = g * n * n + i * n;
|
|
2308
|
+
for (let j = 0; j < n; j++) {
|
|
2309
|
+
const Kij = this.nodeIdeal[g] ? (i === j ? c[k] : 0) : this.K[Kg + j];
|
|
2310
|
+
if (Kij !== 0) lin.node(R[b * M + 1 + j], R[b * M], z[j], v * Kij, -v * F * z[i] * Kij, R[b * M + r]);
|
|
2311
|
+
}
|
|
2312
|
+
continue;
|
|
2313
|
+
}
|
|
2277
2314
|
this._storage(g, i, dt, Kz);
|
|
2278
2315
|
q += F * z[i] * c[k];
|
|
2279
2316
|
dq += F * z[i] * Kz;
|
|
@@ -2282,7 +2319,7 @@ export class Solver {
|
|
|
2282
2319
|
// (where no charge responds and no field reaches, φ isn't defined, nor an unknown)
|
|
2283
2320
|
if (!this.phiUndefined[g]) {
|
|
2284
2321
|
res[R[b * M]] -= v * q;
|
|
2285
|
-
this._j(b, 0, b, 0, v * dq);
|
|
2322
|
+
if (!lin) this._j(b, 0, b, 0, v * dq);
|
|
2286
2323
|
}
|
|
2287
2324
|
}
|
|
2288
2325
|
|
|
@@ -2420,7 +2457,7 @@ export class Solver {
|
|
|
2420
2457
|
aHi += rx.nu[p] * u[b * M + 1 + rx.sp[p]];
|
|
2421
2458
|
aLo += rx.nu[p] * uLo[b * M + 1 + rx.sp[p]];
|
|
2422
2459
|
}
|
|
2423
|
-
const { rate, Cn, Cp, Ca } = this._srhRate(law, c[g * n + law.n.i], c[g * n + law.p.i], aHi + aLo);
|
|
2460
|
+
const { rate, Cn, Cp, Ca } = this._srhRate(law, c[g * n + law.n.i], c[g * n + law.p.i], aHi + aLo, ...this._srhDegen(g, g, law));
|
|
2424
2461
|
dr.fill(0);
|
|
2425
2462
|
this._dlnc(g, law.n.i, Cn, dr);
|
|
2426
2463
|
this._dlnc(g, law.p.i, Cp, dr);
|
|
@@ -2690,39 +2727,28 @@ export class Solver {
|
|
|
2690
2727
|
// still exactly zero at equilibrium. c_L and ex depend on every ζ at their node through K.
|
|
2691
2728
|
_segmentConcentrated(s, bL, bR, mat, h, vel) {
|
|
2692
2729
|
const R = this.rix;
|
|
2693
|
-
const { n, M,
|
|
2694
|
-
const
|
|
2730
|
+
const { n, M, res, z, K } = this;
|
|
2731
|
+
const KL = s * n * n, KR = (s + 1) * n * n;
|
|
2695
2732
|
for (let i = 0; i < n; i++) {
|
|
2696
2733
|
if (!mat.present[i] || mat.D[i] === 0) continue;
|
|
2697
2734
|
const r = 1 + i, zi = z[i];
|
|
2698
|
-
const
|
|
2699
|
-
const g = mat.D[i] / h;
|
|
2700
|
-
const pe = (vel * h) / mat.D[i];
|
|
2701
|
-
const d = zi * (u[bR * M] - u[bL * M]) + ex[gR * n + i] - ex[gL * n + i] - pe;
|
|
2702
|
-
const deta = u[bR * M + r] - u[bL * M + r] + (uLo[bR * M + r] - uLo[bL * M + r]) - pe;
|
|
2703
|
-
const E = Math.expm1(deta);
|
|
2704
|
-
const B = bernoulli(d), Bp = bernoulliDerivative(d);
|
|
2705
|
-
const gBc = g * B * cL;
|
|
2706
|
-
const N = -gBc * E;
|
|
2707
|
-
const dNdd = -g * Bp * cL * E;
|
|
2708
|
-
// Left node: ∂N/∂ζ_Lj = −gE(B + B′)K_L,ij − dNdd·δ_ij, plus the direct η_L,i term.
|
|
2709
|
-
const fL = -g * E * (B + Bp);
|
|
2710
|
-
jL[0] = -fL * this._Kz(gL, i);
|
|
2711
|
-
for (let j = 0; j < n; j++) jL[1 + j] = fL * K[KL + i * n + j];
|
|
2712
|
-
jL[r] += -dNdd + gBc * (E + 1);
|
|
2713
|
-
// Right node: ∂N/∂ζ_Rj = dNdd·(δ_ij − K_R,ij/c_R), plus the direct η_R,i term.
|
|
2714
|
-
jR.fill(0);
|
|
2715
|
-
if (cR > 0) {
|
|
2716
|
-
const fR = -dNdd / cR;
|
|
2717
|
-
jR[0] = -fR * this._Kz(gR, i);
|
|
2718
|
-
for (let j = 0; j < n; j++) jR[1 + j] = fR * K[KR + i * n + j];
|
|
2719
|
-
} else {
|
|
2720
|
-
jR[0] = dNdd * zi; // K/c → δ as c → 0
|
|
2721
|
-
jR[r] -= dNdd;
|
|
2722
|
-
}
|
|
2723
|
-
jR[r] += dNdd - gBc * (E + 1);
|
|
2735
|
+
const { N, E, gBc, dNdd, fL, cR } = this._fluxConcentrated(s, bL, bR, mat, h, vel, i);
|
|
2724
2736
|
res[R[bL * M + r]] += N;
|
|
2725
2737
|
res[R[bR * M + r]] -= N;
|
|
2738
|
+
if (this.lin) {
|
|
2739
|
+
// In difference form (see DifferenceTerms): b on Δη_i and z_i·∂N/∂d on Δφ̂, and the rest
|
|
2740
|
+
// as side terms in each δη_j − z_j δφ̂ at either end (c_L and the excess potentials).
|
|
2741
|
+
const rL = R[bL * M + r], rR = R[bR * M + r], pL = R[bL * M], pR = R[bR * M];
|
|
2742
|
+
this.lin.segment(rL, rR, pL, pR, zi, 0, -gBc * (E + 1), zi * dNdd);
|
|
2743
|
+
for (let j = 0; j < n; j++) {
|
|
2744
|
+
const wL = fL * K[KL + i * n + j] - (j === i ? dNdd : 0);
|
|
2745
|
+
const wR = cR > 0 ? dNdd * ((j === i ? 1 : 0) - K[KR + i * n + j] / cR) : 0;
|
|
2746
|
+
if (wL !== 0) this.lin.side(rL, rR, R[bL * M + 1 + j], pL, z[j], wL);
|
|
2747
|
+
if (wR !== 0) this.lin.side(rL, rR, R[bR * M + 1 + j], pR, z[j], wR);
|
|
2748
|
+
}
|
|
2749
|
+
continue;
|
|
2750
|
+
}
|
|
2751
|
+
const { jL, jR } = this;
|
|
2726
2752
|
for (let k = 0; k < M; k++) {
|
|
2727
2753
|
if (jL[k] !== 0) {
|
|
2728
2754
|
this._j(bL, r, bL, k, jL[k]);
|
|
@@ -2736,6 +2762,40 @@ export class Solver {
|
|
|
2736
2762
|
}
|
|
2737
2763
|
}
|
|
2738
2764
|
|
|
2765
|
+
// Species i's flux across segment s of a non-ideal region, toward +x, and its derivatives in
|
|
2766
|
+
// this.jL and this.jR (over the unknowns of the blocks bL and bR).
|
|
2767
|
+
_fluxConcentrated(s, bL, bR, mat, h, vel, i) {
|
|
2768
|
+
const { n, M, u, uLo, c, z, K, ex, jL, jR } = this;
|
|
2769
|
+
const gL = s, gR = s + 1, KL = gL * n * n, KR = gR * n * n, r = 1 + i, zi = z[i];
|
|
2770
|
+
const cL = c[gL * n + i], cR = c[gR * n + i];
|
|
2771
|
+
const g = mat.D[i] / h;
|
|
2772
|
+
const pe = (vel * h) / mat.D[i];
|
|
2773
|
+
const d = zi * (u[bR * M] - u[bL * M]) + ex[gR * n + i] - ex[gL * n + i] - pe;
|
|
2774
|
+
const deta = u[bR * M + r] - u[bL * M + r] + (uLo[bR * M + r] - uLo[bL * M + r]) - pe;
|
|
2775
|
+
const E = Math.expm1(deta);
|
|
2776
|
+
const B = bernoulli(d), Bp = bernoulliDerivative(d);
|
|
2777
|
+
const gBc = g * B * cL;
|
|
2778
|
+
const N = -gBc * E;
|
|
2779
|
+
const dNdd = -g * Bp * cL * E;
|
|
2780
|
+
// Left node: ∂N/∂ζ_Lj = −gE(B + B′)K_L,ij − dNdd·δ_ij, plus the direct η_L,i term.
|
|
2781
|
+
const fL = -g * E * (B + Bp);
|
|
2782
|
+
jL[0] = -fL * this._Kz(gL, i);
|
|
2783
|
+
for (let j = 0; j < n; j++) jL[1 + j] = fL * K[KL + i * n + j];
|
|
2784
|
+
jL[r] += -dNdd + gBc * (E + 1);
|
|
2785
|
+
// Right node: ∂N/∂ζ_Rj = dNdd·(δ_ij − K_R,ij/c_R), plus the direct η_R,i term.
|
|
2786
|
+
jR.fill(0);
|
|
2787
|
+
if (cR > 0) {
|
|
2788
|
+
const fR = -dNdd / cR;
|
|
2789
|
+
jR[0] = -fR * this._Kz(gR, i);
|
|
2790
|
+
for (let j = 0; j < n; j++) jR[1 + j] = fR * K[KR + i * n + j];
|
|
2791
|
+
} else {
|
|
2792
|
+
jR[0] = dNdd * zi; // K/c → δ as c → 0
|
|
2793
|
+
jR[r] -= dNdd;
|
|
2794
|
+
}
|
|
2795
|
+
jR[r] += dNdd - gBc * (E + 1);
|
|
2796
|
+
return { N, E, gBc, dNdd, fL, cR };
|
|
2797
|
+
}
|
|
2798
|
+
|
|
2739
2799
|
// Ohmic conduction in a metal, in mixed form. The flux J (slot 0 of the left node) obeys
|
|
2740
2800
|
// η_R − η_L + J/g = 0, g = σ RT/(z²F² h) (Ohm's law, J = −g Δη),
|
|
2741
2801
|
// and enters the two nodes' carrier balances as outflow and inflow.
|
|
@@ -2856,7 +2916,7 @@ export class Solver {
|
|
|
2856
2916
|
aLo += rx.nu[p] * uLo[b * M + 1 + rx.sp[p]];
|
|
2857
2917
|
}
|
|
2858
2918
|
const law = rx.srh?.[this.nodeMaterial[g]];
|
|
2859
|
-
if (law) return this._srhRate(law, c[g * n + law.n.i], c[g * n + law.p.i], aHi + aLo).rate;
|
|
2919
|
+
if (law) return this._srhRate(law, c[g * n + law.n.i], c[g * n + law.p.i], aHi + aLo, ...this._srhDegen(g, g, law)).rate;
|
|
2860
2920
|
let P = rx.generation ? rx.kfNode[g] * this.generationScale : rx.kfNode[g];
|
|
2861
2921
|
for (let p = 0; p < rx.sp.length; p++) if (rx.nu[p] > 0) P *= rx.nu[p] === 1 ? c[g * n + rx.sp[p]] : powi(c[g * n + rx.sp[p]], rx.nu[p]);
|
|
2862
2922
|
return P * -Math.expm1(-(aHi + aLo));
|
|
@@ -2870,7 +2930,7 @@ export class Solver {
|
|
|
2870
2930
|
if (law) {
|
|
2871
2931
|
let a = rx.fixedA;
|
|
2872
2932
|
for (let p = 0; p < rx.sp.length; p++) a += rx.nu[p] * (u[b * M + 1 + rx.sp[p]] + uLo[b * M + 1 + rx.sp[p]]);
|
|
2873
|
-
return this._srhRate(law, c[g * n + law.n.i], c[g * n + law.p.i], a).forward;
|
|
2933
|
+
return this._srhRate(law, c[g * n + law.n.i], c[g * n + law.p.i], a, ...this._srhDegen(g, g, law)).forward;
|
|
2874
2934
|
}
|
|
2875
2935
|
let P = rx.generation ? rx.kfNode[g] * this.generationScale : rx.kfNode[g];
|
|
2876
2936
|
for (let p = 0; p < rx.sp.length; p++) if (rx.nu[p] > 0) P *= rx.nu[p] === 1 ? c[g * n + rx.sp[p]] : powi(c[g * n + rx.sp[p]], rx.nu[p]);
|
|
@@ -2884,7 +2944,7 @@ export class Solver {
|
|
|
2884
2944
|
let a = rx.fixedA;
|
|
2885
2945
|
for (let p = 0; p < rx.sp.length; p++) a += rx.nu[p] * (u[b * M + 1 + rx.sp[p]] + uLo[b * M + 1 + rx.sp[p]]);
|
|
2886
2946
|
const law = rx.srh?.[this.nodeMaterial[g]];
|
|
2887
|
-
if (law) return this._srhRate(law, c[g * n + law.n.i], c[g * n + law.p.i], a).oneWay;
|
|
2947
|
+
if (law) return this._srhRate(law, c[g * n + law.n.i], c[g * n + law.p.i], a, ...this._srhDegen(g, g, law)).oneWay;
|
|
2888
2948
|
let P = rx.generation ? rx.kfNode[g] * this.generationScale : rx.kfNode[g];
|
|
2889
2949
|
for (let p = 0; p < rx.sp.length; p++) if (rx.nu[p] > 0) P *= rx.nu[p] === 1 ? c[g * n + rx.sp[p]] : powi(c[g * n + rx.sp[p]], rx.nu[p]);
|
|
2890
2950
|
return P * Math.max(1, Math.exp(-a));
|
|
@@ -2892,21 +2952,46 @@ export class Solver {
|
|
|
2892
2952
|
|
|
2893
2953
|
// SRH kinetics (see srhLaw in device.js): the rate, and its sensitivities to ln n, ln p and
|
|
2894
2954
|
// a = A/RT. With no n₁ given, the trap is midgap: n₁ = p₁ = n_i = √(n p e^{−a}).
|
|
2895
|
-
|
|
2955
|
+
// SRH at electron and hole concentrations cn, cp and affinity a. n₁p₁ = n p e^{−a} (n_i² for
|
|
2956
|
+
// Boltzmann carriers), and under degeneracy each carrier's emission scales with its own
|
|
2957
|
+
// γ = e^{−ex} (its excess chemical potential ex, c/K = ∂ln c/∂ζ its slope): n₁ = γ_n n₁₀ and
|
|
2958
|
+
// p₁ = γ_p p₁₀, n₁₀ the law's n1, or n_i at midgap. (γ_n γ_p split evenly onto both, as it was,
|
|
2959
|
+
// put a degenerate n⁺ region's γ_n on its holes' emission too.) The rate's derivatives in ln n,
|
|
2960
|
+
// ln p and a. For large negative a (strong extraction), np·(1 − e^{−a}) as −n p e^{−a}.
|
|
2961
|
+
_srhRate(law, cn, cp, a, xn = 0, xp = 0, sn = 1, sp = 1) {
|
|
2896
2962
|
const { tn, tp } = law, lnnp = Math.log(cn) + Math.log(cp);
|
|
2897
|
-
let
|
|
2963
|
+
let lnn1, kN = 0, kP = 0, kA = 0; // ln n₁ = kN ln n + kP ln p + kA a + const
|
|
2898
2964
|
if (Number.isNaN(law.n1)) {
|
|
2899
|
-
|
|
2900
|
-
kN =
|
|
2965
|
+
lnn1 = (lnnp - a - xn + xp) / 2; // γ_n n_i, with n_i² = n p e^{−a}/(γ_n γ_p)
|
|
2966
|
+
kN = (2 - sn) / 2;
|
|
2967
|
+
kP = sp / 2;
|
|
2901
2968
|
kA = -0.5;
|
|
2902
|
-
} else
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2969
|
+
} else {
|
|
2970
|
+
lnn1 = Math.log(law.n1) - xn;
|
|
2971
|
+
kN = 1 - sn;
|
|
2972
|
+
}
|
|
2973
|
+
const n1 = Math.exp(lnn1), p1 = Math.exp(lnnp - a - lnn1), np = cn * cp;
|
|
2974
|
+
const den = tp * (cn + n1) + tn * (cp + p1);
|
|
2975
|
+
// np(1 − e^{−a}), with e^{−a} folded into np where it would overflow
|
|
2976
|
+
const f = -Math.expm1(-a), num = a > -700 ? np * f : np - Math.exp(lnnp - a);
|
|
2977
|
+
const rate = num / den;
|
|
2906
2978
|
const dDn = tp * cn + tp * n1 * kN + tn * p1 * (1 - kN);
|
|
2907
2979
|
const dDp = tp * n1 * kP + tn * cp + tn * p1 * (1 - kP);
|
|
2908
2980
|
const dDa = tp * n1 * kA + tn * p1 * (-1 - kA);
|
|
2909
|
-
return { rate, forward: np / den, oneWay: (np / den) * Math.max(1, Math.exp(-a)), Cn: rate * (1 - dDn / den), Cp: rate * (1 - dDp / den), Ca: (np / den) * (1 - f) - (rate * dDa) / den };
|
|
2981
|
+
return { rate, forward: np / den, oneWay: a > -700 ? (np / den) * Math.max(1, Math.exp(-a)) : Math.exp(lnnp - a) / den, Cn: rate * (1 - dDn / den), Cp: rate * (1 - dDp / den), Ca: (a > -700 ? (np / den) * (1 - f) : Math.exp(lnnp - a) / den) - (rate * dDa) / den };
|
|
2982
|
+
}
|
|
2983
|
+
|
|
2984
|
+
// _srhRate's degeneracy arguments: the electrons' at node gn, the holes' at gq.
|
|
2985
|
+
_srhDegen(gn, gq, law) {
|
|
2986
|
+
const [xn, sn] = this._degen(gn, law.n.i), [xp, sp] = this._degen(gq, law.p.i);
|
|
2987
|
+
return [xn, xp, sn, sp];
|
|
2988
|
+
}
|
|
2989
|
+
|
|
2990
|
+
// A carrier's excess chemical potential at node g and ∂ln c/∂ζ there (0 and 1 if ideal).
|
|
2991
|
+
_degen(g, i) {
|
|
2992
|
+
if (this.nodeIdeal[g]) return [0, 1];
|
|
2993
|
+
const n = this.n, c = this.c[g * n + i], K = this.K[g * n * n + i * n + i];
|
|
2994
|
+
return [this.ex[g * n + i], c > 0 && K > 0 ? c / K : 1];
|
|
2910
2995
|
}
|
|
2911
2996
|
|
|
2912
2997
|
// A face reaction (see normalizeFaceReactions). Its rate r_k is an unknown of the face block,
|
|
@@ -2949,7 +3034,7 @@ export class Solver {
|
|
|
2949
3034
|
} else if (rx.srh) {
|
|
2950
3035
|
// SRH, with n and p each at its own side's edge node.
|
|
2951
3036
|
const { n: pn, p: pp } = rx.srh, gn = pn.side ? gR : gL, gq = pp.side ? gR : gL;
|
|
2952
|
-
const s = this._srhRate(rx.srh, c[gn * n + pn.i], c[gq * n + pp.i], aHi + aLo);
|
|
3037
|
+
const s = this._srhRate(rx.srh, c[gn * n + pn.i], c[gq * n + pp.i], aHi + aLo, ...this._srhDegen(gn, gq, { n: pn, p: pp }));
|
|
2953
3038
|
rate = s.rate;
|
|
2954
3039
|
this._dlnc(gn, pn.i, s.Cn, pn.side ? dR : dL);
|
|
2955
3040
|
this._dlnc(gq, pp.i, s.Cp, pp.side ? dR : dL);
|
|
@@ -3049,7 +3134,7 @@ export class Solver {
|
|
|
3049
3134
|
const r = 1 + i, target = this.portEta(port, i), zF = z[i] * F;
|
|
3050
3135
|
for (const g of port.nodes) {
|
|
3051
3136
|
const b = this.blockOfNode[g], o = b * M + r, v = vol[g];
|
|
3052
|
-
const deta = target -
|
|
3137
|
+
const deta = target - u[o] - uLo[o]; // (μ̄_out − μ̄)/RT
|
|
3053
3138
|
if (link.type === 'equilibrium') {
|
|
3054
3139
|
// a device end node's level is its contact's business, where the contact links it
|
|
3055
3140
|
if ((g === 0 && this.model.contacts.left.species[i].type !== 'blocked') || (g === this.nNodes - 1 && this.model.contacts.right.species[i].type !== 'blocked')) continue;
|
|
@@ -3294,7 +3379,7 @@ export class Solver {
|
|
|
3294
3379
|
const link = ct.species[i];
|
|
3295
3380
|
const o = b * M + 1 + i;
|
|
3296
3381
|
if (link.type === 'exchange') {
|
|
3297
|
-
res[R[o]] -= Ac * link.k * (link.mu / model.RT -
|
|
3382
|
+
res[R[o]] -= Ac * link.k * (link.mu / model.RT - u[o] - uLo[o]);
|
|
3298
3383
|
this._j(b, 1 + i, b, 1 + i, Ac * link.k);
|
|
3299
3384
|
} else if (link.type === 'conductance') {
|
|
3300
3385
|
const Vi = (VT * (u[o] + uLo[o])) / z[i];
|
|
@@ -3303,7 +3388,7 @@ export class Solver {
|
|
|
3303
3388
|
B[R[o]] += (-Ac * link.G) / (z[i] * F);
|
|
3304
3389
|
} else if (link.type === 'velocity') {
|
|
3305
3390
|
// N_in = v c (e^(η_out − η) − 1): v (c_eq − c), c_eq in equilibrium with the outside.
|
|
3306
|
-
const ci = c[g * n + i], E = Math.exp(Math.min(this.contactEta(side, i) -
|
|
3391
|
+
const ci = c[g * n + i], E = Math.exp(Math.min(this.contactEta(side, i) - u[o] - uLo[o], 700));
|
|
3307
3392
|
const N = Ac * link.v * ci * (E - 1), d = this.dA;
|
|
3308
3393
|
res[R[o]] -= N;
|
|
3309
3394
|
d.fill(0);
|
|
@@ -3321,7 +3406,7 @@ export class Solver {
|
|
|
3321
3406
|
const o = b * M + 1 + i;
|
|
3322
3407
|
this._replaceRow(b, 1 + i);
|
|
3323
3408
|
this._j(b, 1 + i, b, 1 + i, 1);
|
|
3324
|
-
res[R[o]] = u[o]
|
|
3409
|
+
res[R[o]] = u[o] - this.contactEta(side, i) + uLo[o]; // (the big terms first: u + uLo rounds to u)
|
|
3325
3410
|
if (z[i] !== 0) B[R[o]] += -z[i] / VT;
|
|
3326
3411
|
}
|
|
3327
3412
|
|
|
@@ -3360,7 +3445,7 @@ export class Solver {
|
|
|
3360
3445
|
if (link.type === 'pinned') {
|
|
3361
3446
|
// φ_edge = V_t − zeroCharge (the C → ∞ limit).
|
|
3362
3447
|
this._j(b, 0, b, 0, 1);
|
|
3363
|
-
res[R[b * M]] = u[b * M]
|
|
3448
|
+
res[R[b * M]] = u[b * M] - (Vt - link.zeroCharge) / VT + uLo[b * M];
|
|
3364
3449
|
B[R[b * M]] += -1 / VT;
|
|
3365
3450
|
} else {
|
|
3366
3451
|
// Plain bulk: local neutrality.
|
|
@@ -3422,14 +3507,14 @@ export class Solver {
|
|
|
3422
3507
|
const { M, u, uLo, res, z, VT, model } = this, R = this.rix;
|
|
3423
3508
|
for (const st of this.flatStretches) {
|
|
3424
3509
|
const i = st.species, open = st.leftOpen || st.rightOpen;
|
|
3425
|
-
const { k, hi, lo } = this._flatLevel(st)
|
|
3510
|
+
const { k, hi, lo } = this._flatLevel(st);
|
|
3426
3511
|
for (let g = st.nodes[0]; g <= st.nodes[1]; g++) {
|
|
3427
3512
|
const b = this.blockOfNode[g], o = b * M + 1 + i;
|
|
3428
3513
|
if (this.loc[o] < 0) continue;
|
|
3429
3514
|
this._replaceRow(b, 1 + i);
|
|
3430
3515
|
for (const B of this.termB) B[R[o]] = 0; // (the row's old terminal terms: the end node's own link)
|
|
3431
3516
|
this._j(b, 1 + i, b, 1 + i, 1);
|
|
3432
|
-
res[R[o]] = u[o] + uLo[o] -
|
|
3517
|
+
res[R[o]] = u[o] - hi + (uLo[o] - lo); // (the big terms first: hi + lo rounds to hi)
|
|
3433
3518
|
if (open && z[i] !== 0) this.termB[k][R[o]] += -z[i] / VT;
|
|
3434
3519
|
}
|
|
3435
3520
|
// A face inside the stretch whose link holds the level continuous carries the species' flux
|
|
@@ -3482,7 +3567,8 @@ export class Solver {
|
|
|
3482
3567
|
if (b < nB - 1) sys.C.fill(0, sys.offC[b] + l * sz[b + 1], sys.offC[b] + (l + 1) * sz[b + 1]);
|
|
3483
3568
|
}
|
|
3484
3569
|
|
|
3485
|
-
// Scale every row by its largest Jacobian entry (in place, residual too)
|
|
3570
|
+
// Scale every row by its largest Jacobian entry (in place, residual too), dividing by it: its
|
|
3571
|
+
// reciprocal overflows where it's subnormal (a co-ion crowded out of a double layer, ~1e-310).
|
|
3486
3572
|
_equilibrate() {
|
|
3487
3573
|
const { nB, sys, res, termB } = this, live = this._liveTerms();
|
|
3488
3574
|
const { A, B, C, sizes, offA, offB, offC, offX } = sys;
|
|
@@ -3495,16 +3581,16 @@ export class Solver {
|
|
|
3495
3581
|
for (let k = 0; k < m; k++) mx = Math.max(mx, Math.abs(B[ob + k]));
|
|
3496
3582
|
for (let k = 0; k < mn; k++) mx = Math.max(mx, Math.abs(C[oc + k]));
|
|
3497
3583
|
if (mx === 0) {
|
|
3498
|
-
this.
|
|
3584
|
+
this.rowDiv[offX[b] + r] = 1;
|
|
3499
3585
|
continue;
|
|
3500
3586
|
}
|
|
3501
|
-
const
|
|
3502
|
-
this.
|
|
3503
|
-
for (let k = 0; k < mp; k++) A[oa + k]
|
|
3504
|
-
for (let k = 0; k < m; k++) B[ob + k]
|
|
3505
|
-
for (let k = 0; k < mn; k++) C[oc + k]
|
|
3506
|
-
res[offX[b] + r]
|
|
3507
|
-
for (const k of live) termB[k][offX[b] + r]
|
|
3587
|
+
const d = mx;
|
|
3588
|
+
this.rowDiv[offX[b] + r] = d;
|
|
3589
|
+
for (let k = 0; k < mp; k++) A[oa + k] /= d;
|
|
3590
|
+
for (let k = 0; k < m; k++) B[ob + k] /= d;
|
|
3591
|
+
for (let k = 0; k < mn; k++) C[oc + k] /= d;
|
|
3592
|
+
res[offX[b] + r] /= d;
|
|
3593
|
+
for (const k of live) termB[k][offX[b] + r] /= d; // (each terminal's ∂/∂V)
|
|
3508
3594
|
}
|
|
3509
3595
|
}
|
|
3510
3596
|
}
|
|
@@ -3515,7 +3601,8 @@ export class Solver {
|
|
|
3515
3601
|
_assembleDifference(dt) {
|
|
3516
3602
|
const keep = this.sys;
|
|
3517
3603
|
const rest = this.sysRest ?? (this.sysRest = new BlockTridiagonal(keep.n, keep.sizes));
|
|
3518
|
-
const
|
|
3604
|
+
const n = this.n, nN = this.nNodes;
|
|
3605
|
+
const lin = this.diffTerms ?? (this.diffTerms = new DifferenceTerms(keep.size, nN * n * n, nN * n, 2 * nN * n * n));
|
|
3519
3606
|
this.sys = rest;
|
|
3520
3607
|
this.lin = lin;
|
|
3521
3608
|
try {
|
|
@@ -3536,7 +3623,7 @@ export class Solver {
|
|
|
3536
3623
|
// solve's and leave refined (in the transformed unknowns, as _solveBordered gives them); false
|
|
3537
3624
|
// if refining didn't help, leaving them as they came.
|
|
3538
3625
|
_refine(dt, delta, deltaV) {
|
|
3539
|
-
const { res, termRes, termB, termC, termDI,
|
|
3626
|
+
const { res, termRes, termB, termC, termDI, rowDiv, floating: fl } = this;
|
|
3540
3627
|
const N = this.sys.size, K = fl.length, pins = this.pins, R = this.rix;
|
|
3541
3628
|
const save = { res: Float64Array.from(res), termRes: Float64Array.from(termRes), termB: termB.map((b) => Float64Array.from(b)), termC: termC.map((c) => Float64Array.from(c)), termDI: Float64Array.from(termDI), transformed: this.transformed, pinRes: this.pins.map((p) => p.res) };
|
|
3542
3629
|
const restoreArrays = () => {
|
|
@@ -3568,7 +3655,7 @@ export class Solver {
|
|
|
3568
3655
|
for (let j = 0; j < N; j++) {
|
|
3569
3656
|
let t = jv[j];
|
|
3570
3657
|
for (let a = 0; a < K; a++) t += Bk[a][j] * x[N + a];
|
|
3571
|
-
out[j] = t
|
|
3658
|
+
out[j] = t / rowDiv[j];
|
|
3572
3659
|
}
|
|
3573
3660
|
for (let a = 0; a < K; a++) {
|
|
3574
3661
|
let t = Dk[a] * x[N + a];
|
|
@@ -4755,9 +4842,9 @@ export class Solver {
|
|
|
4755
4842
|
}
|
|
4756
4843
|
|
|
4757
4844
|
// The cuts where the impedance may read a small-signal current. Each is the linearised total
|
|
4758
|
-
// current toward +x through one segment s of
|
|
4759
|
-
//
|
|
4760
|
-
// displacement's. Without ports it's the same through every cut; with them, only between a
|
|
4845
|
+
// current toward +x through one segment s of a region, Σ (g + iω d)·δu over the unknowns idx:
|
|
4846
|
+
// the Scharfetter–Gummel fluxes' derivatives (as in _segmentsDilute, or _segmentConcentrated
|
|
4847
|
+
// for non-ideal statistics) and the displacement's. Without ports it's the same through every cut; with them, only between a
|
|
4761
4848
|
// contact and the nearest port's window (see _impedance).
|
|
4762
4849
|
_currentCuts() {
|
|
4763
4850
|
const { model, n, M, u, uLo, c, z } = this, F = FARADAY;
|
|
@@ -4765,7 +4852,7 @@ export class Solver {
|
|
|
4765
4852
|
const cuts = [];
|
|
4766
4853
|
for (let r = 0; r < regions.length; r++) {
|
|
4767
4854
|
const reg = regions[r], mat = materials[reg.material];
|
|
4768
|
-
if (mat.conductor ||
|
|
4855
|
+
if (mat.conductor || reg.mixing > 0) continue;
|
|
4769
4856
|
const vel = reg.velocity;
|
|
4770
4857
|
for (let s = grid.regionStart[r]; s < grid.regionEnd[r]; s++) {
|
|
4771
4858
|
const bL = s + r, bR = bL + 1, h = grid.segLength[s] / grid.segArea[s];
|
|
@@ -4779,6 +4866,15 @@ export class Solver {
|
|
|
4779
4866
|
const phiL = u[bL * M], phiR = u[bR * M], hasPhi = !this.phiUndefined[s];
|
|
4780
4867
|
for (let i = 0; i < n; i++) {
|
|
4781
4868
|
if (z[i] === 0 || !mat.present[i] || mat.D[i] === 0) continue;
|
|
4869
|
+
if (!mat.ideal) {
|
|
4870
|
+
this._fluxConcentrated(s, bL, bR, mat, h, vel, i);
|
|
4871
|
+
for (let k = 0; k < M; k++) {
|
|
4872
|
+
if (k === 0 && !hasPhi) continue;
|
|
4873
|
+
if (this.jL[k] !== 0) add(bL * M + k, z[i] * F * this.jL[k], 0);
|
|
4874
|
+
if (this.jR[k] !== 0) add(bR * M + k, z[i] * F * this.jR[k], 0);
|
|
4875
|
+
}
|
|
4876
|
+
continue;
|
|
4877
|
+
}
|
|
4782
4878
|
const zi = z[i], r1 = 1 + i, cL = c[s * n + i], g = mat.D[i] / h;
|
|
4783
4879
|
const pe = (vel * h) / mat.D[i];
|
|
4784
4880
|
const d = zi * (phiR - phiL) - pe;
|
package/src/stack.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// that you didn't write: it only moves things to where the definition keeps them, and converts
|
|
5
5
|
// the kit's doping shorthand (donors and acceptors).
|
|
6
6
|
|
|
7
|
-
import { DeviceError, checkOptions } from './errors.js';
|
|
7
|
+
import { DeviceError, checkOptions, shown } from './errors.js';
|
|
8
8
|
import { FARADAY } from './constants.js';
|
|
9
9
|
|
|
10
10
|
const fail = (message) => {
|
|
@@ -131,6 +131,7 @@ const STACK_FIELDS = ['T', 'library', 'species', 'materials', 'stack', 'bulkReac
|
|
|
131
131
|
export function build(def) {
|
|
132
132
|
if (!isObject(def)) fail('build: give { library, stack, … }');
|
|
133
133
|
fields(def, 'build', STACK_FIELDS);
|
|
134
|
+
if (def.T !== undefined && !(typeof def.T === 'number' && Number.isFinite(def.T) && def.T > 0)) fail(`build.T must be the temperature in K, a positive number, got ${shown(def.T)}`);
|
|
134
135
|
if (def.library !== undefined && !Array.isArray(def.library)) fail('build.library must be a list of { species, materials }');
|
|
135
136
|
const { species, materials } = combine(...(def.library ?? []), { species: def.species ?? [], materials: def.materials ?? {} });
|
|
136
137
|
|
package/src/types.js
CHANGED
|
@@ -39,6 +39,8 @@
|
|
|
39
39
|
* @property {{ species: string, conductivity: number }} [conductor] a metal or fast ion
|
|
40
40
|
* conductor: its one carrier and conductivity (S/m); its only level is the carrier's (a metal's
|
|
41
41
|
* Fermi level), and φ is undefined inside
|
|
42
|
+
* @property {number} [T] the temperature its data are for (K): a device at another temperature
|
|
43
|
+
* warns (semiconductor() sets it)
|
|
42
44
|
*/
|
|
43
45
|
|
|
44
46
|
/**
|
package/types/data.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Water with the named ions, as a library piece for `build()`: each ion as a species
|
|
3
|
-
* (c_ref = 1 M) and the material `water` holding them, with D and μ° from `IONS`.
|
|
3
|
+
* (c_ref = 1 M) and the material `water` holding them, with D and μ° from `IONS`. The data are
|
|
4
|
+
* 25 °C's, and the material says so (T: 298.15): a device at another temperature warns.
|
|
4
5
|
* @param {string[]} names ions from `IONS`
|
|
5
6
|
* @param {{ epsr?: number, material?: string }} [opts] permittivity (default that of water;
|
|
6
7
|
* 0 makes the solution strictly neutral, without double layers), and the material's name
|
|
@@ -15,19 +16,56 @@ export function aqueous(names: string[], { epsr, material }?: {
|
|
|
15
16
|
};
|
|
16
17
|
/**
|
|
17
18
|
* A semiconductor from `SEMICONDUCTORS`, as a library piece: electrons `e-` and holes `h+`, with
|
|
18
|
-
* c_ref = Nc and Nv, D from the mobilities by the Einstein relation at
|
|
19
|
-
* anchored at the conduction band) and μ°_h⁺ = Eg·F. The data are for 300 K
|
|
19
|
+
* c_ref = Nc and Nv, D from the mobilities by the Einstein relation at T, and μ°_e⁻ = 0 (φ
|
|
20
|
+
* anchored at the conduction band) and μ°_h⁺ = Eg·F. The data are for 300 K; another T (150 to
|
|
21
|
+
* 500 K) moves them: the gap by Varshni's shift from 300 K, Nc and Nv as T^1.5, the mobilities by
|
|
22
|
+
* lattice-limited power laws (light doping). The material carries its `T`, and a device at
|
|
23
|
+
* another temperature warns: give the device the same T.
|
|
20
24
|
* Statistics are ideal (Boltzmann); add Fermi–Dirac to the material for degenerate doping.
|
|
21
25
|
* @param {string} name 'Si', 'Ge' or 'GaAs'
|
|
22
|
-
* @param {{ material?: string }} [opts]
|
|
26
|
+
* @param {{ material?: string, T?: number }} [opts] the material's name, and the temperature
|
|
27
|
+
* (K, default 300, the table's)
|
|
23
28
|
* @returns {{ species: object[], materials: Record<string, object> }}
|
|
24
29
|
*/
|
|
25
|
-
export function semiconductor(name: string, { material }?: {
|
|
30
|
+
export function semiconductor(name: string, { material, T }?: {
|
|
26
31
|
material?: string;
|
|
32
|
+
T?: number;
|
|
27
33
|
}, ...args: any[]): {
|
|
28
34
|
species: object[];
|
|
29
35
|
materials: Record<string, object>;
|
|
30
36
|
};
|
|
37
|
+
/**
|
|
38
|
+
* A trap level in a semiconductor that holds charge: its two charge states as immobile species
|
|
39
|
+
* (D = 0), filled and emptied by capturing carriers, e⁻ + X⁰ = X⁻ and X⁻ + h⁺ = X⁰ (acceptor-like)
|
|
40
|
+
* or X⁺ + e⁻ = X⁰ and X⁰ + h⁺ = X⁺ (donor-like). In steady state it recombines at exactly the
|
|
41
|
+
* `srh` law's rate with the same τ_n, τ_p and n₁, and its charge is in Poisson's equation, which
|
|
42
|
+
* the `srh` law (the trap's occupancy eliminated) leaves out. Each node keeps its own total.
|
|
43
|
+
* @param {{ species: object[], materials: Record<string, object> }} lib a library entry with e⁻
|
|
44
|
+
* and h⁺ (semiconductor()), returned with the trap's states added
|
|
45
|
+
* @param {{ density: number, tauN: number, tauP: number, n1?: number, charge?: 'acceptor' | 'donor',
|
|
46
|
+
* name?: string, material?: string, T?: number }} opts density N_t (mol/m³); τ_n = 1/(c_n N_t)
|
|
47
|
+
* and τ_p = 1/(c_p N_t) (s) at that density; n₁, the electron density that half-fills it
|
|
48
|
+
* (mol/m³; default n_i, midgap); T (K, default the material's T, else 300)
|
|
49
|
+
* @returns {{ library: object, bulkReactions: object[], c0: Record<string, number> }} the library
|
|
50
|
+
* for build(), the capture reactions, and c0 for each layer holding the trap (its total N_t)
|
|
51
|
+
*/
|
|
52
|
+
export function trap(lib: {
|
|
53
|
+
species: object[];
|
|
54
|
+
materials: Record<string, object>;
|
|
55
|
+
}, { density, tauN, tauP, n1, charge, name, material, T }?: {
|
|
56
|
+
density: number;
|
|
57
|
+
tauN: number;
|
|
58
|
+
tauP: number;
|
|
59
|
+
n1?: number;
|
|
60
|
+
charge?: "acceptor" | "donor";
|
|
61
|
+
name?: string;
|
|
62
|
+
material?: string;
|
|
63
|
+
T?: number;
|
|
64
|
+
}, ...args: any[]): {
|
|
65
|
+
library: object;
|
|
66
|
+
bulkReactions: object[];
|
|
67
|
+
c0: Record<string, number>;
|
|
68
|
+
};
|
|
31
69
|
/**
|
|
32
70
|
* A metal from `METALS` as a conductor material, its carrier `e-`.
|
|
33
71
|
* @param {string} name
|
|
@@ -57,7 +95,7 @@ export const H2O: -237.129e3;
|
|
|
57
95
|
export const WATER_EPSR: 78.3;
|
|
58
96
|
/**
|
|
59
97
|
* Semiconductors at 300 K (Sze, Physics of Semiconductor Devices, 2nd ed., 1981, appendix):
|
|
60
|
-
* relative permittivity, band gap Eg (eV), electron affinity chi (
|
|
98
|
+
* relative permittivity, band gap Eg (eV), electron affinity chi (eV), effective densities of
|
|
61
99
|
* states Nc and Nv (cm⁻³), and drift mobilities of lightly doped material mun and mup
|
|
62
100
|
* (cm²/(V·s)).
|
|
63
101
|
*/
|
package/types/difference.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export class DifferenceTerms {
|
|
2
|
-
constructor(N: any, nodes: any, segments: any);
|
|
2
|
+
constructor(N: any, nodes: any, segments: any, sides?: number);
|
|
3
3
|
N: any;
|
|
4
4
|
dead: Uint8Array<any>;
|
|
5
|
+
nR: Int32Array<any>;
|
|
5
6
|
nI: Int32Array<any>;
|
|
6
7
|
nP: Int32Array<any>;
|
|
7
8
|
nZ: Float64Array<any>;
|
|
@@ -12,6 +13,9 @@ export class DifferenceTerms {
|
|
|
12
13
|
sC: Float64Array<ArrayBuffer>;
|
|
13
14
|
dI: Int32Array<ArrayBuffer>;
|
|
14
15
|
dK: Float64Array<any>;
|
|
16
|
+
xI: Int32Array<ArrayBuffer>;
|
|
17
|
+
xZ: Float64Array<ArrayBuffer>;
|
|
18
|
+
xC: Float64Array<ArrayBuffer>;
|
|
15
19
|
combos: any[];
|
|
16
20
|
t: Float64Array<any>;
|
|
17
21
|
x: Float64Array<any>;
|
|
@@ -20,8 +24,10 @@ export class DifferenceTerms {
|
|
|
20
24
|
nn: number;
|
|
21
25
|
ns: number;
|
|
22
26
|
nd: number;
|
|
23
|
-
|
|
27
|
+
nx: number;
|
|
28
|
+
node(i: any, p: any, z: any, mass: any, charge: any, r?: any): void;
|
|
24
29
|
segment(iL: any, iR: any, pL: any, pR: any, z: any, a: any, b: any, d: any): void;
|
|
30
|
+
side(rL: any, rR: any, i: any, p: any, z: any, w: any): void;
|
|
25
31
|
displacement(pL: any, pR: any, k: any): void;
|
|
26
32
|
kill(row: any): void;
|
|
27
33
|
combine(rk: any, ri: any, w: any): void;
|
package/types/errors.d.ts
CHANGED
|
@@ -6,6 +6,14 @@
|
|
|
6
6
|
* @param {new (message: string) => Error} [Kind]
|
|
7
7
|
*/
|
|
8
8
|
export function checkOptions(where: string, opts: unknown, allowed: string[], Kind?: new (message: string) => Error): void;
|
|
9
|
+
/**
|
|
10
|
+
* A value as an error message shows it: a number as itself (NaN and Infinity too, which JSON
|
|
11
|
+
* would print as null), a string quoted and called one ("350", a string, where a number was
|
|
12
|
+
* wanted).
|
|
13
|
+
* @param {unknown} v
|
|
14
|
+
* @returns {string}
|
|
15
|
+
*/
|
|
16
|
+
export function shown(v: unknown): string;
|
|
9
17
|
export class DeviceError extends Error {
|
|
10
18
|
constructor(message: any);
|
|
11
19
|
}
|
package/types/kit.d.ts
CHANGED
|
@@ -66,4 +66,4 @@ export { hodgkinHuxley, ghkCurrent } from "./channels.js";
|
|
|
66
66
|
export { describe, unitWarnings } from "./describe.js";
|
|
67
67
|
export { henderson, planck } from "./junction.js";
|
|
68
68
|
export { perovskiteCell, PEROVSKITE_SCANS, hysteresis } from "./devices.js";
|
|
69
|
-
export { IONS, H2O, WATER_EPSR, SEMICONDUCTORS, METALS, aqueous, semiconductor, metal } from "./data.js";
|
|
69
|
+
export { IONS, H2O, WATER_EPSR, SEMICONDUCTORS, METALS, aqueous, semiconductor, metal, trap } from "./data.js";
|
package/types/solver.d.ts
CHANGED
|
@@ -131,7 +131,7 @@ export class Solver {
|
|
|
131
131
|
fullOf: Int32Array<ArrayBuffer>;
|
|
132
132
|
res: Float64Array<ArrayBuffer>;
|
|
133
133
|
delta: Float64Array<ArrayBuffer>;
|
|
134
|
-
|
|
134
|
+
rowDiv: Float64Array<ArrayBuffer>;
|
|
135
135
|
_factor(): void;
|
|
136
136
|
_solveLinear(rhs: any, delta: any): void;
|
|
137
137
|
_findStretches(): void;
|
|
@@ -139,6 +139,7 @@ export class Solver {
|
|
|
139
139
|
stretchOf: Int32Array<ArrayBuffer>;
|
|
140
140
|
moieties: Float64Array<any>[];
|
|
141
141
|
flatStretches: any[];
|
|
142
|
+
_roughAmount(st: any): number;
|
|
142
143
|
_moves(st: any): boolean;
|
|
143
144
|
_still(st: any): boolean;
|
|
144
145
|
_feeds(k: any, st: any): any;
|
|
@@ -226,6 +227,14 @@ export class Solver {
|
|
|
226
227
|
_faceVoltage(f: any): number;
|
|
227
228
|
_faceGates(f: any, bf: any, bL: any, bR: any): void;
|
|
228
229
|
_segmentConcentrated(s: any, bL: any, bR: any, mat: any, h: any, vel: any): void;
|
|
230
|
+
_fluxConcentrated(s: any, bL: any, bR: any, mat: any, h: any, vel: any, i: any): {
|
|
231
|
+
N: number;
|
|
232
|
+
E: number;
|
|
233
|
+
gBc: number;
|
|
234
|
+
dNdd: number;
|
|
235
|
+
fL: number;
|
|
236
|
+
cR: number;
|
|
237
|
+
};
|
|
229
238
|
_segmentConductor(s: any, bL: any, bR: any, mat: any, h: any): void;
|
|
230
239
|
_segmentMixing(s: any, bL: any, bR: any, Dm: any, h: any, mat: any): void;
|
|
231
240
|
mixWork: Float64Array<any>[];
|
|
@@ -233,7 +242,7 @@ export class Solver {
|
|
|
233
242
|
bulkRate(rx: any, g: any): number;
|
|
234
243
|
bulkForward(rx: any, g: any): any;
|
|
235
244
|
bulkOneWay(rx: any, g: any): number;
|
|
236
|
-
_srhRate(law: any, cn: any, cp: any, a: any): {
|
|
245
|
+
_srhRate(law: any, cn: any, cp: any, a: any, xn?: number, xp?: number, sn?: number, sp?: number): {
|
|
237
246
|
rate: number;
|
|
238
247
|
forward: number;
|
|
239
248
|
oneWay: number;
|
|
@@ -241,6 +250,8 @@ export class Solver {
|
|
|
241
250
|
Cp: number;
|
|
242
251
|
Ca: number;
|
|
243
252
|
};
|
|
253
|
+
_srhDegen(gn: any, gq: any, law: any): number[];
|
|
254
|
+
_degen(g: any, i: any): number[];
|
|
244
255
|
_faceReaction(rx: any, k: any, f: any, bf: any, bL: any, bR: any, Af: any): void;
|
|
245
256
|
_liveTerms(): any;
|
|
246
257
|
_allTerms: any;
|