Skip to content

SOF-8005: emit RESTART from NWChemInputDataManager - #163

Open
VsevolodX wants to merge 1 commit into
mainfrom
feature/SOF-8005
Open

SOF-8005: emit RESTART from NWChemInputDataManager#163
VsevolodX wants to merge 1 commit into
mainfrom
feature/SOF-8005

Conversation

@VsevolodX

Copy link
Copy Markdown
Member

This PR (wode)

NWChemInputDataManager already received workflowHasRelaxation from Workflow.render via Subworkflow.buildExternalContext — and ignored it. So an NWChem unit following a relaxation re-declared the original geometry and computed the property on the unrelaxed molecule. This emits the RESTART flag the template consumes, mirroring the RESTART_MODE line in QEPWXInputDataManager.

Deliberately not jobHasParent || workflowHasRelaxation, as espresso does. Espresso's prepare_restart symlinks the parent job's whole outdir; rupy's NWChem one (src/software/modeling/nwchem/unit.py) symlinks only the parent's perm/, while nwchem.db sits at the work-dir root because no permanent_dir is set. A child job would therefore render restart nwchem with no geometry block and no database to restart from — an input deck NWChem cannot run. Units of a single job share a work_dir, so the workflowHasRelaxation half is sound and is the one that ships. The comment in the source says this, so nobody "restores parity with espresso" later; the unit test pins both halves.

JobExternalContext stays in the external-context union — the third test case needs it — but the unused jobHasParent field is gone.

Everything under dist/ is build output; this repo commits it by convention, and a git pin installs the committed dist/, not a build.

Follow-up this does not do: relaxation resolves by application name alone (Workflow.ts:352), not by what the workflow computes, which is why the frequency template needed the same restart switch in the standata PR. wode#100 already pointed at resolving via SubworkflowStandata instead.

Tests: 50 passing, including three new cases.


Part of SOF-8005[Standata] Relaxation SWF/WF for NWChem. One ticket, five repos; this is one of five PRs that land together.

The goal, stated once: relax a molecule the same way we relax a material.

total_energy computed HOMO/LUMO on whatever geometry was uploaded — nothing in the NWChem workflows relaxed anything, and get_relaxation_by_application("nwchem") returned {}, so Toggle Relaxation silently no-opped. These PRs close the four gaps between NWChem and what VASP/Espresso already do.

# Capability Repo
1 A relaxation subworkflow exists and Toggle Relaxation resolves it standata
2 The next unit computes on the relaxed geometry wode + esse + standata
3 The relaxed structure comes back as a Material express
4 A test proves it end to end web-app

Evidence

Acceptance test job-nwchem-relaxation-total-energy.feature passes against a live cluster — takes the unrelaxed H2O.poscar, toggles relaxation in the real UI, runs one job:

property value reference (NIST CCCBDB, B3LYP/6-31G)
homo_energy −7.880687 eV −7.880
lumo_energy 1.438531 eV 1.439

Tolerance is 0.02 eV, not the 0.1 eV the other nwchem features use: relaxed and unrelaxed HOMO differ by only 0.053 eV, so 0.1 would pass on an unrelaxed molecule — precisely what this test exists to catch. LUMO differs by 0.341 eV and is the discriminating assertion.

The sharpest evidence is not in the assertions. The relaxation unit reported total_energy = -2078.5728586862333 and the total-energy unit -2078.5728586879750agreeing to 2e-9 eV. The second unit reproduced the first's final energy, which it can only do by computing on the relaxed geometry; a start-from-scratch unit would have recomputed the original upload.

Manual checks

  • Rendered input of the total-energy unit says restart nwchem with no geometry block — read from a real job at job.workflow.subworkflows[].units[].input[0].rendered.
  • [~] The relaxation converged — HOMO/LUMO reproduce published equilibrium values to ~1 meV, which a truncated optimization would not. The literal Optimization converged string was not read; job files are in object storage behind the authenticated API.
  • A relaxed Material appears with a resolvable materialIdstill absent, and deploying express will not fully fix it. is_non_periodic appears nowhere in rupy and Material.__init__ defaults it to False, so the relaxed molecule builds through CrystalParser: cubic lattice type yes, isNonPeriodic no. Timur asked for exactly this on this exact file in express#55 (2020-12-08): "Are we able to retain the fact that this is an isolated molecule, rather than a periodic system…". Needs a rupy change; scoped out here and filed as a follow-up.
  • The generated box — 3.05045924 Å for relaxed water, 5.72171236 Å unrelaxed. Correct by made's convention; periodic images essentially touch, so it must be re-boxed before any periodic reuse.
  • Toggle Relaxation stamps a sane version/build{nwchem, 7.0.2, GNU, isDefaultVersion: true}.
  • npm and python standata both ship it — both lookups return Geometry Relaxation.
  • Frequency (nwchem) with no relaxation renders start nwchem, byte-identically to before.

Review

Two tb-reviewer passes. The first found two blockers — local file: tarball pins in web-app, and a jobHasParent || half that would have rendered a deck NWChem cannot run — both fixed. The second, grounded against the precedent corpus (12,340 comments / 73 repos), found that Toggle Relaxation had become reachable on Frequency (nwchem) while that template still declared its own geometry: it would have relaxed, discarded the result, and reported frequencies for the original molecule, silently. Fixed here.

Known and deliberately not fixed

  • rupy never passes is_non_periodic — above; needs a rupy change.
  • isRelaxed will read False on every NWChem relaxation once express is deployed. _is_relaxed() derives it from pressure and atomic_forces, and NwchemParser implements neither. Unreachable today because extraction fails first.
  • Relaxation resolves by application name alone (wode Workflow.ts:352), not by what the workflow computes. wode#100 already pointed this way.

🤖 Generated with Claude Code

The provider already received workflowHasRelaxation from Workflow.render
via Subworkflow.buildExternalContext and ignored it, so an NWChem unit
following a relaxation re-declared the original geometry and computed the
property on the unrelaxed molecule. Mirrors the RESTART_MODE line in
QEPWXInputDataManager.

Deliberately NOT `jobHasParent || workflowHasRelaxation` as espresso does.
Espresso's prepare_restart symlinks the parent job's whole outdir; rupy's
NWChem one (src/software/modeling/nwchem/unit.py) symlinks only the
parent's perm/, while nwchem.db sits at the work-dir root because no
permanent_dir is set. A child job would therefore render ` restart
nwchem` with no geometry block and no database to restart from -- an
input deck NWChem cannot run. Units of a single job share a work_dir, so
the workflowHasRelaxation half is sound and is the one that ships.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant