Date: 2026-08-25 Purpose: What material::Alloy mixes and how, the validation on record, and — the part to read first — for which alloys the result can be trusted Module: src/physics/materials Implementation: cl_Material_Alloy.{hpp,cpp}, invoked by MaterialFactory::create_material for any label that parses as a composition
This document replaces the February 2026 design notes alloy_mechanical_mixing.md and alloy_transport_mixing.md; their proposals are now implemented, and this document describes the current behavior.
An Alloy is built from a composition formula:
The numbers are integer mass percent: to_pair in src/core/stringtools.hpp parses letters followed by digits. Every element must be one of the pure metals in the roster (Al, Cr, Fe, Ni, Cu, Ag, In, Sn, Pb). The factory instantiates one Metal object per component and hands them to the alloy, which owns them. The last component is the balance: its percentage is recomputed as 100 minus the others (Alloy::set_components, cl_Material_Alloy.cpp:149), so Fe70Cr19Ni10 silently becomes 70/19/11.
RRR is mandatory and must exceed 1; otherwise BELFEM_ERROR fires. It is the only alloying effect the model knows about, and it is fixed at construction: the inherited Material::set_RRR is not overridden and raises an error. The material executable defaults it to 10 for a formula and to 100 for a pure metal.
Three object details matter to callers. It is typed MaterialType::PureMetal, so FEM code treats it like a metal. Its components are constructed without lookup tables of their own. Unlike Metal, whose rho( T, B, beta ) can evaluate Kohler's rule on the fly, Alloy::rho( T, B, beta ) and lambda( T, B, beta ) read the tabulated database and assert its presence; construct the alloy with tables enabled if you will ask for field dependence.
The alloy is a SplineLookupTable: every property is tabulated once at construction on a 4 K grid from 0 K up to the first 4 K multiple at or above the lowest T_max of its components, and served from cubic splines afterwards. The reference density is the mass-weighted harmonic mean of the components' room-temperature densities; the molar mass is the molar-fraction average.
Mass fractions Y_k are fixed. At each temperature, the components' densities are used to recompute volume fractions v_k(T) = (Y_k / ρ_k(T)) / Σ_j (Y_j / ρ_j(T)) (Alloy::update_volume_fractions).
Each component contributes isotropic stiffness from its own E_k(T), ν_k(T): K_k = E_k / (3(1 − 2ν_k)), G_k = E_k / (2(1 + ν_k)). The effective K and G are found by the self-consistent (Eshelby–Hill) scheme for spherical inclusions:
E and ν follow from the converged pair: E = 9KG / (3K + G), ν = (3K − 2G) / (6K + 2G). The arithmetic uses GPa for scaling; the result is stored in Pa.
Spherical inclusions describe an equiaxed microstructure — cast or sintered alloys. Directional or heavily worked microstructures would need an ellipsoidal Eshelby tensor and extra parameters, which the class does not have.
With α_V = Σ v_k α_k and α_R = K_R Σ v_k α_k / K_k, the effective coefficient is
α = α_V + (1/K − 1/K_V) / (1/K_R − 1/K_V) · (α_R − α_V),
using the self-consistent K (cl_Material_Alloy.cpp:372). The formula is exact for two phases and a tight estimate for more; when all K_k coincide the interpolation is undefined and the code takes the mean of the two bounds. At 0 K, α, c_p and λ are set to zero.
c_p = Σ Y_k c_p,k(T) — exact for an extensive property. The electronic coefficient γ = Σ Y_k γ_k is stored as a constant and sets the slope of the c_p spline at 0 K.
ρ(T) = ρ₀ + Σ v_k ρ_i,k(T)
where ρ_i,k is each metal's phonon (Bloch–Grüneisen) resistivity from Metal::rho_i_custom, and ρ₀ is a single residual resistivity for the whole alloy, fixed from the caller's RRR at room temperature:
ρ₀ = Σ v_k ρ_i,k(293.15 K) / (RRR − 1)
(Alloy::set_components). One ρ₀ for all phases is a deliberate simplification: it reproduces the macroscopic RRR by construction and needs no phase-diagram data; it loses the distinction between the residual scattering inside a Pb-rich and a Sn-rich lamella.
Linear (volume-fraction) mixing of the intrinsic parts was chosen over a Bruggeman effective medium after a comparison with the Hariharan et al. 1979 data for 60Sn–40Pb: linear mixing tracks the measured ρ(T) from 4 K to 300 K, Bruggeman's spherical-inclusion geometry suppresses the slope by 40–50 % on a lamellar eutectic. Nordheim's rule is not used — it applies to random solid solutions below the solubility limit, not to the two-phase solders the class was written for.
λ(T) = 1 / (w₀ + Σ v_k w_i,k(T)), with w₀ = ρ₀ / (L₀ T) the residual (Wiedemann–Franz) term and w_i,k = hust(P_k, T) each metal's intrinsic phonon-limited thermal resistivity from its Hust coefficients (fn_hust.hpp). The pure-metal Hust form has a third, interaction term w_i0 whose empirical constant is unknown for a mixture; it is dropped, which slightly underestimates λ where w₀ and w_i are comparable and is immaterial when the alloy's large ρ₀ dominates.
Alloy::populate_rho_database (cl_Material_Alloy.cpp:529) tabulates ρ(T, B, β) exactly as Metal does, but evaluates each component's Kohler curve at the similarity parameter it would see inside the alloy:
S_k = ρ_ref,k / (ρ₀ + ρ_i,k(T)), δ_k = kohler_k(B, S_k, β), ρ(T, B, β) = ρ(T) · (1 + Σ v_k δ_k).
Because ρ₀ of an alloy is far larger than any pure metal's, S_k is small and the magnetoresistance is weak — the expected behavior of a dirty conductor, though not one this path has been checked against field data. Every component must provide a Kohler curve; all nine roster metals do. λ(T, B, β) follows by Wiedemann–Franz scaling, λ(T) ρ(T) / ρ(T, B, β), the same closure Metal uses. The table is cached as <label>_RRR<n>.hdf5 in the run directory like a metal's, probed for the current format on load and rebuilt if it predates it.
| Property | 0 K start condition | End condition |
|---|---|---|
| E, ν | clamped, zero slope | parabolic |
| c_p | clamped, slope γ | parabolic |
| ρ | clamped, zero slope | parabolic |
| α, λ | parabolic | parabolic |
The model is a two-phase composite rule plus one residual-resistivity knob. It is trustworthy exactly when the real alloy is one of those two things, and it fails when alloying creates something no constituent has: a new crystal structure, a magnetic state, an intermetallic. The dividing line in one sentence: the method holds when the alloy keeps its constituents' crystal structure and magnetic state; the residual resistivity is the only alloying effect it models.
Trustworthy
Right mechanically, wrong magnetically
Not to be trusted
Reference values from the NIST cryogenic material fits (https://trc.nist.gov/cryogenics/materials/304Stainless/304Stainless_rev.htm):
| T [K] | k [W/(m·K)] | c_p [J/(kg·K)] | E [GPa] | ΔL/L₂₉₃ [%] | α [10⁻⁶/K] |
|---|---|---|---|---|---|
| 4 | 0.27 | 2.1 | 210 | −0.297 | — |
| 77 | 7.9 | 205 | 214 | −0.280 | 7.0 |
| 293 | 15.1 | 471 | 200 | 0 | 15.4 |
What the mixture gives, and why: