Materials

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 datum holds 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.