Get the results out#

Finished materials carry an OPTIMADE-shaped record.json. This page is how you list them, export them, and read the fields you will actually rank on.

List what finished#

$ matmelt results
Results of run nacl-demo:
        Finished materials
┏━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━┓
┃ Material     ┃ Parent ┃ Record ┃
┡━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━┩
│ Cl1Na1_3D-6  │ Cl1Na1 │ yes    │
│ Cl1Na1_3D-10 │ Cl1Na1 │ yes    │
│ Cl1Na1_3D-16 │ Cl1Na1 │ yes    │
│ Cl1Na1_3D-25 │ Cl1Na1 │ yes    │
└──────────────┴────────┴────────┘
4 DONE material(s), 4 with extracted record(s).

Record: no is normal rather than broken — a material can be DONE without a record if the run stopped before extract. The store is opened read-only, so this is safe to run against a workspace that is still being written to.

Export the records#

$ matmelt results --export finished.json
Exported 4 record(s) to finished.json.

One JSON array, written atomically, with one entry per material:

entries: 4 | keys per entry: ['id', 'record']
record top-level: ['attributes', 'id', 'type']

A record that cannot be read is skipped loudly rather than silently dropped, so the count in the message is the count in the file.

What is in a record#

The standard OPTIMADE fields describe the structure:

chemical_formula_reduced: ClNa
chemical_formula_descriptive: Cl1Na1
nsites: 2
elements: ['Cl', 'Na']
nelements: 2
dimension_types: [1, 1, 1]
last_modified: 2026-08-09T00:53:33+00:00

plus lattice_vectors, cartesian_site_positions, species, species_at_sites, elements_ratios, chemical_formula_anonymous, nperiodic_dimensions and structure_features.

Everything MatMelt adds lives under attributes._mcli, which is OPTIMADE’s convention for custom fields:

_mcli keys: ['geometry_source', 'provenance', 'screen']

provenance records how the candidate was generated:

{
  "dimension": "3D",
  "space_group": 6,
  "space_group_symbol": "Pm",
  "lattice_type": "monoclinic",
  "formula": "Cl1Na1"
}

screen records the relaxation that let it through, including the settings, so a number is never separated from how it was produced:

{
  "category": "RELAXED",
  "converged": true,
  "n_steps": 160,
  "final": {
    "e_eV": -6.524272949937968,
    "e_eV_atom": -3.262136474968984,
    "fmax_eV_A": 0.007047402896295252,
    "stress_max_GPa": 0.2323758502727508,
    "volume_A3": 53.97049592754401,
    "min_bond_A": 2.6713578838390584
  },
  "settings": {
    "model": "mace-mp:small",
    "device": "cpu",
    "dtype": "float64",
    "fmax": 0.05,
    "max_steps": 200
  }
}

When the optional calculate stage ran, a calculate key joins them, carrying the DFTB+ result and the full healing-attempt history.

Rank the survivors#

The relaxed energy per atom is the field to sort on:

$ python3 -c "
import json
records = json.load(open('finished.json'))
rows = sorted(
    (e['record']['attributes']['_mcli']['screen']['final']['e_eV_atom'], e['id'])
    for e in records
)
for energy, mid in rows:
    print(f'{energy:8.4f} eV/atom  {mid}')
"
 -3.2621 eV/atom  Cl1Na1_3D-6
 -3.2409 eV/atom  Cl1Na1_3D-16
 -3.2036 eV/atom  Cl1Na1_3D-25
 -2.8984 eV/atom  Cl1Na1_3D-10

Warning

Foundation-model energies are a screening signal, not converged thermodynamics. Use them to rank candidates and to throw out the implausible; do not report them as formation energies. The optional calculate stage exists for higher fidelity.

Filter without exporting#

Records also sit in each material’s directory under run.work_dir, so ordinary tools work directly:

$ python3 -c "
import json, glob
for path in sorted(glob.glob('materials-work/*/record.json')):
    a = json.load(open(path))['attributes']
    print(a['_mcli']['provenance']['space_group'],
          a['chemical_formula_reduced'],
          round(a['_mcli']['screen']['final']['e_eV_atom'], 4))
"
10 ClNa -2.8984
16 ClNa -3.2409
25 ClNa -3.2036
6 ClNa -3.2621

Filtering on _mcli.provenance.dimension is how you separate 2-D layer-group results from 3-D ones in a mixed run.

Machine-readable listing#

$ matmelt results --json

Same information as the table, as data. --export writes the records themselves; --json describes what finished.