[RFC] Change the atom group to SOA
This is a PR with massive changes to introduce the SOA atom group class cvm::atom_group_soa, which tries to implement the first step in https://github.com/Colvars/colvars/discussions/655. ~~Currently there are two LAMMPS tests failed but I cannot figure out why for the time being.~~
@HanatoK I looked quickly at the output of the LAMMPS tests. The errors are very small, and probably to be expected given the magnitude of the changes.
On a quick look this looks amazing :-D
We need to figure out how to decide that the tests we have (or those that we could add) are sufficient to make the COLVARS_SOA codepath the main one. As we discussed earlier, I am totally in agreement that the original data layout (now almost ~20 years old) no longer reflects the features of modern hardware.
The issue with the LAMMPS tests should be solved by commit https://github.com/Colvars/colvars/pull/788/commits/d688465494037376bc62fc0ddecca02ae7654bf0.
In my tests using TRPV1, this PR alone brings a 6-10% performance gain. I haven't tested combining this with #783 yet.
RMSD benchmark results are attached here for future reference:
For nested loops in coordNum and selfCoordNum, I think the performance is more compiler-dependent and also platform-dependent. With Clang 18 and above or GCC 15, users might see the performance improvement. However, with GCC 12/13, there is little to no difference, and with GCC 14, users might even see performance regression after switching to SOA. The micro-benchmark results are shown below:
Great work @HanatoK! I don't have the Colvars knowledge to review all the changes but I noticed there is no changes for GROMACS related files. I guess this is mostly an internal rewrite with the proxy almost not modified hence the lack of changes?
Great work @HanatoK! I don't have the Colvars knowledge to review all the changes but I noticed there is no changes for GROMACS related files. I guess this is mostly an internal rewrite with the proxy almost not modified hence the lack of changes?
Hi @HubLot ! This is a rewritten of the atom group class, and does not affect the proxy. However, since this PR relates to the performance, I would like to know how it affects the speed in GROMACS+Colvars simulations. I am not sure if the performance is improved or degraded under the default compiler flags of GROMACS. I used GROMACS some times but I am not an expert of it and I am sure that you know more about GROMACS than me. Do you have any test cases for profiling the Colvars performance in GROMACS?
@HanatoK I disabled the check for GNU Make in LAMMPS (which will be removed after the upcoming LAMMPS stable release), so that the test failure for that doesn't stop the other library tests
I don't know why the GROMACS tests suddenly failed. I will check them.
It looks like https://gitlab.com/gromacs/gromacs/-/commit/f1d17c175a8bd98330e96dde45c92cb4b36a6bb3 changes the Colvars interface but the changes are not synchronized here. What should I do?
It looks like https://gitlab.com/gromacs/gromacs/-/commit/f1d17c175a8bd98330e96dde45c92cb4b36a6bb3 changes the Colvars interface but the changes are not synchronized here. What should I do?
Ignore it for now. I want to take a look at that in a couple of weeks, unless @HubLot or @jhenin give it a try first. Fortunately GROMACS 2026 is still enough in the future
This Gromacs story raises the point of how we track evolving Gromacs versions. Thanks to CI tests, the Gromacs repo is very likely to be self-consistent at a given point in time. This would argue in favor of not tracking these files at all, or at least not trying to update them if they are already present?
This Gromacs story raises the point of how we track evolving Gromacs versions. Thanks to CI tests, the Gromacs repo is very likely to be self-consistent at a given point in time. This would argue in favor of not tracking these files at all, or at least not trying to update them if they are already present?
Is it possible to use a specific version of GROMACS for the CI testing in Colvars, just like NAMD?
Hi @giacomofiorin and @jhenin! Aside from the atoms in cartesian, are the atoms in an atom group expected be aranged in the same order as their insertion order? In other way, can I sort the atoms in the atom group according to their proxy indices (except in cartesian)? I am trying another change (see https://github.com/HanatoK/colvars/commit/a66fe4655a5a26acfe74d55412499d40a889ecd8) but not quite sure if it breaks other things.
See cvm::atom_group::create_sorted_ids(): you would certainly have to update sorted_atoms_ids and sorted_atoms_ids_map after changing the atom order.
I'm thinking on the rmsd and eigenvector components in particular.
The value of rmsd depends on the order of atoms in the input, only if the reference coordinates are written directly in the configuration string (I don't know anyone who does it in practice, but that's supported).
Same thing with the projection vector for the eigenvector component: if it's provided inline, then it will be kept in the order provided, and expected to match the order of atoms in the group.
EDIT: sorry, after the CVCs are initialized, it is too late to update the sorted atom maps. That's because cvm::load_coords uses it to remap input coordinates (assumed sorted) into the user-specified order of atoms in the atom group. So if you sort atoms after the reference positions are read, you need to re-order those as well. If the sorting is done just when the atom group is being initialized, before the CVC can read reference positions, we should be good.
See
cvm::atom_group::create_sorted_ids():you would certainly have to updatesorted_atoms_idsandsorted_atoms_ids_mapafter changing the atom order. I'm thinking on the rmsd and eigenvector components in particular. The value ofrmsddepends on the order of atoms in the input, only if the reference coordinates are written directly in the configuration string (I don't know anyone who does it in practice, but that's supported). Same thing with the projection vector for theeigenvectorcomponent: if it's provided inline, then it will be kept in the order provided, and expected to match the order of atoms in the group.
The sorting of atom groups happens when they are created and before calling create_sorted_ids(). You can see that the changes do not break the tests (see https://github.com/HanatoK/colvars/commit/a66fe4655a5a26acfe74d55412499d40a889ecd8). However, I am not sure if the tests cover all corner cases.
I was editing my message above as you replied. I don't think the tests have out-of-order atoms for this case, let me check.
I can confirm, we don't have the right test for that. Here are good test colvars for the deca-alanine system:
colvar {
name r1
rmsd {
atoms {
atomNumbers 4 14 24 34
}
refPositions (0, 0, 0) (1, 1, 1) (2, 2, 2) (3, 3, 3)
}
}
colvar {
name r2
rmsd {
atoms {
atomNumbers 14 24 34 4
}
refPositions (0, 0, 0) (1, 1, 1) (2, 2, 2) (3, 3, 3)
}
}
I'm thinking on the rmsd and eigenvector components in particular. The value of
rmsddepends on the order of atoms in the input, only if the reference coordinates are written directly in the configuration string (I don't know anyone who does it in practice, but that's supported). Same thing with the projection vector for theeigenvectorcomponent: if it's provided inline, then it will be kept in the order provided, and expected to match the order of atoms in the group.
If it helps, we could also remove the inlined coordinates feature altogether. I don't think I have used it much myself in 20 years or so, i.e. from before we contributed the first version of Colvars into the NAMD repo.
It was a fall-back option for when you can't read PDB files, but the XYZ file reader added later made that redundant IMO.
If it helps, we could also remove the inlined coordinates feature altogether. I don't think I have used it much myself in 20 years or so, i.e. from before we contributed the first version of Colvars into the NAMD repo.
Do you mean the refPositions? I have tried @jhenin's test case and https://github.com/HanatoK/colvars/commit/a66fe4655a5a26acfe74d55412499d40a889ecd8 indeed breaks it. In my opinion, the atoms in the atom group are better to be sorted according to their proxy indices, as this can probably make accessing the buffers in the proxy more memory-coalesced, which would be helpful in future GPU porting.
Do you mean the
refPositions? I have tried @jhenin's test case and HanatoK@a66fe46 indeed breaks it. In my opinion, the atoms in the atom group are better to be sorted according to their proxy indices, as this can probably make accessing the buffers in the proxy more memory-coalesced, which would be helpful in future GPU porting.
I agree. However, that also will mean sorting the colvarproxy buffers, which currently are populated in the order that the variables are defined but not sorted.
Do you mean the
refPositions? I have tried @jhenin's test case and HanatoK@a66fe46 indeed breaks it. In my opinion, the atoms in the atom group are better to be sorted according to their proxy indices, as this can probably make accessing the buffers in the proxy more memory-coalesced, which would be helpful in future GPU porting.I agree. However, that also will mean sorting the colvarproxy buffers, which currently are populated in the order that the variables are defined but not sorted.
Maybe you are right. An MD engines may have its internal order as well, and it is indeed possible to sort the proxy buffers to match the internal order, but that could be a bit complicated as we have to sort the atom groups again. We can optimize them in the future of course.
Commit https://github.com/Colvars/colvars/pull/788/commits/5eea84f9a213ce2883eddd91d261626cd04179c0 adds support of SOA atom groups in the NAMD CudaGlobalMaster interface.