SOF-8005: parse NWChem initial and final geometry - #165
Open
VsevolodX wants to merge 3 commits into
Open
Conversation
NwchemParser implemented none of IonicDataMixin's four geometry methods,
whose bodies are bare `pass`, so lattice_basis_to_poscar raised on None
and every NWChem job silently failed to publish its structures --
extract_structures runs app-agnostically for every modeling unit, and
extract_property swallows the exception into a log.error.
One extractor keyed on the "Output coordinates" block, plus four thin
delegates. Notes:
- The block header carries the units the input declared. test-001 is a
`geometry units au` run and prints no angstrom block at all, so the
units word is read rather than assumed; an angstroms block is taken
verbatim rather than rescaled through two Bohr radii that disagree in
the last digits.
- The cell is not ours to invent: made's calculate_padded_cell_simple_cubic,
the same convention every non-periodic material on the platform gets.
- BASIS in tests/fixtures/nwchem/references.py held test-001's printed
a.u. geometry mislabelled `"units": "angstrom"`. It was never used by
any test, so nothing caught it. Corrected and now asserted.
Also returns those structures as molecules. NWChem works in the finite
molecular picture, but Material defaulted is_non_periodic to False and
rupy cannot correct it -- it only ever sees the material's _id, never the
material. So a relaxed molecule came back as a periodic crystal, with
volume/density where inchi/inchi_key belong. The parser now answers for
itself, an explicit kwarg still wins, and `isNonPeriodic` is serialized
so the flag survives to the platform. Timur asked for exactly this on
exactly this file in express#55 (2020-12-08).
Verified on a real job once deployed: H2O, CUB, inchi 1S/H2O/h1H2.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
VsevolodX
force-pushed
the
feature/SOF-8005
branch
from
August 14, 2026 01:15
a7dd652 to
2a42ffd
Compare
_lattice_vectors was derived per-block, so initial and final got different boxes -- 5.72 A and 3.05 A for the same water molecule. The final one shrink-wrapped the relaxed geometry: made's padding factor is 2x the max pairwise distance, which for water leaves ~0.8 A of vacuum a side, and the two structures could not be compared. An optimization moves atoms inside a fixed box; it does not resize the box. The cell is now derived once, from the first geometry block, and both structures share it -- fixed-cell semantics, and the relaxed molecule sits in the roomier unrelaxed box instead of being wrapped tight. Smaller than what it replaces: _lattice_vectors no longer takes `last`. Still made's convention, unchanged; only how many times it is applied. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The cell was derived from the first geometry block alone, so a relaxation that expands a molecule left atoms outside the box. Reproduced: a diatomic going 0.2 -> 2.5 A landed at z = 4.0 and -1.0 in a 3.0 A box, which reads as extra fragments and turns inchi 1S/H2O/h1H2 into 1S/H2O.2H2/h1H2;2*1H -- silently wrong chemistry, not a visible failure. Still one cell for both, so the two structures stay comparable; it is now sized to whichever geometry needs more room. Contracting relaxations, the common case, are unaffected: the fixture still gives 5.72171236 for both, and the H2O acceptance job still gives 3.163849. Also drops four restatements of why the cell is shared, keeping the explanation where the logic is. Found by review: the problem was repetition, not volume -- express sits below this repo's docstring density. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR (express)
NwchemParserimplemented none ofIonicDataMixin's four geometry methods, whose bodies are barepass. Solattice_basis_to_poscarraised onNone, and every NWChem job ever run silently failed to publish its structures —extract_structures()runs app-agnostically for every modeling unit, andextract_propertyswallows the exception into alog.erroron the compute node. That predates the relaxation work entirely.One extractor keyed on the
Output coordinatesblock, plus four thin delegates. Three things worth a reviewer's attention:tests/fixtures/nwchem/test-001is ageometry units aurun that prints no angstrom block at all — the plan's instruction to key on the literalOutput coordinates in angstromswould have returnedNonefor it, leaving that silent failure open for every au-geometry job. The units word is read rather than assumed. Anangstromsblock is taken verbatim rather than rescaled through two Bohr radii that disagree in the last digits.made'scalculate_padded_cell_simple_cubic, the same convention every non-periodic material on the platform gets. Initial and final therefore get different edges, as made would give them: 5.72171236 Å vs 3.05045924 Å for the H2O fixture. The basis takes its edge from_lattice_vectorsso it is centered in the box that ships with it.BASISintests/fixtures/nwchem/references.pywas wrong and unused. It held test-001's printed a.u. geometry tagged"units": "angstrom"— added in the original NWChem PR and never referenced by any test, so nothing caught it. Corrected to that geometry converted and centered, and now actually asserted.Tests: 22 passing (unit + integration), including a regression case for a numeric row that fits the column shape but has no element symbol — it is skipped rather than raising, because rupy would swallow the exception into a silently missing
final_structure.Pre-existing on
main, untouched: 11 failures intests/integration/parsers/test_structure.py,tests/unit/parsers/test_structure_parser.pyandtests/integration/properties/test_material.py, all espresso structure parsing. Confirmed by stashing every change and re-running.Part of SOF-8005 — [Standata] Relaxation SWF/WF for NWChem. One ticket, five repos; this is one of five PRs that land together.
total_energycomputed HOMO/LUMO on whatever geometry was uploaded — nothing in the NWChem workflows relaxed anything, andget_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.MaterialEvidence
Acceptance test
job-nwchem-relaxation-total-energy.featurepasses against a live cluster — takes the unrelaxedH2O.poscar, toggles relaxation in the real UI, runs one job:homo_energylumo_energyTolerance 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.5728586862333and the total-energy unit-2078.5728586879750— agreeing to 2e-9 eV. The second unit reproduced the first's final energy, which it can only do by computing on the relaxed geometry; astart-from-scratch unit would have recomputed the original upload.Manual checks
restart nwchemwith nogeometryblock — read from a real job atjob.workflow.subworkflows[].units[].input[0].rendered.Optimization convergedstring was not read; job files are in object storage behind the authenticated API.Materialappears with a resolvablematerialId— still absent, and deploying express will not fully fix it.is_non_periodicappears nowhere in rupy andMaterial.__init__defaults it toFalse, so the relaxed molecule builds throughCrystalParser: cubic lattice type yes,isNonPeriodicno. 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.{nwchem, 7.0.2, GNU, isDefaultVersion: true}.Geometry Relaxation.Frequency (nwchem)with no relaxation rendersstart nwchem, byte-identically to before.Review
Two
tb-reviewerpasses. The first found two blockers — localfile:tarball pins in web-app, and ajobHasParent ||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 onFrequency (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
is_non_periodic— above; needs a rupy change.isRelaxedwill readFalseon every NWChem relaxation once express is deployed._is_relaxed()derives it frompressureandatomic_forces, andNwchemParserimplements neither. Unreachable today because extraction fails first.wode Workflow.ts:352), not by what the workflow computes. wode#100 already pointed this way.🤖 Generated with Claude Code