Materials — `.hmt`
Declare a material with its data and their sources, and let the build derive what follows from it — a part's mass, a selection's ranking, a crystal's density, a heat treatment's proof.
A .hmt file declares materials the way Hilbert declares everything else: as models. A material is a model
under a category (Metal, Ceramic, Polymer, Glass, Composite), and every other declaration in the dialect
is a model too — a part, a requirement, a route, a crystal structure, a potential, a phase system. The build derives
their members from the data. Nothing you would otherwise look up in a handbook table is typed twice.
.hmt |
is, in Hilbert | the build |
|---|---|---|
material X : Metal { … } |
a model under a category | reduces every datum to SI, solves bal in the composition exactly |
part P of X { … } |
a model under Part |
derives mass, margin, resistance, cost and embodied energy |
requirement R { … } + select R from Metal |
a model under Requirement |
derives the material index, ranks the library by it |
process … route R : X → … by [ … ] |
a model under Route |
proves the heat treatment — or refuses to build |
structure S : Cubic { … } |
a model under a crystal system | generates the atoms from the space group, derives density |
potential P : LennardJones { … } |
a model under Potential |
derives the crystal the potential predicts |
system S : Binary { … } |
a model under Binary |
finds equilibrium as the lower convex hull |
open Physis.Quantities
open Materials.Categories
material Al7075 : Metal {
weight Al bal, Zn 5.6, Mg 2.5, Cu 1.6
temper T6
datum density = 2810 kg/m³ source "MMPDS-2023"
datum modulus = 71.7 GPa source "MMPDS-2023"
datum yield = 503 MPa within 21 MPa at direction L, thickness 6..50 mm basis A source "MMPDS-2023 Table 3.7.4.0"
}
part Spar of Al7075 { volume = 0.00025 m³, stress = 100 MPa }
new Al7075().Yield(); // 503e6 — in pascals, reduced from MPa by the build
new Al7075().FractionAl(); // 0.903 — `bal` solved exactly
new Spar().Mass(); // 0.7025 kg — volume × a density the part was never told
new Spar().Margin(); // 5.03 — an allowable over a stress, neither written on the part
A property is not a number
Every datum is a partial function: a value, its uncertainty (within), the domain it holds over (at),
its basis (A, B, typical) and its source. A datum with no source does not build (MT0031). Asking a
property outside the domain it was measured over is refused, and the refusal names the coordinate that missed.
Some properties can be averaged and some cannot. Density and modulus are volume averages; strength and toughness
are the worst feature in the volume, so no mixing rule ever produces one (Kinds). A composite’s yield is
measured on the composite or it does not exist.
Choosing a material
State the job; the build derives the index. Nobody writes E^(1/2)/ρ, so nobody writes the wrong one.
requirement StiffBeam { demand = stiffness, loading = beam }
select StiffBeam from Metal
requirement CheapBeam { demand = stiffness, loading = beam, over = cost }
select CheapBeam from Metal
demand |
loading |
index derived |
|---|---|---|
stiffness |
tie / beam / panel |
E/ρ, E^(1/2)/ρ, E^(1/3)/ρ |
strength |
tie / beam / panel |
σf/ρ, σf^(2/3)/ρ, σf^(1/2)/ρ |
over = cost or over = carbon changes what is being spent — the divisor becomes ρ·C_m — and nothing else.
A library is a category. from Metal ranks every material under Metal in the compilation, including the
ones open Materials.Library brings in; nothing is listed. The compiled requirement answers Power() and
Slope() (the Ashby selection line), and Score…() / Rank…() per material, plus Ranked(). A material missing
a property the index needs is dropped, not scored as zero — one with no price is not a free one — and Ranked()
says how many survived.
Heat treatment
A route is a derivation, and the build proves it: the phases must close, each step must consume what the last one produced, and the kinetics must allow each arrow. The material says how it hardens, in its own file.
material Steel4140 : Metal {
phase ferrite
diffusional pearlite
datum critical = 25 K/s source "…" -- from the CCT diagram of the heat
}
process austenitise : ferrite → austenite { temperature = 1123 K }
process quench : austenite → martensite { rate = 50 K/s }
process temper : martensite → tempered + carbide { temperature = 873 K }
route Hardened : Steel4140 → tempered 0.92 + carbide 0.08 by [austenitise, quench, temper]
Change quench to 5 K/s and the file does not build: the austenite transforms on the way down, and the error
names pearlite as what forms instead (MT0122).
Crystals
Write a crystal the way a crystallographer does — a space group, the free cell parameters, one line per orbit:
open Chemistry.Elements
structure StrontiumTitanate : Cubic {
group(221)
datum a = 390.5 pm source "…"
site Sr(0, 0, 0)
site Ti(0.5, 0.5, 0.5)
site O(0.5, 0.5, 0) -- an orbit: the group carries it to all three faces
}
The build generates the group from its generators, computes each site’s multiplicity from its orbit, and derives
Atoms() (5), SitesO() (3), Volume() and Density() — 5117 kg/m³, the handbook’s. A group must agree with its
crystal system (MT0171), and a cell is given only the parameters its system leaves free: a cubic cell is a, a
hexagonal one a and c.
Composites
material GlassFilledEpoxy : Composite {
matrix Epoxy
inclusion EGlass(0.10) -- spheres, volume fraction
}
material ShortFibreEpoxy : Composite {
matrix Epoxy
inclusion EGlass(0.30, 20) -- aligned short fibres, aspect ratio 20
}
Density() is the exact volume average. For spheres the build gives the Hashin–Shtrikman bracket
(ModulusLower(), ModulusUpper()) always, and a Mori–Tanaka Modulus() only while a mean field is honest —
up to a quarter by volume. Past that there is no Modulus() to call, and your own code will not compile against
one. For fibres it gives Halpin–Tsai between the rule of mixtures and its inverse.
Potentials
potential Argon : LennardJones {
datum epsilon = 0.01034 eV source "…"
datum sigma = 340 pm source "…"
}
potential Mace : Learned {
core zbl
}
A Lennard-Jones potential compiles to the fcc crystal it predicts: Lattice(), Cohesive(), C11(), C12(),
C44(), and Cauchy() — how far the crystal is from C₁₂ = C₄₄, which every pair potential obeys. A Learned
potential (an ONNX MLIP, reached through fn in .hb) must declare its repulsive core; without one it does not
build, because nothing in a training set was ever at short separation.
Phase equilibrium and solidification
system RegularGap : Binary {
at(1000 K)
phase solution(0 J/mol, 0 J/mol, 20000 J/mol) -- °G_A, °G_B, then Redlich–Kister ⁰L, ¹L, …
overall(0.4)
}
material Al4Cu : Metal {
weight Al bal, Cu 4.5
solute Cu
datum eutectic = 0.332 source "…"
datum solubility = 0.0565 source "…"
}
A system compiles to its tie-lines (Tie1Low(), Tie1High(), …), and for the overall composition the phase count,
the lever-rule fractions and the degrees of freedom left. Equilibrium is the lower convex hull of the phases’
free-energy curves — global minimisation, which cannot land on a metastable tangent.
A casting alloy that names its solute gets its solidification bracketed: EutecticLever() (full diffusion in
the solid) and EutecticScheil() (none), with the partition coefficient derived from the phase diagram’s two
numbers rather than typed. For Al–4.5Cu that is 0 and about 9 %; a real casting lies between.
The fold — one material, every dialect
The same material reaches the other dialects without its numbers being copied:
| where | written | derived |
|---|---|---|
.hmt part |
part Spar of Al7075 { volume, stress } |
mass, margin, resistance, cost, embodied energy |
.hph simulation |
simulate Run { material Al7075 … } |
one param per property the material declares |
.hd design |
material WroughtIron, figure Core of Copper = … |
mass, and a density field across a multi-material part |
.he circuit |
resistor lead a → b of Copper { length, area } |
R = ρ·L/A |
A .hd design is evaluated rather than compiled, so the host hands it its materials: Materials.Stocks.Of reads
a .hmt and returns each material’s density, moduli, expansion and yield in SI, ready to pass to Designs.Read.
What is not here yet
- Operations for every space group. A group needs its generators — a few lines — or a CIF that lists its operations. The groups shipped are 221, 225, 227, 229, 62 and 194; any other is refused rather than guessed.
- Embedded-atom and Tersoff potentials as declarations. They are functional forms, and a
datumholds a number. The engine has them; the dialect does not yet say them. - TTT and continuous-cooling kinetics as declarations, and CALPHAD assessments read from a TDB file.
- OPTIMADE import.
of <material>in.hm.