htesp.workflow

HTESP workflow layer – a single-file Python replacement for src/bash/*.

Every bash scan script of the package is a method of HTESPWorkflow. The method keeps the name and the argument contract of the script it replaces (start, end exclusive, track file, optional extra argument), so mainprogram.py can keep dispatching to it unchanged.

Design notes

  • Every top-level “for material” loop is a multiprocessing loop. HTESPWorkflow.map() fans the per-material body out over min(len(materials), workers) processes and falls back to a plain serial loop when only one core (or one material) is available, or when HTESP_WORKERS=1 / --workers 1 is given. Results come back ordered by the material index, so every list/CSV written after the loop (result.csv, econv.csv, mpid-finished.in …) is deterministic and no longer depends on scheduling order – something the bash layer’s in-loop counters could never guarantee.

  • No shared mutable state between iterations. The bash layer wrote fixed-name scratch files (mass.dat, qpoint.dat, kpoint.dat, scf_dir/kpathlines.dat, BZ.pdf, temp*.in …) into the project root, which is what made a naive &/GNU-parallel port unsafe. Here each material body runs inside its own private scratch directory (HTESPWorkflow.scratch()) that carries a local scf_dir; the helper modules keep their existing “write next to me” behaviour and the produced artefacts are moved to their final destination afterwards.

  • No ``os.chdir`` leaking across iterations. pushd() always restores the previous directory, and a failed cd raises instead of letting the body (rm -r ..., sbatch ...) run in the project root – the single most destructive behaviour of the bash layer.

  • Repeated bash fragments became one method each, e.g. qe_section(), final_coordinates(), prefix_of(), nbnd_heuristic(), read_mesh_file(), stage_and_submit(), Scheduler.submit(). The ~60% of the bash layer that was copy-pasted boilerplate exists exactly once here.

  • Python helpers are imported, not exec’d. qe_input.py, kpath.py, elph.py, band.py, dos.py, q2r.py, matdyn.py, matdyn_dos.py, vasp_process.py, plot.py &c. are imported once per process and their main() (or the function their if __name__ == "__main__" block calls) is invoked directly through run_helper(), which temporarily installs the sys.argv those modules expect. No os.system round-trip, no interpreter start-up per material.

  • Job ids are captured. sbatch --parsable ids are recorded in <stage dir>/.htesp_job.json so status checks no longer have to grep squeue output for a compound name (B, C, Si … used to match half the queue).

Usage

from htesp.workflow import HTESPWorkflow wf = HTESPWorkflow() # reads ./input.in wf.relax_scan(1, 5, “mpid.in”) wf.create_inputs(1, 5, “mpid.in”, nkpt=50)

or from the command line:

python workflow.py relax-scan 1 5 mpid.in
python workflow.py create-inputs 1 5 mpid.in 50 --workers 8
python workflow.py phonopy-scan 1 5 mpid.in 1

Written as the Python port of the HTESP bash layer (original bash by Niraj K. Nepal, Ph.D.).

Module Attributes

PROJECT_DIRS

directories the workflow creates below the project root

SCRATCH_ROOT

name of the private scratch tree (one sub-directory per material per stage)

PLACEHOLDER

optional marker line in batch.header.

SCRIPTS

bash script name -> method name.

PROCESSES

mainprogram process number -> method name (documentation / convenience).

Functions

argv(*args)

Temporarily install sys.argv for a helper module that parses it.

concat(destination, *sources)

cat a b c > destination (missing pieces are skipped, not fatal).

copy_file(src, dst[, missing_ok])

cp src dst -- returns False instead of raising when src is absent.

ensure_dir(path)

field_of(line, index[, default])

awk {print $index} (1-based), tolerant of short lines.

grep(pattern, path[, regex])

grep pattern path -> matching lines (empty list if the file is gone).

grep_count(pattern, path[, regex])

grep pattern path | wc -l.

is_number(value)

last_match_field(pattern, path, index[, default])

grep pattern file | tail -n 1 | awk '{print $index}'.

main([argv_in])

move_file(src, dst[, missing_ok])

pushd(path)

cd path for the duration of the block, always restoring the old cwd.

read_indexed_file(path)

v<N> <value> files: pressure.in, charge.in -> [(key, value)].

read_lines(path)

read_mesh_file(path, base[, default_divisor])

Parse qpoint.in / kpoint.in; returns (mesh, shift).

read_text(path[, default])

read_track_file(path, start, end, root)

Parse v<N> <mpid> <compound> lines for start <= N < end.

remove(path[, recursive])

rm / rm -r that never escapes to a wildcard in the wrong cwd.

remove_glob(pattern[, recursive])

run_helper(module, entry, *args[, capture])

Import module and call entry with sys.argv = [module, *args].

to_float(value[, default])

to_int(value[, default])

write_lines(path, lines)

write_track_file(path, rows)

Write the v<N> rows with deterministic numbering, after the loop.

Classes

HTESPWorkflow([root, workers, dry_run, ...])

All former src/bash scripts, as methods, parallel by default.

Material(index, mpid, compound, root)

One v<N> <mpid> <compound> entry of a track file.

QEText()

Section extraction / editing for pw.x inputs and outputs.

Result(index, mpid, compound, status, ...)

What one material's body reports back to the (serial) finish phase.

Scheduler(root[, command, dry_run, throttle])

Job submission, job-id capture and queue queries.

htesp.workflow.PROJECT_DIRS = ('scf_dir', 'elph_dir', 'q2r_dir', 'matdyn_dir', 'kpath', 'plots')

directories the workflow creates below the project root

htesp.workflow.SCRATCH_ROOT = '.htesp_scratch'

name of the private scratch tree (one sub-directory per material per stage)

htesp.workflow.PLACEHOLDER = 'submission here'

optional marker line in batch.header. When it is absent the command is appended instead, which is what mainprogram jobscript has always done and what every shipped batch.header expects.

htesp.workflow.pushd(path: PathLike | str)[source]

cd path for the duration of the block, always restoring the old cwd.

Replaces the 84 unguarded cd X ... cd ../../ pairs of the bash layer. A missing directory raises here instead of silently leaving the body to run in the project root.

htesp.workflow.argv(*args: Any)[source]

Temporarily install sys.argv for a helper module that parses it.

htesp.workflow.run_helper(module: str, entry: str, *args: Any, capture: bool = False)[source]

Import module and call entry with sys.argv = [module, *args].

This is the replacement for every os.system("<helper>.py a b c") call in the bash layer. capture=True returns whatever the helper printed on stdout (needed for qe_axsf2cellpos.py, which writes its result there).

htesp.workflow.grep(pattern: str, path: PathLike | str, regex: bool = False) → list[str][source]

grep pattern path -> matching lines (empty list if the file is gone).

htesp.workflow.grep_count(pattern: str, path: PathLike | str, regex: bool = False) → int[source]

grep pattern path | wc -l.

htesp.workflow.field_of(line: str, index: int, default: str = '') → str[source]

awk {print $index} (1-based), tolerant of short lines.

htesp.workflow.last_match_field(pattern: str, path, index: int, default: str = '') → str[source]

grep pattern file | tail -n 1 | awk '{print $index}'.

htesp.workflow.copy_file(src, dst, missing_ok: bool = True) → bool[source]

cp src dst – returns False instead of raising when src is absent.

htesp.workflow.remove(path, recursive: bool = False) → None[source]

rm / rm -r that never escapes to a wildcard in the wrong cwd.

htesp.workflow.concat(destination, *sources) → None[source]

cat a b c > destination (missing pieces are skipped, not fatal).

class htesp.workflow.Material(index: int, mpid: str, compound: str, root: Path)[source]

One v<N> <mpid> <compound> entry of a track file.

phonon_folder(prefer: str = 'phonon') → str[source]

phonon/ when it exists, otherwise calc/ (bash convention).

class htesp.workflow.Result(index: int, mpid: str = '', compound: str = '', status: str = 'ok', message: str = '', job: str | None = None, rows: dict = <factory>, log: list[str] = <factory>)[source]

What one material’s body reports back to the (serial) finish phase.

say(*parts: Any) → None[source]

Buffer a line; the parent process replays it in material order.

htesp.workflow.read_track_file(path, start: int, end: int, root: Path) → list[Material][source]

Parse v<N> <mpid> <compound> lines for start <= N < end.

end is exclusive, matching for ((ii=$1; ii<$2; ++ii)). Entries that the track file does not contain are reported once and skipped instead of producing an R- path (the bash layer happily built R-/relax and then ran rm -r in the project root).

htesp.workflow.write_track_file(path, rows: Sequence[tuple[str, str]]) → None[source]

Write the v<N> rows with deterministic numbering, after the loop.

class htesp.workflow.Scheduler(root: Path, command: str = 'sbatch', dry_run: bool = False, throttle: float = 0.25)[source]

Job submission, job-id capture and queue queries.

Replaces jobscript.sh (qerun / vasprun) and the five places where that ladder was re-inlined at a different relative depth. The CALC_VISIBLE_WITH_* marker files are read once from the project root rather than looked up at ../../, ../../../ and ../../../../.

submit(script: str, cwd, mpid: str = '', compound: str = '', tag: str | None = None, rename: bool = True) → str | None[source]

Submit script from cwd; returns the job id (or None).

rename reproduces the mv run-<tag>.sh <name>.sh behaviour that makes the job visible under a useful name in squeue.

is_running(cwd) → bool[source]

True when any job recorded for cwd is still queued or running.

This replaces squeue -o '%.100j' | grep "$B", which matched any job whose name merely contained the compound name.

htesp.workflow.read_mesh_file(path, base: Sequence[int], default_divisor: int = 2) → tuple[list[int], list[int]][source]

Parse qpoint.in / kpoint.in; returns (mesh, shift).

One implementation for the five copies the bash layer carried. Accepted contents: f (divide base by f), n1 n2 n3, f s1 s2 s3 and n1 n2 n3 s1 s2 s3. A missing file means base / default_divisor.

htesp.workflow.read_indexed_file(path) → list[tuple[str, str]][source]

v<N> <value> files: pressure.in, charge.in -> [(key, value)].

class htesp.workflow.QEText[source]

Section extraction / editing for pw.x inputs and outputs.

The bash layer re-derived section boundaries with sed -n '/A/,/B/p' | sed '$d' 26 times and hard-coded the Begin final coordinates block layout in 8 places. All of that lives here once, and the relax-vs-vc-relax difference (no CELL_PARAMETERS block for calculation='relax') is handled instead of silently deleting the first atoms.

static section(text: str, start_pat: str, end_pat: str | None = None, include_end: bool = False) → list[str][source]

Lines from the first start_pat up to (not including) end_pat.

classmethod card(text: str, name: str) → list[str][source]

The named card, up to the next card keyword.

classmethod header(text: str) → list[str][source]

Everything before the first card keyword (the namelists).

static value(text: str, key: str, default: str = '') → str[source]

key = value, from a namelist (first occurrence).

classmethod prefix(text: str) → str[source]

prefix = 'x', -> 'x' (quotes kept: helpers expect them).

static kmesh(text: str) → tuple[list[int], list[int]][source]

K_POINTS automatic mesh and shift.

static drop(lines: Sequence[str], *patterns: str) → list[str][source]

sed '/pat/d' for each pattern.

static drop_namelist(lines: Sequence[str], name: str) → list[str][source]

Remove &NAME ... / (used to strip &IONS/&CELL for scf).

static insert_after(lines: Sequence[str], anchor: str, *new: str) → list[str][source]

sed '/anchor/a text' (after the first match only).

classmethod set_key(lines: Sequence[str], namelist: str, key: str, value: Any) → list[str][source]

Set key = value inside &NAMELIST, replacing any old entry.

static final_coordinates(scf_out) → list[str][source]

Begin/End final coordinates -> CELL_PARAMETERS + positions.

Bash did sed '$d' | sed '1,4d' | sed '5d', which assumes the vc-relax layout (volume/density lines, then the cell block). For calculation = 'relax' that deleted the header and the first two atoms. Here the block is parsed by keyword, so both work and an unconverged run yields an empty list instead of a corrupt file.

static last_cell_block(scf_out, natoms: int) → list[str][source]

Last CELL_PARAMETERS (angstrom) + positions of an unfinished run.

class htesp.workflow.HTESPWorkflow(root: PathLike | str = '.', workers: int | None = None, dry_run: bool = False, submit_command: str = 'sbatch', keep_scratch: bool = False, log_level: int = 20)[source]

All former src/bash scripts, as methods, parallel by default.

Parameters:
  • root – Project directory (the one holding input.in); defaults to the cwd.

  • workers – Size of the process pool used for every per-material loop. None means min(os.cpu_count(), 8); 1 disables multiprocessing. The environment variable HTESP_WORKERS overrides the default.

  • dry_run – Build every input file but never call the scheduler.

failures: list[Result]

results of the most recent map() call (see failed_count)

materials(start: int, end: int, track: str | None = None) → list[Material][source]

Resolve [start, end) of track (default: input.in line 4).

The bash layer located the track file with find * -name $3 | tail -n 1: a full-tree walk on every invocation that could pick a nested copy under completed/ or R*/pressure/. Here the name is resolved against the project root and only searched for if that fails.

map(body: Callable[[Material], Result], materials: Sequence[Material], parallel: bool = True) → list[Result][source]

Run body for every material, in parallel, ordered results back.

This is the top-level loop of the package. body must be a bound method of this instance (so it pickles), must not rely on the process cwd persisting between calls, and must not write fixed-name files into the project root – use scratch() for that.

property failed_count: int

How many materials failed in the most recent map() call.

failure_summary() → str[source]

One line per failed material, for the caller’s error report.

scratch(material: Material, stage: str, copy: Sequence[str] = (), local_scf_dir: bool = True)[source]

A private working directory for one material.

Everything the helper modules write with a fixed name (mass.dat, qpoint.dat, kpoint.dat, BZ.pdf, scf_dir/kpathlines.dat, elph-<id>-<comp>.in …) lands here instead of in the shared project root, which is what makes the loop safe to parallelise.

copy names files, relative to the project root, that must be visible inside the scratch directory (config.json and qpoint.in are always copied when present).

collect_scratch(work: Path, patterns: dict[str, str]) → list[str][source]

Move artefacts out of a scratch dir: {glob: destination dir}.

remove(path, recursive: bool = False) → None[source]

remove(), but a no-op under --dry-run.

mainprogram 20 (clean-scan) and mainprogram 28 (pressure-reset) are the two stages that delete real results. They used to delete unconditionally, so --dry-run destroyed exactly what the user was checking. Every deletion in those stages goes through here.

remove_glob(pattern: str, recursive: bool = False) → None[source]

remove() for a glob; also a no-op under --dry-run.

prefix_of(material: Material) → str[source]

prefix = 'x', from the relax input, falling back to the template.

16 copies of grep "prefix = " ... | sed 's/.$//' in bash.

static nbnd_heuristic(nelec: int, soc: bool = False, spin: bool = False, style: str = 'qe') → int[source]

One place for what bash spelled out three (mutually inconsistent) ways.

style='qe' : +20 with SOC/spin, +10 below 30 electrons, else nelec style='vasp' : +20 with SOC, +10 below 30 electrons, else 1.5*n/2 style='epw' : 2*n with SOC, else n+10

qmesh_for(kmesh: Sequence[int]) → list[int][source]

q-mesh from qpoint.in (or k-mesh / 2 when it is absent).

stage_and_submit(material: Material, stage: str, script: str, tag: str, files: dict[str, str] | None = None, result: Result | None = None) → Result[source]

mkdir -p <stage>; cp <files>; cp <script>; cd; sbatch; cd ../../

The submit block that the bash layer repeated in 28 places. files maps destination name inside the stage dir to a path relative to the project root.

run_qe_input(mpid: str) → None[source]

qe_input.py <mpid> – download/convert an MP structure to scf.in.

run_kpath(mode: str, *args: Any) → None[source]

kpath.py point|line ... (plus the KPT_OPT marker its main writes).

run_elph(material: Material, prefix: str) → None[source]

elph.py <mpid> <comp> <prefix> – imported, mode from config.

run_vasp_process(what: str) → None[source]

vasp_process.py POSCAR|eigen|conventional|symmetrize|<scf.in>.

relax_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 1 – submit the first structural relaxation.

further_relax_input(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 2 – harvest the relaxed structure into a new input.

further_relax_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 3 – resubmit the relaxation with the updated input.

fine_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 5 – scf on the fine (doubled) k-mesh, in calc/.

coarse_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 6 – scf on the coarse k-mesh (keeps the fine results).

create_inputs(start: int, end: int, track: str | None = None, nkpt: int | None = None, *_) → list[Result][source]

mainprogram 4 – every downstream QE input from the relaxed scf.out.

This was the worst shared-state offender of the bash layer: it wrote mass.dat, qpoint.dat (appended!), kpoint.dat, BZ.pdf and scf_dir/kpathlines.dat into the project root and then let four helper scripts read them back by name. Each material now builds inside its own scratch directory, so the loop parallelises safely.

elph_status(material: Material, folder: str = 'calc') → dict[source]

Classify one el-ph run. One implementation for ph-scan + checkph.

The bash versions of this classification disagreed with each other and mis-filed the most common failure: dync == 0 (only .dyn0 written, i.e. the job died at start-up) fell into the “unconverged” branch and got alpha_mix instead of recover=.true..

ph_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 7 – submit/restart the ph.x el-ph calculation.

phcheck_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram checkph – classify every el-ph run, write the 4 lists.

checkfreq_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram checkfreq – flag imaginary phonon frequencies.

q2r_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 8 – real-space force constants.

matdyn_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 9 – phonon bands along the high-symmetry path.

matdyn_dos_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 10 – phonon DOS and linewidths.

dynmat_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 23 – diagonalise the dynamical matrix (dynmat.axsf).

lambda_scan(start: int, end: int, track: str | None = None, qgauss: float = 0.12, smearing: int = 0, mustar: float = 0.16, *_) → list[Result][source]

mainprogram 11 – run lambda.x on the login node.

phonband_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 12 – process phonon bands and mode-resolved lambda.

bandscf_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 13 – stage bands/ and submit the scf step.

band_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 14 – run the QE bands calculation.

bandp_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 15 – band post-processing (bands.x / EIGENVAL).

dos_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 16 – stage and submit the DOS run.

dosp_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 17 – dos.x post-processing.

pdos_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 18 – projwfc.x partial DOS.

plot_scan(start: int, end: int, track: str | None = None, nkpt: int | None = None, plot: str | None = None, *_) → list[Result][source]

mainprogram 19 – one PDF per material per requested plot type.

clean_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 20 – drop heavy files, copy finished runs to completed/.

extract_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 21 – Tc / lambda summary into result.csv + cifs.

download_input(start: int | None = None, end: int | None = None, track: str | None = None, *_) → list[Result][source]

mainprogram download – pull MP structures and build the inputs.

The bash script ignored its own $1 $2 $3 and re-read the bounds from input.in; here the arguments win and input.in is only the fallback, so the method behaves like every other stage.

info_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram compound – print structural/electronic information.

double_kmesh(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram change_k – rewrite the k-mesh per kpoint.in.

magmom_extract(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram magmom_extract – dump the MAGMOM block of each OUTCAR.

ifermi_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram fermisurface – ifermi info + a plotting job.

sitesub_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 29 – site-substitution inputs (needs bsym).

atom_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

Isolated-atom QE inputs in a 23x24x25 A box (called manually).

charge_input(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram charge-input – inputs for charged cells.

map_any(method: Callable[[Any], Any], items: Sequence[Any], parallel: bool = True) → list[Any][source]

Like map() but for the inner loops over modes/pressures/cells.

pressure_input(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram pressure-input – inputs for a pressure/volume series.

pressure_relax_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 26 – relaxation of every point of the pressure series.

pressure_ph_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 27 – el-ph for every point of the pressure series.

pressure_reset(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 28 – remove the pressure/ tree of each material.

distortion_relax_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 24 – relax the structure distorted along each mode.

band_distort_scan(start: int, end: int, material_dir: str | None = None, *_) → list[Any][source]

band-distort-scan <first-mode> <last-mode> (inside a material dir).

Kept as a public entry point because distortion.sh documents it as a stand-alone command.

distortion_energy_scan(start: int, end: int, track: str | None = None, *_) → list[Result][source]

mainprogram 25 – collect the per-mode total energies.

energy_distort_scan(start: int, end: int, material_dir: str | None = None, *_) → list[list][source]

energy-distort-scan <first-mode> <last-mode> -> csv rows.

phonopy_scan(start: int, end: int, track: str | None = None, step: Any = 1, *_) → list[Result][source]

mainprogram e0 / phono1..5 / eos-* / ev-collect / phono*-pressure.

epw_bash_scripts(start: int, end: int, track: str | None = None, process: str = 'epw1', projection: str | None = None, *_) → list[Result][source]

mainprogram epw1..5 / qe-ph / wann-* / epw-* – the EPW pipeline.

wt_bash_scripts(start: int, end: int, track: str | None = None, process: str = 'wt1-b', *_) → list[Result][source]

mainprogram wt1 / wt2 – WannierTools inputs (bulk / with surface).

cancel_job(start_number: int, num_points: int, cancel_command: str = 'scancel', *_) → None[source]

cancel_job <first id> <count> <command> (count is exclusive now).

check_calc(queue_command: str = 'squeue', account_id: str = '', *_) → None[source]

check_calc <queue command> <account> – show the slurm logs of jobs.

history(count: int = 10, *_) → None[source]

history.sh – the last mainprogram commands of the shell history.

static distortion_help() → str[source]

distortion.sh – the soft-mode tutorial text.

sumpdos(atom: str, orbital: str, cwd: str | None = None) → None[source]

sumpdos.sh <atom> <orbital> – sum the projected DOS files.

vasp_phonopy_template() → Path[source]

vasp-phonopy.sh – write the default vasp-phonopy.in.

generate_submission_file(which_calc: str, parallel_command: str = 'mpirun', nproc: int = 1, *_) → list[Path][source]

generate_submission_file.sh – build run-*.sh from batch.header.

The legacy bash version emitted run.sh, q2r.sh, matdyn.sh … while every scan script expects run-scf.sh, run-q2r.sh, run-matdyn.sh … The names produced here are the ones the rest of the workflow actually looks for.

elph_finished_not_copied(start: int, end: int, track: str | None = None, *_) → list[Material][source]

Finished el-ph runs that are not in completed/ yet.

htesp.workflow.SCRIPTS: dict[str, str] = {'atom-scan': 'atom_scan', 'band-distort-scan': 'band_distort_scan', 'band-scan': 'band_scan', 'bandp-scan': 'bandp_scan', 'bandscf-scan': 'bandscf_scan', 'cancel_job': 'cancel_job', 'charge-input': 'charge_input', 'check_calc': 'check_calc', 'checkfreq-scan': 'checkfreq_scan', 'clean-scan': 'clean_scan', 'coarse-scan': 'coarse_scan', 'create-inputs': 'create_inputs', 'distortion-energy-scan': 'distortion_energy_scan', 'distortion-relax-scan': 'distortion_relax_scan', 'distortion.sh': 'distortion_help', 'dos-scan': 'dos_scan', 'dosp-scan': 'dosp_scan', 'double-kmesh': 'double_kmesh', 'download-input': 'download_input', 'dynmat-scan': 'dynmat_scan', 'elph_finished_but_not_copied_to_completed_folder': 'elph_finished_not_copied', 'energy-distort-scan': 'energy_distort_scan', 'epw-bash-scripts': 'epw_bash_scripts', 'extract-scan': 'extract_scan', 'fine-scan': 'fine_scan', 'further-relax-input': 'further_relax_input', 'further-relax-scan': 'further_relax_scan', 'generate_submission_file.sh': 'generate_submission_file', 'history.sh': 'history', 'ifermi-scan': 'ifermi_scan', 'info-scan': 'info_scan', 'lambda-scan': 'lambda_scan', 'magmom-extract': 'magmom_extract', 'matdyn-dos-scan': 'matdyn_dos_scan', 'matdyn-scan': 'matdyn_scan', 'pdos-scan': 'pdos_scan', 'ph-scan': 'ph_scan', 'phcheck-scan': 'phcheck_scan', 'phonband-scan': 'phonband_scan', 'phonopy-scan': 'phonopy_scan', 'plot-scan': 'plot_scan', 'pressure-input': 'pressure_input', 'pressure-ph-scan': 'pressure_ph_scan', 'pressure-relax-scan': 'pressure_relax_scan', 'pressure-reset': 'pressure_reset', 'q2r-scan': 'q2r_scan', 'relax-scan': 'relax_scan', 'sitesub-scan': 'sitesub_scan', 'sumpdos.sh': 'sumpdos', 'vasp-phonopy.sh': 'vasp_phonopy_template', 'wt-bash-scripts': 'wt_bash_scripts'}

bash script name -> method name. mainprogram calls the scripts by these names, so python workflow.py <script-name> <args...> is a drop-in replacement for running the script itself.

htesp.workflow.PROCESSES: dict[str, str] = {'1': 'relax_scan', '10': 'matdyn_dos_scan', '11': 'lambda_scan', '12': 'phonband_scan', '13': 'bandscf_scan', '14': 'band_scan', '15': 'bandp_scan', '16': 'dos_scan', '17': 'dosp_scan', '18': 'pdos_scan', '19': 'plot_scan', '2': 'further_relax_input', '20': 'clean_scan', '21': 'extract_scan', '23': 'dynmat_scan', '24': 'distortion_relax_scan', '25': 'distortion_energy_scan', '26': 'pressure_relax_scan', '27': 'pressure_ph_scan', '28': 'pressure_reset', '29': 'sitesub_scan', '3': 'further_relax_scan', '4': 'create_inputs', '5': 'fine_scan', '6': 'coarse_scan', '7': 'ph_scan', '8': 'q2r_scan', '9': 'matdyn_scan', 'change_k': 'double_kmesh', 'charge-input': 'charge_input', 'checkfreq': 'checkfreq_scan', 'checkph': 'phcheck_scan', 'compound': 'info_scan', 'download': 'download_input', 'fermisurface': 'ifermi_scan', 'magmom_extract': 'magmom_extract', 'pressure-input': 'pressure_input'}

mainprogram process number -> method name (documentation / convenience).