Your first run#

This walkthrough goes from an empty directory to a screened crystal structure with an OPTIMADE record. It takes about a minute of compute. Every output below is real — only absolute paths have been shortened.

It assumes matmelt --version works (Installation) and that SMACT, PyXtal and MACE are importable by some interpreter (The tool and the science stack).

1. Scaffold a config#

$ mkdir matmelt-demo && cd matmelt-demo
$ matmelt init

init writes a commented matmelt.yaml and immediately runs the environment check against it, so you find out at once whether this machine can do the work:

Wrote starter config: matmelt.yaml
Edit run.elements and the backends/stages blocks for your machines; re-run
'matmelt doctor' after any change.
Checking the environment against it now:
...
│ compose   │ smact       │ python3     │ local │ ok     │ smact importable    │
│ structure │ pyxtal      │ python3     │ local │ ok     │ pyxtal importable   │
│ screen    │ mace        │ python3     │ local │ ok     │ mace importable     │
│ extract   │ stdlib only │ python3     │ local │ ok     │ standard library    │
│           │             │             │       │        │ only -- always      │
│           │             │             │       │        │ ready               │
└───────────┴─────────────┴─────────────┴───────┴────────┴─────────────────────┘
Seed enumeration: 2 element(s) -> 3 combination(s) (size 1: 2, size 2: 1).
doctor: all checks passed.

If any stage says MISSING, fix it before continuing — the command to run is printed under the table.

2. Make three edits#

Open matmelt.yaml. The scaffold already targets sodium and chlorine, which is what we want. Change three things:

run:
  name: my-first-run
  work_dir: ./materials-work
  elements: [Na, Cl]
  combination_sizes: [2]          # binaries only, so this run stays small

pipeline:
  stop_after: structure           # stop after generating candidates
stages:
  screen:
    backend: laptop
    options:
      python: python3
      device: cpu
      model_size: small           # ~32 MB; the default 'medium' is better science

combination_sizes: [2] narrows the seeds from three (Na, Cl, and Na–Cl) to just the binary. stop_after: structure deliberately stops the run before screening, so you can look at what was generated before spending compute on it. model_size: small keeps the first model download small.

Check the edits:

$ matmelt doctor
doctor: all checks passed.

3. Generate candidate structures#

$ matmelt run --yes
Run my-first-run: compose -> structure
Seed enumeration: 2 element(s) -> 1 combination(s) (size 2: 1).
Seeded 1 combination(s); starting the drain loop.
pass 1: submitted=1
pass 2: expanded=1, children=1, submitted=1
pass 8: expanded=1, children=37
  Materials by state
┏━━━━━━━━━━━━┳━━━━━━━┓
┃ State      ┃ Count ┃
┡━━━━━━━━━━━━╇━━━━━━━┩
│ EXPANDED   │     2 │
│ STRUCTURED │    37 │
└────────────┴───────┘
stop_after structure: stage drained; materials rest at its output, ready for the
next stage -- raise or remove stop_after (or use --only) to continue them.

About ten seconds. Read that summary carefully, because it shows the funnel’s shape:

  • One seed, Cl-Na, went into compose, which asked SMACT which charge-balanced compositions are plausible and produced one: Cl1Na1.

  • That composition went into structure, which asked PyXtal for a candidate crystal in each 3D space group and got 37 valid ones.

  • The two parents are EXPANDED — a terminal state meaning “this fanned out into children”, not a failure.

  • The 37 candidates rest at STRUCTURED. A mid-funnel stop_after is a pause, not a retirement: they are live and claimable by a later run.

4. Look at what you have#

$ matmelt status --state STRUCTURED
Run my-first-run: 37 material(s) at STRUCTURED.
 Materials at STRUCTURED
┏━━━━━━━━━━━━━━━┳━━━━━━━━┓
┃ Material      ┃ Parent ┃
┡━━━━━━━━━━━━━━━╇━━━━━━━━┩
│ Cl1Na1_3D-1   │ Cl1Na1 │
│ Cl1Na1_3D-2   │ Cl1Na1 │
│ Cl1Na1_3D-3   │ Cl1Na1 │
│ Cl1Na1_3D-6   │ Cl1Na1 │
│ Cl1Na1_3D-10  │ Cl1Na1 │
...

Each id says what the material is: composition, dimensionality, and space-group number. Cl1Na1_3D-221 is the candidate in space group 221, Pm-3m.

On disk, each material has its own directory:

$ ls materials-work/Cl1Na1_3D-221/
structure.cif  structure.json

5. Screen one candidate#

Screening all 37 would take a few minutes. Push a single one through instead — --materials restricts a run to the materials you name (and anything they fan out into). First raise the stop stage so the run may go all the way:

pipeline:
  stop_after: extract
$ matmelt run --materials Cl1Na1_3D-221 --yes
Run my-first-run: compose -> structure -> screen -> extract
Seed enumeration: 2 element(s) -> 1 combination(s) (size 2: 1).
foundation model (size=small) ready in ~/.cache/mace
--materials: no seed combination matched -- relying on materials already in the
store.
pass 1: submitted=1
pass 8: completed=1, submitted=1
pass 9: completed=1, finalized=1
  Materials by state
┏━━━━━━━━━━━━┳━━━━━━━┓
┃ State      ┃ Count ┃
┡━━━━━━━━━━━━╇━━━━━━━┩
│ DONE       │     1 │
│ EXPANDED   │     2 │
│ STRUCTURED │    36 │
└────────────┴───────┘
--materials: the selected materials are settled; unselected materials were not
run.

About fifteen seconds: one MACE relaxation, then extraction into a record. The other 36 candidates are untouched and still waiting.

Note

--yes answers the model-download consent prompt in advance. Run without it and MatMelt asks first, disclosing the size and the cache location; declining stops the run cleanly rather than failing partway.

6. Read the result#

$ matmelt results
Results of run my-first-run:
        Finished materials
┏━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━┓
┃ Material      ┃ Parent ┃ Record ┃
┡━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━┩
│ Cl1Na1_3D-221 │ Cl1Na1 │ yes    │
└───────────────┴────────┴────────┘
1 DONE material(s), 1 with extracted record(s).

The material’s directory now holds the whole story:

$ ls materials-work/Cl1Na1_3D-221/
record.json  relaxed.cif  screen_result.json  structure.cif  structure.json

screen_result.json is the screening verdict — what was decided, and on what evidence:

{
  "category": "RELAXED",
  "converged": true,
  "n_steps": 5,
  "final": {
    "e_eV_atom": -3.2325740511589527,
    "fmax_eV_A": 3.4855789502953297e-15,
    "stress_max_GPa": 0.09507366185438959,
    "volume_A3": 41.89601877227525,
    "min_bond_A": 3.007841059579302
  }
}

RELAXED means the relaxation converged and the relaxed cell passed the physical sanity checks — bond lengths, residual stress, volume change and energy all within bounds. A candidate that fails those gets FAILED with the reasons listed, which is a result, not an error: the run continues and its exit code stays 0.

relaxed.cif is the relaxed structure. record.json is the OPTIMADE-shaped record — composition fields, lattice vectors, sites, and MatMelt’s own provenance under _mcli:

{
  "dimension": "3D",
  "space_group": 221,
  "space_group_symbol": "Pm-3m",
  "lattice_type": "cubic",
  "formula": "Cl1Na1"
}

To collect every finished record into one file:

$ matmelt results --export records.json
Exported 1 record(s) to records.json.

What you just did#

You ran a four-stage pipeline: SMACT proposed a composition, PyXtal generated 37 symmetry-constrained candidates, MACE relaxed one of them and judged it, and the extract stage turned the survivor into a portable record. Everything ran on your own machine, in a workspace you can inspect, resume or throw away.

The 36 untouched candidates are the natural next step: remove --materials and run again, and MatMelt picks up exactly where it left off.

Next: Verify your install — a short checklist proving the install is sound. Then the tutorials, which widen the element set (T1), explain every config key (T2), and move the expensive stage onto another machine (T3).