---
description: What each stage actually computes — SMACT charge balance, PyXtal symmetry generation, MACE relaxation and its sanity bounds, DFTB+ through AiiDA — and how far the numbers can be trusted.
---

# What the stages actually compute

MatMelt is orchestration; the science belongs to established packages, each
owned by you rather than bundled by us. This page says what each stage asks its
package for, what the answer means, and where the limits are.

## `compose` — which compositions are worth considering

Given an element combination such as `Cl–Na`, the stage asks **SMACT** which
stoichiometries are chemically plausible: it enumerates oxidation-state
assignments and keeps combinations that can balance charge. `threshold` caps the
stoichiometric coefficients explored, and raising it finds more exotic
stoichiometries at combinatorially greater cost.

Stoichiometries are reduced to their smallest whole-number ratio, so `Cl2Na2`
and `Cl1Na1` are one candidate, not two. Where several oxidation-state
assignments lead to the same formula they are merged into one composition that
records all of them — the compound is one candidate; how you can rationalise its
charges is metadata.

Single-element seeds are a special case handled explicitly: charge balance says
nothing about an element with itself, so the stage emits elemental compositions
`X1 … Xn` directly (allotrope stoichiometries — this is how a `C60` candidate is
reachable) without reducing them, since reduction would collapse every `Xn` back
into `X1`.

**What this is not:** a thermodynamic stability filter. It answers "is this
chemically conceivable", not "does it form".

## `structure` — candidate crystals with real symmetry

Each composition goes to **PyXtal**, which generates a random structure
*constrained by a symmetry group*: atoms are placed on Wyckoff positions
compatible with the group, so the result is a crystal rather than a box of
atoms. The stage tries each group of each requested dimensionality **once**:

| `dimensions` | Family | Groups |
|---|---|---|
| `3D` | space groups | 1–230 |
| `2D` | layer groups | 1–80 |
| `1D` | rod groups | 1–75 |

Many attempts legitimately fail — a group may be incompatible with the
stoichiometry — and those are **counted and reported**, not silently swallowed,
because "37 of 230 groups produced a valid crystal" is information about the
composition, not noise. Each survivor is written with its provenance and named
`<Formula>_<DIM>-<SG>`, e.g. `Cl1Na1_3D-225`.

**What this is not:** a crystal structure prediction search. There is no
optimisation over configurations, no evolutionary algorithm, and one sample per
group. It is a broad, cheap, symmetry-diverse net — deliberately, because the
next stage is what pays.

## `screen` — relax with MACE, then apply physical sanity

Each candidate is relaxed with a **MACE** machine-learned interatomic potential
(the MACE-MP foundation model unless you point `model_path` at your own). The
relaxation is variable-cell — atoms *and* lattice move — driven by LBFGS to the
configured `fmax`, in `float64` because a reliable stress tensor needs it.

Then the result is classified against fixed physical bounds:

| Check | Bound | What it catches |
|---|---|---|
| Minimum bond length | ≥ 1.2 Å | Atoms overlapping — unphysical geometry |
| Residual stress | ≤ 2.0 GPa | Cell not mechanically equilibrated |
| Volume change | ≤ ±60 % | Relaxation ran away from the candidate |
| Energy per atom | −35 to +10 eV | The model is extrapolating, not predicting |
| Final force | ≤ 0.5 eV/Å | No local minimum reached |
| Energy rise | ≤ 0.01 eV/atom | The "relaxation" went uphill |

Failing any of them is a `FAILED` verdict with the measured value and the bound
quoted, so you can judge the rejection rather than trust it.

**These bounds are constants, not options.** That is a deliberate trade: making
them configurable per run would make verdicts incomparable across a database,
which defeats the purpose of screening at scale. What *is* configurable is the
model, the device, the dtype and the relaxation targets — the things that affect
how the number is computed rather than what counts as acceptable.

A missing observable is skipped rather than treated as a failure: an unavailable
measurement is not evidence against a structure.

**What this is not:** a stability calculation. There is no energy-above-hull
gate, no competing-phase comparison, and no formation energy. Screening asks
"is this a converged, physically sensible structure", not "is this the ground
state".

:::{warning}
Foundation-model energies are a **screening signal**. They rank candidates and
discard the implausible; they are not converged thermodynamics and should not be
reported as formation energies. That is what the next stage is for.
:::

## `calculate` — DFTB+ through your own AiiDA

The optional stage runs survivors through **DFTB+**, a semi-empirical
tight-binding method: far cheaper than DFT, far more faithful than a potential.
MatMelt generates the input — a self-consistent-charge calculation with rational
geometry optimisation, a k-mesh you configure, and per-species angular momenta
chosen from the periodic block — and submits one WorkChain per material through
your AiiDA installation.

The **self-healing** belongs to the `aiida-mydftbp` plugin, not to us: when a
calculation fails to converge, the WorkChain adjusts parameters and retries along
ladders it knows about. MatMelt's job is to launch, wait, and extract — including
the *full* attempt history, so a converged result carries the record of what it
took to get there. Slater–Koster absolute paths are stripped from that record,
because a parameter-set path on someone's cluster is not part of the science.

An exhausted healing ladder is a terminal verdict rather than something to retry:
the plugin already tried everything it knows.

**What this is not:** DFT. Results are only as good as the Slater–Koster
parameter set you point it at, and that set has a limited element coverage —
which is why a missing parameter file is a loud, actionable failure rather than a
silent stall.

## `extract` — a portable record

The final stage assembles an **OPTIMADE**-shaped `record.json`: standard fields
for the structure, with everything MatMelt adds namespaced under `_mcli` —
generation provenance, the screening verdict and its settings, and the DFTB+
result when there is one.

It is the only stage with no science dependency at all. Geometry parsing is
best-effort by design: if the relaxed structure cannot be read, the record is
still written from the composition metadata, with the failure stated loudly and
the geometry source recorded as absent. A record that admits what it does not
have is more useful than no record.

## Reading results honestly

The funnel is a filter, and each stage is cheaper than the next by design. What
survives to `DONE` is *a converged, physically plausible structure whose energy
a foundation model ranked favourably* — and, if you ran `calculate`, one a
semi-empirical method also relaxed successfully. That is a strong shortlist, and
it is not a claim of synthesisability, stability, or novelty.

The provenance in every record is what makes the shortlist useful later: the
model, the device, the dtype, the relaxation settings, the space group, the
dimensionality, and the attempt history are all recorded next to the numbers, so
a result can be re-examined rather than merely believed.

## Related

- {doc}`../reference/config` — every option named here, with its default.
- {doc}`../how-to/export-results` — the record fields, in full.
- {doc}`stage-contract` — why a rejection is a result and a crash is not.
