Skip to content

feat: add vaspcheck-outcar — per-step SCF and ionic convergence checker#14

Open
patrickmelix wants to merge 4 commits intomainfrom
feat/outcar-convergence-check
Open

feat: add vaspcheck-outcar — per-step SCF and ionic convergence checker#14
patrickmelix wants to merge 4 commits intomainfrom
feat/outcar-convergence-check

Conversation

@patrickmelix
Copy link
Copy Markdown
Member

@patrickmelix patrickmelix commented Mar 20, 2026

Description:

Adds a new standalone module tools4vasp.outcar_convergence and the CLI command vaspcheck-outcar for inspecting VASP OUTCAR files without requiring a full VASP directory or an ASE calculator object. Accepts plain OUTCAR and gzip-compressed OUTCAR.gz files, or a directory containing either.

Checks performed

POTCAR/POSCAR alignment Reads the POTCAR title lines and POSCAR element line echoed in the OUTCAR header and verifies that the element order matches. A mismatch means VASP applied the wrong pseudopotential to each species, silently corrupting all energies and forces. PAW potential suffixes (_pv, _d, _sv, …) are stripped before comparison. Returns None (rather than raising) when the header is absent, e.g. for a truncated file.

Per-step SCF convergence Reports whether each ionic step's SCF cycle reached the required accuracy (reached required accuracy - stopping SCF-cycle) or hit NELM without converging. Returns one bool per ionic step, so unconverged frames can be identified and excluded from training data individually.

Ionic/geometry convergence Checks for reached required accuracy - stopping structural energy minimisation anywhere in the file. Works for geometry optimisations, dimer TS searches, and NEB image relaxations.

Public API

from tools4vasp.outcar_convergence import (
    check_potcar_poscar_alignment,   # alignment only
    check_scf_convergence_per_step,  # List[bool], one per ionic step
    check_ionic_convergence,         # bool
    check_outcar,                    # all checks in one dict
    run,                             # check_outcar + human-readable stdout
)

check_outcar(path) returns:

key | type | meaning -- | -- | -- outcar_path | str | resolved file path used potcar_aligned | bool\|None | True=OK, False=mismatch, None=header absent potcar_message | str | "OK" or mismatch/error detail poscar_elements | List[str] | elements from POSCAR line potcar_elements | List[str] | elements from POTCAR lines n_steps | int | number of ionic steps found scf_converged | List[bool] | per-step SCF flags n_scf_failed | int | count of SCF-failed steps ionic_converged | bool | geometry/TS/NEB convergence

CLI

vaspcheck-outcar                      # OUTCAR in current directory
vaspcheck-outcar path/to/dir          # OUTCAR in given directory
vaspcheck-outcar path/to/OUTCAR       # direct file path
vaspcheck-outcar path/to/OUTCAR.gz    # gzip-compressed OUTCAR

Example output:

OUTCAR      : /path/to/OUTCAR
POTCAR/POSCAR alignment : OK
Ionic steps : 47
SCF         : all steps converged
Ionic       : CONVERGED

Relation to existing vaspcheck

vaspcheck requires a full VASP directory and reads the last step only via ASE. vaspcheck-outcar operates on the raw OUTCAR text and reports every ionic step independently — useful for filtering training data for ML force-field fitting and for checking bare OUTCAR/OUTCAR.gz archives where no other input files are present.

Tests

49 tests across 6 classes, all passing. ruff clean.

New module `tools4vasp.outcar_convergence` reads raw OUTCAR (plain or
gzip-compressed) and reports:
- SCF convergence for every ionic step independently
- Overall ionic/geometry relaxation convergence

Key functions:
  check_scf_convergence_per_step(outcar_path) -> List[bool]
  check_ionic_convergence(outcar_path) -> bool
  check_outcar(path) -> dict  (accepts file or directory)
  run(path)           -> dict + human-readable stdout summary

CLI entry point `vaspcheck-outcar [path]` registered in pyproject.toml.
Accepts plain OUTCAR, OUTCAR.gz, or a directory containing either.

35 tests added (conftest.py fixtures + test_outcar_convergence.py),
all passing; ruff clean.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@patrickmelix patrickmelix added enhancement New feature or request AI AI generated labels Mar 20, 2026
patrickmelix and others added 3 commits March 20, 2026 13:27
Adds check_potcar_poscar_alignment() and _parse_potcar_poscar_elements()
to detect the common mistake of applying the wrong POTCAR to a species,
which silently corrupts energies and forces.

Parsing reads the POTCAR title lines and POSCAR element line echoed in
every OUTCAR header; strips PAW suffixes (_pv, _d, _sv, …); handles the
doubled POTCAR block VASP writes (header + footer); works transparently
with OUTCAR.gz via the existing _read_outcar_text() helper.

check_outcar() now includes potcar_aligned (True/False/None), potcar_message,
poscar_elements, and potcar_elements in its result dict. None means the
header was absent (truncated file) — check_outcar() never raises on a
missing header, it degrades gracefully.

vaspcheck-outcar CLI output gains a "POTCAR/POSCAR alignment" line.

14 new tests added (TestParsePotcarPoscarElements, TestCheckPotcarPoscarAlignment,
TestCheckOutcarAlignment); 49 tests total, all passing; ruff clean.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
VASP 5.x indents the POTCAR: and POSCAR: header lines with a leading
space, e.g. " POTCAR:    PAW_PBE Si 05Jan2001". The parser was using
str.startswith('POTCAR:') which missed these lines, causing every
VASP 5.x OUTCAR to report "header absent" instead of checking alignment.

Fix: strip each line before the startswith check. The downstream element
extraction already used split/strip so no further changes needed.

Regression test added: _POTCAR_POSCAR_HEADER_LEADING_SPACE fixture with
the exact indentation style seen in real VASP 5.4.4 OUTCARs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two bugs caught by auditing against real VASP 5.4.4 OUTCARs:

1. _ITER_STEP_RE: regex required a leading space before the dashes
   (^ -{38,}) but VASP 5.x writes no leading space on Iteration lines.
   Fixed to ^\s*-{38,} to accept zero or more leading spaces.

2. _SCF_CONVERGED_STR: "reached required accuracy - stopping SCF-cycle"
   is VASP 6.x only. VASP 5.x writes "aborting loop because EDIFF is
   reached" instead. Both strings are now checked (_SCF_CONVERGED_STRS
   tuple) so the module works across VASP versions.

Test fixtures updated to use real VASP 5.4.4 format (no leading space,
VASP 5.x SCF string). VASP 6.x fixture added (OUTCAR_ONE_STEP_CONVERGED_V6)
with a dedicated test to ensure both versions are covered.

Previously both bugs caused check_scf_convergence_per_step() to silently
return [] for all real VASP 5.x OUTCARs, disabling the SCF filter.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI AI generated enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants