httk.workflow.vasp

Small, dependency-free VASP runner helpers for native v2 workflows.

This is an independent, data-oriented interface rather than a port of the historic VASP_* Python or shell APIs. Historical authorship is documented in v1_runtime/NOTICE.

The implementation is split across cohesive sibling modules — inputs, diagnostics, remedies, and reports — and this package is a thin public facade that re-exports their surface unchanged. Importing the package also registers the packaged VASP templates with the generic scaffold (see the templates module), which is how httk workflow job new --template vasp-relax resolves a runner the scaffold never names.

Attributes

Classes

PoscarHeader

The VASP-5 header information needed by execution helpers.

PotcarAssembly

One assembled POTCAR and the provenance of every piece in it.

PotcarChoice

Which pseudopotential of a library one species was given.

VaspPreparationOptions

Options for dependency-free VASP input preparation.

RemedyPolicy

One named, ordered ladder of bounded remedies.

VaspRemedyDecision

One explicit bounded remedy proposal.

VaspRunReport

Classified result of one supervised VASP execution.

Functions

clean_outcar(→ pathlib.Path)

Remove the largest reproducible k-point detail blocks from OUTCAR.

clean_vasp_outputs(, also_remove, Ellipsis])

Remove standard rerun outputs while preserving declared names.

diagnose_vasp_files(...)

Diagnose completion and final convergence from VASP output files.

last_oszicar_energy(→ float | None)

Return the final E0 value, or None when it is absent.

last_vasprun_volume(→ float | None)

Return the final volume reported by vasprun.xml.

outcar_plane_wave_count(→ int | None)

Return OUTCAR's maximum plane-wave count.

outcar_potim(→ float | None)

Return the last optimizer step size from OUTCAR.

validate_vasp_workdir(→ pathlib.Path)

Validate VASP's conservative absolute-path length constraint.

assemble_potcar(, provenance)

Assemble POTCAR from explicit species and a configurable suffix policy.

automatic_kpoint_grid(→ tuple[int, int, int])

Calculate a reciprocal-length automatic grid.

calculate_nbands(→ int)

Calculate a conservative VASP band count from input metadata.

contcar_to_poscar(→ pathlib.Path)

Replace CONTCAR's comment with the reference POSCAR comment.

derive_seed(→ int)

Derive one reproducible 63-bit seed from a caller-supplied string.

normalize_poscar_handedness(→ pathlib.Path)

Make a left-handed POSCAR lattice right-handed without moving sites.

potcar_summary(→ pathlib.Path)

Write a non-potential metadata summary suitable for logs.

prepare_vasp_inputs(→ dict[str, object])

Prepare POSCAR, POTCAR, KPOINTS, and INCAR with recorded choices.

rattle_poscar(→ pathlib.Path)

Apply a deterministic bounded perturbation to POSCAR site coordinates.

read_incar(→ dict[str, str])

Read the last value of each simple INCAR assignment.

read_poscar_header(→ PoscarHeader)

Read a VASP-5 POSCAR header without interpreting site coordinates.

scale_poscar_lattice(→ pathlib.Path)

Multiply POSCAR's universal linear scale by a positive factor.

suggested_magnetic_moments(→ str)

Return the explicit comment override or a five-per-atom default.

update_incar(→ pathlib.Path)

Atomically replace selected INCAR tags while preserving other lines.

write_automatic_kpoints(→ pathlib.Path)

Write a standard automatic KPOINTS file.

apply_vasp_remedy(→ pathlib.Path)

Explicitly apply a proposed remedy through a replayable workdir batch.

job_remedy_history_path(→ pathlib.Path)

Return the job-scoped remedy history file of one job payload.

plan_vasp_remedy(→ VaspRemedyDecision)

Return, but do not apply, the next remedy of policy.

register_remedy_policy(→ RemedyPolicy)

Register one named remedy policy and return the normalized result.

remedy_policy(→ RemedyPolicy)

Return one registered remedy policy, naming the alternatives if absent.

remedy_policy_names(→ tuple[str, Ellipsis])

Return the names of every registered remedy policy, in registration order.

run_vasp(→ VaspRunReport)

Run VASP with live VASP-5/6 diagnostics and a structured report.

Package Contents

httk.workflow.vasp.VASP_RESTART_ARTIFACTS: tuple[str, Ellipsis] = ('CONTCAR', 'vasp-run-report.json')
httk.workflow.vasp.clean_outcar(path: str | os.PathLike[str] = 'OUTCAR', output: str | os.PathLike[str] = 'OUTCAR.cleaned') pathlib.Path[source]

Remove the largest reproducible k-point detail blocks from OUTCAR.

httk.workflow.vasp.clean_vasp_outputs(directory: str | os.PathLike[str] = '.', *, keep: collections.abc.Iterable[str] = (), also_remove: collections.abc.Iterable[str] = ()) tuple[pathlib.Path, Ellipsis][source]

Remove standard rerun outputs while preserving declared names.

The files in VASP_RESTART_ARTIFACTSCONTCAR and vasp-run-report.json — are kept even without keep, because they are what the remedy machinery and restart promotion read: a pre-run cleanup that deletes them destroys the evidence of the run it is cleaning up after. Name them in also_remove to delete them anyway.

httk.workflow.vasp.diagnose_vasp_files(directory: str | os.PathLike[str] = '.') tuple[httk.workflow.supervision.Diagnostic, Ellipsis][source]

Diagnose completion and final convergence from VASP output files.

httk.workflow.vasp.last_oszicar_energy(path: str | os.PathLike[str] = 'OSZICAR') float | None[source]

Return the final E0 value, or None when it is absent.

httk.workflow.vasp.last_vasprun_volume(path: str | os.PathLike[str] = 'vasprun.xml') float | None[source]

Return the final volume reported by vasprun.xml.

httk.workflow.vasp.outcar_plane_wave_count(path: str | os.PathLike[str] = 'OUTCAR') int | None[source]

Return OUTCAR’s maximum plane-wave count.

httk.workflow.vasp.outcar_potim(path: str | os.PathLike[str] = 'OUTCAR') float | None[source]

Return the last optimizer step size from OUTCAR.

httk.workflow.vasp.validate_vasp_workdir(path: str | os.PathLike[str] = '.', *, maximum_length: int = 240) pathlib.Path[source]

Validate VASP’s conservative absolute-path length constraint.

httk.workflow.vasp.DEFAULT_KPOINT_CENTERING = 'Monkhorst-Pack'
httk.workflow.vasp.KPOINT_CENTERINGS = ('Gamma', 'Monkhorst-Pack')
class httk.workflow.vasp.PoscarHeader[source]

The VASP-5 header information needed by execution helpers.

comment: str
scale: float
lattice: tuple[tuple[float, float, float], Ellipsis]
species: tuple[str, Ellipsis]
counts: tuple[int, Ellipsis]
class httk.workflow.vasp.PotcarAssembly[source]

One assembled POTCAR and the provenance of every piece in it.

path: pathlib.Path
library: pathlib.Path
choices: tuple[PotcarChoice, Ellipsis]
provenance: pathlib.Path
as_mapping() dict[str, object][source]
class httk.workflow.vasp.PotcarChoice[source]

Which pseudopotential of a library one species was given.

The suffix policy of assemble_potcar() silently prefers one PAW variant over another, and the choice changes the numbers a calculation produces, so every choice is recorded: the variant directory, the suffix that selected it, the full source path, its digest, and the TITEL the potential names itself with.

species: str
variant: str
suffix: str
source: pathlib.Path
sha256: str
titel: str | None
as_mapping() dict[str, object][source]
class httk.workflow.vasp.VaspPreparationOptions[source]

Options for dependency-free VASP input preparation.

accuracy_per_atom is the target total-energy accuracy in eV per atom: EDIFFG is set to that budget for the whole cell and EDIFF to the same budget divided by ediff_margin, so the electronic loop converges roughly one and a half orders of magnitude tighter than the ionic loop it feeds. The margin of 33 is a heuristic, empirical default carried over from httk v1, not a derived quantity.

kpoint_density: float = 20.0
centering: str = 'Monkhorst-Pack'
accuracy_per_atom: float | None = 0.001
ediff_margin: float = 33.0
pseudopotential_library: str | os.PathLike[str] | None = None
parallel_tag: str | None = None
parallel_value: int | None = None
normalize_handedness: bool = True
incar_tags: collections.abc.Mapping[str, object]
httk.workflow.vasp.assemble_potcar(library: str | os.PathLike[str], *, poscar: str | os.PathLike[str] = 'POSCAR', output: str | os.PathLike[str] = 'POTCAR', suffix_preference: collections.abc.Iterable[str] = ('_3', '_2', '_d', '_sv', '_pv', '', '_h', '_s'), provenance: str | os.PathLike[str] | None = None) PotcarAssembly[source]

Assemble POTCAR from explicit species and a configurable suffix policy.

The suffix policy decides which PAW variant each species gets, so the result describes what it chose: the returned PotcarAssembly names every potential, and the same record is written next to the POTCAR as <POTCAR>.provenance.json unless provenance names another file.

httk.workflow.vasp.automatic_kpoint_grid(density: float, *, poscar: str | os.PathLike[str] = 'POSCAR', minimum: int = 3, equal: bool = False, bump: int = 0) tuple[int, int, int][source]

Calculate a reciprocal-length automatic grid.

httk.workflow.vasp.calculate_nbands(*, poscar: str | os.PathLike[str] = 'POSCAR', potcar: str | os.PathLike[str] = 'POTCAR', incar: str | os.PathLike[str] = 'INCAR', divisor: int | None = None) int[source]

Calculate a conservative VASP band count from input metadata.

The count is a heuristic, deliberately generous margin over VASP’s own default of roughly half the valence electrons plus half the atom count: too few bands is a run that stops with TOO FEW BANDS or converges to the wrong state, while a handful of extra empty bands costs only time. The spin-polarized branch adds 0.6 * electrons plus a magnetization- or atom-count-derived margin, and the maximum of the candidate formulas wins; the numbers themselves are empirical defaults carried over from httk v1. The result is rounded up to an even number, and to a multiple of divisor when a parallel band divisor (NPAR) is in play, because VASP would otherwise round NBANDS up itself and report a changed value.

httk.workflow.vasp.contcar_to_poscar(contcar: str | os.PathLike[str] = 'CONTCAR', *, reference: str | os.PathLike[str] = 'POSCAR', output: str | os.PathLike[str] = 'POSCAR') pathlib.Path[source]

Replace CONTCAR’s comment with the reference POSCAR comment.

httk.workflow.vasp.derive_seed(entropy: str) int[source]

Derive one reproducible 63-bit seed from a caller-supplied string.

The string is the caller’s own identity of the perturbation — an attempt ordinal, a job key, a remedy step — so the same attempt always derives the same seed and two different attempts derive different ones, without anything reading a clock or a global random state.

httk.workflow.vasp.normalize_poscar_handedness(path: str | os.PathLike[str] = 'POSCAR') pathlib.Path[source]

Make a left-handed POSCAR lattice right-handed without moving sites.

httk.workflow.vasp.potcar_summary(path: str | os.PathLike[str] = 'POTCAR', output: str | os.PathLike[str] = 'POTCAR.summary') pathlib.Path[source]

Write a non-potential metadata summary suitable for logs.

httk.workflow.vasp.prepare_vasp_inputs(options: VaspPreparationOptions | None = None, *, directory: str | os.PathLike[str] = '.') dict[str, object][source]

Prepare POSCAR, POTCAR, KPOINTS, and INCAR with recorded choices.

incar_tags is applied to the INCAR first and wins over everything derived afterwards: the derived values are defaults for what the caller did not say, so an explicit EDIFF, MAGMOM, or NBANDS survives preparation, and an explicit ISPIN is what the band-count heuristic reads.

httk.workflow.vasp.rattle_poscar(path: str | os.PathLike[str] = 'POSCAR', *, amplitude: float = 0.01, seed: int | None = None, entropy: str | None = None) pathlib.Path[source]

Apply a deterministic bounded perturbation to POSCAR site coordinates.

A perturbation has to be reproducible and different between two attempts of the same calculation, so this function never invents entropy of its own: either seed names the stream explicitly, or entropy is a string derive_seed() turns into one — typically something attempt-derived, such as f"{job_key}:{attempt_ordinal}". Giving neither is refused rather than silently repeated, because two retries that rattle identically are two identical calculations.

httk.workflow.vasp.read_incar(path: str | os.PathLike[str] = 'INCAR') dict[str, str][source]

Read the last value of each simple INCAR assignment.

httk.workflow.vasp.read_poscar_header(path: str | os.PathLike[str] = 'POSCAR') PoscarHeader[source]

Read a VASP-5 POSCAR header without interpreting site coordinates.

httk.workflow.vasp.scale_poscar_lattice(factor: float, path: str | os.PathLike[str] = 'POSCAR') pathlib.Path[source]

Multiply POSCAR’s universal linear scale by a positive factor.

httk.workflow.vasp.suggested_magnetic_moments(path: str | os.PathLike[str] = 'POSCAR') str[source]

Return the explicit comment override or a five-per-atom default.

The five Bohr magnetons per atom are a heuristic starting guess, not a physical prediction: a deliberately high initial moment lets a spin-polarized relaxation fall into a low-spin solution, whereas starting too low tends to keep it there, so overestimating is the safer direction. The value of five is the empirical default carried over from httk v1. Encode a per-structure choice in the POSCAR comment as [MAGMOM=...].

httk.workflow.vasp.update_incar(values: collections.abc.Mapping[str, object], path: str | os.PathLike[str] = 'INCAR') pathlib.Path[source]

Atomically replace selected INCAR tags while preserving other lines.

VASP allows several ;-separated assignments per line, and read_incar() reads them all, so an update has to rewrite the individual statements of a line rather than drop or keep the whole line: updating ISYM in ISPIN = 2 ; ISYM = 2 leaves ISPIN = 2 and appends the new ISYM, instead of leaving a line that still assigns the old value.

httk.workflow.vasp.write_automatic_kpoints(grid: collections.abc.Sequence[int], path: str | os.PathLike[str] = 'KPOINTS', *, centering: str = DEFAULT_KPOINT_CENTERING) pathlib.Path[source]

Write a standard automatic KPOINTS file.

The centering defaults to DEFAULT_KPOINT_CENTERING here, in VaspPreparationOptions, and in the Bash bridge, so a workflow that hits a k-point failure class still has the Gamma remedy available.

httk.workflow.vasp.DEFAULT_REMEDY_HISTORY = '.httk-vasp/remedies.json'
httk.workflow.vasp.REMEDY_OPERATIONS = ('bump_bands', 'bump_kpoints', 'centering', 'contcar_to_poscar', 'equal_kpoints', 'scale_ediff',...
class httk.workflow.vasp.RemedyPolicy[source]

One named, ordered ladder of bounded remedies.

A policy is data, not code: sequences maps a diagnosed problem to the escalating steps tried for it, precedence orders the problems so one diagnosis is remedied at a time, and refusals names the problems this policy deliberately has no input remedy for. A group with its own reviewed practice registers its own policy with register_remedy_policy() instead of editing this module.

name: str
sequences: collections.abc.Mapping[str, RemedySequence]
precedence: tuple[str, Ellipsis]
refusals: collections.abc.Mapping[str, str]
class httk.workflow.vasp.VaspRemedyDecision[source]

One explicit bounded remedy proposal.

policy: str
problem: str
step: int
changes: tuple[tuple[str, object], Ellipsis]
give_up: bool
reason: str
as_mapping() dict[str, object][source]
httk.workflow.vasp.apply_vasp_remedy(decision: VaspRemedyDecision, *, directory: str | os.PathLike[str] = '.', history_path: str | os.PathLike[str] = DEFAULT_REMEDY_HISTORY, durable: bool = False) pathlib.Path[source]

Explicitly apply a proposed remedy through a replayable workdir batch.

The history is recorded before the inputs change, so an application interrupted halfway advances the ladder rather than repeating one remedy for ever. A history file inside the VASP directory is written by the same replayable batch as the inputs; a job-scoped one, which the batch cannot reach, is written atomically just before the batch commits.

durable synchronizes the batch and the job-scoped history on a durable workspace, so a power cut cannot lose a remedy the ladder has already recorded. It defaults to False for a caller applying a remedy outside an attempt; the Bash bridge sources it from the workspace durability contract.

httk.workflow.vasp.job_remedy_history_path(payload: str | os.PathLike[str]) pathlib.Path[source]

Return the job-scoped remedy history file of one job payload.

The escalation ladder is a property of the job, not of the directory one attempt happened to run in, so it lives beside the job state in <payload>/.httk-job/ rather than in the workdir. A job with an isolated workdir therefore keeps escalating instead of silently starting the ladder from the beginning on every attempt.

httk.workflow.vasp.plan_vasp_remedy(diagnostics: collections.abc.Sequence[httk.workflow.supervision.Diagnostic], *, directory: str | os.PathLike[str] = '.', history_path: str | os.PathLike[str] = DEFAULT_REMEDY_HISTORY, policy: str = 'reviewed-v1') VaspRemedyDecision[source]

Return, but do not apply, the next remedy of policy.

The decision is validated against the real contents of directory: a ladder step whose changes cannot be executed there is skipped, and the first executable step wins. When nothing is left the decision gives up, so a runner only ever hands apply_vasp_remedy() a remedy it can perform.

httk.workflow.vasp.register_remedy_policy(name: str, sequences: collections.abc.Mapping[str, collections.abc.Sequence[collections.abc.Sequence[tuple[str, object]]]], precedence: collections.abc.Sequence[str], *, refusals: collections.abc.Mapping[str, str] | None = None, replace: bool = False) RemedyPolicy[source]

Register one named remedy policy and return the normalized result.

Every problem named in sequences must also appear in precedence, which is what decides which of several simultaneous diagnostics is acted on, and every change must spell one supported remedy operation, so a policy that cannot be executed is refused when it is registered rather than when a run needs it.

httk.workflow.vasp.remedy_policy(name: str) RemedyPolicy[source]

Return one registered remedy policy, naming the alternatives if absent.

httk.workflow.vasp.remedy_policy_names() tuple[str, Ellipsis][source]

Return the names of every registered remedy policy, in registration order.

class httk.workflow.vasp.VaspRunReport[source]

Classified result of one supervised VASP execution.

process: httk.workflow.supervision.ProcessReport
classification: str
diagnostics: tuple[httk.workflow.supervision.Diagnostic, Ellipsis]
as_mapping() dict[str, object][source]
write(path: str | os.PathLike[str]) pathlib.Path[source]
httk.workflow.vasp.run_vasp(argv: collections.abc.Sequence[str], *, directory: str | os.PathLike[str] = '.', timeout: float | None = None, termination_grace: float = 10.0, report_path: str | os.PathLike[str] = 'vasp-run-report.json') VaspRunReport[source]

Run VASP with live VASP-5/6 diagnostics and a structured report.