Skip to content

PN Junction model from Sze - #242

Open
mdmaas wants to merge 6 commits into
gdsfactory:mainfrom
EpsilonForge:pn_junction
Open

PN Junction model from Sze#242
mdmaas wants to merge 6 commits into
gdsfactory:mainfrom
EpsilonForge:pn_junction

Conversation

@mdmaas

@mdmaas mdmaas commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements a PN-junction depletion model for the 2D TW-MZM workflow, replacing the hand-picked junction capacitance with textbook physics. Builds on #233 (contains its commits; this PR shrinks to the feature commit once #233 merges).

Formulas (Sze & Ng, Physics of Semiconductor Devices, 3rd ed., Wiley, ch. 2)

Built-in voltage:

$$V_{bi} = \frac{k_B T}{q},\ln!\left(\frac{N_A N_D}{n_i^2}\right)$$

Abrupt-junction depletion width under reverse bias $V_R$:

$$W = \sqrt{\frac{2,\varepsilon_s,(V_{bi}+V_R)}{q}\cdot\frac{N_A+N_D}{N_A,N_D}}$$

Asymmetric split of the depletion into the two sides:

$$x_p = W,\frac{N_D}{N_A+N_D} \quad \text{(into P)}, \qquad x_n = W,\frac{N_A}{N_A+N_D} \quad \text{(into N)}$$

Linearly graded junction (grade constant $a = |dN/dx|$):

$$W = \left[\frac{12,\varepsilon_s,(V_{bi}+V_R)}{q,a}\right]^{1/3}$$

Depletion capacitance:

$$C_j = \frac{\varepsilon_s}{W} ;;\text{(per unit area)}, \qquad C = \frac{\varepsilon_s A}{W}$$

Doping concentrations use the industry-standard $\mathrm{cm^{-3}}$; lengths in µm.

User API

from gsim.common.stack.junction import PNJunctionConfig

junc = PNJunctionConfig(na_cm3=1e19, nd_cm3=1e19, v_reverse=0.0)
junc.w_um, junc.xp_um, junc.xn_um, junc.capacitance(length_um, height_um)

Two representation modes, auto-selected from $W$ vs the flanking doped sections — high-res when $W \ge \tfrac{1}{5}\min(\text{P flank},\text{N flank})$, capacitance otherwise (manual override via mode=):

  • capacitance: geometry unchanged (adjacent P/N); computed $C$ applied as a lumped Impedance boundary — one call:
    sim.set_pn_junction(junc, layer_p="p_rib", layer_n="n_rib",
                        length_um=10.0, height_um=0.22)
  • high_res: contiguous depleted-Si dielectric strip of width $W$ drawn between P and N on its own GDS layer and resolved on the actual mesh (pure real $\varepsilon_s$, no carriers); no lumped boundary

The profile builder returns the doped regions, the P/N regions, and the junction metadata (widths/capacitance/chosen mode):

pn = make_pn_junction_profile(comp, ..., junction=junc,
                              p_region=("p_rib", (21, 0), sigma),
                              n_region=("n_rib", (20, 0), sigma),
                              junction_region=("junction", (22, 0)),
                              mode="auto")
pn["junction"]["mode"], pn["junction"]["c_f"]

Demo

The 2d_twmzm notebook now illustrates this: the default junction ($N_A=N_D=10^{18},\mathrm{cm^{-3}}$, $V_R=0$, with $T$ and $n_i$ exposed as user parameters) gives $W \approx 50$ nm and auto-selects high-res mode — the depletion strip is drawn on the actual mesh. A doping sweep in the demo shows $W$ crossing back below the threshold into capacitance mode at heavier doping.

Also fixed

  • build_doped_cross_section() never registered the merged doping/rib materials on stack.materials, so doped domains silently resolved to eps=1.0 without conductivity in generated Palace configs (visible in prior demo artifacts). Now registered, with regression test.

Tests

41 new tests: physics values/limits/scalings and error paths, profile geometry/materials/auto-mode boundary cases, and end-to-end Palace checks (Impedance $C_s$ value in capacitance mode; junction dielectric domain group with $\varepsilon = 11.9$/no conductivity in high-res mode).

@codecov

codecov Bot commented Aug 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 80.49536% with 63 lines in your changes missing coverage. Please review.
✅ Project coverage is 61.99%. Comparing base (c3f26a4) to head (a152263).
⚠️ Report is 39 commits behind head on main.

Files with missing lines Patch % Lines
src/gsim/palace/runtime.py 67.37% 34 Missing and 12 partials ⚠️
src/gsim/common/stack/junction.py 88.28% 7 Missing and 6 partials ⚠️
src/gsim/common/stack/doping.py 96.55% 1 Missing and 1 partial ⚠️
src/gsim/palace/base.py 75.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #242      +/-   ##
==========================================
+ Coverage   59.98%   61.99%   +2.01%     
==========================================
  Files          94      106      +12     
  Lines       13334    15382    +2048     
  Branches     2703     3028     +325     
==========================================
+ Hits         7998     9536    +1538     
- Misses       4439     4869     +430     
- Partials      897      977      +80     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant