-
Notifications
You must be signed in to change notification settings - Fork 55
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
RATTLE Implementation #132
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #132 +/- ##
==========================================
+ Coverage 72.18% 72.44% +0.26%
==========================================
Files 35 36 +1
Lines 5278 5444 +166
==========================================
+ Hits 3810 3944 +134
- Misses 1468 1500 +32 ☔ View full report in Codecov by Sentry. |
I agree this is not clear and much of implementing this correctly will be calling the constraint functions at the correct point. See for instance OpenMM, which has examples of where to call the constraints for Verlet and Langevin dynamics. There is also a Julia RATTLE implementation here but I don't know how good it is.
Yes I think we might want to switch to
I think it follows LAMMPS, you might get more from the original PRs (#82 and #84).
Look in the source code if possible? |
Just some notes from LAMMPS SHAKE source: |
Useful threads from LAMMPS
Things to remember:
|
|
Anyone have any clue why when I simulate hydrogen gas the rotational DoF suddenly freeze? Basically the first 200 timesteps look normal then rotations completely stop and the molecules just move around the box constrained interacting as if they cannot rotate. When I simulate the same thing in LAMMPS the H2 molecules spin like crazy. I'm not really convinced this is an artifact of my SHAKE implementation but I don't know what else could cause it. |
Could you give code to reproduce the issue? It might also be worth comparing to the same simulation without constraints, i.e. with a strong harmonic bond and a small time step. If that simulation doesn't show the issue then it is probably something to do with the constraints. |
This is the input I am using. I uploaded the xyz file for this with 1 molecule (where you can also see what I am talking about). In the 1 molecule case the two atoms do not interact with each other so this rotation is just from the initial velocity. It might look like the molecule does not translate from the initial velocity but I think they do and its just small. The weirder thing to me is that the particles stop rotating and moving. After looking at all the output I noticed that the velocity vectors eventually end up pointing towards the COM of the molecule effectively canceling each other out. Why this is the case I have no idea. I tested the exact same system in LAMMPS with SHAKE and this does not happen. I plan to test the original implementation of SHAKE in Molly (I have only changed how it is initialized not the algorithm itself) to see if this phenomena occurs as well and also the harmonic bonds. Edit: Tried with just Verlet algorithm as well and the same issue pops up. r_cut = 8.5u"Å"
temp = 300.0u"K"
#Initialize atoms (0.0252259036145 molecules / nm^3 typical for H2 gas at STP)
n_atoms_half = 200
atom_mass = 1.0u"u"
atoms = [Atom(index = i, mass=atom_mass, σ=2.928u"Å", ϵ=0.074u"kcal* mol^-1") for i in 1:n_atoms_half]
max_coord = 200.0u"Å" # nm
coords = [max_coord .* rand(SVector{3}) for i in 1:n_atoms_half]
#Add bonded atoms
bond_length = 0.74u"Å" #hydrogen bond length
constraints = []
for j in range(1, n_atoms_half)
push!(atoms, Atom(index = j + n_atoms_half, mass = atom_mass, σ=2.928u"Å", ϵ=0.074u"kcal* mol^-1"))
push!(coords, coords[j] .+ SVector(bond_length,0.0u"Å",0.0u"Å"))
push!(constraints, DistanceConstraint(SVector(j, j+n_atoms_half), bond_length))
end
constraint_algorithm = SHAKE(similar(coords))
velocities = [random_velocity(atom_mass, temp) for i in 1:length(atoms)]
# velocities = [[0.0u"nm/ps", 0.0u"nm/ps", 0.0u"nm/ps"] for i in 1:length(atoms)]
boundary = CubicBoundary(max_coord)
neighbor_finder = DistanceNeighborFinder(eligible = trues(length(atoms),length(atoms)), dist_cutoff = 1.5*r_cut)
sys = System(
atoms = atoms,
coords = coords,
boundary = boundary,
velocities=velocities,
pairwise_inters=(
LennardJones(
cutoff = ShiftedPotentialCutoff(r_cut),
use_neighbors = true,
energy_units = u"kcal * mol^-1",
force_units = u"kcal * mol^-1 * Å^-1"
),
),
neighbor_finder = neighbor_finder,
constraints = constraints,
constraint_algorithm = constraint_algorithm,
loggers=(
tot_eng = TotalEnergyLogger(1),
coords_out = CoordinateLogger(1),
vels_out = VelocityLogger(1)
),
energy_units = u"kcal * mol^-1",
force_units = u"kcal * mol^-1 * Å^-1"
)
simulator = VelocityVerlet(dt = 0.002u"ps")
simulate!(sys, simulator, 100_000, n_threads = 1) |
I've found the issue, our original implementation of SHAKE was only modifying the positions when it needed to be modifying the forces and it was doing so in the incorrect place anyways. There is still the units issue I messaged you on Slack Joe, but for documentation I will explain here as well. In the working version I modify the accelerations which have some bizarre units |
untis are hard coded at the moment to work with my input
I am having a look at this but it is a large and complex change and I am not so familiar with the algorithms. There are a couple of thoughts I have so far:
Let me know what you think. There's a lot of good work in here but I want to make sure it's a flexible and accurate approach to constraints. We shouldn't require too much caution on behalf of the user when using constraints, which basically all biomolecular simulations will do. |
Tests passed locally, just to summarize this PR. New Features:
Things to double check before merging:
What I was unable to achieve:
|
Nice. I'll try and review this properly over the next few days. From an initial pass, could you remove all commented-out code and anything that is just setting up for later. Also the field in |
Why not do the eligible matrix automatically? It is something that HAS to be done when you use constraints. I don't really see a scenario where having that be automatic would break things? |
For the standard molecular case pairwise interactions are excluded for constrained atoms, but there are more general simulation cases where people may want other behaviour. |
Can I add a flag for this? I think by default we should do this, it is what I would expect the code to do and also a far more common use case imo. (then again Ive never simulated macromolecules). I guess I dont see how even with many body interactions you wouldnt want this behavior. Arent intra molecular forces usually off? |
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 is starting to take shape, well done. I left lots of comments. You will also need to merge/rebase recent changes.
I think for now we should not change the neighbour list automatically. For biomolecular simulation it should be done during system setup from a file, as it is for bonds currently. That can be a future change. The user would specify which type of constraints they want, e.g. all bonds to H, then these would be added and the bonds removed.
I removed the automatic update to the eligible list, but I've left the function to disable the interactions given a list of constraints. I also updated the docs code to reflect that this should be done with the code I put there. |
|
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.
Okay this looks good, just some minor changes before merge.
Nice one, thanks 🎉 |
Implemented iterative scheme for RATTLE....completely untested but I have a many clarifying questions/thoughts.
apply_constraints!
interface will need to change as RATTLE and SHAKE have to be applied at different points in the integration process. That said not sure how to fix that at the moment in a pretty way.