$extrastylesheet
parallel_algebra.h
Go to the documentation of this file.
00001 // The libMesh Finite Element Library.
00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
00003 
00004 // This library is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU Lesser General Public
00006 // License as published by the Free Software Foundation; either
00007 // version 2.1 of the License, or (at your option) any later version.
00008 
00009 // This library is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 // Lesser General Public License for more details.
00013 
00014 // You should have received a copy of the GNU Lesser General Public
00015 // License along with this library; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018 
00019 #ifndef LIBMESH_PARALLEL_ALGEBRA_H
00020 #define LIBMESH_PARALLEL_ALGEBRA_H
00021 
00022 // This class contains all the functionality for bin sorting
00023 // Templated on the type of keys you will be sorting and the
00024 // type of iterator you will be using.
00025 
00026 
00027 // Local Includes
00028 #include "libmesh/libmesh_config.h"
00029 
00030 #include "libmesh/auto_ptr.h"
00031 #include "libmesh/parallel.h"
00032 #include "libmesh/point.h"
00033 #include "libmesh/tensor_value.h"
00034 #include "libmesh/vector_value.h"
00035 
00036 // C++ includes
00037 #include <cstddef>
00038 
00039 namespace libMesh {
00040 namespace Parallel {
00041 // StandardType<> specializations to return a derived MPI datatype
00042 // to handle communication of LIBMESH_DIM-vectors.
00043 //
00044 // We use static variables to minimize the number of MPI datatype
00045 // construction calls executed over the course of the program.
00046 //
00047 // We use a singleton pattern because a global variable would
00048 // have tried to call MPI functions before MPI got initialized.
00049 //
00050 // We use MPI_Create_struct here because our vector classes might
00051 // have vptrs, and I'd rather not have the datatype break in those
00052 // cases.
00053 template <typename T>
00054 class StandardType<TypeVector<T> > : public DataType
00055 {
00056 public:
00057   explicit
00058   StandardType(const TypeVector<T> *example=NULL) {
00059     // We need an example for MPI_Address to use
00060     TypeVector<T> *ex;
00061     UniquePtr<TypeVector<T> > temp;
00062     if (example)
00063       ex = const_cast<TypeVector<T> *>(example);
00064     else
00065       {
00066         temp.reset(new TypeVector<T>());
00067         ex = temp.get();
00068       }
00069 
00070     // _static_type never gets freed, but it only gets committed once
00071     // per T, so it's not a *huge* memory leak...
00072     static data_type _static_type;
00073     static bool _is_initialized = false;
00074     if (!_is_initialized)
00075       {
00076 #ifdef LIBMESH_HAVE_MPI
00077         StandardType<T> T_type(&((*ex)(0)));
00078 
00079 #if MPI_VERSION == 1
00080 
00081         int blocklengths[LIBMESH_DIM+2];
00082         MPI_Aint displs[LIBMESH_DIM+2];
00083         MPI_Datatype types[LIBMESH_DIM+2];
00084         MPI_Aint start, later;
00085 
00086         MPI_Address(ex, &start);
00087         blocklengths[0] = 1;
00088         displs[0] = 0;
00089         types[0] = MPI_LB;
00090         for (unsigned int i=0; i != LIBMESH_DIM; ++i)
00091           {
00092             MPI_Address(&((*ex)(i)), &later);
00093             blocklengths[i+1] = 1;
00094             displs[i+1] = later - start;
00095             types[i+1] = T_type;
00096           }
00097         MPI_Address((ex+1), &later);
00098         blocklengths[LIBMESH_DIM+1] = 1;
00099         displs[LIBMESH_DIM+1] = later - start;
00100         types[LIBMESH_DIM+1] = MPI_UB;
00101 
00102         MPI_Type_struct (LIBMESH_DIM+2, blocklengths, displs, types, &_static_type);
00103 
00104 #else // MPI_VERSION >= 2
00105 
00106         int blocklength = LIBMESH_DIM;
00107         MPI_Aint displs, start;
00108         MPI_Datatype tmptype, type = T_type;
00109 
00110         MPI_Get_address (ex,   &start);
00111         MPI_Get_address (&((*ex)(0)), &displs);
00112 
00113         // subtract off offset to first value from the beginning of the structure
00114         displs -= start;
00115 
00116         // create a prototype structure
00117         MPI_Type_create_struct (1, &blocklength, &displs, &type, &tmptype);
00118 
00119         // resize the structure type to account for padding, if any
00120         MPI_Type_create_resized (tmptype, 0, sizeof(TypeVector<T>), &_static_type);
00121 #endif
00122 
00123         MPI_Type_commit (&_static_type);
00124 #endif // #ifdef LIBMESH_HAVE_MPI
00125 
00126         _is_initialized = true;
00127       }
00128     _datatype = _static_type;
00129   }
00130 };
00131 
00132 template <typename T>
00133 class StandardType<VectorValue<T> > : public DataType
00134 {
00135 public:
00136   explicit
00137   StandardType(const VectorValue<T> *example=NULL) {
00138     // We need an example for MPI_Address to use
00139     VectorValue<T> *ex;
00140     UniquePtr<VectorValue<T> > temp;
00141     if (example)
00142       ex = const_cast<VectorValue<T> *>(example);
00143     else
00144       {
00145         temp.reset(new VectorValue<T>());
00146         ex = temp.get();
00147       }
00148 
00149     // _static_type never gets freed, but it only gets committed once
00150     // per T, so it's not a *huge* memory leak...
00151     static data_type _static_type;
00152     static bool _is_initialized = false;
00153     if (!_is_initialized)
00154       {
00155 #ifdef LIBMESH_HAVE_MPI
00156         StandardType<T> T_type(&((*ex)(0)));
00157 
00158 #if MPI_VERSION == 1
00159 
00160         int blocklengths[LIBMESH_DIM+2];
00161         MPI_Aint displs[LIBMESH_DIM+2];
00162         MPI_Datatype types[LIBMESH_DIM+2];
00163         MPI_Aint start, later;
00164 
00165         MPI_Address(ex, &start);
00166         blocklengths[0] = 1;
00167         displs[0] = 0;
00168         types[0] = MPI_LB;
00169         for (unsigned int i=0; i != LIBMESH_DIM; ++i)
00170           {
00171             MPI_Address(&((*ex)(i)), &later);
00172             blocklengths[i+1] = 1;
00173             displs[i+1] = later - start;
00174             types[i+1] = T_type;
00175           }
00176         MPI_Address((ex+1), &later);
00177         blocklengths[LIBMESH_DIM+1] = 1;
00178         displs[LIBMESH_DIM+1] = later - start;
00179         types[LIBMESH_DIM+1] = MPI_UB;
00180 
00181         MPI_Type_struct (LIBMESH_DIM+2, blocklengths, displs, types, &_static_type);
00182 
00183 #else // MPI_VERSION >= 2
00184 
00185         int blocklength = LIBMESH_DIM;
00186         MPI_Aint displs, start;
00187         MPI_Datatype tmptype, type = T_type;
00188 
00189         MPI_Get_address (ex,   &start);
00190         MPI_Get_address (&((*ex)(0)), &displs);
00191 
00192         // subtract off offset to first value from the beginning of the structure
00193         displs -= start;
00194 
00195         // create a prototype structure
00196         MPI_Type_create_struct (1, &blocklength, &displs, &type, &tmptype);
00197 
00198         // resize the structure type to account for padding, if any
00199         MPI_Type_create_resized (tmptype, 0, sizeof(VectorValue<T>), &_static_type);
00200 #endif
00201 
00202         MPI_Type_commit (&_static_type);
00203 #endif // #ifdef LIBMESH_HAVE_MPI
00204 
00205         _is_initialized = true;
00206       }
00207     _datatype = _static_type;
00208   }
00209 };
00210 
00211 template <>
00212 class StandardType<Point> : public DataType
00213 {
00214 public:
00215   explicit
00216   StandardType(const Point *example=NULL)
00217   {
00218     // Prevent unused variable warnings when !LIBMESH_HAVE_MPI
00219     libmesh_ignore(example);
00220 
00221     // _static_type never gets freed, but it only gets committed once
00222     // per T, so it's not a *huge* memory leak...
00223     static data_type _static_type;
00224     static bool _is_initialized = false;
00225     if (!_is_initialized)
00226       {
00227 #ifdef LIBMESH_HAVE_MPI
00228 
00229         // We need an example for MPI_Address to use
00230         Point *ex;
00231 
00232         UniquePtr<Point> temp;
00233         if (example)
00234           ex = const_cast<Point *>(example);
00235         else
00236           {
00237             temp.reset(new Point());
00238             ex = temp.get();
00239           }
00240 
00241         StandardType<Real> T_type(&((*ex)(0)));
00242 
00243 #if MPI_VERSION == 1
00244 
00245         int blocklengths[LIBMESH_DIM+2];
00246         MPI_Aint displs[LIBMESH_DIM+2];
00247         MPI_Datatype types[LIBMESH_DIM+2];
00248         MPI_Aint start, later;
00249 
00250         MPI_Address(ex, &start);
00251         blocklengths[0] = 1;
00252         displs[0] = 0;
00253         types[0] = MPI_LB;
00254         for (unsigned int i=0; i != LIBMESH_DIM; ++i)
00255           {
00256             MPI_Address(&((*ex)(i)), &later);
00257             blocklengths[i+1] = 1;
00258             displs[i+1] = later - start;
00259             types[i+1] = T_type;
00260           }
00261         MPI_Address((ex+1), &later);
00262         blocklengths[LIBMESH_DIM+1] = 1;
00263         displs[LIBMESH_DIM+1] = later - start;
00264         types[LIBMESH_DIM+1] = MPI_UB;
00265 
00266         MPI_Type_struct (LIBMESH_DIM+2, blocklengths, displs, types, &_static_type);
00267 
00268 #else // MPI_VERSION >= 2
00269 
00270         int blocklength = LIBMESH_DIM;
00271         MPI_Aint displs, start;
00272         MPI_Datatype tmptype, type = T_type;
00273 
00274         MPI_Get_address (ex,   &start);
00275         MPI_Get_address (&((*ex)(0)), &displs);
00276 
00277         // subtract off offset to first value from the beginning of the structure
00278         displs -= start;
00279 
00280         // create a prototype structure
00281         MPI_Type_create_struct (1, &blocklength, &displs, &type, &tmptype);
00282 
00283         // resize the structure type to account for padding, if any
00284         MPI_Type_create_resized (tmptype, 0, sizeof(Point), &_static_type);
00285 #endif
00286 
00287         MPI_Type_commit (&_static_type);
00288 #endif // #ifdef LIBMESH_HAVE_MPI
00289 
00290         _is_initialized = true;
00291       }
00292     _datatype = _static_type;
00293   }
00294 };
00295 
00296 // StandardType<> specializations to return a derived MPI datatype
00297 // to handle communication of LIBMESH_DIM*LIBMESH_DIM-tensors.
00298 //
00299 // We use a singleton pattern here because a global variable would
00300 // have tried to call MPI functions before MPI got initialized.
00301 //
00302 // We assume contiguous storage here
00303 template <typename T>
00304 class StandardType<TypeTensor<T> > : public DataType
00305 {
00306 public:
00307   explicit
00308   StandardType(const TypeTensor<T> *example=NULL) :
00309     DataType(StandardType<T>(example ?  &((*example)(0,0)) : NULL), LIBMESH_DIM*LIBMESH_DIM) {}
00310 
00311   inline ~StandardType() { this->free(); }
00312 };
00313 
00314 template <typename T>
00315 class StandardType<TensorValue<T> > : public DataType
00316 {
00317 public:
00318   explicit
00319   StandardType(const TensorValue<T> *example=NULL) :
00320     DataType(StandardType<T>(example ?  &((*example)(0,0)) : NULL), LIBMESH_DIM*LIBMESH_DIM) {}
00321 
00322   inline ~StandardType() { this->free(); }
00323 };
00324 } // namespace Parallel
00325 } // namespace libMesh
00326 
00327 #endif // LIBMESH_PARALLEL_ALGEBRA_H