Skip to content

Commit 4f9cbb0

Browse files
andyclaude
andcommitted
tests/parsers: enforce len(TEVEC) <= len(GEOMTRACE)
GeomTracePropertyPanel plots any PropTSVector<Geometry Step> alongside GEOMTRACE, and OnPointClick passes the curve index straight to GTStepCmd. An index past the last GEOMTRACE frame trips PropTSVecTable::value()'s bounds check and the atoms collapse to the origin -- so a code that prints a per-cycle energy but not per-cycle geometries must not map that energy to TEVEC. CLAUDE.md records the rule and two mopac cases mention it in comments, but nothing checked it. It is a crash, not a cosmetic one, and it is exactly the kind of thing that only shows up when someone clicks a point on the plot. Each firing of a Frequency=all entry contributes one step, so the step count is the number of blocks whose script emitted that key. Verified the check is live rather than dead code: relaxing it to >= makes five cases fail (nwchem-h2o-opt, orca-h2o-opt, orca-h2o-optfreq, orca-oh-uhf and one more), i.e. those really do carry both keys and are really being compared. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EFMUNbw2UpRPmgsqviAowb
1 parent dba9583 commit 4f9cbb0

2 files changed

Lines changed: 40 additions & 0 deletions

File tree

‎tests/parsers/cases.py‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,3 +1179,13 @@
11791179
"job we have. The same data is captured by gaussian-16.db, so this is "
11801180
"harmless -- but the entry is dead code.",
11811181
}
1182+
1183+
1184+
# ---------------------------------------------------------------------------
1185+
# Cases where TEVEC legitimately has more steps than GEOMTRACE.
1186+
# Should stay empty: see the invariant check in run_tests.py. An entry here
1187+
# means a real code prints more per-cycle energies than geometries, and the
1188+
# GUI consequence (atoms collapsing to the origin) has to be handled some
1189+
# other way.
1190+
# ---------------------------------------------------------------------------
1191+
KNOWN_LONG_TEVEC = {}

‎tests/parsers/run_tests.py‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,36 @@ def run_case(case, res, verbose=False):
301301
% (typ, key))
302302

303303
res.xfail_reason = None
304+
# --- cross-property invariant: len(TEVEC) <= len(GEOMTRACE) ------------
305+
#
306+
# GeomTracePropertyPanel plots any PropTSVector<Geometry Step> alongside
307+
# GEOMTRACE, and OnPointClick passes the curve index straight to
308+
# GTStepCmd. An index past the last GEOMTRACE frame trips
309+
# PropTSVecTable::value()'s bounds check and the atoms collapse to the
310+
# origin. So a code that prints a per-cycle energy but not per-cycle
311+
# geometries must not map that energy to TEVEC.
312+
#
313+
# Each firing of a Frequency=all entry contributes one step, so the step
314+
# count is the number of blocks whose script emitted that key. CLAUDE.md
315+
# records this rule and two cases note it in comments, but nothing
316+
# actually checked it until now -- and it is a crash, not a cosmetic.
317+
steps = {}
318+
for entryType, (entry, recs_per_block) in emitted.items():
319+
for block, recs, rc, err in recs_per_block:
320+
for rec in recs:
321+
steps[rec['key']] = steps.get(rec['key'], 0) + 1
322+
nTrace = steps.get('GEOMTRACE', 0)
323+
nEnergy = steps.get('TEVEC', 0)
324+
if nTrace and nEnergy and nEnergy > nTrace:
325+
allowed = CASEDEFS.KNOWN_LONG_TEVEC.get(case['name'])
326+
res.check(allowed is not None, case['name'],
327+
'TEVEC has %d step(s) but GEOMTRACE only %d. '
328+
'GeomTracePropertyPanel indexes the trace with the energy '
329+
'curve\'s own index, so the extra point(s) run past the '
330+
'last frame and the atoms collapse to the origin '
331+
'(PropTSVecTable::value bounds check).'
332+
% (nEnergy, nTrace))
333+
304334
return result, ''.join(report)
305335

306336

0 commit comments

Comments
 (0)