-
Notifications
You must be signed in to change notification settings - Fork 77
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
GlobalParameterState and changes for multi-restraint calculations #363
Conversation
The default is still lambda_restraints, but this will enable multi-restraint simulations.
…callback. This breaks backwards compatibility so the old signature is deprecated. This change allows composable states to restore the old value if something goes wrong, thus leaving the object in a consistent state if eventual ComposableStateError are raised and catched.
In future versions, exact treatment of PME will be implemented with the NonbondedForce offset mechanism offered starting from OpenMM 7.3 instead of using updateParametersInContext so the argument will be meaningless.
This class will simplify a lot the implementation of AlchemicalState, RestraintState, and all other composable states that require controlling a global parameter. This class also add the logic to control parameters that have a specific suffix appended to their name. This feature will enable multi-restraint and multi-alchemical-region simulations in the future.
Is this ready for merging? If so, I am going to pull master into here to see if it fixes the tests. I want to make sure this is working as intended. Do you also want to try to fix some of the CodeClimate things its complaining about? I can take a pass through that if you have other things you are working on. |
Whops! I didn't notice the failing doctests, I can fix it. I've already merged |
Tests finally pass! Hopefully, this is the last time I need to write special code for Python 2. |
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.
A couple small things I found and have questions on, if you can justify why you think they should not be changed, thats also fine
""" | ||
|
||
def __init__(self, restraint_parameters, restrained_atom_indices1, | ||
restrained_atom_indices2, *args, **kwargs): | ||
restrained_atom_indices2, controlling_parameter_name, |
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.
Can we make controlling_parameter_name
have a default? E.g. controlling_parameter_name = 'lambda_restraints'
? Or would we instead just want controlling_parameter_name = 'restraints'
and the lambda_
prefix is assumed prepended?
|
||
""" | ||
|
||
def __init__(self, energy_function, restraint_parameters, | ||
restrained_atom_indices1, restrained_atom_indices2): | ||
restrained_atom_indices1, restrained_atom_indices2, | ||
controlling_parameter_name='lambda_restraints'): |
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, see, here in this subclass, controlling_parameter_name
an optional keyword arg, which changes the call from the parent function. We should make it consistent in the base class as well
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.
We should make it consistent in the base class as well
Sounds good! I'll move the default to the base class and use kwargs here. I'll have to keep it buried in kwargs
in the base class though because Python 2 doesn't allow having both kwargs and keyword arguments.
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.
Oh yeah... I forgot about that. Might be best to leave it then and it can be removed in 0.17 when we drop Py2 officially
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 just rememberd why I did this. It's because I need to use controlling_parameter_name
in the subclass so I need the default to be specified there. I wouldn't write the default in two places as it's harder to keep track of (i.e., if a dev changes only one of the two the code may become inconsistent and unintuitive).
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.
Also a good point
openmmtools/forces.py
Outdated
energy_function = 'lambda_restraints * ' + energy_function | ||
super(RadiallySymmetricBondRestraintForce, self).__init__(restraint_parameters, | ||
[restrained_atom_index1], [restrained_atom_index2], energy_function) | ||
energy_function = controlling_parameter_name + ' * ' + energy_function |
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.
So I just noticed a potential bug here. If the user passes in an energy_function
which has additive terms and not wrapped in ( )
, this could lead to unintended behavior, which would NOT throw an error. Off the top of my head, the only practical thing I can think of is some kind of external field or shifted function, but this is also an easy enough fix it may be worth fixing now.
e.g.
>>> energy_function = '(K/2)*r^2 + 5*r'
>>> controlling_parameter_name = 'X`
>>> controlling_parameter_name + ' * ' + energy_function
X * (K/2)*r^2 + 5*r
the 5*r
term won't be scaled.
Easy fix is just controlling_parameter_name + ' * (' + energy_function + ')'
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.
Good catch! Will change it.
Awesome, I think this is ready. Do we want to cut a release after this? |
I'd wait to release until we're sure these changes will work for the multi-restriants feature in YANK. I don't think we have an |
Okay we'll hold off on the release. I'll use this branch for developing the new restraints in YANK. I'm on the fence about whether we should merge this or not. If we plan on making changes to this, then I would be hesitant to do so. |
That's fine I think! Let's remember to merge it before making other changes to |
These tests pass locally.
Fix Python 2.7 ABC reference by just removing it. Add a check to ensure the distance variable is in the energy_string
Expanded test to ensure deserialization correctly restores Python accessed properties Changed name of the CV Distance from `Distance` to `symmetric_restraint_distance` Removed the `restraint_parameters` property as it was not called by any test or implementation here or in YANK. It also would have been a pain to restore correctly. Added helper function for the regex search of energy strings for implementations to follow. Installed NetCDF4 from pip on windows due to odd bug in Conda's NetCDF4 on windows having DLL errors for... reasons?
Try again to fix windows netcdf. Pinning libnetcdf to the last good version the netcdf4 lib built against on CondaForge
Convert RadiallySymmetricRestraint Forces to CV Forces
HA! HAHAHAHAHAHA! Finally got the windows tests to pass! |
I've reverted the commits implementing the CV restraint conversion, which are blocking this PR. Once I merge this, I'll open a separate PR reverting the reverted commits that we can merge once we've figure out a way to solve the performance issues. |
IComposableState._on_setattr
to fix a bug where the objects were temporarily left in an inconsistent state when an exception was raised and caught.update_alchemical_charges
inAlchemicalState
in anticipation of the new implementation of the exact PME that will be based on theNonbondedForce
offsets rather thanupdateParametersInContext()
.'lambda_restraints'
. This will enable multi-restraints simulations.states.GlobalParametersState
. This more or less generalize the logic ofAlchemicalState
and implement the "suffix" mechanism that we'll be able to use in multi-restraint calculations to control parameters such aslambda_restraints_restraint1
,lambda_restraints_restraint2
and, in the future, in multiple alchemical region calculations. With this, the newRestraintState
class in YANK can be simplified to:AlchemicalState
will be similarly simplified, but we'll have to wait to do it until the new exact PME implementation will be in.