diff --git a/doc/src/Developer_notes.rst b/doc/src/Developer_notes.rst index cd3c51fed6..33565a9fdd 100644 --- a/doc/src/Developer_notes.rst +++ b/doc/src/Developer_notes.rst @@ -65,6 +65,139 @@ when converting "12.5", while the ValueTokenizer class will throw an :cpp:func:`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 `: `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 `. + +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 ` 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 +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 `: + +.. 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 `: + +.. 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 ` 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 ` +command: + +.. code-block:: C++ + + neighbor->add_request(this, "delete_atoms", NeighConst::REQ_FULL); + Fix contributions to instantaneous energy, virial, and cumulative energy ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^