Implementing new neighborhood detection algorithm

Hello,

I’d like to test some neighborhood detection algorithms in LAMMPS but I’m a bit confused about how should I approach it. I see that neighbor.h has a lot of stuff defined, and that its implementations are separated in files neigh_full.cpp, neigh_gran.cpp, neigh_half_bin.cpp, neigh_half_bin.cpp, neigh_half_multi.cpp, neigh_half_nsq.cpp…

Should I just add my methods in neighbor.h and a separated file? ie. if I want to implement Multi Step, I’d do something like Neighbor::full_multi_step, Neighbor::half_multi_step?

And can you point me to a detailed explanation of these codes? If there is one. :slight_smile:

[]’s

Hello,

I’d like to test some neighborhood detection algorithms in LAMMPS but I’m
a bit confused about how should I approach it. I see that neighbor.h has a
lot of stuff defined, and that its implementations are separated in files
neigh_full.cpp, neigh_gran.cpp, neigh_half_bin.cpp, neigh_half_bin.cpp,
neigh_half_multi.cpp, neigh_half_nsq.cpp…

​the neighbor list (management) code in ​LAMMPS is one of the most complex
parts in LAMMPS, and making modifications there is not for the faint of
heart. more importantly, it requires a lot of reading and understanding of
the mechanisms at work.

Should I just add my methods in neighbor.h and a separated file? ie. if I
want to implement Multi Step, I’d do something
like Neighbor::full_multi_step, Neighbor::half_multi_step?

​what do you mean by "Multi Step"​? what would be the expected benefit or
new functionality that you want to achieve, that none of the existing
routines can do?

​before making a recommendation on an implementation strategy, please ​see
my comments below.

And can you point me to a detailed explanation of these codes? If there is
one. :slight_smile:

​the source code *is* the detailed​ explanation.

the basic flow of control is the following:

- pair styles, fixes, computes and commands that need a neighbor list
create an instance of the NeighRequest class through calling
neighbor->request(), those requests are stored in neighbor->requests

- the required properties and flags for the neighbor list are set by
changing public flag variables in the neighbor list request

- during the "init" phase of a run or minimization, the neighbor list code
adjust internal flags and determines which low-level routine is to be
called to satisfy the individual request. the selected routine is assigned
to a function pointer. at this point conditions like newton on/off, r-RESPA
vs. verlet, GPU, KOKKOS, USER-CUDA, USER-OMP, PERI, GRANULAR support and
whether a given neighbor list can be constructed as a subset of another are
evaluated and flagged.

- when a neighborlist build is triggered, the corresponding build function
pointer is called.

you can place the implementation of your new functions wherever you want.
it would be consistent with the rest to have those in a separate file. if
your new functions would be part of a package, you need to create
corresponding dummies (check out how it is done for the USER-OMP package
for example), so that the code will link correctly, if the package is not
installed. you have to decide how the new build routines are going to be
triggered and then change or augment the code in the NeighRequest class
and/or Neighbor::init() accordingly.

​axel.​

Thanks for your answer Axel!

What I’m trying to do is something like Han’s "Performance comparisons of tree-based and cell-based contact detection algorithms” (2007, Engineering Computations). So, to do this I need to implement some contact detection algorithms. Note that I want only to change the way the lists are created, nothing more.

The Mutli-step that i mentioned is the MMR algorithm as defined by Munjiza, I do want to test others, like Sorting Contact Detection, etc.

I thought that instead of modifying Neighbor::init(), I should follow the example of neigh_*.h/cpp files, and implement something like Neighbor::full_mmr(), Neighbor::half_mmr(), Neighbor::full_sorting(), Neighbor::half_sorting(), etc.

In fact I’m studying discrete element method, but I thought LAMMPS was better suited to my problem (and better documented :D). So here I am.

Thanks again, and a happy new year.

Thanks for your answer Axel!

What I’m trying to do is something like Han’s "Performance comparisons of
tree-based and cell-based contact detection algorithms” (2007, Engineering
Computations). So, to do this I need to implement some contact detection
algorithms. Note that I want only to change the way the lists are created,
nothing more.

​yes, but as i mentioned before, this requires modifications to some of the
most complex code in LAMMPS.​
you can make your life massively easier by using the MiniMD package from
https://mantevo.org/
this implements only the lj/cut model from LAMMPS and the required neighbor
list variant. that code is much easier to figure out.

The Mutli-step that i mentioned is the MMR algorithm as defined by
Munjiza, I do want to test others, like Sorting Contact Detection, etc.

I thought that instead of modifying Neighbor::init(), I should follow the
example of neigh_*.h/cpp files, and implement something like
Neighbor::full_mmr(), Neighbor::half_mmr(), Neighbor::full_sorting(),
Neighbor::half_sorting(), etc.

​implementing those doesn't automatically mean, they are used. that is
where the ​Neighbor::init() code comes into play.

In fact I’m studying discrete element method, but I thought LAMMPS was
better suited to my problem (and better documented :D). So here I am.

​not sure if you are on the right path here. LAMMPS is not very much tuned
for DEM and primarily optimized for simulation of liquids with quite soft
interaction models of systems with homogeneous particle density. for those
applications, especially when running in parallel across a very large
number of processors with domain decomposition, the most efficient way to
build neighbor lists is using verlet lists built from cell lists. most of
the neighbor lists variants are just special variants for that, handling
certain special cases (full vs. half lists, newton's 3rd law for pairs
across subdomain boundaries, systems with different models or largely
different cutoffs for subsets of atom types, multi-timestep integration).
LAMMPS isn't designed for hard spheres and the quite different ways how
time integration is handled in those scenarios.

​i suspect that the biggest stumbling block is the fact that LAMMPS is from
ground up designed for running in parallel using domain decomposition (so
is MiniMD), and that may be a dealbreaker in your case.

axel.

I’ll look into MiniMD and some others alternatives then :).

Thanks for your help Axel.

[]’s

I’ll add that to add a new neighbor list creation method (to simply test out)

you need to do 2 or 3 things:

a) add the method itself, e.g. half_bin_newton(), which is what

these files contain many of: neigh_half_bin.cpp, neigh_half_multi, neigh_respa, etc

b) provide a hook to call that method, this is done in neighbor.cpp. Search

for the string half_bin_newton and you will find the choose_build method,

which determines which method to use for a variety of conditions. To test

something you could simply overwrite one of these with your new method.

c) the binning methods all use stencils of bins, so the neigh_stencil.cpp file

has methods for each kind of stencil as in (a), and the choose_stencil method

in neighbor.cpp has similar logic to (b)

If you come up with a method faster than what LAMMPS already does, let us know!

Steve

Thanks for the help!

Sure I will.

[]'s