-
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
Periodic polymer #1170
Periodic polymer #1170
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1170 +/- ##
==========================================
+ Coverage 87.32% 87.35% +0.02%
==========================================
Files 62 62
Lines 6525 6540 +15
==========================================
+ Hits 5698 5713 +15
Misses 827 827 ☔ View full report in Codecov by Sentry. |
ea3bda7
to
c281341
Compare
@jaclark5 Funnily enough, just last week a co-worker and I were discussing how we could do this to help with a problem we are facing, so thank you for getting this started! I'm reading through the lines 202 to 221 where the error is raised. It seems like the goal here is to align the chain backbone along the z-axis so that this periodic bond is roughly <0, 0, 1>, and the periodicity of the compound is This seems to work great with the For example, if I try using SMILES to create a polyethylene chain:
then this line:
returns If z-axis alignment is going to be enforced, maybe we should call the
With the polyethylene example above,
So, for the sake of being more generally usable (especially with monomers created from SMILES), I think we should 1) call the Let me know what you think, or if this causes any other issues that I'm missing. |
Hey @chrisjonesBSU that sounds good to me! Do you want to add that as a contributor to this PR, or I can add it in. I think this change will provide a more robust function, but I don't think that's the overall problem. I've been using this with a LJ system which is easy to align perfectly, but it's throwing an error because the x and y coordinates aren't perfect, despite being within 0.001 Å. I could add a tolerance keyword argument, but I'll just make it relative to the longest bond length in the system. |
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 few code quality changes to make it more readable. As an overall change, I think this should live as a separate method for the Polymer recipe, as opposed to an argument to the build function. e.g.
Current use case:
polymer.build(n=3, make_periodic=True)
New use case
polymer.build(n=3, add_hydrogens=False)
polymer.align_periodic_bond(axis="z")
"""This function could align on the x,y, or z dimension using coordinate transforms.
Only functions if `self.head_groups is [None, None]`
Could check polymer.box to see if bond is periodic or non-periodic and raise Errors/Warnings
"""
May also need to adjust some port removal at the end of the build stage, since it seems like it wipes all ports. Either that, or this align_periodic_bond method takes the particles to create the bonds between as the argument, and if it isn't passed just takes the first and last children in the list.
mbuild/lib/recipes/polymer.py
Outdated
) | ||
] | ||
) | ||
self.periodic = [ |
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'm not sure we should be making an extra compound attribute here. Compound.periodicity
already exists, which is a tuple of size three Booleans. Should we use that?
I also have issue with modifying this attribute as a whole here. What if you've already set the polymer peridocity for some reason? This would overwrite and could be missed.
polymer = mb.lib.recipes.Polymer()
polymer.periodicity = (False, True, False) # periodic in Y dimension
polymer.add_monomer(some_monomer)
polymer.build(n=3, make_periodic=True)
print(polymer.periodicity) # == (False, False, True)
If we do keep it as self.periodic, then that information will not be converted anywhere, which would be confusing.
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 could use periodicity, as it is written here, that may have been my intention when I first wrote it. I could also make it an internal variable for the error check so that it's not exposed.
Until the polymer is built, I'm not sure how the periodicity could be set, so this would take care of that for you. I will admit that I haven't used or set the periodicity when using mbuild since I usually make a large molecule, add a box around it, and solvate it with packmol.
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 that's fair. Periodicity is typically used when doing the simulation side of things anyways, so most of the time it's set in the control files (which is external to MoSDeF). In mBuild, it's mostly used when tiling out compounds, you can tile them out based on their periodicity. However, it is an attribute of a compound that recipes and other building methods can take advantage of. So it's possible to have some use case that would build a polymer, and then do something with that periodicity, which would be overwritten here. That's why I'm a little hesitant to have it modified here, so I agree an internal variable may be the way to go.
Co-authored-by: CalCraven <54594941+CalCraven@users.noreply.github.com>
I think it should be a method, but that it should still be a keyword argument in
|
I think with these answers in mind, and the Zen of python echoing that explicit is better than implicit, this should be a separate method to call explicitly. |
I am learning towards agreeing with @jaclark5. First, the periodic bond doesn't necessarily need to be handled carefully. The bonds and angles being off initially is fixed easily by a quick energy minimization (e.g. short simulation after finishing mbuild -> gmso -> simulation engine). But yeah, I also agree that the Second, the information needed to form this bond is already conveniently available during the Also, I agree that this process isn't that different in principle than 1) Placing hydrogen atoms back onto the head and tail monomers out of convenience and 2) adding end-groups monomers automatically after building up the polymer. |
Ahh, I see you addressed the second point in an earlier comment @CalCraven
Either way, I think that we should make it easier to automatically bond the head and tail monomers. We shouldn't have more If we are going to have a separate function to both orient a polymer chain along an axis and form a head-tail-bond, then maybe the head and tail ports should be stored as properties or attributes of the |
Agreed, the indices stuff can get confusing since we don't provide a great way to visualize which particles have which indices other than print with enumeration.
I think that's a great idea, that would be a useful feature to have for other Polymer based methods in general, such as some sort of crosslinking algorithm. I'm also thinking if you wanted to make a polymer with more ports such that you could form other bonds later, just bllindly removing all the ports maybe should be adjusted. |
Yeah these are good points. I am surprised that the energy minimization works at all with a molecule with this high of energy. I think that's what I'm most worried about, adding a few hydrogens should work in almost all cases. However, creating this bond seems to me like it would cause lots of issues in a simulation workflow if you didn't really know what you were doing. |
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.
@jaclark5 based on the discussion yesterday, I think we should go in the direction of having head and tail port properties, and using them where needed. Since a periodic bond will always be between head and tail ports, we can remove the 2 port parameters from create_periodic_bond
.
I tried to push all of these changes, but I don't think this PR selected the option to allow edits by maintainers.
If we go in the direction of having properties for head and tail ports, then I think the workflow of having
as opposed to
One thing that could come up is if I think there are multiple ways to handle this. We could throw and error in Let us know what you think @jaclark5 |
Agreed, I think you could still add the bond even if the polymer is capped with hydrogens. I think the way to do that would be to add an argument head = head_port.anchor
bonded_atoms = list(nx.neighbors(self.root.bond_graph, head))
cappedBool = False
for atom in bonded_atoms:
if atom.name == "H":
self.remove(atom)
raise UserWarning(f"Removing {atom} because remove_caps was set to True")
cappedBool = True
break
if not cappedBool and remove_caps:
raise ValueError(f"Could not find Hydrogen on {head =} or {tail =} to remove. Consider setting remove_caps=False") |
Code coverage should pass if you just add a loop to check the axis arguments |
I think this is ready to merge. It could use a couple more tests in Thank you @jaclark5, this is a really helpful addition! |
Once this is updated to the main branch, we can merge! |
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.
LGTM!
PR Summary:
Resolves #1171
PR Checklist