Molecule topology for ghost atoms

Hello,
I’m currently trying to redesign the local neighbor listing in pair_style mesocnt to use the bond topology rather than relying on consecutive numbering of atoms in each molecule. This would allow for the simulation of nanotube rings or periodic nanotubes where the ends of the nanotube are bonded to each other.
The pair_style uses LAMMPS neighbor lists to set up connected chains of bonded atoms which are then used as single neighbor entities for the energy and force calculation. In the current implementation, this is done by looking at consecutive atom IDs, but as mentioned above, this requires consecutive labelling of the atoms. Clearly, this doesn’t support connecting two nanotube ends as their IDs differ by more than one.
Instead, I would like to use the bond topology to trace out bonded chains of atoms and use them as neighbor chains. The crucial element in this is the pointer **bond_atom, which stores bond information, but only for local atoms, and not ghost atoms. The method therefore only works for serial simulations and breaks when parallelized.
Is there a way to access global molecule topology information locally in a pair_style?
Alternatively, would it be possible to also communicate ghost atom information (similar to atom->tag)? If performance would take a hit, maybe this could be toggled by an additional comm_modify flag.

Thanks,
Philipp

If you want to access atoms that are directly or indirectly connected via bonds to an atom, you can process the Atom::special list. It contains the atom IDs of all 1-2, 1-3, and 1-4 neighbors. You can then identify of that atom is local or a ghost by using the Atom::map() function, which returns the local index or -1.

This is used by a few commands where you can look for inspiration. Just grep for atom->special.

Thanks for the reply Axel. Atom::special is indeed better than Atom::bond_atom for my uses, but it has the same issue that all values for ghost atoms remain initialised to zero and don’t contain actual information.

Here’s some output concerning atoms owned by a process:

nlocal: 26, nghost: 16
tag: 1 2 3 26 27 28 4 5 29 30 6 7 31 32 8 9 33 34 10 11 35 36 12 13 37 38 | 14 15 39 40 16 17 41 42 22 23 47 48 24 25 49 50
map(tag): 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
bond_atom: 2 3 4 27 28 29 5 6 30 31 7 8 32 33 9 10 34 35 11 12 36 37 13 14 38 25 | 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
nspecial: 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 | 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
special: (2, 25) (1, 3) (2, 4) (27, 50) (26, 28) (27, 29) (3, 5) (4, 6) (28, 30) (29, 31) (5, 7) (6, 8) (30, 32) (31, 33) (7, 9) (8, 10) (32, 34) (33, 35) (9, 11) (10, 12) (34, 36) (35, 37) (11, 13) (12, 14) (36, 38) (37, 39) | (9, 11) (0, 0) (0, 0) (0, 0) (0, 0) (0, 0) (0, 0) (0, 0) (0, 0) (0, 0) (0, 0) (0, 0) (0, 0) (0, 0) (0, 0) (0, 0)

The rows are the printed values of some atom arrays for all local + ghost atoms of a process. The vertical line | indicates the switch from local to ghost atoms. As you can see, using map(tag) for the ghost atoms returns their local ID rather than -1, and all bond_atom, nspecial and special do not contain useful information for the ghosts. Curiously, bond_atom for the last local atom is wrong but special is right for the same atom.

Judging by your reply, I assume Atom::special should contain information for the ghost atom too, right? If I misunderstood this, is there a way to get that information somehow?

Thanks

LAMMPS generally has only minimal information stored for ghost atoms in order to conserve memory and reduce communication overhead.

The special arrays contain the “special” neighbors, i.e. atoms connected via bonds. First all 1-2 neighbors, then the 1-3 neighbors and finally the 1-4 neighbors. The nspecial array contains cumulative counts, i.e. the index into the second dimension of special where the 1-2, 1-3, and 1-4 neighbor list ends.

If you need to compute properties between local and ghost atoms, you usually need to do that on the MPI rank that owns the atom of a pair. If this information is needed with a ghost atom, then you need to store this into an array and then initiate a forward communication. please see: 4.5. Communication patterns — LAMMPS documentation

Yes, for as long at the atom with the tag is present, the map function will return the id in the local arrays. -1 is returned when the atom is not present (e.g. when the communication cutoff is too short for it).

There is a difference in how bond_atom stores information and the special list depending on the state of the newton bond setting. With an “on” setting each bond is only “owned” once, while with “off” it is “owned” by both atoms.

It is difficult to give more specific advice without knowing what specifically you are trying to achieve and how.

Thanks for the suggestion and explanation. The forward communication did the trick. For completeness, I am trying to group all neighbor atoms (list->neighlist) into bonded clusters, i.e. the groups should contain all neighbor atoms that can be reached by tracing along the bonds from any other neighbor atom in the same group. This grouping should include ghost atoms, hence my need to have special neighbor information for ghost atoms too. By communicating atom->special forward to the ghost atoms and getting image information using domain->closest_image, I can now correctly reconstruct the bond topology within the neighbor lists.

Thanks for the help!