-
Notifications
You must be signed in to change notification settings - Fork 80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Exact PME electrostatics treatment and fast computation of reduced potentials #320
Conversation
Tests pass finally. |
I'm going to push here also the implementation of #321 while this is waiting for review because I need everything in one place. |
I've added another couple of features/optimizations.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me, I have a couple places where I thought of a "what if X happens," but they are corner cases. Do you know if the tests should pass at this point, or are they broken pending other fixes?
# Handle lambda_electrostatics changes with exact PME electrostatic treatment. | ||
# If the context doesn't use exact PME electrostatics, or if lambda_electrostatics | ||
# hasn't changed, we don't need to do anything. | ||
if (_UPDATE_ALCHEMICAL_CHARGES_PARAMETER not in context_parameters or |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens here if _UPDATE_ALCHEMICAL_CHARGES_PARAMETER
is False?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_UPDATE_ALCHEMICAL_CHARGES_PARAMETER
is a module-level constant so it should be always a string.
@@ -1143,6 +1426,39 @@ def _build_alchemical_bond_list(alchemical_atoms, reference_forces, system): | |||
# Internal usage: Alchemical forces | |||
# ------------------------------------------------------------------------- | |||
|
|||
def _add_alchemical_forces(self, alchemical_system, alchemical_forces_by_lambda): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to fall back on not using force groups if there are not enough available?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can set split_alchemical_forces
to False
if there are not enough force groups available. Otherwise, RuntimeError
is raised.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, but I mean can we just default to fall back to non-split_alchemical_forces
if there are too many forces to split into the 32 groups?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah! I see, sorry. I went for the exception because in general, I would prefer to know if there's a performance penalty instead of proceeding silently, but I can change this behavior if you think we should automatically fall back to split_alchemical_forces=False
.
I think it'd be very easy for an application to go with something like this anyway:
try:
factory.create_alchemical_system(...)
except RuntimeError:
factory.split_alchemical_forces = False
factory.create_alchemical_system(...)
@@ -1167,10 +1483,11 @@ def _alchemically_modify_PeriodicTorsionForce(reference_force, alchemical_region | |||
""" | |||
# Don't create a force if there are no alchemical torsions. | |||
if len(alchemical_region.alchemical_torsions) == 0: | |||
return [copy.deepcopy(reference_force)] | |||
return {'': [copy.deepcopy(reference_force)]} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand the need for the change do key-less dict here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Each alchemically_modify_X()
method now has a different signature. The key of the returned dict
is the parameter that controls that force so that we know upstream in which force group to put it.
return [force, custom_force] | ||
return {'': [force], 'lambda_bonds': [custom_force]} | ||
|
||
def _get_electrostatics_energy_expressions(self, reference_force): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if someone specifies an exact force and not PME?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As long as reference_force
is a NonbondedForce
, the method should behave correctly. We call this only inside _alchemically_modify_NonbondedForce
.
Potential energy of this configuration. | ||
kinetic_energy : simtk.unit.Quantity | ||
Kinetic energy of this configuration. | ||
potential_energy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happened to the docstring here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
potential_energy
and kinetic_energy
are properties now so I moved their docstrings in the property definitions.
Thanks for the review! I just noticed that in |
Fix #319.
I've run some
timeit
tests, and reading the charges from theCustomNonbondedForce
is actually pretty fast so I don't think implementing the caching system for the charges is worth it. WithI got on the cluster (CUDA platform)