Deep, code-cited reference. See the readable summary for the public version. This page is the full provenance: canonical formula, reference resolution, rollup schema, best-available rule, error taxonomy.
Grain-boundary Segregation Energy — Methodology
Scientific and numerical specification of the GB-segregation track for the
mlip-benchmark-gbsegbench corpus. Covers the canonical Eseg formula, how
the four energies are resolved on the MLIP side, the per-(potential,
structure_id) best-available rule across BFGS and FIRE, the rollup CSV
schema, and the error taxonomy used by the leaderboard.
Reference implementation: benchmark/build_eseg_dfs.py (compute_eseg,
build_dft_df, build_surrogate_df).
1. Quantity computed
For each (host, GB, solute, site, GB-construction variant) row, the segregation energy per defect is
Eseg = (E_seg - E_pure_GB) - (E_elem_bulk - E_host_bulk) - n_host_diff · mu_host
n_host_diff = (n_host_seg - n_host_pure_GB) - (n_host_elem_bulk - n_host_host_bulk)
mu_host = E_host_bulk / n_host_host_bulk
| Symbol | Meaning |
|---|---|
E_seg |
total energy of the segregated GB cell (the host GB + solute atom on a site) |
E_pure_GB |
total energy of the pure-host GB reference cell (same GB, no solute) |
E_elem_bulk |
total energy of the elemental-X bulk reference (host + 1 X impurity) |
E_host_bulk |
total energy of the pure-host bulk reference |
n_host_* |
count of host atoms in each cell |
mu_host |
per-atom chemical potential of the host, defined from E_host_bulk |
n_host_diff |
stoichiometric correction so the four-term sum is composition-balanced |
The same four energies are used on both DFT and MLIP sides — that's why the
bulk and pure-GB references were ingested as separate structure rows and
worked through the same single-point / relax pipeline as the segregated
structures. DB key: (structure_id, potential).
The canonical formula is implemented in compute_eseg (build_eseg_dfs.py,
lines 54–64). A sanity check in main() confirms that the formula
reconstructed from the four DFT references matches the Eseg_reported column
on every row to within 1e-6 eV (the formula sanity line in the build log).
2. Why no E_seg_corrected
Eseg is a difference of total energies between systems with the same
composition (modulo n_host_diff · mu_host, which restores composition
balance). The per-(composition, ISPIN) offset corrections used on the ASSYST
single-point track (assyst_systemspin_offsets memory) are constant per
composition-system, so they cancel in the formula by construction. We do NOT
emit E_seg_corrected, E_seg_corrected_global, or any related column —
there is no analogous correction to apply without changing the science.
This is the locked decision for the gbseg track; do not introduce a corrected column downstream.
3. Reference resolution (the four energies on the MLIP side)
The four energies all come from the same mlip_calc table, looked up by
structure.atoms_hash:
E_segis read for the segregatedstructurerow directly.E_pure_GBis resolved perGB(the columnstructure.gb) via the variant's_refs.pkl; the resultingatoms_hashis looked up inmlip_calc.E_elem_bulkis resolved perelement(a host cell + 1 X atom, solen(atoms) = n_host + 1) — same lookup path.E_host_bulkis resolved once per variant (pure host bulk) and re-used across all rows of that variant.
Variant-specific fallback rules
- KP variants (
FeGB_KP_Relaxed_Substitutional,_Interstitial,FeGB_KP_Unrelaxed_Substitutional): used as the fallback reference set for all other variants when the local_refs.pklhas the wrong atoms object (a known issue with KS variants — primitive atoms paired with full-cell energies). - KS variants (
FeGB_KS_Relaxed_Substitutional,_Interstitial,FeGB_KS_Unrelaxed_Substitutional,_Interstitial): full-cell atoms substituted from the KP fallback when the local refs disagree onlen(atoms)vsn_host(pick_hash,build_eseg_dfs.pylines 96–109). - OMAT variants (
FeGB_OMAT_Substitutional,_Interstitial): the generation used inconsistent k-meshes between cubic bulk cells and non-cubic GB cells. The OMAT elem_bulk and host_bulk DFT references are overridden with the KP bulk references (k-mesh consistent) on both DFT (formula) and MLIP (atoms_hash lookup) sides — seebuild_eseg_dfs.pylines 163–169. - Ni variants (
NiGB_Substitutional_Relaxed,_Interstitial_Relaxed): Ni-host references via the variant's own_refs.pkl.
The _refs.pkl files live under /ptmp/hmai/Benchmark_Potential/dft/; one
per variant.
4. Best-available (BFGS-then-FIRE) algorithm rule
Relaxation initial frame. The MLIP relaxation is initialised from the unrelaxed (as-constructed / DFT-input) geometry — the relaxation's initial frame is the unrelaxed structure, not the DFT-relaxed frame. So the
gbseg-relaxed-*buckets measure the MLIP relaxing the corpus from the unrelaxed starting geometry, while thegbseg-unrelaxed-*buckets are single-point energies on that same unrelaxed geometry (no relaxation).
The corpus was first relaxed with BFGS, fmax = 0.01 eV/Å, max_steps = 10000. A subset of structures errored or step-capped — almost all on heavy-radioactive solutes (Z = 84–88) that the underlying calculators do not embed. Those structures were re-attempted with FIRE, fmax = 0.01, max_steps = 250 in a dais-handback ingest (merged 2026-06-13).
For each (potential, structure_id) the rollup picks the best-available
result:
algo_used = 'BFGS' if status_BFGS == 'done'
else 'FIRE' if status_FIRE == 'done'
else NULL (row excluded)
energy_used = E_final from algo_used
n_steps_used = n_steps from algo_used
max_force_used = max_force_final from algo_used
Per-row provenance is preserved via:
algo_used— one ofBFGS,FIRE, or NULL (excluded)n_best_from_bfgs— count ofalgo_used='BFGS'rows per potentialn_best_from_fire— count ofalgo_used='FIRE'rows per potential
An Eseg value is reported only when all four feeding energies
(E_seg, E_pure_GB, E_elem_bulk, E_host_bulk) have a best-available
done result for that potential. Missing any one ⇒ NaN ⇒ row excluded from
the rollup.
5. Rollup CSV schema (per_potential_eseg.csv)
One row per (potential, host, GB, partition, element) bucket plus
__all__ aggregate rows at each level. Consumed by
/segregation and /elements/[el].
| column | type | meaning |
|---|---|---|
potential |
str | normalized potential id (matches the metadata.json key) |
display_name |
str | display name from metadata.json / gbseg-metadata.json |
host |
str | Fe or Ni |
gb |
str | grain-boundary id (e.g. S5_310_001) |
partition |
str | one of gbseg-relaxed-sub, gbseg-relaxed-int, gbseg-unrelaxed-sub, gbseg-unrelaxed-int |
element |
str | solute symbol; __all__ for the per-(host,GB,partition) aggregate |
n_struct |
int | number of (potential, structure_id) rows with best-available done and a finite Eseg |
n_best_from_bfgs |
int | count of rows where algo_used='BFGS' |
n_best_from_fire |
int | count of rows where algo_used='FIRE' |
eseg_rmse_eV |
float | RMSE of (Eseg^MLIP − Eseg^DFT) over n_struct rows |
eseg_mae_eV |
float | MAE of the same |
eseg_spearman |
float | Spearman ρ of Eseg^MLIP vs Eseg^DFT over n_struct rows |
snapshot_date |
date | per-potential rollup-build date |
The headline number on the leaderboard is eseg_rmse_eV from the
partition='gbseg-relaxed-sub', element='__all__' row, count-weighted
across (host, GB) (see §6).
6. Aggregation (count-weighted, two-step)
Matches the ASSYST headline pattern (headline_rmse_provenance memory):
- Per-bucket at
(potential, host, gb, partition, element)level:RMSE = sqrt(mean((Eseg^MLIP - Eseg^DFT)^2)),MAE,Spearman ρover the structures where the MLIP has a best-availabledoneEseg. - Top-line at
(potential, partition)level: count-weighted mean of the bucket-level metrics, weights =n_structper bucket.
Both eseg_rmse_eV and eseg_mae_eV are emitted. RMSE is the
default leaderboard headline (matches the ASSYST precedent); MAE is shown
alongside.
The headline bucket is partition = 'gbseg-relaxed-sub'. The interstitial,
unrelaxed-sub, and unrelaxed-int partitions are reported as drill-downs.
7. Error taxonomy
errors.parquet.py surfaces these classes per (potential, structure_id, algo) — the SQL classifies on the mlip_relax row (and its sibling row
under the other algo):
| class | rule (SQL pseudocode) |
|---|---|
none |
status = 'done' |
unsupported_element |
error_msg ~ '^KeyError|no embedding|unsupported' — most failures here are Z ∈ {84..88} radioactive solutes that no MLIP embeds |
diverged |
max_force_final IS NULL OR max_force_final > 100 |
step_cap |
max_force_final IS NOT NULL AND max_force_final ≤ 100 AND n_steps = max_steps |
env_flake |
error_msg IS NOT NULL AND a sibling row for the same (potential, structure_id) with the other algo has status = 'done' — i.e. one algo worked and the other didn't, which points at env/numerics rather than the structure |
lost_to_ether |
present in mlip_relax_claim_queue and no row in mlip_relax — worker claimed but crashed before commit. Already recovered by the dais handback pass; should be zero on the live rollup. |
The unsupported_element class is expected on Z = 84–88 across most
potentials and is not a benchmark defect.
8. Partitions
partition |
corpus | comment |
|---|---|---|
gbseg-relaxed-sub |
FeGB / NiGB Relaxed Substitutional | the headline E_seg bucket |
gbseg-relaxed-int |
FeGB / NiGB Relaxed Interstitial | drill-down |
gbseg-unrelaxed-sub |
Unrelaxed (DFT-geometry) Substitutional | single-point only, no relax drift |
gbseg-unrelaxed-int |
Unrelaxed (DFT-geometry) Interstitial | single-point only |
The cleavage partition (gbseg-cleavage) lives on its own page —
see /methodology/deep/cleavage.
9. Implementing code
benchmark/build_eseg_dfs.py— canonical formula (compute_eseg), DFT dataframe build (build_dft_df), MLIP dataframe build (build_surrogate_df).benchmark/plot_eseg.py,benchmark/per_potential_eseg_bar.py— plotting- per-potential bar chart (used to vet the rollup pre-vendor).
benchmark/eval/build_gbseg_rollup.py— count-weighted two-step aggregation into the leaderboard CSV (Task B will vendor this output).
Linked into the wiki hub at
/u/hmai/llm-wiki/wiki/mlip-benchmark-gbsegbench-relax.md.
10. Parameter summary
| Parameter | Value |
|---|---|
| Eseg | (E_seg-E_pure_GB)-(E_elem_bulk-E_host_bulk)-n_host_diff·mu_host |
| Sign convention | DFT-consistent (negative ⇒ solute prefers the GB site) |
| Energy field | smeared VASP energy (not energy_zero); see feedback_energy_sigma |
| BFGS protocol | fmax = 0.01 eV/Å, max_steps = 10000 |
| FIRE handback | fmax = 0.01 eV/Å, max_steps = 250, merged 2026-06-13 |
| Best-available rule | BFGS-done → FIRE-done → exclude |
| Outlier filter | |E| > 1e4 eV per cell → drop (catastrophic MLIP failures) |
| Aggregation | count-weighted two-step, RMSE default, MAE alongside |
| Magnetic facet | not introduced (corpus is all-magnetic by definition) |
| Corrected variant | not introduced (offsets cancel by construction) |
| DB key | (structure_id, potential); one Eseg per row |
Implementation: benchmark/build_eseg_dfs.py ·
rollup builder: benchmark/eval/build_gbseg_rollup.py (Task B) ·
page consumer: src/segregation.md + src/elements/[el].md (Task D) ·
wiki hub: wiki/mlip-benchmark-gbsegbench-relax.md.