Repository navigation
Initialize useOptimizedPme so pre-evaluation PME queries do not throw bad_cast - #5486
Open
barlowa124 wants to merge 1 commit into
Open
barlowa124 wants to merge 1 commit into
barlowa124 wants to merge 1 commit into
Conversation
The flag was only assigned inside execute(), so getPMEParameters() read an indeterminate value when getPMEParametersInContext() was called before any force or energy evaluation. When it read as nonzero, the kernel downcast an empty Kernel and threw std::bad_cast. On machines where the read happened to be zero the call returned correct values, which made the bug hard to reproduce. Initialize the flag to false so the method returns the parameters computed during initialize() until the optimized kernel exists. Fixes openmm#5392.
barlowa124
marked this pull request as ready for review
October 5, 2026 01:02
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.
useOptimizedPme was read before execute() ever set it. Initialized it to false.
The section below was generated with AI assistance (Devin) and checked locally before submission.
Fixes #5392.
CpuCalcNonbondedForceKernel::useOptimizedPmewas only assigned insideexecute(). CallinggetPMEParametersInContext()before the first force or energy evaluation read an indeterminate value. When it read as nonzero,getPMEParameters()downcast an emptyKerneland threwstd::bad_cast. The flag is now initialized tofalsein the constructor, so pre-evaluation queries return the parameters computed byinitialize().execute()reassigns the flag on every call, so the initialized value never affects the evaluation path.Verification of the fix
Every read and write of
useOptimizedPmewas audited. It is written only insideexecute(), first unconditionally reset tofalse, then set fromsupportsKernelsfor PME and LJPME. It is read in three places, insideexecute()(safe, since it is set earlier in the same function) and ingetPMEParameters()andgetLJPMEParameters(), the pre-evaluation crash path.The else-branches the fix makes reachable before evaluation return fields that
initialize()already sets (nonbondedMethod,ewaldAlpha,gridSize, and for LJPMEewaldDispersionAlphaanddispersionGridSize), andinitialize()runs at Context creation, before any public query is possible.The constructor init list was audited against every member read between
initialize()andexecute().useOptimizedPmewas the only member left uninitialized.optimizedPmeandoptimizedDispersionPmedefault-construct empty and are only dereferenced under the flag.CpuCalcConstantPotentialForceKernelalready handles this correctly by guarding withhasInitializedPme, which is constructor-initialized.falseis the correct initial value becauseexecute()unconditionally reassigns the flag, so the initial value is only ever consulted by the pre-evaluation query path, where the non-optimized parameters are the right answer.One pre-existing oddity was noticed but left alone as out of scope.
getLJPMEParameters()castsoptimizedDispersionPmetoCalcPmeReciprocalForceKernel, notCalcDispersionPmeReciprocalForceKernel. It works because both exposegetPMEParametersthrough a compatible interface, and the branch is unreachable until LJPME supports the optimized path.Test
Added
testPMEParametersBeforeEvaluationtotests/TestEwald.h, following the issue's reproduction pattern. It evaluates and deletes one Context, then queries parameters on a second Context before evaluation. It asserts the returned alpha and grid dimensions againstNonbondedForceImpl::calcPMEParameters. Whether the test trips on the unfixed code is environment-dependent, matching the nondeterminism reported in the issue. On the fixed code it confirms the parameters are correct.TestCpuEwaldandTestReferenceEwaldpass locally on this branch.