Hi Axel,
Thanks for your reply. The information here is very helpful, especially Point 3. I understand bonded atom info is stored with atom (presumably stored in bond_atom and bond_type), but I’m still confused about the implementation. Let me be more specific about my understanding of the general steps in saving the bonded info. You can point out which part I misunderstand.
Step 1:
In read_data.cpp
, utils::read_lines_from_file
reads in all bonded information on rank 0 from the data file and broadcast it to all MPI ranks (as you said).
Step 2:
atom->data_bonds
is called to save bond info to all particles owned by each MPI rank. I’m looking at the following section in atom.cpp
:
if ((m = map(atom1)) >= 0) {
if (count) count[m]++;
else {
bond_type[m][num_bond[m]] = itype;
bond_atom[m][num_bond[m]] = atom2;
num_bond[m]++;
avec->data_bonds_post(m, num_bond[m], atom1, atom2, id_offset);
}
}
if (newton_bond == 0) {
if ((m = map(atom2)) >= 0) {
if (count) count[m]++;
else {
bond_type[m][num_bond[m]] = itype;
bond_atom[m][num_bond[m]] = atom1;
num_bond[m]++;
avec->data_bonds_post(m, num_bond[m], atom1, atom2, id_offset);
}
}
}
This section looks like it stores bonded info based on newton_bond
. So say I’m on rank 1 that has nlocal_1 particles at the time of data reading, and m
is the local ID that is mapped from global ID atom1
and loops over all particles on rank 1; i.e. bond_type
and bond_atom
are built for those nlocal_1 particles on rank 1 (and are saved on rank 1?).
Somewhere between Step 2 and 3, the time advancing loop starts.
Step 3:
At the time of data reading, the neighbor list is generated, and the topology is also built, through neigh_bond->build()
. neigh_bond
is a NTopo
class, and I’m looking at ntopo_bond_all.cpp
for build()
method:
for (i = 0; i < nlocal; i++)
for (m = 0; m < num_bond[i]; m++) {
atom1 = atom->map(bond_atom[i][m]);
......
atom1 = domain->closest_image(i, atom1);
if (newton_bond || i < atom1) {
if (nbondlist == maxbond) {
maxbond += DELTA;
memory->grow(bondlist, maxbond, 3, "neigh_topo:bondlist");
}
bondlist[nbondlist][0] = i;
bondlist[nbondlist][1] = atom1;
bondlist[nbondlist][2] = bond_type[i][m];
nbondlist++;
}
It builds bondlist
and nbondlist
using atom info and neighbor info on each rank. Say I’m still on rank 1, and at the time of data reading, nlocal
in Step 3 is equal to nlocal_1 from Step 2. So all good.
Step 4:
bondlist
and nbondlist
are used in various Bond::compute()
methods to calculate forces and update attributes in the atom
class.
And somewhere here the time advancing loop ends.
Here is my question for Step 3. At a later time when particles move to new ranks and new neighbor lists are built, nlocal
may represent different particles. Still using rank 1 as an example. Now rank 1 own nlocal_1_later particles, which in an extreme case can be completely different from the nlocal_1 particles in Step 2. As a result, Step 3 loops through nlocal_1_later particles. However, bond_atom is not updated, so the first index of bond_atom should represent nlocal_1 particles from Step 2; i.e. i
in atom1 = atom->map(bond_atom[i][m])
should only loop through nlocal_1 particles, not nlocal_1_later particles at a later time. So what I see is a mismatched bond info in bond_atom
and bond_type
. What am I missing here? Thanks.