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:

Variant-specific fallback rules

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 the gbseg-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:

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):

  1. 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-available done Eseg.
  2. Top-line at (potential, partition) level: count-weighted mean of the bucket-level metrics, weights = n_struct per 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

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.