describe new neighbor list request APIs

This commit is contained in:
Axel Kohlmeyer
2022-03-03 06:35:47 -05:00
parent a0996da644
commit 13bf72e61c

View File

@ -65,6 +65,139 @@ when converting "12.5", while the ValueTokenizer class will throw an
:cpp:func:`ValueTokenizer::next_int()
<LAMMPS_NS::ValueTokenizer::next_int>` is called on the same string.
Requesting and accessing neighbor lists
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LAMMPS uses Verlet-style neighbor lists to avoid having to loop over
*all* pairs of *all* atoms when computing pairwise properties with a
cutoff (e.g. pairwise forces or radial distribution functions). There
are three main algorithms that can be selected by the :doc:`neighbor
command <neighbor>`: `bin` (the default, uses binning to achieve linear
scaling with system size), `nsq` (without binning, quadratic scaling),
`multi` (with binning, optimized for varying cutoffs or polydisperse
granular particles). In addition how the neighbor lists are constructed
a number of different variants of neighbor lists need to be created
(e.g. "full" or "half") for different purposes and styles and those may
be be required in every time step ("perpetual") or on some steps
("occasional").
The neighbor list creation is managed by the ``Neighbor`` class.
Individual classes can obtain a neighbor list by creating an instance of
a ``NeighRequest`` class which is stored in a list inside the
``Neighbor`` class. The ``Neighbor`` class will then analyze the
various requests and apply optimizations where neighbor lists that have
the same settings will be created only once and then copied, or a list
may be constructed by processing a neighbor list from a different
request that is a superset of the requested list. The neighbor list
build is then :doc:`processed in parallel <Developer_par_neigh>`.
The most commonly required neighbor list is a so-called "half" neighbor
list requested by a pair style, where each pair of atoms is listed only
once (except when then :doc:`newton command setting <newton>` for pair
is off; in that case pairs straddling sub-domains or periodic boundaries
will be listed twice). Thus these are the default settings when a
neighbor list request is created in:
.. code-block:: C++
void Pair::init_style()
{
neighbor->add_request(this, NeighConst::REQ_DEFAULT);
}
void Pair::init_list(int /*id*/, NeighList *ptr)
{
list = ptr;
}
The ``this`` pointer argument is required so the neighbor list code can
access the requesting class instance to store the assembled neighbor
list with that instance by calling its ``init_list()`` member function.
The second argument contains a bitmask of flags that determines the kind
of neighbor list, i.e. a perpetual "half" neighbor list here.
To adjust a neighbor list request to the specific needs of a style
usually just a different additional request flag is needed. The :doc:`tersoff <pair_tersoff>` pair
style, for example, needs a "full" neighbor list:
.. code-block:: C++
void PairTersoff::init_style()
{
// [...]
neighbor->add_request(this, NeighConst::REQ_FULL);
}
When a pair style supports r-RESPA time integration with different cutoff regions,
the request flag may depend on the corresponding r-RESPA settings. Here an example
from pair style lj/cut:
.. code-block:: C++
void PairLJCut::init_style()
{
int list_style = NeighConst::REQ_DEFAULT;
if (update->whichflag == 1 && utils::strmatch(update->integrate_style, "^respa")) {
auto respa = (Respa *) update->integrate;
if (respa->level_inner >= 0) list_style = NeighConst::REQ_RESPA_INOUT;
if (respa->level_middle >= 0) list_style = NeighConst::REQ_RESPA_ALL;
}
neighbor->add_request(this, list_style);
// [...]
}
In case a class would need to make multiple neighbor list requests with different
settings each request can set an id which is then used in the corresponding
``init_list()`` function to assign it to the suitable pointer variable. This is
done for example by the :doc:`pair style meam <pair_meam>`:
.. code-block:: C++
void PairMEAM::init_style()
{
// [...]
neighbor->add_request(this, NeighConst::REQ_FULL)->set_id(1);
neighbor->add_request(this, NeighConst::REQ_DEFAULT)->set_id(2);
}
void PairMEAM::init_list(int id, NeighList *ptr)
{
if (id == 1) listfull = ptr;
else if (id == 2) listhalf = ptr;
}
Fixes may require a neighbor list that is only build occasionally (or
just once) and this can also be indicated by a flag. As an example here
is the request from the ``FixPeriNeigh`` class which is created
internally by :doc:`Peridynamics pair styles <pair_peri>`:
.. code-block:: C++
neighbor->add_request(this, NeighConst::REQ_FULL|NeighConst::REQ_OCCASIONAL);
It is also possible to request a neighbor list that uses a different cutoff
than what is usually inferred from the pair style settings (largest cutoff of
all pair styles plus neighbor list skin). The following is used in the
:doc:`compute rdf <compute_rdf>` command implementation:
.. code-block:: C++
if (cutflag)
neighbor->add_request(this,NeighConst::REQ_OCCASIONAL)->set_cutoff(mycutneigh);
else
neighbor->add_request(this,NeighConst::REQ_OCCASIONAL);
The neighbor list request function has a slightly different set of arguments
when created by a command style. In this case the neighbor list is
*always* an occasional neighbor list, so that flag is not needed. However
for printing the neighbor list summary the name of the requesting command
should be set. Below is the request from the :doc:`delete atoms <delete_atoms>`
command:
.. code-block:: C++
neighbor->add_request(this, "delete_atoms", NeighConst::REQ_FULL);
Fix contributions to instantaneous energy, virial, and cumulative energy
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^