FLOOXS » TclLib » Models

Models — TclLib Procs

97 documented proc(s) in TclLib/Models/.

::BandGap::schema · ::Bands::__compose_mobility · ::Bands::__compose_population · ::Bands::__family_shift · ::BandStructure::__assign_family_shifts · ::BandStructure::__compose_flat · ::BandStructure::__compose_multivalley · ::BandStructure::__hole_solution_name · ::BandStructure::__install_strain_params · ::Compose::eval_numeric · ::ConductivityMultiplier::schema · ::Defaults::device · ::Defaults::diffuse · ::Defaults::register · ::Defaults::stress · ::Device::__flag_present · ::Device::__render_const · ::Device::__render_pde · ::Device::__resolve_selone · ::Device::__result_get · ::Device::__result_has · ::Device::Aggregate::__dir_projection · ::Device::assert_consumed · ::Device::consume · ::Device::dict_deep_merge · ::Device::dos_m32 · ::Device::is_dict · ::Device::lowest_affinity · ::Device::render · ::Device::resolve_models · ::Device::valley_l_dir_index · ::Device::valley_x_dir_index · ::Elastic::atensor · ::Elastic::cubic_cij · ::Elastic::cubic_stiffness · ::Elastic::hex_cij · ::Elastic::pack_cij · ::Elastic::transiso_cij · ::Generation::Avalanche::vanOberstraeten::__tanh · ::Generation::B2B::__schenk_kernel · ::Hall::lorentz_tensor · ::HighFieldMobility::schema · ::HighFieldMobility::wrap_carrier · ::Mobility::__carrier_slice · ::Mobility::compose_carrier · ::Mobility::Klaassen::__build_dopant · ::Mobility::Klaassen::build · ::Permittivity::schema · ::Pull::__has_builder · ::Pull::collect_specs · ::Pull::parse_flags · ::Pull::resolve_select_one · ::Pull::select_one · ::Quantum::schema · ::Stress::schema · ::Transport::schema · __device_bool · __device_contacts · __device_feqf_continuity · __device_get · __device_sg_continuity · __device_shared_preamble · __device_shared_tail · __diffuse_collect_species · __diffuse_emit_species_solutions · __diffuse_emit_temp · __diffuse_is_interface · __diffuse_shared_preamble · __internal_substrate_fill_lines · arr · ConcBind · device · DiffLimit · diffuse · diffuse_pull · init_adapt_fields · MatBandGap · MatNcTotal · MatNvTotal · matparam_proc · matparam_sub · matparam_sub3 · models_dict_get · pde_append · pde_flush · pde_init · pde_keys · pde_peek · pde_set_self · pull_check · pull_check_all · spec_const · spec_snap · spec_snap_init · stress · SurfDiffLimit · voigt_components

::BandGap::schema

file: TclLib/Models/BandGap/compose.tcl

::BandGap::schema — known/required param sets per model, consumed by
::Pull::resolve_select_one at slice-materialization time (typo guard
per chain link + required-present on the merged params).  Values may
be composition-rule lists; validation is key-based.

::Bands::__compose_mobility

file: TclLib/Models/Bands/compose.tcl

Per-band mobility composer.  Mathiessen-sums the band's declared
Mobility models; applies optional HighFieldMobility wrap.  Each
model's sub-dict still uses the per-carrier shape ({electron {…}
hole {…}}); the band's quasi_fermi picks which carrier slice to
dispatch.

::Bands::__compose_population

file: TclLib/Models/Bands/compose.tcl

Per-band population — Fermi-Dirac selector.

::Bands::__family_shift

file: TclLib/Models/Bands/compose.tcl

Per-band strain shift dispatch — X/L family bands compute via the
XBandEdgeShiftStrain / LBandEdgeShiftStrain Tcl helpers; other
families default to zero (override via explicit `shift` key in the
band slice).  `miller` comes from ctx (the `device pull miller=`
argument, default (001)<100>).

::BandStructure::__assign_family_shifts

file: TclLib/Models/BandStructure/compose.tcl

Strain shift assignment per valley family.  Stores into the upvar'd
shifts array.  X-family valleys get XBandEdgeShiftStrain entries
indexed by their |Dir|; L-family valleys get LBandEdgeShiftStrain;
Γ-family valleys get a (currently zero) hydrostatic shift.

::BandStructure::__compose_flat

file: TclLib/Models/BandStructure/compose.tcl

Single-effective-band emission.

::BandStructure::__compose_multivalley

file: TclLib/Models/BandStructure/compose.tcl

Multi-valley emission (lifted from BandstructurePackage steps
2/4/5/7/8/10 as pure function).

::BandStructure::__hole_solution_name

file: TclLib/Models/BandStructure/compose.tcl

Map schema band names (LH/HH/SO) to the legacy solution names that
downstream code (avalanche, B2B, Schenk) reads.  Unknown band names
pass through verbatim so materials can introduce additional bands.

::BandStructure::__install_strain_params

file: TclLib/Models/BandStructure/compose.tcl

Install per-material deformation potentials from a `BandStructure {
StrainParams { … } }` dict slice into `::<mat>::<key>` namespace
vars.  Compat shim for the Tcl strain helpers (XBandEdgeShiftStrain
in TclLib/Device/Utilities/Strain/XValley.tcl, LBandEdgeShiftStrain
in LValley.tcl, __Compliance / __Stiffness in scalartensor.tcl) that
still read namespace vars by qualified name.  Compose::eval_value
handles composition rules (`{linear A B}` for SiGe) at install time
using the material's `x` from ctx.

Idempotent — re-running with the same dict produces the same vars.
The dict is the source of truth; F3 deletes this proc when the
helpers take args.

::Compose::eval_numeric

file: TclLib/Models/Combinators.tcl

::Compose::eval_numeric — numeric twin of eval_value for Tcl-time
consumers (the stress kernels do their matrix math in Tcl, so
composition-dependent stiffnesses must resolve to NUMBERS at pull
time, not Alagator strings).  `x` is the material's composition
fraction (numeric); plain scalar values pass through verbatim.

Rules:
  linear         A B          → A*(1-x) + B*x
  linear_bowing  A B bowing b → A*(1-x) + B*x - b*x*(1-x)
  linear_neg     A B          → -(A*(1-x) + B*x)
  poly_T         …            → error (needs Temp at solve time —
                                 not expressible numerically here)

::ConductivityMultiplier::schema

file: TclLib/Models/ConductivityMultiplier/compose.tcl

::ConductivityMultiplier::schema — known/required param sets per
model, consumed by ::Pull::resolve_select_one.

::Defaults::device

file: TclLib/Models/Defaults.tcl

::Defaults::device — returns a copy of the device-domain master.
Lazy-sources every baseline.tcl on first call.

::Defaults::diffuse

file: TclLib/Models/Defaults.tcl

::Defaults::diffuse — returns a copy of the diffusion-domain master.
Lazy-sources every baseline.tcl on first call.

::Defaults::register

file: TclLib/Models/Defaults.tcl

::Defaults::register <mat> <full_dict>

Splits a material's full physics dict by family name into stress-
domain, device-domain, and diffusion-domain slices and stores each
in the corresponding subsystem-specific global.  Baselines call
this at source time.

::Defaults::stress

file: TclLib/Models/Defaults.tcl

::Defaults::stress — returns a copy of the stress-domain master.
Lazy-sources every baseline.tcl on first call.

::Device::__flag_present

file: TclLib/Models/Render.tcl

Internal: does a flag (literal token) appear in the flags list?

::Device::__render_const

file: TclLib/Models/Render.tcl

::Device::__render_const — emit a `solution $mat add name=$name const
<flags> val=$val` call.

::Device::__render_pde

file: TclLib/Models/Render.tcl

::Device::__render_pde — emit a `solution $mat add name=$name pde
<flags> val=$val` call.

::Device::__resolve_selone

file: TclLib/Models/DeviceWrapper.tcl

::Device::__resolve_selone — chain-aware select-one slice resolution.

Calls `::Pull::resolve_select_one` on the UN-merged models dict to
pick the closest ancestor's declared model and chain-merge params
within it, returning `{<chosen_model> <merged_params>}` wrapped as a
single-entry dict.  Empty dict when no link declares the family.

`resolve deep` families don't come through here — their slice is
exactly the family's share of the material's full deep merge, so the
dispatcher consumes it straight from `wd` (one chain walk per
material instead of one per family).

::Device::__result_get

file: TclLib/Models/DeviceWrapper.tcl

::Device::__result_get — return ctx.__results__.<family> as a dict,
defaulting to an empty dict when the family didn't emit (or never
ran).  Replaces the open-coded `[dict exists … ? dict get : dict
create]` idiom that used to appear in every downstream composer.

::Device::__result_has

file: TclLib/Models/DeviceWrapper.tcl

::Device::__result_has — does ctx have a non-empty key from the
named family's published result dict?  Used by composers to check
upstream emissions (e.g. BandStructure published Elec).

::Device::Aggregate::__dir_projection

file: TclLib/Models/Aggregate/compose.tcl

Project a direction vector onto axes — returns dict {x sign y sign z sign}
where sign is "1", "-1", or "0" for null projection.

::Device::assert_consumed

file: TclLib/Models/Inheritance.tcl

::Device::assert_consumed <where> <mat> <wd>

Per-material leftover check used by both `device pull` and `stress
pull` dispatchers.  Raises when any family is left in $wd after the
subsystem's composers have consumed their share, naming the
subsystem ($where prefix), the material, and the leftover families.

Catches "deck passed an out-of-domain dict" (e.g. unfiltered
::Models handed to stress pull) and "subsystem composer forgot to
consume its family".  Single source of truth for the error format.

::Device::consume

file: TclLib/Models/Inheritance.tcl

::Device::consume <dictvar> <key> ?<default>?

Reads and removes a key from a dict variable in one shot.  Returns
the value (or $default if the key is absent).  This is how the
top-level dispatcher implements consume-and-validate: each family
entry is read and removed as it dispatches; any unconsumed key at
the end raises.

::Device::dict_deep_merge

file: TclLib/Models/Inheritance.tcl

::Device::dict_deep_merge <parent> <child>

Recursive leaf-level merge.  At each level: if a key exists in both
parent and child AND both values are themselves dicts, recurse.
Otherwise child wins.

::Device::dos_m32

file: TclLib/Models/BandStructure/dir.tcl

DOS-mass term for BandEdgeNumberOfStates' linear m-slot.

BandEdgeNumberOfStates returns T^1.5 * m * const^1.5 — its `m`
argument is the DOS effective mass RAISED TO 3/2, not the mass
itself (Nc ∝ m_dos^{3/2}).  For an ellipsoidal valley
m_dos = (ml·mt²)^(1/3), so the slot takes (ml·mt²)^(1/2).

This was computed inline (with diverging exponents — Bands and
MatNcTotal passed the raw (ml·mt²)^(1/3), under-counting Nc by
m_dos^{1/2}) in three places; every valley-mass consumer goes
through here now.  Numeric masses fast-path to a number;
composition-rule strings stay symbolic.

::Device::is_dict

file: TclLib/Models/Inheritance.tcl

::Device::is_dict <value>

Heuristic: a Tcl value is "dict-like" if it has even length AND
`dict size` succeeds on it.  Used to decide whether deep_merge
should recurse at this level or treat the value as a leaf.  Lists
(like Dir = {1 0 0}) have odd length only for odd-element lists,
so {Dir {1 0 0}} treats the {1 0 0} as 1-element dict at this
heuristic — accepted because {1 0 0} merging never recurses into
0/0 the way leaf-overrides need.  Acceptable false-positive for
the rare 3-element direction value.

A cleaner alternative is to mark dict values explicitly, but the
heuristic works for every value shape FLOOXS actually uses.

::Device::lowest_affinity

file: TclLib/Models/BandStructure/dir.tcl

Compose a nested-ternary "max over a list" Alagator expression.
Dedupes identical entries first so a 6-valley X-only material with
shared χ collapses to a trivial constant.  Caller supplies the list;
rule-evaluation (Compose::eval_value for composition rules) happens
upstream — this proc treats every entry as opaque.

::Device::render

file: TclLib/Models/Render.tcl

::Device::render <mat> <decls>

Iterate decls (a dict of name → spec) and emit one `solution $mat
add ...` call per entry.  The order is dict-iteration order, which
in Tcl is insertion order, which equals the order the upstream
compose procs returned their spec dicts.  Per-material registration
semantics; cross-material solutions stay outside this composer
(FEQFDevicePackage sets them up before the pull walks materials).

::Device::resolve_models

file: TclLib/Models/Inheritance.tcl

::Device::resolve_models <mat> ?<models_dict>?

Returns the effective ::Models-style dict for $mat — recursive deep
merge of every link in `mater name=$mat chain` (root first, child
last, so child values win at leaf level).  Materials with no entry
contribute nothing to the merge.

If `models_dict` is supplied, walks IT instead of the `::Models`
global.  Empty string (the default) means "use ::Models".  Used by
the explicit `device pull=$dict` path where the deck owns the dict
locally.

Returns an empty dict if no link in the chain has an entry.

::Device::valley_l_dir_index

file: TclLib/Models/BandStructure/dir.tcl

Index a {111}-family direction into LBandEdgeShiftStrain's flat list.
Returns 0/1/2/3 for the four (111) variants; raises on anything else.

::Device::valley_x_dir_index

file: TclLib/Models/BandStructure/dir.tcl

Index an axis-aligned direction into XBandEdgeShiftStrain's flat list.
Accepts {±1 0 0}/{0 ±1 0}/{0 0 ±1} (the six X-valley directions);
strain shifts are symmetric across the sign so we work in |dir|.

::Elastic::atensor

file: TclLib/Models/Elastic.tcl

::Elastic::atensor — full anisotropic ATensor Alagator substring from
the first twelve entries of a packed stiffness list.

::Elastic::cubic_cij

file: TclLib/Models/Elastic.tcl

::Elastic::cubic_cij — rotated cubic stiffness for an arbitrary
Miller orientation.

Args:
  C11, C12, C44 — cubic stiffness constants in crystal frame
                  (dynes/cm^2 or Pa)
  Miller        — orientation in (hkl)<uvw> notation; default (001)<100>

Returns the packed 15-element list (see pack_cij above).

::Elastic::cubic_stiffness

file: TclLib/Models/Elastic.tcl

::Elastic::cubic_stiffness — cubic 6x6 stiffness matrix in crystal
frame from C11, C12, C44.

::Elastic::hex_cij

file: TclLib/Models/Elastic.tcl

::Elastic::hex_cij — hexagonal (wurtzite / 4H-6H SiC) stiffness from
the five independent constants, c-axis carried by the chosen device
axis (no rotation — axis-aligned only; C66 = (C11-C12)/2 within the
basal plane).

Args:
  C11 C12 C13 C33 C44 — hexagonal stiffness constants (crystal
                         convention: c-axis = 3-direction)
  axis                 — device axis carrying the crystal c-axis
                         (x | y | z; default x, matching the
                         transiso_cij convention)

Thermodynamic stability is enforced (C11 > |C12| and
(C11+C12)*C33 > 2*C13^2) — a violating set is a deck typo, not a
material.

Returns the packed 12-element list (normal 3x3 block row-major,
then xy / yz / xz shear stiffnesses — the ::Elastic::atensor order).

::Elastic::pack_cij

file: TclLib/Models/Elastic.tcl

::Elastic::pack_cij — pack a rotated 6x6 stiffness matrix C + the
three 2D-RHS compliance entries from S into the 15-element list this
file's consumers share:
  c00 c01 c02 c10 c11 c12 c20 c21 c22 c33 c44 c55 s02 s12 s22
where c33/c44/c55 in the output correspond to C(5,5), C(3,3), C(4,4)
— the C++ stress.cc ordering (re-orders shears xy/yz/zx).

::Elastic::transiso_cij

file: TclLib/Models/Elastic.tcl

::Elastic::transiso_cij — transverse-isotropic stiffness from
engineering constants.

Args:
  E1, E2 — Young's moduli (1 = out of plane, 2 = in plane)
  G12    — Shear modulus in plane containing the 1-axis
  v12    — Poisson's ratio for stress-1 / strain-2 coupling
  v23    — Poisson's ratio within the isotropic plane

Fixed-orientation contract: the matrix is built with axis-0 = the
symmetry axis (the out-of-plane "1-direction") and axes 1,2 = the
isotropic plane.  FLOOXS device convention puts the out-of-plane
direction on device-X, so the matrix is already in device frame —
there is NO orientation parameter.  Wire a Bond rotation only after
the matrix is reordered to the (100,010,001) crystal-axis convention.

Returns a 12-element list (no 2D-RHS compliance terms — transverse-iso
decks don't use those entries):
  c00 c01 c02 c10 c11 c12 c20 c21 c22 c33 c44 c55

::Generation::Avalanche::vanOberstraeten::__tanh

file: TclLib/Models/Generation/Avalanche.tcl

Internal: hyperbolic tangent as an Alagator expression.

::Generation::B2B::__schenk_kernel

file: TclLib/Models/Generation/B2B.tcl

--- Shared Schenk kernel ---

The three Schenk variants (Schenk / SchenkMultiValley / MultiBandSchenk)
share the n / p / SchenkSRH density-correction expression and the
Fc_pm / Fc_mp / exp-sum body shape.  Each variant differs only in:
  - how many EgEff terms enter the inner sum (1 vs 6),
  - what those EgEff strings look like (literal Eg, EgEff alagator
    field, or per-(valley, band) Eg+Delta combinations),
  - any auxiliary spec-dict entries that need to ride along (e.g.
    SchenkMultiValley's EgEff declaration).

The kernel below absorbs the shared body.  N==1 emits the byte-exact
legacy expression (no leading `0+`, no `/N.` divisor).  N>1 builds
the parenthesized `(0+term1+...+termN)` sum and divides by N (matches
MultiBandSchenk's legacy `/6.`).

::Hall::lorentz_tensor

file: TclLib/Models/Hall/compose.tcl

::Hall::lorentz_tensor — population × (I + μ_H B×) Lorentz rotation
tensor for the QF continuity wrap.  `pop` is the carrier population
symbol (Elec / Hole); `mob` the Hall-mobility symbol (HallEmob /
HallHmob).  Single source for the tensor layout — consumed by the
legacy Transport/Hall model and by the Aggregate magnetic-field
branch (which were byte-identical copies).

::HighFieldMobility::schema

file: TclLib/Models/HighFieldMobility/compose.tcl

::HighFieldMobility::schema — model-level key sets for the resolver.
The model slice is role-nested ({electron {…} hole {…}}), so the
schema validates the ROLE keys; the per-role param sets stay in the
Canali builder's pull_check (which also serves the Bands
highfield_mobility path that bypasses the resolver).

::HighFieldMobility::wrap_carrier

file: TclLib/Models/HighFieldMobility/compose.tcl

::HighFieldMobility::wrap_carrier — apply the at-most-one declared
HFM wrap to a low-field μ-string for one carrier.

At-most-one mutex is enforced on `fam_dict`.  When the chosen model
doesn't declare the carrier slice, returns `mu_lo` unchanged (the
carrier-blind pass-through contract).  When `mu_lo` is "", returns
"" without dispatching (nothing to wrap).

Used by:
  - ::Device::HighFieldMobility (called twice; result wraps into the
    Emob / Hmob spec-dict overrides).
  - ::Bands::__compose_mobility (called once for the band's
    quasi_fermi-implied carrier).

Args mirror ::Mobility::compose_carrier: $where defaults to
"HighFieldMobility $mat".

::Mobility::__carrier_slice

file: TclLib/Models/Mobility/compose.tcl

Internal helper: extract a model dict's carrier slice (electron or
hole sub-dict).  Returns "" if the carrier isn't declared for this
model.

::Mobility::compose_carrier

file: TclLib/Models/Mobility/compose.tcl

::Mobility::compose_carrier — walk a Mobility-family slice for one
carrier and return the Mathiessen-composed μ-string (or "" when no
declared model produced a contribution).

Dispatch is dictionary-driven: the model name IS the namespace.  For
each declared {Model, model_dict} entry the proc probes
`::Mobility::<Model>::<carrier>` via auto-load (high-field saturation
wraps live under HighFieldMobility; piezo/orientation tensors under
ConductivityMultiplier — neither participate at this layer).

Used by:
  - ::Device::Mobility (called twice, once per carrier; result wraps
    into the Emob / Hmob spec-dict entries).
  - ::Bands::__compose_mobility (called once for the band's
    quasi_fermi-implied carrier; result is the per-band Mob_<band>).

Args:
  mat       — material name; first positional arg to each model builder.
  carrier   — "electron" or "hole".
  fam_dict  — the {Model { electron {…} hole {…} } …} slice.
  T x_expr  — temperature and composition fraction (forwarded to builders).
  where     — error-label prefix; defaults to "Mobility $mat".

::Mobility::Klaassen::__build_dopant

file: TclLib/Models/Mobility/Klaassen.tcl

Internal: build Klaassen mobility for one (material, carrier, dopant)
slice.  Used by __build below; returns the per-dopant Alagator string
or "" when the dopant's params are incomplete.

::Mobility::Klaassen::build

file: TclLib/Models/Mobility/Klaassen.tcl

Build full Klaassen mobility for one (material, carrier) — the
`build` entry point every Mobility model exposes (probed by
::Mobility::compose_carrier).  Walks the dopants sub-dict, builds
one per-dopant Klaassen expression per fully-declared dopant,
Mathiessen-sums them.  Doping / carrier field names are the
canonical Alagator symbols (Accept / Donor / Elec / Hole).

::Permittivity::schema

file: TclLib/Models/Permittivity/compose.tcl

::Permittivity::schema — known/required param sets per model,
consumed by ::Pull::resolve_select_one at slice-materialization time.

::Pull::__has_builder

file: TclLib/Models/Combinators.tcl

::Pull::__has_builder — does proc $qual exist (already defined or
auto-loadable from tclIndex)?  Returns 1 if callable, 0 otherwise.
Consolidates the `[info procs $qual] ne "" || [auto_load $qual]` probe
that appeared across the framework (3× inside this file, 3× in
Mobility/compose.tcl's three-shape per-carrier classification).

::Pull::collect_specs

file: TclLib/Models/Combinators.tcl

::Pull::collect_specs — spec-dict-collecting compose over per-model
builders that return `{<spec_dict> <g_keys>}` 2-list pairs.

Generation/B2B's per-model compose procs all return this 2-list:
spec-dict entries to merge into the family's spec-dict, plus a list
of solution names that contribute additively to the family-level G
sum.  This helper iterates the fam_dict, dispatches each model, and
accumulates both halves.

Returns `{<merged_spec_dict> <accumulated_g_keys>}`; both empty when
fam_dict is empty.  Raises with $where prefix on missing builder.

Args mirror sum_models / select_one.

::Pull::parse_flags

file: TclLib/Models/Combinators.tcl

::Pull::parse_flags — wrapper-level flag-list parser shared by the
`device` and `stress` Tcl wrappers.  Iterates the args list (NOT a
string-mapped concat) so brace-quoted values (`pull=$models`, the
`movie={…}` callback) survive intact.  Accepts:
  `bareword`       → value 1
  `!bareword`      → value 0
  `key=value`      → value
  `key=`  `value`  → value   (split-token form)
Returns a dict.  Exact-token matching only — substring forms like
`t.init` cannot false-positive a `init` lookup.

::Pull::resolve_select_one

file: TclLib/Models/Combinators.tcl

::Pull::resolve_select_one — chain-aware select-one resolver.

For mutex (select-one) families, a pure ::Device::resolve_models
deep-merge would combine a parent's model with a child's into one
slice that then trips the mutex check, mangling the obvious "child
overrides parent" intent.  This resolver implements the correct
semantics:

  1. Closest ancestor with a declaration in $family picks the model.
     Each link in the chain is mutex-checked individually.
  2. Within that chosen model, params chain-merge per-key (root-
     first so the closest descendant wins at leaf level).

Lifted from the former stress-only `__stress_resolve_elasticity`;
parametrized by family name so Permittivity / Quantum / Transport /
Elasticity (and any future select-one family) share one walker.

Optional schema validation: when `schema` is non-empty it's a dict
`{<Model> {known {…} required {…}} …}`.  The resolver then validates
at the point the slice is materialized from the chain:
  - the chosen model must be a schema key (unknown-model typo)
  - every key in every chain link's slice must be in the model's
    known set — the error names WHICH ancestor declared the typo
  - every required key must be present in the merged params
With schema validation in the resolver, the per-model builders stay
pure expression builders.  Empty schema skips all three checks
(device-side selone families validate in their builders today).

Interface materials (`mater interface M1 /M2`) have an empty inherit
chain — fall back to the literal material name so their slices stay
reachable (doc/BOTTOMUP.md §8.4), matching `models_dict_get`.

Args:
  models    — un-merged per-material dict (the deck-owned `::Models`-
              shape value)
  mat       — material being resolved
  family    — family name (e.g. Elasticity, Permittivity)
  schema    — optional per-model {known required} dict (see above)

Returns `{model params}` where `model` is the chosen model name and
`params` is its chain-merged param dict.  Returns `{"" {}}` when no
link in the chain declares the family.

::Pull::select_one

file: TclLib/Models/Combinators.tcl

::Pull::select_one — mutex-checked dispatch to at most one model.

Validates that `fam_dict` declares at most one model; raises with
$where prefix on mutex violation.  Dispatches to
`::${ns}::${model}::${suffix}` via auto_load probe and returns the
raw model result.  When `fam_dict` is empty, dispatches the
`default_model` (with {} params) if non-empty, else returns "".

Used by selector families where the declared model picks a
discretization or a single physical law (Permittivity, Quantum).

Args:
  fam_dict       — family slice; 0 or 1 model declared
  ns, suffix     — as above
  mat            — material name; first positional arg to builder
  where          — error-label prefix
  default_model  — fallback model when fam_dict is empty;
                   "" → return "" (caller decides whether that's OK)
  args           — extra trailing args after (mat, params)

::Quantum::schema

file: TclLib/Models/Quantum/compose.tcl

::Quantum::schema — known/required param sets per model, consumed by
::Pull::resolve_select_one at slice-materialization time.

::Stress::schema

file: TclLib/Models/StressWrapper.tcl

::Stress::schema — single source of truth for the families stress
pull owns and their declared models.  `::Pull::resolve_select_one`
validates every chain link's slice against `known` and the merged
params against `required`.  Builders live at
::Elasticity::<Model>::expression and are pure expression builders.

::Transport::schema

file: TclLib/Models/Transport/compose.tcl

::Transport::schema — known/required param sets per model, consumed
by ::Pull::resolve_select_one.  QF / Velocity / SG take no params;
Hall requires both factors (a deliberate anisotropy choice needs
both); DPTensor's nested valley_axes sub-dicts validate inside the
builder.

__device_bool

file: TclLib/Models/DeviceWrapper.tcl

Internal helper: boolean flag presence (returns 1 if set to non-zero).

__device_contacts

file: TclLib/Models/DeviceWrapper.tcl

Contact-dispatch loop used by both modes.  Per-contact: insulator
(Oxide/SiO2/HfO2) → Gate with the adjacent semiconductor's work
function; semiconductor → mode-specific Ohmic (FEQFOhmic for `feqf`,
SGOhmic for `sg`).  FEQF retains the legacy Polysilicon special
case: when the contact has an insulator + Polysilicon stack, emit
Gate with the hardcoded name `gate` and wfn=4.6 instead of dispatching
by adjacent material.

__device_feqf_continuity

file: TclLib/Models/DeviceWrapper.tcl

FEQF-mode carrier-shape continuity solutions: Lambda + Qfn/Qfp PDEs
+ scalar Emfn/Emfp from quasi-Fermi gradients.

__device_get

file: TclLib/Models/DeviceWrapper.tcl

Internal helper: pull a flag value from the parsed dict, with default.

__device_sg_continuity

file: TclLib/Models/DeviceWrapper.tcl

SG-mode carrier-shape continuity solutions: Elec/Hole PDEs + Qfn/Qfp
const + per-axis Emfn{x,y,z}/Emfp{x,y,z} field-magnitude solutions.

__device_shared_preamble

file: TclLib/Models/DeviceWrapper.tcl

Shared preamble emitted by `device pull` for both FEQF and SG modes.
Stamps the doping aliases, the `d` default, the Silicon/Oxide Dcm
distance field, and the Potential / Circuit / DevPsi solutions that
every contact and per-material composer references.

__device_shared_tail

file: TclLib/Models/DeviceWrapper.tcl

Shared trailing solutions for both modes: scalar E magnitude, the
Silicon Eperp surface-perpendicular field, and the Jn/Jp
current-magnitude solutions.  The Temp/T stamp that used to sit
between Eperp and Jn (feqf only, hardcoded 300) moved to the
device_pull preamble, which stamps the actual T= argument for every
mode.

__diffuse_collect_species

file: TclLib/Models/DiffuseWrapper.tcl

Collect every species name declared across every bulk material's
Diffusion slice (excluding the Interfaces sub-family — those write
into existing bulk solutions, not their own unknowns).  Returned in
deterministic first-seen order so re-emission is stable.

__diffuse_emit_species_solutions

file: TclLib/Models/DiffuseWrapper.tcl

Auto-emit global `solution add name=$sp solve !damp !negative` for
every declared bulk species.  Species like Int/Vac/I2/Boron are
pre-declared in src/FLOOXS.models as `nosolve`; this flip is what
turns them into PDE unknowns.  `solution add` is idempotent — the
C-side handler updates flags without re-creating the entry.

__diffuse_emit_temp

file: TclLib/Models/DiffuseWrapper.tcl

Auto-emit a per-material `Temp const val=$T add solve` solution.
Idempotent across materials — only the first material that hits this
helper installs the global Temp; subsequent calls are no-ops.

__diffuse_is_interface

file: TclLib/Models/DiffuseWrapper.tcl

Is $mat an interface material?  `mater interface M1 /M2` materials
don't appear in `mater list`; we detect them by the `Mat1_Mat2`
underscore-name pattern AND by checking both halves are declared
materials.

__diffuse_shared_preamble

file: TclLib/Models/DiffuseWrapper.tcl

Shared preamble — `Noni`/`Poni`/`Stress_x`/`Velocity_mag` const
solutions referenced by the rate procs' Alagator expressions.
Idempotent; safe to re-run.

__internal_substrate_fill_lines

file: TclLib/Models/InternalSubstrate.tcl

Internal helper: given a sorted unique list of required positions plus
a target gap, return a denser list with intermediate fill points so
every consecutive pair is within `target`.

arr

file: TclLib/Models/DiffusionHelpers.tcl

Numeric Arrhenius helper: pre * exp(-act / kT).  Tcl-time evaluation
(distinct from the Alagator `[Arrhenius {…} …]` literal that DiffLimit /
ConcBind / SurfDiffLimit return).  Used by deck-time dict construction
(`dict set ... D0 [arr 0.138 1.37 $kT]`) to compute the numeric value
the Diffusion composer will stamp into the namespace var.

ConcBind

file: TclLib/Models/DiffusionHelpers.tcl

Concentration-binding equilibrium: lattice density × exp(entropy)
× exp(-binding/kT).  Returns a `[Arrhenius {…} …]` literal.

device

file: TclLib/Models/DeviceWrapper.tcl

device — TCAD-side wrapper that translates legacy device-command
flag sets into `solve <mode>` calls.  Subcommands:
  device pull T=… miller=…   pull-mode equation setup
  device init                soft reset + steady solve
  device                     steady solve
  device freq=Hz [complex]   AC small-signal
  device time=s […]          transient
  device store|restore|clear DC checkpoint primitives
Forwards everything else to `solve` with the appropriate mode.

DiffLimit

file: TclLib/Models/DiffusionHelpers.tcl

Diffusion-limited reaction rate constant for capture of $Species by $Mat.
Returns a literal `[Arrhenius {(4π Σ D0 · Lspa)} barrier]` string.

diffuse

file: TclLib/Models/DiffuseWrapper.tcl

diffuse — Tcl wrapper.  Intercepts `diffuse pull` (Tcl-side
equation setup) and forwards every other invocation to the renamed
C command via `tailcall` so the wrapper's frame is gone before the
C runs.  See cov_complex_newton history for why bog-standard
`uplevel 1` doesn't work for the non-pull path: the wrapper's
leftover proc frame interferes with the C-side internal Tcl_Eval
sequence (`solution name=Temp …` → `diffstep …`).

diffuse_pull

file: TclLib/Models/DiffuseWrapper.tcl

diffuse pull — pull-mode equation setup.

Walks `mater list` and dispatches each material's `::Models <Mat>
Diffusion` dict slice through the per-sub-family composers in
TclLib/Models/Diffusion/.  Interface materials (not in `mater list`)
are dispatched in a second phase.

Per-material baseline.tcl files (TclLib/Device/<Mat>/baseline.tcl)
are auto-sourced by `::Defaults::diffuse` when called bareword.

init_adapt_fields

file: TclLib/Models/AdaptFields.tcl

Substeps 3a + 3b fields.  Additional Grid.* fields are added by later
Phase-3 substeps (ShrinkEarly, ShrinkLate, GridAddPerp, Refine.Stop, ...).

perp.add.dist / Max.Radius / bound.add.dist / Corner.Add are only read by
the growing-mesh GridAdd path (LCOV_EXCL'd in coverage today, since the
active deposit goes through DepLvl which calls GridUpd(do_add=0)).
Defaults track the historical 0.1*UnitScl values; decks override with
`sel z=<expr>*Mater(SomeMat) ...` for per-material scoping.

MatBandGap

file: TclLib/Models/MatAccessors.tcl

Build the Varshni temperature-dependent bandgap expression for a
material.  Returns an Alagator string Eg0 - α·T² / (T+β) safe to
embed in `solution add name=Eg val=…`.  Used by the per-material
`<Mat>::BandGap` accessor shims.

MatNcTotal

file: TclLib/Models/MatAccessors.tcl

Material-effective Nc: Σ over all declared conduction valleys of
`BandEdgeNumberOfStates T= m=(ml·mt²)^(1/3)`.  Useful for decks /
tests that want a single per-material Nc rather than the per-valley
decomposition the dispatcher emits.

MatNvTotal

file: TclLib/Models/MatAccessors.tcl

Material-effective Nv: Σ over all declared hole bands of
`BandEdgeNumberOfStates T= m=<band m>`.

NB: ValenceBands `m` values are stored PRE-RAISED to the 3/2 power
(BandEdgeNumberOfStates' m-slot convention — Si LH 0.1737 ≈
0.31^{3/2}), so they pass through verbatim.  Conduction valleys
store raw ml/mt and go through ::Device::dos_m32 instead.

matparam_proc

file: TclLib/Models/Matparam.tcl

matparam_proc — chain-walking proc resolver.

Symmetric to matparam (which walks the chain for data) — walks the inherit
chain looking for a proc named ::<link>::<proc_name> and returns its fully
qualified name (e.g. ::Silicon::Nc).  Returns "" if no link in the chain
defines the proc.  Forces auto_load on each candidate before testing
existence so a chain link whose source file hasn't loaded yet still
resolves.

Used by the Transport/DPTensor and BandStructure/StrainKP composers to
resolve per-material accessor procs (Nc, Nv, Get3DElecDPTensor,
Get3DElecDPTensorPiezoHall, ElecHallFactorTemp) — a child material
inheriting Silicon picks up Silicon's accessors automatically, no
per-variant proc required.  These accessors are the transitional
bridge to dict slices (see CLAUDE.md "Composer-internal per-material
accessors").

matparam_sub

file: TclLib/Models/Matparam.tcl

Same shape but for nested per-species namespaces.  Used by chemistry:
parameters live at ::<mat>::<sub>::<key> where <sub> is the species name.
Example: matparam_sub Silicon Smic Bind  => $::Silicon::Smic::Bind.

matparam_sub3

file: TclLib/Models/Matparam.tcl

Four-deep variant: ::<mat>::<sub>::<def>::<key>.  Used by the dopant library
where per-(dopant, defect) params live at ::<Mat>::<Dopant>::<Defect>::<Key>
(e.g. ::Silicon::Boron::Int::Binding).  Closes the gap left by Dopant.tcl's
dopant_has2 / dopant_get2 helpers, which read the literal 4-deep namespace
without walking the inherit chain — meaning a SiGe-derived deck couldn't
inherit Silicon's per-(dopant, defect) params without redeclaring them all.

models_dict_get

file: TclLib/Models/Matparam.tcl

models_dict_get — chain-walking dict accessor.

Walks `mater name=$mat chain` and returns the dict slice at the given
path for the FIRST chain link that has it.  Returns "" when no link
has the path.  Canonical chain-walk for `device pull=…` and `stress
pull=…` callers that own their dict locally.

Examples (assuming SiGech inherits Silicon):
  dict set models Silicon Elasticity Anisotropic {C11 165.6e10 ...}
  models_dict_get $models SiGech Elasticity                   ;# → {Anisotropic {C11 165.6e10 ...}}
  models_dict_get $models SiGech Elasticity Anisotropic C11   ;# → 165.6e10
  models_dict_get $models Polysilicon Elasticity              ;# → ""

pde_append

file: TclLib/Models/PdeAccumulator.tcl

---- APPEND (cross-coupling fragment) ----
The fragment is expected to be sign-prefixed: "+ X" / "- Y".  Empty-slot
semantics: store as "0 fragment" so the equation parses cleanly even before
the self-contribution is added.

pde_flush

file: TclLib/Models/PdeAccumulator.tcl

---- FLUSH ----
Emits one `solution <Mat> name=<Sol> pde value="<accumulator>"` per
populated slot.  With -mater <Mat>, restricts emission to that material.
The flush is a side-effect — it doesn't clear the accumulator (use
pde_init * * if you want to wipe).

pde_init

file: TclLib/Models/PdeAccumulator.tcl

---- INIT ----

pde_keys

file: TclLib/Models/PdeAccumulator.tcl

Return all (Mat, Sol) keys currently in the accumulator.

pde_peek

file: TclLib/Models/PdeAccumulator.tcl

---- inspection helpers ----

pde_set_self

file: TclLib/Models/PdeAccumulator.tcl

---- SET_SELF (own bulk contribution, idempotent across rebuild passes) ----

pull_check

file: TclLib/Models/Combinators.tcl

pull_check — strict-consumption + required-present check.

Pull-mode model procs all open with the same preamble:
  - validate that every key in $params is in the known set (typo
    guard)
  - check that every required key is present; if not, the model
    drops out (additive sites return "", wrapper sites return the
    pass-through input)

This helper collapses that preamble.  Returns 1 when every required
key is present, 0 otherwise.  Raises with $where as the message
prefix when params contains an unknown key.

Usage:
  if { ![pull_check $params {a b c d} {a b c} "Family/Model $mat $role"] } {
      return ""   ;# additive
      return $mu  ;# wrapper
  }
  set a [dict get $params a]; …

One pattern the helper does NOT cover:
  - "missing required → error" sites (e.g. Transport/Hall must have
    factor_e + factor_h).  Those call pull_check and then raise
    explicitly on the 0 return.
Select-one families that need per-chain-link validation (Elasticity)
pass a schema to ::Pull::resolve_select_one instead — validation
happens where the slice is materialized from the chain.

pull_check_all

file: TclLib/Models/Combinators.tcl

Ergonomic shortcuts for the two pull_check shapes that dominate the
per-model builders:

  pull_check_all   $params $known $where  →  pull_check $params $known $known $where
                   every key in $known is required; missing → drop the model
  pull_check_known $params $known $where  →  pull_check $params $known {}     $where
                   every key in $known is optional; never drops the model,
                   just enforces typo guard

Partial-required sites (where required ⊊ known — e.g. Klaassen's `NrefD`
is optional within an otherwise-required set) keep the explicit
three-argument `pull_check` form.

spec_const

file: TclLib/Models/Render.tcl

Spec-dict constructors — every model proc that returns a spec-dict uses
these instead of the verbatim `[dict create kind <K> flags <F> val <V>]`
literal.  Keeps the spec-dict shape in one place; gives `Render.tcl` the
single seam to extend (e.g. the `kind snap` shape for `sel z=` snapshots).

`spec_const $val`              → const-solve solution (the most common form).
`spec_const $val $flag_list`   → const with explicit flag list.
`spec_pde   $val`              → pde-solve solution.
`spec_pde   $val $flag_list`   → pde with explicit flag list.

spec_snap

file: TclLib/Models/Render.tcl

`kind snap` emits a `sel z= <val> name= <name>` snapshot instead of a
`solution add` — used when the field must be a Jacobian-isolated
instantaneous value, not a const-solve solution whose Jacobian would
propagate through downstream assembly (the canonical use is the
DPTensor model's HallMob = r*Emob snapshot, which would otherwise
diverge the PiezoHall breakdown test by ~200×).

spec_snap_init

file: TclLib/Models/Render.tcl

`kind snap_init` is the guarded variant: the snapshot stamps only
when the field doesn't already exist (DataExists).  Used for
zero-initializing strain / stress / B scratch fields without
clobbering pre-stamped data (e.g. a stress solve that ran before
`device pull`).  Plain `snap` stays unguarded — HallMob must
re-evaluate on every pull.

stress

file: TclLib/Models/StressWrapper.tcl

stress — elastic equation compile (`pull` / `pull=$dict`) and Newton
solve (`calcstress` / `!calcstress`).  See file header for the
validation / inheritance semantics.

SurfDiffLimit

file: TclLib/Models/DiffusionHelpers.tcl

Surface diffusion-limited rate at a Mat/Side interface.  Uses Side's D0 +
Lspa and Mat's KinkSite.

voigt_components

file: TclLib/Models/Elastic.tcl

voigt_components — canonical six-component Voigt sequence used by every
stress-side consumer that iterates strain/stress components.  Ordering
is load-bearing for UniformStress / StressFromStrain (compliance-matrix
matvec depends on it); other consumers (e.g. the `stress pull` field
preamble) only need the six component labels and any order would work,
but they call this proc anyway so the labels never drift out of sync.