-
Notifications
You must be signed in to change notification settings - Fork 81
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
ThermodynamicState support for more barostats #437
Conversation
- supports MonteCarloAnistropicBarostat with same pressure along all axes - supports MonteCarloMembraneBarostat with zero surface tension
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.
Thanks so much for the fixes and for taking the time to add comprehensive tests. I've added only a couple of minor comments where I think the code has a possible bug or made a little more robust.
Fixing the docstrings and the changelog to make clear that the new barostats are supported would also be very helpful.
openmmtools/states.py
Outdated
else: | ||
self._pressure = pressure # Pressure here can also be None. | ||
self._barostat_type = openmm.MonteCarloBarostat |
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 do you think about making _barostat_type
a private property that simply returns type(self.barostat)
? Because this attribute is accessed very rarely, I'd prefer to make it slightly slower but avoid redundancies.
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 would rather like to keep it as it is. The reason is that _initialize
calls _is_barostat_consistent
indirectly (through _unsafe_set_system
and _check_system_consistency
_). At this point, self.barostat
is not available, since self._standard_system
is not initialized, yet.
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 see what you mean. It may be safe after all though because, if I understand correctly the code I wrote, _is_barostat_consistent
shouldn't be called when self.barostat
is unavailable (I'm looking at these lines: https://github.com/Olllom/openmmtools/blob/other_barostats/openmmtools/states.py#L1341-L1342).
openmmtools/states.py
Outdated
scaled = [barostat.getScaleX(), barostat.getScaleY(), barostat.getScaleY()] | ||
if sum(scaled) == 0: | ||
raise ThermodynamicsError(ThermodynamicsError.UNSUPPORTED_ANISOTROPIC_BAROSTAT) | ||
active_pressures = [pressure for pressure, active in zip(pressures, scaled)] |
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.
active
here is unused.
You probably wanted to add an if active
at the end of the list comprehension.
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! Thank you.
As an extension (but feel free to postpone this to a future PR if you don't need it) we could allow |
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.
allow
self.pressure
to be a vector to support different values of pressures for the axes of the anisotropic MC barostat.
I am not sure what the pV term should look like in the reduced potential for anisotropic pressure. From what I see in textbooks, it should probably be the arithmetic mean of the pressures in all scaled directions. However, the implementation of the MonteCarloAnisotropicBarostat confuses me (if the pressure in one direction is zero, there is no energetic penalty of scaling the overall volume along that axis, which would point to using a geometric rather than an arithmetic mean).
I am happy to add full support for anisotropic pressure once I know that answer.
An easier and more relevant addition for us would be nonzero surface tension. I will add some code for this to the pull request. |
Good point about the pV work. Feel very free to implement only the bits you need. This is already very helpful. |
I added
Point 2. should enable multistate simulations on CUDA in mixed and double precision, It also makes it unnecessary to reduce CUDA_VISIBLE_DEVICES to a single device in multinode-gpu simulations. Instead the device ID can be set as a platform property. |
This PR is ready to go on my end. |
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.
Love the new changes, thank you so much! The failing test is unrelated so you can ignore it.
The only possibly major things are these:
-
ThermodynamicState.apply_to_context()
modifies the surface tension as well, but with the current code,ContextCache
won't be able to recognize that it can effectively transform a context to use a different surface tension. To do this you'll have to add a_STANDARD_SURFACE_TENSION
(like here) and modifyThermodynamicState._standardize_system()
. In this way, the hash of a thermodynamic state won't change if you alter only the surface tension. -
I still think
_barostat_type
should be better implemented as a property. The fact that we can have redundant info and inconsistencies in the internal state of the object makes me a little uncomfortable. A couple of examples:- If we call
_unsafe_set_system(system, fix_state=True)
with a system with a different barostat,self._barostat_type
will remain outdated. This might actually be a bug when this is called throughset_system(..., fix_state=True)
(if I understand correctly the code). - We can have a thermodynamic state in NVT with
thermo_state._barostat_type == MonteCarloBarostat
instead of the saferNone
. I don't think this causes problems right now, but you never know what can happen in the future.
- If we call
openmmtools/states.py
Outdated
@@ -2032,6 +2105,11 @@ def volume(self): | |||
"""The volume of the box (read-only)""" | |||
return _box_vectors_volume(self.box_vectors) | |||
|
|||
@property | |||
def area(self): |
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 do you think about calling this xy_area
or area_xy
? I'd skip reading the docstring with this 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.
Done
update release history refactor area->area_xy # Conflicts: # docs/releasehistory.rst
update release history refactor area->area_xy # Conflicts: # docs/releasehistory.rst
Hi Andrea, thanks for your suggestions and sorry for the delay. I have incorporated all of your requests. In order to allow compatibility between states with different surface tensions, I basically mimicked the pressure implementation. This should be the most consistent way to standardize the system, since the surface tension needs to be defined by the ThermodynamicState rather than the system barostat. Instead of having a field for the barostat type, I added a private method |
Since this PR has added significant complexity, is there anything we could implement at the OpenMM API for these barostats that would significantly simplify this code? We're looking for features to add for the next OpenMM release, so if there is an easy way to extend the OpenMM API to facilitate this, please let us know! |
Thanks @Olllom ! I'll take a look at the changes before the end of the week. Now that we merged the multiple alchemical region features, I should be able to take a look at your other PR modifying the alchemical factory too next week. |
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.
Looks great, thank you! I've only found a couple of minor typos or things that may have been forgotten in the code, but I think this is essentially ready to be merged. Nice job!
openmmtools/states.py
Outdated
if barostat is not None: | ||
self._barostat_type = type(barostat) | ||
|
||
# If surface tension is None, we try to infer the pressure from the barostat. |
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.
"infer the pressure" -> "infer the surface tension"
|
||
|
||
def _set_barostat_surface_tension(self, barostat, gamma): | ||
# working around a bug in the unit conversion https://github.com/openmm/openmm/issues/2406 |
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.
Nice catch!
Great! |
Almost! It looks there's one of the new tests failing: https://travis-ci.org/choderalab/openmmtools/jobs/603266322#L3314 |
There are also these other two errors in the "allowed failures" that I haven't seen before, but I'm not sure this is related to your changes so I'd address in a separate PR unless you know why that is happening: https://travis-ci.org/choderalab/openmmtools/jobs/603266325#L3185 |
I confirm that the latter tests are unrelated as they appear also in a PR without these changes so there's just the surface tension test to fix. |
Is there anything we could implement at the OpenMM API for these barostats that would significantly simplify this code? |
Nothing particularly useful comes to mind. I think most of the complexity here comes from the fact that we're providing a unified API to a bunch of objects that have different parameters and (consequently) different APIs. We could create a general |
@jchodera Something like this old issue of yours would be useful to simplify the API: openmm/openmm#1440 In this way, OpenMM could provide a simplified API to set things like temperature, pressure, surface tension, but also step size, etc. But this would only simplify the present code to a certain degree. IMHO a lot of the complexity in the On a side note, one rather boring feature that would be very useful for us is native OpenMM support for the van-der-Waals force switch (see #431). We have to use custom forces for the vdW in most of our simulations to get the correct lipid areas, which is quite a significant performance hit. |
@andrrizzi should be fixed now. |
Fantastic. Thanks again for the really nice work on tests too. Merging. |
Description
Thermodynamic state supports
see #436
Todos
Status