Discontinuous Galerkin Library
#include "dg/algorithm.h"
dg::aCommunicator< LocalContainer > Struct Template Referenceabstract

Struct that performs collective scatter and gather operations across processes on distributed vectors using MPI. More...

Public Types

using value_type = get_value_type< LocalContainer >
 reveal value type More...
 
using container_type = LocalContainer
 reveal local container type More...
 

Public Member Functions

LocalContainer allocate_buffer () const
 Allocate a buffer object of size buffer_size() More...
 
void global_gather (const value_type *values, LocalContainer &buffer) const
 \( w = G v\). Globally (across processes) gather data into a buffer More...
 
LocalContainer global_gather (const value_type *values) const
 \( w = G v\). Globally (across processes) gather data into a buffer (memory allocating version) More...
 
void global_scatter_reduce (const LocalContainer &toScatter, value_type *values) const
 \( v = G^\mathrm{T} w\). Globally (across processes) scatter data accross processes and reduce on multiple indices More...
 
unsigned buffer_size () const
 The local size of the buffer vector w = local map size. More...
 
unsigned local_size () const
 The local size of the source vector v = local size of the dg::MPI_Vector More...
 
bool isCommunicating () const
 True if the gather/scatter operation involves actual MPI communication. More...
 
MPI_Comm communicator () const
 The internal MPI communicator used. More...
 
virtual aCommunicatorclone () const =0
 Generic copy method. More...
 
virtual ~aCommunicator ()
 vritual destructor More...
 

Protected Member Functions

 aCommunicator (unsigned local_size=0)
 only derived classes can construct More...
 
 aCommunicator (const aCommunicator &src)
 only derived classes can copy More...
 
aCommunicatoroperator= (const aCommunicator &src)
 only derived classes can assign More...
 
void set_local_size (unsigned new_size)
 Set the local size of the source vector v. More...
 

Detailed Description

template<class LocalContainer>
struct dg::aCommunicator< LocalContainer >

Struct that performs collective scatter and gather operations across processes on distributed vectors using MPI.

In order to understand what this class does you should first really(!) understand what gather and scatter operations are, so grab pen and paper:

First, we note that gather and scatter are most often used in the context of memory buffers. The buffer needs to be filled wih values (gather) or these values need to be written back into the original place (scatter).

Gather: imagine a buffer vector w and a map (the "gather map") that gives to every element in this vector w an index into a source vector v where the value of this element should be taken from i.e. \( w[i] = v[\text{idx}[i]] \) Note that an index into the source vector v can appear several times or not at all. This is why the source vector v can have any size and even be smaller than w.

Scatter: imagine a buffer vector w and a map that gives to every element in the buffer w an index into a target vector v where this element should go to. Note again that an index into v can appear several times or never at all. If the index appears more than once, we perform a reduction operation (we sum up all elements) on these indices initializing the sum with 0. Note that \( v[\text{idx}[i]] = w[i] \) is an INCORRECT definition of this, because it does not show the reduction.

It is more accurate to represent the gather and scatter operation by a matrix. The gather matrix \( G\) is just a (permutation) matrix of 1's and 0's with exactly one "1" in each line. In a "coo" formatted sparse matrix format the values array would consist only of "1"s, the row array is just the index and the column array is the gather map.

\[ \vec w = G \vec v \]

where \( G \in \mathbb{R}^{N_w \times N_v}\) and \(N_w\) and \( N_v\) can have any sizes. We have \( G_{ij} = \delta_{\text{idx}_ij}\) The above definition uniquely identifies the scatter matrix as the transpose of the gather matrix of the same index map

\[ S\equiv G^\mathrm{T}\]

We have \( S_{ij} = \delta_{\text{idx}_j i}\) and \( \vec v = S \vec w\). A simple consistency test is given by \( (Gv)\cdot (Gv) = S(Gv)\cdot v\).

The scatter matrix can thus have zero, one or more "1"s in each line.

Note
There is no "scatter map" or "gather map", there is just an integer index map idx \((i)\) that maps each index \( i \) in \( w\) to an index \( \text{idx}(i)\) in \( v\). Think of it more in terms of a "connector". In code this is represented by the vector "idx" with elements idx[i] = idx \((i)\).

We distinguish between

bijective: If the gather map idx[i] is bijective, each element of the source vector v maps to exactly one location in the buffer vector w. In this case the scatter matrix S is the inverse of G and v and w have the same size.

surjective: If the gather map idx[i] is surjective, each element of the source vector v maps to at least one location in the buffer vector w. This means that the scatter matrix S can have more than one 1's in each line and w has at least the size of v.

general: In general the gather map idx[i] might or might not map an element of the source vector v. This means that the scatter matrix S can have one or more empty lines and w may be smaller than v.

Note
If v is filled with its indices, i.e. \( v[i] = i \), then the gather operation will reproduce the index map in the buffer w or

\[ \vec{\text{idx}} = G \vec i\]

In case the index map is bijective the index map can be inverted and we have

\[ \vec{\text{idx}^{-1}} = S \vec i\]

This class performs these operations for the case that v and w are distributed across processes. We always assume that the source vector v is distributed equally among processes, i.e. each process holds a chunk of v of equal size. On the other hand the local size of w may vary among processes depending on the gather/scatter map.

Template Parameters
LocalContainera container on a shared memory system (must be default constructible)

Member Typedef Documentation

◆ container_type

template<class LocalContainer >
using dg::aCommunicator< LocalContainer >::container_type = LocalContainer

reveal local container type

◆ value_type

template<class LocalContainer >
using dg::aCommunicator< LocalContainer >::value_type = get_value_type<LocalContainer>

reveal value type

Constructor & Destructor Documentation

◆ ~aCommunicator()

template<class LocalContainer >
virtual dg::aCommunicator< LocalContainer >::~aCommunicator ( )
inlinevirtual

vritual destructor

◆ aCommunicator() [1/2]

template<class LocalContainer >
dg::aCommunicator< LocalContainer >::aCommunicator ( unsigned  local_size = 0)
inlineprotected

only derived classes can construct

Parameters
local_sizethe local size of the source vector v

◆ aCommunicator() [2/2]

template<class LocalContainer >
dg::aCommunicator< LocalContainer >::aCommunicator ( const aCommunicator< LocalContainer > &  src)
inlineprotected

only derived classes can copy

Parameters
srcsource

Member Function Documentation

◆ allocate_buffer()

template<class LocalContainer >
LocalContainer dg::aCommunicator< LocalContainer >::allocate_buffer ( ) const
inline

Allocate a buffer object of size buffer_size()

Returns
a buffer object on the stack
Note
if buffer_size()==0 the default constructor of LocalContainer is called

◆ buffer_size()

template<class LocalContainer >
unsigned dg::aCommunicator< LocalContainer >::buffer_size ( ) const
inline

The local size of the buffer vector w = local map size.

Consider that both the source vector v and the buffer w are distributed across processes. In Feltor the vector v is (usually) distributed equally among processes and the local size of v is the same for all processes. However, the buffer size might be different for each process.

Returns
buffer size (may be different for each process)
Note
may return 0
Attention
it is NOT a good idea to check for zero buffer size if you want to find out whether a given process needs to send MPI messages or not. The first reason is that even if no communication is happening the buffer_size is not zero as there may still be local gather/scatter operations. The right way to do it is to call isCommunicating()
See also
local_size() isCommunicating()

◆ clone()

template<class LocalContainer >
virtual aCommunicator * dg::aCommunicator< LocalContainer >::clone ( ) const
pure virtual

Generic copy method.

Returns
pointer to allocated object

Implemented in dg::BijectiveComm< Index, Vector >, dg::SurjectiveComm< Index, Vector >, and dg::GeneralComm< Index, Vector >.

◆ communicator()

template<class LocalContainer >
MPI_Comm dg::aCommunicator< LocalContainer >::communicator ( ) const
inline

The internal MPI communicator used.

can be e.g. used to assert that communicators of matrix and vector are the same

Returns
MPI Communicator

◆ global_gather() [1/2]

template<class LocalContainer >
LocalContainer dg::aCommunicator< LocalContainer >::global_gather ( const value_type values) const
inline

\( w = G v\). Globally (across processes) gather data into a buffer (memory allocating version)

The transpose operation is global_scatter_reduce()

Parameters
valuessource vector v; data is collected from this vector (must have local_size() elements)
Returns
object of size buffer_size() that holds the gathered data
Note
If !isCommunicating() then this call will not involve MPI communication but will still gather values according to the given index map

◆ global_gather() [2/2]

template<class LocalContainer >
void dg::aCommunicator< LocalContainer >::global_gather ( const value_type values,
LocalContainer &  buffer 
) const
inline

\( w = G v\). Globally (across processes) gather data into a buffer

The transpose operation is global_scatter_reduce()

Parameters
valuessource vector v; data is collected from this vector
bufferon output holds the gathered data ( must be of size buffer_size() )
Note
If !isCommunicating() then this call will not involve MPI communication but will still gather values according to the given index map

◆ global_scatter_reduce()

template<class LocalContainer >
void dg::aCommunicator< LocalContainer >::global_scatter_reduce ( const LocalContainer &  toScatter,
value_type values 
) const
inline

\( v = G^\mathrm{T} w\). Globally (across processes) scatter data accross processes and reduce on multiple indices

This is the transpose operation of global_gather()

Parameters
toScatterbuffer vector w; (has to be of size given by buffer_size() )
valuestarget vector v; on output contains values from other processes sent back to the origin (must have local_size() elements)
Note
If !isCommunicating() then this call will not involve MPI communication but will still scatter and reduce values according to the given index map

◆ isCommunicating()

template<class LocalContainer >
bool dg::aCommunicator< LocalContainer >::isCommunicating ( ) const
inline

True if the gather/scatter operation involves actual MPI communication.

This is more than just a test for zero message size. This is because even if a process has zero message size indicating that it technically does not need to send any data at all it might still need to participate in an MPI communication (sending an empty message to indicate that a certain point in execution has been reached). Only if NONE of the processes in the process group has anything to send will this function return false. This test can be used to avoid the gather operation alltogether in e.g. the construction of a MPI distributed matrix.

Note
this check may involve MPI communication itself, because a process needs to check if itself or any other process in its group is communicating.
Returns
False, if the global gather can be done without MPI communication (i.e. the indices are all local to each calling process), or if the communicator is MPI_COMM_NULL. True else.
See also
buffer_size()

◆ local_size()

template<class LocalContainer >
unsigned dg::aCommunicator< LocalContainer >::local_size ( ) const
inline

The local size of the source vector v = local size of the dg::MPI_Vector

Consider that both the source vector v and the buffer w are distributed across processes. In Feltor the vector v is (usually) distributed equally among processes and the local size of v is the same for all processes.

Returns
local size of v (same for all processes)
Note
Important only for general scatter operations where some elements of v might have to be set to zero
See also
buffer_size()

◆ operator=()

template<class LocalContainer >
aCommunicator & dg::aCommunicator< LocalContainer >::operator= ( const aCommunicator< LocalContainer > &  src)
inlineprotected

only derived classes can assign

Parameters
srcsource
Returns
*this

◆ set_local_size()

template<class LocalContainer >
void dg::aCommunicator< LocalContainer >::set_local_size ( unsigned  new_size)
inlineprotected

Set the local size of the source vector v.

Parameters
new_sizethe new local size for the source vector v

The documentation for this struct was generated from the following file: