Documentation
Heat treatment and phase simulation
Run a temperature-time cycle on a steel grade and get phase fractions, dilatation and predicted hardness back.
You have a thermal cycle in mind — austenitize at 900 °C, hold, quench — and you want to know what microstructure and what hardness come out the other end. Normally that means a dilatometer, a Gleeble, or a hardness traverse on a sectioned coupon. The heat treatment simulator answers the same question numerically: give it a grade and a temperature-versus-time schedule, and it integrates the phase transformation kinetics step by step and reports what forms and how hard it ends up.
It is the right tool when you already know the thermal path and want the outcome. If instead you want to know which cooling rates produce which structures — the map rather than one point on it — use CCT diagram generation. If you want the dilatometry signal a physical Gleeble would record, or a thermomechanical test, use Virtual Gleeble.
What it models#
The simulator solves phase transformation kinetics at a single material point. There are no spatial gradients: no through-thickness temperature profile, no surface-to-core variation. Every point of your specimen is assumed to follow the temperature history you supplied.
Five phases are tracked, in this order: Ferrite, Pearlite, Bainite, Martensite, Austenite. Ferrite, pearlite and bainite are computed from a Kirkaldy-Venugopalan rate equation; martensite uses the athermal Koistinen-Marburger equation with a coefficient of 0.013. The same kinetics engine sits underneath all four simulators in Phases.
A worked example#
Type this into the chat, with nothing loaded beforehand:
Run a heat treatment on DC04: heat to 900 °C, hold 5 seconds, then cool to room temperature.
Because you named a grade and named the simulation, the agent has everything it needs. It replies with a Heat Treatment Configuration card showing the Material, a Cooling Rate (°C/s) field with 1 / 10 / 100 °C/s comparison buttons, a read-only summary of your curve written as <time>s → <temperature>°C pairs, a read-only auto step size, and any composition overrides. An Advanced button opens the same configuration in the simulation panel, where the full curve editor lives.
The cooling rate field is derived from the final descending segment of the curve, so it appears only when your cycle actually ends by cooling. A cycle that ends on an isothermal hold has no final cooling segment, and the field and its comparison buttons are not rendered.
Nothing runs until you press Run Simulation. That confirmation step is deliberate — the card is where you check that the schedule the agent understood is the schedule you meant. It is also where a chemistry warning reaches you before you spend a run: if the active material sits outside the range the kinetics model was fitted over, the card says so above the fields. See the Limits section below.
Press it, and the run executes. Progress messages appear as the solver works, then you get a written summary plus the figures. The run is stored as the next version in your session — run_001, run_002, and so on. See sessions, runs and artifacts for how to get back to it later, and long-running simulations for what happens when you close the tab mid-run.
If you have no material loaded and you ask for "a heat treatment" without naming a grade, nothing runs. You get asked which material first. There is no default grade in this product — see the material catalog.
What you can control#
| Parameter | Meaning | Units | Default | Range |
|---|---|---|---|---|
| Material | The grade or workspace material | — | none — always required | any catalog grade, workspace material, or confirmed custom chemistry |
| Temperature curve | The time-temperature schedule | s, °C | 0 s / 860 °C, 5 s / 860 °C, 10 s / 20 °C on the chat card | at least 2 points, and at most 256 on the durable path; see the Celsius caveat below |
| Cooling rate | Rewrites the curve's final descending segment to cool at this rate | °C/s | read back from the curve — 168 °C/s for the default card | 0.01–1000 °C/s |
| Time step | Integration step size | s | derived from the cycle, targeting 400 steps, with dt clamped to 0.01–5 s | not settable from chat; see below |
| Initial phase fractions | The starting microstructure | fraction 0–1 | determined automatically | five physical phases, each in 0–1, summing to 1.0 within 0.05 |
| Composition override | Chemistry changes on top of the base grade | wt % | the grade's own chemistry | the 20 card elements, each in 0–100 wt %; total ~100 % within 0.5 wt % |
Step size is derived, not asked for. The card computes it from your cycle so the temperature resolution stays roughly constant whether the run quenches in 9 s or air-cools for 15 minutes, and shows the result as Step size: auto — 0.025s over 10s for the default cycle. Any step size a model pre-filled into the parameter block is discarded on submit. Over MCP, ask the Phases agent for an explicit step size in your message; its internal simulation call can supply time_step, clamped to 0.01–30 s. Direct-tool compatibility callers can also supply that tool argument.
Step budgets differ by execution path. Every workspace runs heat treatment through the durable worker today; the in-process path described here and below is how runs recorded before that were executed, and it is still what you read when you open one of those older runs. In-process, the step count is round(total time / time step) clamped to between 50 and 10 000 steps, and the run reports back a sim_config block: the simulated time, the number of steps, the effective step size, and the step size you requested. On the durable worker the budget is tighter: at most 900 steps and at most 256 curve points. A fine step over a long cycle is coarsened to that cap rather than refused, so asking for 0.1 s over a 3600 s cycle lands at 900 steps and dt ≈ 4 s. Because that clamp is applied before the budget is checked, an ordinary chat submission does not hit the budget at all; HT scientific work budget is exceeded comes from the paths that submit an unclamped step, such as a dynamic-workflow candidate. A malformed curve — fewer than 2 or more than 256 points, times that do not increase, or a temperature outside −273.15 to 4000 °C — is refused with HT scientific input is invalid, which is a different message and a different problem. The durable path publishes no sim_config; it writes results/summary.json (ht-results/v1) instead, carrying the final hardness, the total step count, the total simulated time and the final phase fractions.
The 20 recognized element keys are C, Mn, Si, Ni, Cr, Mo, Cu, S, P, Al, As, W, V, Ti, Bo, Nb, N, O, Fe, Zr. Anything else is rejected with Unknown element. Each value must lie in 0–100 wt %, and the total must come to ~100 % within 0.5 wt %; otherwise you get Composition total is <x> wt%, expected ~100. Omit Fe to auto-balance it. Omit Fe and it is balanced for you. The tolerance is deliberate rather than sloppy — the shipped 22MnB5 deck's own total is 100.160, which an exact-100 rule would reject. Changing chemistry goes through the confirmation gate described in your own chemistry before it can be simulated.
Describing a schedule#
You do not need to write coordinates. Describe the cycle the way you would to a colleague and the agent turns it into curve points, which you then check on the card:
Run a heat treatment on EN13261: heat from room temperature to 900 °C over 2 seconds, hold for 5 seconds, then cool to 20 °C by 50 seconds.
Temper this steel at 600 °C for 30 seconds, starting from 100% martensite.
Run a heat treatment on DP600 holding at 860 °C for 5 seconds, then cooling to 20 °C at 30 °C/s.
A requested rate is expressed by shaping the cooling segment: 860 °C to 20 °C at 30 °C/s takes 28 s, so that last example becomes [[0, 860], [5, 860], [33, 20]]. The step size is then chosen automatically from the cycle, and asking for a specific one in chat gets you an explanation and an offer of the cooling rate instead.
Two things to keep in mind.
Time is in seconds, always. A "one hour hold" is 3600 s. The card's auto step tops out at 5 s, so a cycle that long integrates in 720 steps; a finer step passed to the tool directly is coarsened to the durable path's 900-step cap — dt ≈ 4 s — rather than refused.
Keep peak temperatures at or below 1000 °C. Curve temperatures are auto-detected by magnitude: if the highest temperature in your curve is 1000 or below, the values are read as Celsius; above 1000 they are read as already being Kelvin. A peak you write as 1100 meaning 1100 °C is interpreted as 1100 K, which is about 827 °C. This is the single most common way to get a quietly wrong answer out of this simulator.
The cooling segment is what sets the microstructure. 860 °C → 20 °C over 5 s is roughly 168 °C/s; the same drop over 40 s is roughly 21 °C/s. You do not have to do that arithmetic yourself: type the rate straight into the Cooling Rate (°C/s) field on the card or in the panel's configure tab and the curve's last segment is rewritten to match, keeping the austenitising temperature, the hold and the end temperature where they were. The three buttons beside the field — 1, 10 and 100 °C/s — are illustrative comparison points for looking at model response across an order of magnitude. They carry their own caveat in the interface, and it is worth repeating here: they are not quench-medium or grade-specific recommendations. Phases will not call a numeric rate "water quench" or "air cool" unless you supply that mapping yourself; the solver models a temperature history, not a quench medium.
Reading the results#
Once the written answer has finished streaming, the figures appear inline in the chat under Generated figures, between the findings and the next steps. Captions are derived from the file name, so a run executed in-process and a run executed by the durable worker are captioned almost identically even though the underlying files are named differently.
| Figure | In-process file | Worker file | Caption in chat |
|---|---|---|---|
| Phase fractions vs time | Time_phase.png | plots/time-phase.png | Phase Fractions vs Time |
| Dilatation vs time | Time_dilatation.png | plots/Time_dilatation.png | Dilatation vs Time |
| Dilatation vs temperature | Temp_dilatation.png | plots/Temp_dilatation.png | Dilatation vs Temperature |
| Hardness vs time | Time_statevars.png | plots/hardness.png | Hardness (HV30) / Hardness |
Phase fractions — the five phase fractions against time on a left axis, with temperature overlaid on a right axis. This is the plot to read first: it shows when austenite formed, when it decomposed, and into what. The in-process figure runs its left axis 0 to 1.05, puts temperature on the right axis in Kelvin, and labels its legend entries Ferrite (x1), Pearlite (x2), Bainite (x3), Martensite (x4), Austenite (x5), plus Temperature. The worker figure runs its left axis from −0.02, puts temperature on the right axis in °C, and uses plain phase names in the legend. Check the axis label before you read a number off it.
Dilatation vs time — time on X, temperature (K) on the left axis, dilatation on the right. Dilatation here is the sum of two contributions: a phase-weighted thermal term, using per-phase expansion coefficients (ferrite, pearlite and bainite 12.0 × 10⁻⁶ /K, martensite 10.5 × 10⁻⁶ /K, austenite 18.0 × 10⁻⁶ /K), plus the transformation dilatation increment returned by the solver at each step. It is reported as ΔL/L₀ — dimensionless, and zero-referenced at the first point of your curve — so the curve is a relative signal, not an absolute length. The durable path treats that zero reference as contractual: a result whose first dilatation sample is not zero is rejected with HT dilatation result must be zero-referenced, and the summary stamps dilatation_unit: "dimensionless" and dilatation_reference: "zero_at_first_curve_point". The deviation from a straight thermal line is the transformation signal — the same feature you would identify on a real dilatometer trace to pick off transformation start and finish temperatures.
Dilatation vs temperature — the same dilatation signal with temperature (K) on X. This is the axis pairing a dilatometry trace is normally read on. Ask for it by name (Plot dilatation vs temperature) and you get this figure rather than the time-based one.
Hardness — Vickers hardness against time. Hardness is computed at every step from the current phase mixture using Kasuya-Yurioka, Krauss and Maynier relations — one for ferrite plus pearlite, one for bainite and one for martensite, with the bainite and martensite relations switching at 0.12 % C — combined as a fraction-weighted mixture. Read it as a bulk, rule-of-mixtures hardness for the whole mixture, never as the intrinsic hardness of one constituent. The worker figure labels the axis Hardness (HV); the in-process Time_statevars.png is drawn by a generic plotter that labels only its time axis, so HV30 reaches you there through the gallery caption rather than off the figure. See hardness validation for how far to trust the number on your grade.
Ask for a specific plot and you get that plot:
Show me the dilatation curve from that run.
The numeric data is stored alongside the images, and here the two execution paths genuinely differ. An in-process run writes plain text files: Time_phase.txt carries time, temperature in Kelvin, then the phase columns; Time_statevars.txt carries time and hardness; Time_dilatation.txt carries time and dilatation; PhaseLog.txt records the step count, wall time and final hardness in a single line. The material card actually simulated is stored too, as mat_Steel.k and material_resolved.k, with a material_resolution.json recording how the material was resolved. Everything is also zipped as outputs.zip.
A durable worker run publishes six files instead: the four plots above, plus results/summary.json and results/time-phase.csv. The CSV carries one header row — Time_s, Temp_C, HV, Dilatation_delta_L_over_L0, then one column per phase — and one row per step, so temperature there is in Celsius, not Kelvin. The physics is the same on both paths; the file names, the numeric formats, one gallery caption and some axis units are what differ.
To come back to a run later:
List my runs.
Inspect run 3.
Inspecting a run returns its metadata and a signed link per plot. Those links are matched against a fixed list of in-process file names, so on a durable run — which is every run today — the tool's plots map comes back empty even though the figures are in storage; the gallery the run itself streamed is still the reliable way to see them. Inspection also does not hand back the contents of the numeric text files, so do not expect a column of hardness values to appear in the chat because you asked to inspect a run.
Initial phases (PHC)#
Every run has to start from some microstructure. In Phases this is called the initial phase composition, or PHC, and it covers the five physical phases.
Most of the time you never touch it. When you supply a curve but no explicit starting phases, the simulator reads the material card's equilibrium curves at your curve's first temperature. If that temperature is at or above Ac1 (the lowest temperature at which the card's equilibrium austenite fraction is above zero), it interpolates the equilibrium fractions there and normalizes them to sum to 1.0. Bainite and martensite are always set to zero in that case — they carry negative sentinel values in the card because they are non-equilibrium phases that only form on cooling.
If your start temperature is below Ac1, equilibrium says nothing useful about a history-dependent microstructure, so the derivation declines and a fallback takes over. The order matters: an active workspace material's own stored start state is used if it has one, and only if there is none does the card's authored room-temperature value stand. A start state edited through the material UI therefore changes every sub-Ac1 run on that material, quietly and without appearing in your request.
You will meet PHC directly in two situations. The first is tempering or any cycle whose starting structure is the point of the experiment — a tempering run only means something if you start it from martensite. The second is when you want to isolate the decomposition of a fully austenitic structure without simulating the soak that produced it.
Both are expressed in plain language:
Set the initial phases on my active material to 100% austenite.
The simulation panel's configure tab gives you the same control as a form. It carries a Preset selector with five built-in cycles — Austenite Cool (Default), Austenitize + Quench, Normalizing (Air Cool), Isothermal Hold (700 °C) and Tempering (600 °C) — and the tempering preset pins the start state to 100 % martensite for you. Beside it sits a phase donut with an explicit toggle: edit a fraction and the tab reads Start state pinned to these fractions, with a Derive it from the cycle instead link that hands the decision back to the automatic derivation.
The rules are simple. Each value must be between 0 and 1, all five physical phases participate, and they must sum to 1.0 within 0.05 — otherwise you get Sum of physical phases must be ~1. In the configure tab the tolerance is tighter, 0.01, and the run button stays disabled until the fractions balance.
An imposed starting state is an input, not a result. If you start a run at 100 % austenite, that is not evidence that austenitization completed under your cycle — it is an assumption you made. Phases is explicit about that distinction and will not present one as the other.
Limits#
- No default material. A heat treatment request without a grade, a workspace material, an active session material, or a chemistry returns
Please choose a material before running a simulation. Examples: DC04, DP600, 22MnB5, EN13261, a workspace material, or a custom composition.and nothing executes. - Single material point. No spatial gradients, no section size, no quench severity, no surface-versus-core.
- Celsius is inferred from magnitude. Peaks above 1000 are read as Kelvin. Keep example peaks at or below 1000 °C.
- The card warns when your chemistry is outside the fitted range. If the resolver places the active material outside the composition range the transformation-kinetics model was fitted over, the configuration card shows an Outside the kinetics model's fitted range banner before you run, stating that the phase fractions and hardness that run reports are not validated there. It appears only for that verdict — other kinetics problems are reported as run failures or as model notes on the material, not as this banner — and only while the card is still about to run that chemistry.
- The material must resolve two capabilities before a run version is allocated: a base card and transformation kinetics. If either cannot be resolved the run fails with
Required material physics is unavailable for HT, followed by the specific warnings. Where a custom chemistry has no published kinetics model, the verified template's authored kinetics are reused and reported as apreserved_sourcefallback with a warning — that is a fallback, not a calibration claim for your chemistry. See the capability matrix. - Custom chemistry needs a verified template. Without one the run is refused:
This custom material has no active verified template. Reload the material or select its structural template before running HT. - The stress-strain figure is not produced by current runs. It exists in the product's plot vocabulary, but the heat treatment path writes no strain-stress data, so no such plot appears in the gallery.
- The exact artifact set depends on which path executed the run. The durable worker publishes a phase plot, a hardness plot, both dilatation plots, a
summary.jsonand atime-phase.csvinstead of the text files above. Both dilatation figures survive on that path — you do not lose the dilatometry signal by running durably. - Confirming a chemistry is not calibrating it. Confirmation stores a stable definition and a compatible base card; it computes no kinetics and no flow stress.
- Workspace viewers cannot run simulations. The attempt returns
This workspace role cannot run simulations. Ask a workspace admin for member access.— see workspaces and roles. - One request runs one simulator. Asking for a heat treatment will not also produce a CCT diagram, and loading or editing a material never triggers a run on its own.
Broader model limitations — where the kinetics over-predict martensite, where hardness runs high, and how card-predicted critical temperatures differ from independently validated measurements — are collected in known limits. If a run refuses or a result looks wrong, common problems lists the messages you are most likely to meet and what each one means.
Where to go next#
- Your first simulation for the end-to-end walkthrough
- How the conversation works for why the agent asks before it runs
- Long-running simulations for what the durable path changes
- Compare two grades for running the same cycle on two steels
- Parameter blocks for the configuration card format
- Glossary for the vocabulary used above

