final tweaks
This commit is contained in:
@ -29,33 +29,36 @@ is updated (e.g. their positions) and this updated information needs to
|
||||
be **copied** to the corresponding ghost atoms.
|
||||
|
||||
And second, *reverse communication* which sends ghost atom information
|
||||
from each processor to the owning processor to **accumulate** (sum) the
|
||||
values with the corresponding owned atoms. The need for this arises
|
||||
when data is computed and also stored with ghost atoms (e.g. forces when
|
||||
using a "half" neighbor list) and thus those terms need to be added to
|
||||
their corresponding atoms on the process where they are "owned" atoms.
|
||||
Please note, that with the :doc:`newton off <newton>` setting this does
|
||||
not happen and the neighbor lists are constructed that these pairs are
|
||||
computed on both MPI processes containing one of the atoms and only the
|
||||
data pertaining to the local atom is stored.
|
||||
from each processor to the owning processor to **accumulate** (sum)
|
||||
the values with the corresponding owned atoms. The need for this
|
||||
arises when data is computed and also stored with ghost atoms
|
||||
(e.g. forces when using a "half" neighbor list) and thus those terms
|
||||
need to be added to their corresponding atoms on the process where
|
||||
they are "owned" atoms. Please note, that with the :doc:`newton off
|
||||
<newton>` setting this does not happen and the neighbor lists are
|
||||
constructed so that these interactions are computed on both MPI
|
||||
processes containing one of the atoms and only the data pertaining to
|
||||
the local atom is stored.
|
||||
|
||||
The time-integration classes in LAMMPS invoke these operations each
|
||||
timestep via the *forward_comm()* and *reverse_comm()* methods in the
|
||||
*Comm* class. Which per-atom data is communicated depends on the
|
||||
currently used :doc:`atom style <atom_style>` and whether
|
||||
:doc:`comm_modify vel <comm_modify>` setting is "no" (default) or "yes".
|
||||
:doc:`comm_modify vel <comm_modify>` setting is "no" (default) or
|
||||
"yes".
|
||||
|
||||
Similarly, *Pair* style classes can invoke the *forward_comm(this)*
|
||||
and *reverse_comm(this)* methods in the *Comm* class to perform the
|
||||
same operations on per-atom data that is stored within the pair style
|
||||
class. Note that this function requires passing the ``this`` pointer
|
||||
as the first argument to be able to call the "pack" and "unpack" functions
|
||||
discussed below. An example for the use of these functions are many-body pair
|
||||
styles like the embedded-atom method (EAM) which compute intermediate
|
||||
values in the first part of the compute() function that need to be
|
||||
stored on both, owned and ghost atoms for the second part of the force
|
||||
computing. The *Comm* class methods perform the MPI communication for
|
||||
buffers of per-atom data. They "call back" to the *Pair* class so it can *pack*
|
||||
same operations on per-atom data that is generated and stored within
|
||||
the pair style class. Note that this function requires passing the
|
||||
``this`` pointer as the first argument to enable the *Comm* class to
|
||||
call the "pack" and "unpack" functions discussed below. An example of
|
||||
the use of these functions are many-body pair styles like the
|
||||
embedded-atom method (EAM) which compute intermediate values in the
|
||||
first part of the compute() function that need to be stored by both
|
||||
owned and ghost atoms for the second part of the force computation.
|
||||
The *Comm* class methods perform the MPI communication for buffers of
|
||||
per-atom data. They "call back" to the *Pair* class so it can *pack*
|
||||
or *unpack* the buffer with data the *Pair* class owns. There are 4
|
||||
such methods that the *Pair* class must define, assuming it uses both
|
||||
forward and reverse communication:
|
||||
@ -65,32 +68,37 @@ forward and reverse communication:
|
||||
* pack_reverse_comm()
|
||||
* unpack_reverse_comm()
|
||||
|
||||
The arguments to these methods include the buffer and a list of atoms to
|
||||
pack or unpack. The *Pair* class also must set the *comm_forward* and
|
||||
*comm_reverse* variables which store the number of values it will store
|
||||
in the communication buffers for each operation. This means it can
|
||||
choose to store multiple per-atom values in the buffer, if desired, and
|
||||
they will be communicated together to minimize communication overhead.
|
||||
The communication buffers are defined as arrays containing ``double``
|
||||
values. To correctly store integers that may be 64-bit (bigint,
|
||||
tagint, imageint) in the buffer, you need to use the `ubuf union
|
||||
<Communication buffer coding with ubuf>`_.
|
||||
The arguments to these methods include the buffer and a list of atoms
|
||||
to pack or unpack. The *Pair* class also must set the *comm_forward*
|
||||
and *comm_reverse* variables which store the number of values stored
|
||||
in the communication buffers for each operation. This means, if
|
||||
desired, it can choose to store multiple per-atom values in the
|
||||
buffer, and they will be communicated together to minimize
|
||||
communication overhead. The communication buffers are defined vectors
|
||||
containing ``double`` values. To correctly store integers that may be
|
||||
64-bit (bigint, tagint, imageint) in the buffer, you need to use the
|
||||
`ubuf union <Communication buffer coding with ubuf>`_ construct.
|
||||
|
||||
The *Fix*, *Compute*, and *Dump* classes can also invoke the same kind of
|
||||
forward and reverse communication operations using *Comm* class methods.
|
||||
The same pack/unpack methods and comm_forward/comm_reverse variables
|
||||
must be defined by the *Fix* or *Compute* class.
|
||||
The *Fix*, *Compute*, and *Dump* classes can also invoke the same kind
|
||||
of forward and reverse communication operations using the same *Comm*
|
||||
class methods. Likewise the same pack/unpack methods and
|
||||
comm_forward/comm_reverse variables must be defined by the calling
|
||||
*Fix*, *Compute*, or *Dump* class.
|
||||
|
||||
For *Fix* classes there is an optional second argument to the
|
||||
*forward_comm()* and *reverse_comm()* call which are used when there are
|
||||
communications with buffer sizes different from the value set in the
|
||||
comm_forward/comm_reverse variables. For this to work a class member
|
||||
variable must be set to indicate to the pack/unpack routines which
|
||||
which data needs to be packed into and unpacked from the buffer.
|
||||
*forward_comm()* and *reverse_comm()* call which can be used when the
|
||||
fix performs multiple modes of communication, with different numbers
|
||||
of values per atom. The fix should set the *comm_forward* and
|
||||
*comm_reverse* variables to the maximum value, but can invoke the
|
||||
communication for a particulard mode with a smaller value. For this
|
||||
to work, the *pack_forward_comm()*, etc methods typically use a class
|
||||
member variable to choose which values to pack/unpack into/from the
|
||||
buffer.
|
||||
|
||||
Finally, for reverse communications in *Fix* classes there is also
|
||||
the *reverse_comm_variable()* method that allows the communication to have
|
||||
a different amount of data per-atom. It invokes these corresponding callback methods:
|
||||
Finally, for reverse communications in *Fix* classes there is also the
|
||||
*reverse_comm_variable()* method that allows the communication to have
|
||||
a different amount of data per-atom. It invokes these corresponding
|
||||
callback methods:
|
||||
|
||||
* pack_reverse_comm_size()
|
||||
* unpack_reverse_comm_size()
|
||||
@ -133,8 +141,8 @@ processor sends to the first processor, and the first processor
|
||||
receives from the last processor.
|
||||
|
||||
Invoking the *ring()* method passes each processor's buffer in *P*
|
||||
steps around the ring. At each step a *callback* method (provided as
|
||||
an argument to ring()) in the caller is invoked. This allows each
|
||||
steps around the ring. At each step a *callback* method, provided as
|
||||
an argument to ring(), in the caller is invoked. This allows each
|
||||
processor to examine the data buffer provided by every other
|
||||
processor. It may extract values needed by its atoms from the
|
||||
buffers, or it may alter placeholder values in the buffer. In the
|
||||
@ -145,18 +153,18 @@ Note that the *ring* operation is similar to an MPI_Alltoall()
|
||||
operation where every processor effectively sends and receives data to
|
||||
every other processor. The difference is that the *ring* operation
|
||||
does it one step at a time, so the total volume of data does not need
|
||||
to be stored by every processor. However, *ring* is also less
|
||||
efficient than MPI_Alltoall() because of the *P* stages required. So
|
||||
it is typically only suitable for small data buffers and occasional
|
||||
operations that are not time-critical.
|
||||
to be stored by every processor. However, the *ring* operation is
|
||||
also less efficient than MPI_Alltoall() because of the *P* stages
|
||||
required. So it is typically only suitable for small data buffers and
|
||||
occasional operations that are not time-critical.
|
||||
|
||||
Irregular operation
|
||||
===================
|
||||
|
||||
The *irregular* operation is provided by the *Irregular* class.
|
||||
Irregular communication is when each processor knows what data it
|
||||
needs to send to what processor, but does not know what processors are
|
||||
sending it data. An example for LAMMPS is when load-balancing is
|
||||
The *irregular* operation is provided by the *Irregular* class. What
|
||||
LAMMPS terms irregular communication is when each processor knows what
|
||||
data it needs to send to what processor, but does not know what
|
||||
processors are sending it data. An example is when load-balancing is
|
||||
performed and each processor needs to send some of its atoms to new
|
||||
processors.
|
||||
|
||||
@ -194,7 +202,7 @@ communicated to a new owning processor.
|
||||
Rendezvous operation
|
||||
====================
|
||||
|
||||
Finally, the *rendezvous* operation is invoked vie the *rendezvous()*
|
||||
Finally, the *rendezvous* operation is invoked via the *rendezvous()*
|
||||
method in the *Comm* class. Depending on how much communication is
|
||||
needed and how many processors a LAMMPS simulation is running on, it
|
||||
can be a much more efficient choice than the *ring()* method. It uses
|
||||
@ -203,14 +211,15 @@ communication. The rendezvous algorithm is described in detail in
|
||||
:ref:`(Plimpton) <Plimpton>`, including some LAMMPS use cases.
|
||||
|
||||
For the *rendezvous()* method, each processor specifies a list of *N*
|
||||
datums to send, each to a specified processor. Internally, this
|
||||
communication is performed as an irregular operation. The received
|
||||
datums are returned to the caller via invocation of *callback*
|
||||
function, provided as an argument to rendezvous(). The caller can
|
||||
then process the received datums and (optionally) assemble a new list
|
||||
of datums to communicate to a new list of specific processors. When
|
||||
the callback function exits, the *rendezvous()* method performs a
|
||||
second irregular communication on the new list of datums.
|
||||
datums to send and which processor to send each of them to.
|
||||
Internally, this communication is performed as an irregular operation.
|
||||
The received datums are returned to the caller via invocation of
|
||||
*callback* function, provided as an argument to *rendezvous()*. The
|
||||
caller can then process the received datums and (optionally) assemble
|
||||
a new list of datums to communicate to a new list of specific
|
||||
processors. When the callback function exits, the *rendezvous()*
|
||||
method performs a second irregular communication on the new list of
|
||||
datums.
|
||||
|
||||
Examples in LAMMPS of use of the *rendezvous* operation are the
|
||||
:doc:`fix rigid/small <fix_rigid>` and :doc:`fix shake
|
||||
|
||||
Reference in New Issue
Block a user