libMesh
parallel_algebra.h
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2019 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 #ifndef LIBMESH_PARALLEL_ALGEBRA_H
20 #define LIBMESH_PARALLEL_ALGEBRA_H
21 
22 // This class contains all the functionality for bin sorting
23 // Templated on the type of keys you will be sorting and the
24 // type of iterator you will be using.
25 
26 
27 // libMesh includes
28 #include "libmesh/libmesh_config.h"
29 #include "libmesh/point.h"
30 #include "libmesh/tensor_value.h"
31 #include "libmesh/vector_value.h"
32 #include "libmesh/auto_ptr.h" // libmesh_make_unique
33 
34 // TIMPI includes
35 #include "timpi/op_function.h"
36 #include "timpi/standard_type.h"
37 
38 // C++ includes
39 #include <cstddef>
40 #include <memory>
41 
42 namespace TIMPI {
43 
48 using libMesh::Point;
49 
50 // StandardType<> specializations to return a derived MPI datatype
51 // to handle communication of LIBMESH_DIM-vectors.
52 //
53 // We use MPI_Create_struct here because our vector classes might
54 // have vptrs, and I'd rather not have the datatype break in those
55 // cases.
56 template <typename T>
57 class StandardType<TypeVector<T>> : public DataType
58 {
59 public:
60  explicit
61  StandardType(const TypeVector<T> * example=nullptr) {
62  // We need an example for MPI_Address to use
63  TypeVector<T> * ex;
64  std::unique_ptr<TypeVector<T>> temp;
65  if (example)
66  ex = const_cast<TypeVector<T> *>(example);
67  else
68  {
69  temp = libmesh_make_unique<TypeVector<T>>();
70  ex = temp.get();
71  }
72 
73 #ifdef LIBMESH_HAVE_MPI
74  StandardType<T> T_type(&((*ex)(0)));
75 
76  // We require MPI-2 here:
77  int blocklength = LIBMESH_DIM;
78  MPI_Aint displs, start;
79  MPI_Datatype tmptype, type = T_type;
80 
81  timpi_call_mpi
82  (MPI_Get_address (ex, &start));
83  timpi_call_mpi
84  (MPI_Get_address (&((*ex)(0)), &displs));
85 
86  // subtract off offset to first value from the beginning of the structure
87  displs -= start;
88 
89  // create a prototype structure
90  timpi_call_mpi
91  (MPI_Type_create_struct (1, &blocklength, &displs, &type,
92  &tmptype));
93  timpi_call_mpi
94  (MPI_Type_commit (&tmptype));
95 
96  // resize the structure type to account for padding, if any
97  timpi_call_mpi
98  (MPI_Type_create_resized (tmptype, 0, sizeof(TypeVector<T>),
99  &_datatype));
100 
101  timpi_call_mpi
102  (MPI_Type_commit (&_datatype));
103 
104  timpi_call_mpi
105  (MPI_Type_free (&tmptype));
106 #endif // #ifdef LIBMESH_HAVE_MPI
107  }
108 
109  StandardType(const StandardType<TypeVector<T>> & timpi_mpi_var(t))
110  : DataType()
111  {
112  timpi_call_mpi (MPI_Type_dup (t._datatype, &_datatype));
113  }
114 
115  ~StandardType() { this->free(); }
116 };
117 
118 
119 template <typename T>
120 class StandardType<VectorValue<T>> : public DataType
121 {
122 public:
123  explicit
124  StandardType(const VectorValue<T> * example=nullptr) {
125  // We need an example for MPI_Address to use
126  VectorValue<T> * ex;
127  std::unique_ptr<VectorValue<T>> temp;
128  if (example)
129  ex = const_cast<VectorValue<T> *>(example);
130  else
131  {
132  temp = libmesh_make_unique<VectorValue<T>>();
133  ex = temp.get();
134  }
135 
136 #ifdef LIBMESH_HAVE_MPI
137  StandardType<T> T_type(&((*ex)(0)));
138 
139  int blocklength = LIBMESH_DIM;
140  MPI_Aint displs, start;
141  MPI_Datatype tmptype, type = T_type;
142 
143  timpi_call_mpi
144  (MPI_Get_address (ex, &start));
145  timpi_call_mpi
146  (MPI_Get_address (&((*ex)(0)), &displs));
147 
148  // subtract off offset to first value from the beginning of the structure
149  displs -= start;
150 
151  // create a prototype structure
152  timpi_call_mpi
153  (MPI_Type_create_struct (1, &blocklength, &displs, &type,
154  &tmptype));
155  timpi_call_mpi
156  (MPI_Type_commit (&tmptype));
157 
158  // resize the structure type to account for padding, if any
159  timpi_call_mpi
160  (MPI_Type_create_resized (tmptype, 0,
161  sizeof(VectorValue<T>),
162  &_datatype));
163 
164  timpi_call_mpi
165  (MPI_Type_commit (&_datatype));
166 
167  timpi_call_mpi
168  (MPI_Type_free (&tmptype));
169 #endif // #ifdef LIBMESH_HAVE_MPI
170  }
171 
172  StandardType(const StandardType<VectorValue<T>> & timpi_mpi_var(t))
173  : DataType()
174  {
175 #ifdef LIBMESH_HAVE_MPI
176  timpi_call_mpi (MPI_Type_dup (t._datatype, &_datatype));
177 #endif
178  }
179 
180  ~StandardType() { this->free(); }
181 };
182 
183 
184 template <>
185 class StandardType<Point> : public DataType
186 {
187 public:
188  explicit
189  StandardType(const Point * example=nullptr)
190  {
191  // Prevent unused variable warnings when !LIBMESH_HAVE_MPI
192  libmesh_ignore(example);
193 
194 #ifdef LIBMESH_HAVE_MPI
195 
196  // We need an example for MPI_Address to use
197  Point * ex;
198 
199  std::unique_ptr<Point> temp;
200  if (example)
201  ex = const_cast<Point *>(example);
202  else
203  {
204  temp = libmesh_make_unique<Point>();
205  ex = temp.get();
206  }
207 
208  StandardType<libMesh::Real> T_type(&((*ex)(0)));
209 
210  int blocklength = LIBMESH_DIM;
211  MPI_Aint displs, start;
212  MPI_Datatype tmptype, type = T_type;
213 
214  timpi_call_mpi
215  (MPI_Get_address (ex, &start));
216  timpi_call_mpi
217  (MPI_Get_address (&((*ex)(0)), &displs));
218 
219  // subtract off offset to first value from the beginning of the structure
220  displs -= start;
221 
222  // create a prototype structure
223  timpi_call_mpi
224  (MPI_Type_create_struct (1, &blocklength, &displs, &type,
225  &tmptype));
226  timpi_call_mpi
227  (MPI_Type_commit (&tmptype));
228 
229  // resize the structure type to account for padding, if any
230  timpi_call_mpi
231  (MPI_Type_create_resized (tmptype, 0, sizeof(Point),
232  &_datatype));
233 
234  timpi_call_mpi
235  (MPI_Type_commit (&_datatype));
236 
237  timpi_call_mpi
238  (MPI_Type_free (&tmptype));
239 #endif // #ifdef LIBMESH_HAVE_MPI
240  }
241 
242  StandardType(const StandardType<Point> & timpi_mpi_var(t))
243  : DataType()
244  {
245  timpi_call_mpi (MPI_Type_dup (t._datatype, &_datatype));
246  }
247 
248  ~StandardType() { this->free(); }
249 };
250 
251 
252 // OpFunction<> specializations to return an MPI_Op version of the
253 // reduction operations on LIBMESH_DIM-vectors.
254 //
255 // We use static variables to minimize the number of MPI datatype
256 // construction calls executed over the course of the program.
257 //
258 // We use a singleton pattern because a global variable would
259 // have tried to call MPI functions before MPI got initialized.
260 //
261 // min() and max() are applied component-wise; this makes them useful
262 // for bounding box reduction operations.
263 template <typename V>
265 {
266 public:
267 #ifdef LIBMESH_HAVE_MPI
268  static void vector_max (void * invec, void * inoutvec, int * len, MPI_Datatype *)
269  {
270  V *in = static_cast<V *>(invec);
271  V *inout = static_cast<V *>(inoutvec);
272  for (int i=0; i != *len; ++i)
273  for (int d=0; d != LIBMESH_DIM; ++d)
274  inout[i](d) = std::max(in[i](d), inout[i](d));
275  }
276 
277  static void vector_min (void * invec, void * inoutvec, int * len, MPI_Datatype *)
278  {
279  V *in = static_cast<V *>(invec);
280  V *inout = static_cast<V *>(inoutvec);
281  for (int i=0; i != *len; ++i)
282  for (int d=0; d != LIBMESH_DIM; ++d)
283  inout[i](d) = std::min(in[i](d), inout[i](d));
284  }
285 
286  static void vector_sum (void * invec, void * inoutvec, int * len, MPI_Datatype *)
287  {
288  V *in = static_cast<V *>(invec);
289  V *inout = static_cast<V *>(inoutvec);
290  for (int i=0; i != *len; ++i)
291  for (int d=0; d != LIBMESH_DIM; ++d)
292  inout[i](d) += in[i](d);
293  }
294 
295  static MPI_Op max()
296  {
297  // _static_op never gets freed, but it only gets committed once
298  // per T, so it's not a *huge* memory leak...
299  static MPI_Op _static_op;
300  static bool _is_initialized = false;
301  if (!_is_initialized)
302  {
303  timpi_call_mpi
304  (MPI_Op_create (vector_max, /*commute=*/ true,
305  &_static_op));
306 
307  _is_initialized = true;
308  }
309 
310  return _static_op;
311  }
312  static MPI_Op min()
313  {
314  // _static_op never gets freed, but it only gets committed once
315  // per T, so it's not a *huge* memory leak...
316  static MPI_Op _static_op;
317  static bool _is_initialized = false;
318  if (!_is_initialized)
319  {
320  timpi_call_mpi
321  (MPI_Op_create (vector_min, /*commute=*/ true,
322  &_static_op));
323 
324  _is_initialized = true;
325  }
326 
327  return _static_op;
328  }
329  static MPI_Op sum()
330  {
331  // _static_op never gets freed, but it only gets committed once
332  // per T, so it's not a *huge* memory leak...
333  static MPI_Op _static_op;
334  static bool _is_initialized = false;
335  if (!_is_initialized)
336  {
337  timpi_call_mpi
338  (MPI_Op_create (vector_sum, /*commute=*/ true,
339  &_static_op));
340 
341  _is_initialized = true;
342  }
343 
344  return _static_op;
345  }
346 
347 #endif // LIBMESH_HAVE_MPI
348 };
349 
350 template <typename T>
351 class OpFunction<TypeVector<T>> : public TypeVectorOpFunction<TypeVector<T>> {};
352 
353 template <typename T>
354 class OpFunction<VectorValue<T>> : public TypeVectorOpFunction<VectorValue<T>> {};
355 
356 template <>
357 class OpFunction<Point> : public TypeVectorOpFunction<Point> {};
358 
359 // StandardType<> specializations to return a derived MPI datatype
360 // to handle communication of LIBMESH_DIM*LIBMESH_DIM-tensors.
361 //
362 // We assume contiguous storage here
363 template <typename T>
364 class StandardType<TypeTensor<T>> : public DataType
365 {
366 public:
367  explicit
368  StandardType(const TypeTensor<T> * example=nullptr) :
369  DataType(StandardType<T>(example ? &((*example)(0,0)) : nullptr), LIBMESH_DIM*LIBMESH_DIM) {}
370 
371  inline ~StandardType() { this->free(); }
372 };
373 
374 template <typename T>
375 class StandardType<TensorValue<T>> : public DataType
376 {
377 public:
378  explicit
379  StandardType(const TensorValue<T> * example=nullptr) :
380  DataType(StandardType<T>(example ? &((*example)(0,0)) : nullptr), LIBMESH_DIM*LIBMESH_DIM) {}
381 
382  inline ~StandardType() { this->free(); }
383 };
384 } // namespace TIMPI
385 
386 #endif // LIBMESH_PARALLEL_ALGEBRA_H
TIMPI::StandardType< TypeTensor< T > >::StandardType
StandardType(const TypeTensor< T > *example=nullptr)
Definition: parallel_algebra.h:368
TIMPI::StandardType< TypeVector< T > >::~StandardType
~StandardType()
Definition: parallel_algebra.h:115
TIMPI::TypeVectorOpFunction
Definition: parallel_algebra.h:264
TIMPI::StandardType< TypeVector< T > >::StandardType
StandardType(const TypeVector< T > *example=nullptr)
Definition: parallel_algebra.h:61
TIMPI::TypeVectorOpFunction::min
static MPI_Op min()
Definition: parallel_algebra.h:312
op_function.h
TIMPI::StandardType< TypeTensor< T > >::~StandardType
~StandardType()
Definition: parallel_algebra.h:371
TIMPI::TypeVectorOpFunction::vector_min
static void vector_min(void *invec, void *inoutvec, int *len, MPI_Datatype *)
Definition: parallel_algebra.h:277
libMesh::VectorValue
This class defines a vector in LIBMESH_DIM dimensional Real or Complex space.
Definition: exact_solution.h:54
TIMPI::TypeVectorOpFunction::vector_max
static void vector_max(void *invec, void *inoutvec, int *len, MPI_Datatype *)
Definition: parallel_algebra.h:268
TIMPI::StandardType< VectorValue< T > >::StandardType
StandardType(const StandardType< VectorValue< T >> &timpi_mpi_var(t))
Definition: parallel_algebra.h:172
TIMPI::StandardType< VectorValue< T > >::~StandardType
~StandardType()
Definition: parallel_algebra.h:180
TIMPI::StandardType< TypeVector< T > >::StandardType
StandardType(const StandardType< TypeVector< T >> &timpi_mpi_var(t))
Definition: parallel_algebra.h:109
libMesh::libmesh_ignore
void libmesh_ignore(const Args &...)
Definition: libmesh_common.h:526
libMesh::TensorValue
This class defines a tensor in LIBMESH_DIM dimensional Real or Complex space.
Definition: exact_solution.h:53
libMesh::Point
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:38
TIMPI::TypeVectorOpFunction::sum
static MPI_Op sum()
Definition: parallel_algebra.h:329
TIMPI::StandardType< Point >
Definition: parallel_algebra.h:185
TIMPI::TypeVectorOpFunction::max
static MPI_Op max()
Definition: parallel_algebra.h:295
TIMPI::StandardType< TensorValue< T > >::~StandardType
~StandardType()
Definition: parallel_algebra.h:382
TIMPI::StandardType< TensorValue< T > >::StandardType
StandardType(const TensorValue< T > *example=nullptr)
Definition: parallel_algebra.h:379
TIMPI::TypeVectorOpFunction::vector_sum
static void vector_sum(void *invec, void *inoutvec, int *len, MPI_Datatype *)
Definition: parallel_algebra.h:286
TIMPI::StandardType< Point >::StandardType
StandardType(const Point *example=nullptr)
Definition: parallel_algebra.h:189
standard_type.h
libMesh::libMeshPrivateData::_is_initialized
bool _is_initialized
Flag that tells if init() has been called.
Definition: libmesh.C:246
TIMPI
Definition: libmesh_common.h:664
libMesh::TypeVector
This class defines a vector in LIBMESH_DIM dimensional space of type T.
Definition: tensor_tools.h:45
TIMPI::StandardType< VectorValue< T > >::StandardType
StandardType(const VectorValue< T > *example=nullptr)
Definition: parallel_algebra.h:124
libMesh::TypeTensor
This class defines a tensor in LIBMESH_DIM dimensional space of type T.
Definition: tensor_tools.h:47
TIMPI::StandardType< Point >::~StandardType
~StandardType()
Definition: parallel_algebra.h:248
TIMPI::StandardType< Point >::StandardType
StandardType(const StandardType< Point > &timpi_mpi_var(t))
Definition: parallel_algebra.h:242