[lammps-users] From global ID to ghost local index. Mask out atoms from neighbor list.

Dear LAMMPS users,

I’m writing a custom fix to implement hydrodynamic propulsion of a colloid (rigid bunch of particles, ~25 per colloid) in a solvent (DPD particles, ~10^4). The fix looks for solvent neighbors of the colloids central particle (using the neighbor list) and applies them a certain force that depends on their relative position to the colloid. Then, for each solvent neighbor, I compute the nearest colloid particle and apply to it the opposite force.

I am doing this last part by building an array (at setup) that has the global IDs of the particles of the colloid (since these particles will not ever leave the colloid nor new ones will join). Then when I need to apply the force to the nearest particle I just loop over this array, then use atom->map() to get the local index and find the nearest colloid particle.

I am facing a “problem” with periodic boundary conditions (running in serial). Of course, when the colloid is crossing the PBC some of the neighbor solvent particles are ghosts (those which are at the opposite side of the PBC with respect to the central particle, from which I’m getting the neighbors), thus, when I loop over the array I previously mentioned, and use atom->map(), the local indexes I get for the colloid particles that are at the other side, are of course the “real” (or owned) ones (not ghosts), so when I compute the distance, I am actually computing the distance between a ghost solvent particle (outside the box, see ASCII below) and a owned colloid particle (inside the box at the other side of the PBC) and of course those distances are always greater than the distance to the other colloid particles, so I end up with no force on the colloid particles that are at the other side, until the central particle crosses.

I have badly patched this just by adding (or subtracting) the sim box side when computing the distance from solvent to colloid particle. But of course this will not work when running in parallel, which I plan to do.

So I was wondering if there is some way to get the local index of the ghost particles of the colloid without looping over all owned + ghost atoms. I think it is impossible but maybe I have missed something.

One way would be of course using the neighbor list (I already requested) to find the neighbors of the solvent particles, but I wanted to avoid this under the assumption that it would perform worse since the requested neighbor list has a big cutoff. Thus my next question, would it be possible to “mask out” the solvent atoms (by type or by group) from the neighbor list? So that the loop for finding the shorter distance would only run over the colloid particles? If not, would it make sense to request another neighbor list with a lower cutoff? Any other ideas, comments?

You don’t have to loop over all atoms,
The Atom class has a member “sametag” that could be used as follows:

int idx = atom->map(mytag[i]);
while (idx >= 0) {
// code to check whether this is the/a suitable local atom
if (suitable) break;
idx = atom->sametag[idx];
}
// check if idx < 0, then atom with tag is not present on this subdomain.

So each sametag value points to another atom with the same tag until it becomes -1 indicating the end of the chain.
Mind you, for this to work reliably, your communication cutoff has to be large enough.

Wonderful!

Thanks again Axel.