---
description: Add the optional DFTB+ stage through your own AiiDA — the config block, the doctor probe, the SKF node, and how to push already-screened materials through it.
---

# Add the DFTB+ `calculate` stage

`calculate` is optional. It takes materials that survived screening and runs
them through DFTB+ using **your own AiiDA installation** — MatMelt launches the
`mydftbp.single` WorkChain, waits, and extracts the result. It never ships,
installs or imports AiiDA on your behalf.

## Prerequisites

An interpreter with `aiida-core`, `aiida-mydftbp` and `ase`; a working AiiDA
profile with its daemon running; and a configured DFTB+ code:

```console
$ verdi profile list
$ verdi code list
$ verdi daemon status
```

The code's computer decides where DFTB+ actually runs — that is AiiDA's job, not
a MatMelt backend's. **Do not point this stage at an `ssh_exec` backend**: it
only needs to reach the interpreter that talks to your profile, which is
normally the local one.

## The config block

```yaml
stages:
  calculate:
    backend: laptop
    options:
      python: python3
      profile: my-profile
      code_label: dftbplus@cluster
      skf_prefix: /opt/skf/ptbp/complete_set/
      skf_local_path: /home/alice/skf/ptbp/complete_set/
      kpoints: [4, 4, 4]
      max_wallclock_seconds: 3600
```

`code_label` and `skf_prefix` are required; everything else has a default
({doc}`../reference/config`). Two traps worth naming:

- **`skf_prefix` is a path on the machine DFTB+ runs on**, not on your laptop.
  It is baked into the generated HSD input.
- **`skf_local_path` is a path on your machine**, used only to *create* the
  Slater–Koster node the first time. Omit it and a missing node is a loud
  failure instead of a silent stall.

Stage order is fixed, so `calculate` sits between `screen` and `extract`
wherever you write it in the file.

## Check it before running

```console
$ matmelt doctor
```

The readiness table gains three rows — the import names differ from the package
names, and the fix hint gets them right:

```text
│ calculate │ aiida         │ python3     │ local │ ok      │ aiida importable │
│ calculate │ aiida_mydftbp │ python3     │ local │ MISSING │ ModuleNotFoundE… │
│           │               │             │       │         │ No module named  │
│           │               │             │       │         │ 'aiida_mydftbp'  │
│ calculate │ ase           │ python3     │ local │ ok      │ ase importable   │
└───────────┴───────────────┴─────────────┴───────┴─────────┴──────────────────┘
To fix the missing requirements, run:
  python3 -m pip install aiida-mydftbp
```

An import probe cannot tell whether your *profile* works, so `doctor` also loads
the profile and looks the code up for real:

```text
Calculate AiiDA: ok -- AiiDA profile 'Macremote' loads; code
'remote-code@remotecomputer' found
```

The two failures you are most likely to see, both live:

```text
Calculate AiiDA: PROBLEM -- AiiDA not ready:
aiida.common.exceptions.NotExistent: no Code found with LABEL<dftbplus@cluster>:
No result was found
```

```text
Calculate AiiDA: PROBLEM -- AiiDA not ready:
aiida.common.exceptions.ProfileConfigurationError: profile `nosuchprofile` does
not exist
```

A wrong `code_label` is the commonest setup mistake. Copy it from
`verdi code list` rather than typing it.

## Run it

On already-screened materials, run the one stage:

```console
$ matmelt run --only calculate --yes
```

`--only` requires that `pipeline.stop_after` is not set (they conflict, exit
`2`). Materials land in `CALCULATED`; a mid-funnel `--only` never retires them
as `DONE`, so `extract` still has work to do:

```console
$ matmelt run --only extract --yes
```

Or drop `--only` and let the whole funnel run, in which case new materials flow
through `calculate` on their way to `DONE`.

To try it on one material first:

```console
$ matmelt run --only calculate --materials Cl1Na1_3D-225 --yes
```

## What happens per material

The stage's runner converts `relaxed.cif` to `.gen`, generates the DFTB+ HSD
input, ensures the Slater–Koster `FolderData` node exists (finding it by label,
or creating it from `skf_local_path`), submits one `mydftbp.single` WorkChain,
and **records the submission before it polls**. That ordering is what makes the
stage restart-safe: kill MatMelt mid-poll and the WorkChain carries on in your
daemon, and the next run re-attaches to it by uuid instead of submitting a
second one.

`calc_result.json` holds the outcome, including every self-healing attempt the
plugin made, with absolute SKF paths stripped out. `extract` folds it verbatim
into the final record under `_mcli.calculate`.

## Reading the verdicts

The plugin's WorkChain does its own retrying, so its terminal exit statuses are
final answers rather than transient errors:

| Outcome | MatMelt's response |
|---|---|
| Converged | Advance to `CALCULATED` |
| Exit 310, 320, 330, 340, 350, 360 | **Terminal** science verdict — `FAILED` at attempt 1, no retry |
| Exit 300, 370, unknown, or a broken result file | Retryable fault — spends `retry_budget` |

A material that failed with a terminal status will fail identically if you retry
it; one that faulted may not. {doc}`diagnose-a-failure` explains how to tell
them apart from `status` alone.

:::{note}
The `doctor` output on this page is live, captured against a real AiiDA profile.
The end-to-end run results come from the acceptance run recorded in the
project's notes (WorkChain pk 13524, converged at −90.31 eV; the SKF node
created once and reused; a SIGKILL mid-poll re-attached by uuid with zero
resubmissions), because a working DFTB+ machine is not reproducible while
writing docs.
:::

## Related

- {doc}`../tutorials/t6-calculate-dftb` — the same setup as a tutorial.
- {doc}`view-a-structure` — exporting the DFTB+ relaxed geometry afterwards.
- {doc}`../reference/config` — every option, with defaults.
