GEOS
MpiWrapper.hpp
Go to the documentation of this file.
1 /*
2  * ------------------------------------------------------------------------------------------------------------
3  * SPDX-License-Identifier: LGPL-2.1-only
4  *
5  * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
6  * Copyright (c) 2018-2024 TotalEnergies
7  * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University
8  * Copyright (c) 2023-2024 Chevron
9  * Copyright (c) 2019- GEOS/GEOSX Contributors
10  * All rights reserved
11  *
12  * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details.
13  * ------------------------------------------------------------------------------------------------------------
14  */
15 
20 #ifndef GEOS_COMMON_MPIWRAPPER_HPP_
21 #define GEOS_COMMON_MPIWRAPPER_HPP_
22 
23 #include "common/DataTypes.hpp"
24 #include "common/Span.hpp"
25 #include "common/TypesHelpers.hpp"
26 
27 #include <numeric>
28 
29 #if defined(GEOS_USE_MPI)
30  #include <mpi.h>
31 #define MPI_PARAM( x ) x
32 #else
33 #define MPI_PARAM( x )
34 typedef int MPI_Comm;
35 
36 #define MPI_COMM_NULL ((MPI_Comm)0x04000000)
37 #define MPI_COMM_WORLD ((MPI_Comm)0x44000000)
38 #define MPI_COMM_SELF ((MPI_Comm)0x40000000)
39 
40 
41 typedef int MPI_Datatype;
42 #define MPI_CHAR ((MPI_Datatype)0x4c000101)
43 #define MPI_SIGNED_CHAR ((MPI_Datatype)0x4c000118)
44 #define MPI_UNSIGNED_CHAR ((MPI_Datatype)0x4c000102)
45 #define MPI_BYTE ((MPI_Datatype)0x4c00010d)
46 #define MPI_C_BOOL ((MPI_Datatype)0x4c00013f)
47 #define MPI_WCHAR ((MPI_Datatype)0x4c00040e)
48 #define MPI_SHORT ((MPI_Datatype)0x4c000203)
49 #define MPI_UNSIGNED_SHORT ((MPI_Datatype)0x4c000204)
50 #define MPI_INT ((MPI_Datatype)0x4c000405)
51 #define MPI_UNSIGNED ((MPI_Datatype)0x4c000406)
52 #define MPI_LONG ((MPI_Datatype)0x4c000807)
53 #define MPI_UNSIGNED_LONG ((MPI_Datatype)0x4c000808)
54 #define MPI_FLOAT ((MPI_Datatype)0x4c00040a)
55 #define MPI_DOUBLE ((MPI_Datatype)0x4c00080b)
56 #define MPI_LONG_DOUBLE ((MPI_Datatype)0x4c00100c)
57 #define MPI_LONG_LONG_INT ((MPI_Datatype)0x4c000809)
58 #define MPI_UNSIGNED_LONG_LONG ((MPI_Datatype)0x4c000819)
59 #define MPI_LONG_LONG MPI_LONG_LONG_INT
60 
61 typedef int MPI_Op;
62 
63 #define MPI_MAX (MPI_Op)(0x58000001)
64 #define MPI_MIN (MPI_Op)(0x58000002)
65 #define MPI_SUM (MPI_Op)(0x58000003)
66 #define MPI_PROD (MPI_Op)(0x58000004)
67 #define MPI_LAND (MPI_Op)(0x58000005)
68 #define MPI_BAND (MPI_Op)(0x58000006)
69 #define MPI_LOR (MPI_Op)(0x58000007)
70 #define MPI_BOR (MPI_Op)(0x58000008)
71 #define MPI_LXOR (MPI_Op)(0x58000009)
72 #define MPI_BXOR (MPI_Op)(0x5800000a)
73 #define MPI_MINLOC (MPI_Op)(0x5800000b)
74 #define MPI_MAXLOC (MPI_Op)(0x5800000c)
75 #define MPI_REPLACE (MPI_Op)(0x5800000d)
76 #define MPI_NO_OP (MPI_Op)(0x5800000e)
77 
78 #define MPI_SUCCESS 0 /* Successful return code */
79 #define MPI_UNDEFINED (-32766)
80 #define MPI_STATUS_IGNORE (MPI_Status *)1
81 #define MPI_STATUSES_IGNORE (MPI_Status *)1
82 #define MPI_REQUEST_NULL ((MPI_Request)0x2c000000)
83 typedef int MPI_Request;
84 
85 typedef int MPI_Info;
86 #define MPI_INFO_NULL (MPI_Info)(0x60000000)
87 
88 struct MPI_Status
89 {
90  int junk;
91 };
92 
93 #endif
94 
95 #if defined(NDEBUG)
96 #define MPI_CHECK_ERROR( error ) ((void) error)
97 #else
98 #define MPI_CHECK_ERROR( error ) GEOS_ERROR_IF_NE( error, MPI_SUCCESS );
99 #endif
100 
101 
102 namespace geos
103 {
104 
106 #ifdef GEOS_USE_MPI
107 extern MPI_Comm MPI_COMM_GEOS;
108 #else
109 extern int MPI_COMM_GEOS;
110 #endif
111 
122 {
123 public:
124 
129  enum class Reduction
130  {
131  Max,
132  Min,
133  Sum,
134  Prod,
135  LogicalAnd,
136  LogicalOr,
137  };
138 
143  enum class PairReduction
144  {
145  Max,
146  Min,
147  };
148 
154  template< typename FIRST, typename SECOND >
155  struct PairType
156  {
157  FIRST first;
158  SECOND second;
159  };
160 
161  MpiWrapper() = delete;
162 
176 
177  static void barrier( MPI_Comm const & MPI_PARAM( comm )=MPI_COMM_GEOS );
178 
179  static int cartCoords( MPI_Comm comm, int rank, int maxdims, int coords[] );
180 
181  static int cartCreate( MPI_Comm comm_old, int ndims, const int dims[], const int periods[],
182  int reorder, MPI_Comm * comm_cart );
183 
184  static int cartRank( MPI_Comm comm, const int coords[] );
185 
186  static void commFree( MPI_Comm & comm );
187 
188  static int commRank( MPI_Comm const & MPI_PARAM( comm )=MPI_COMM_GEOS );
189 
190  static int commSize( MPI_Comm const & MPI_PARAM( comm )=MPI_COMM_GEOS );
191 
192  static bool commCompare( MPI_Comm const & comm1, MPI_Comm const & comm2 );
193 
194  static bool initialized();
195 
196  static int init( int * argc, char * * * argv );
197 
202  static void finalize();
203 
204  static MPI_Comm commDup( MPI_Comm const comm );
205 
206  static MPI_Comm commSplit( MPI_Comm const comm, int color, int key );
207 
208  static int test( MPI_Request * request, int * flag, MPI_Status * status );
209 
210  static int testAny( int count, MPI_Request array_of_requests[], int * idx, int * flags, MPI_Status array_of_statuses[] );
211 
212  static int testSome( int count, MPI_Request array_of_requests[], int * outcount, int array_of_indices[], MPI_Status array_of_statuses[] );
213 
214  static int testAll( int count, MPI_Request array_of_requests[], int * flags, MPI_Status array_of_statuses[] );
215 
222  static int check( MPI_Request * request, int * flag, MPI_Status * status );
223 
236  static int checkAny( int count, MPI_Request array_of_requests[], int * idx, int * flag, MPI_Status array_of_statuses[] );
237 
247  static int checkAll( int count, MPI_Request array_of_requests[], int * flag, MPI_Status array_of_statuses[] );
248 
249  static int wait( MPI_Request * request, MPI_Status * status );
250 
251  static int waitAny( int count, MPI_Request array_of_requests[], int * indx, MPI_Status array_of_statuses[] );
252 
253  static int waitSome( int count, MPI_Request array_of_requests[], int * outcount, int array_of_indices[], MPI_Status array_of_statuses[] );
254 
255  static int waitAll( int count, MPI_Request array_of_requests[], MPI_Status array_of_statuses[] );
256 
257  static double wtime( void );
258 
259 
269  static int activeWaitAny( const int count,
270  MPI_Request array_of_requests[],
271  MPI_Status array_of_statuses[],
272  std::function< MPI_Request ( int ) > func );
273 
283  static int activeWaitSome( const int count,
284  MPI_Request array_of_requests[],
285  MPI_Status array_of_statuses[],
286  std::function< MPI_Request ( int ) > func );
287 
300  static int activeWaitSomeCompletePhase( const int participants,
301  stdVector< std::tuple< MPI_Request *, MPI_Status *, std::function< MPI_Request ( int ) > > > const & phases );
302 
316  static int activeWaitOrderedCompletePhase( const int participants,
317  stdVector< std::tuple< MPI_Request *, MPI_Status *, std::function< MPI_Request ( int ) > > > const & phases );
319 
320 #if !defined(GEOS_USE_MPI)
321  static stdMap< int, std::pair< int, void * > > & getTagToPointersMap()
322  {
323  static stdMap< int, std::pair< int, void * > > tagToPointers;
324  return tagToPointers;
325  }
326 #endif
327 
332  static int nodeCommSize();
333 
339  template< typename CONTAINER >
341  {
342  // Collected data which must be trivially copyable
343  CONTAINER data;
344  // Number of elements per rank
345  stdVector< integer > counts;
346  // Starting index for each rank in 'data'
347  stdVector< integer > offsets;
348  };
349 
360  template<
361  typename CONTAINER,
362  typename VALUE_T = typename CONTAINER::value_type,
363  typename = std::enable_if_t<
364  std::is_trivially_copyable_v< VALUE_T > &&
365  std::is_same_v< decltype(std::declval< CONTAINER >().data()), VALUE_T * > &&
366  std::is_same_v< decltype(std::declval< CONTAINER >().size()), std::size_t >
367  >
368  >
370  gatherBufferRank0( CONTAINER const & localBuffer );
371 
379  std::function< void(string_view) > && func );
380 
392  template< typename T_SEND, typename T_RECV >
393  static int allgather( T_SEND const * sendbuf,
394  int sendcount,
395  T_RECV * recvbuf,
396  int recvcount,
397  MPI_Comm comm = MPI_COMM_GEOS );
398 
411  template< typename T_SEND, typename T_RECV >
412  static int allgatherv( T_SEND const * sendbuf,
413  int sendcount,
414  T_RECV * recvbuf,
415  int * recvcounts,
416  int * displacements,
417  MPI_Comm comm = MPI_COMM_GEOS );
418 
425  template< typename T >
426  static void allGather( T const myValue, array1d< T > & allValues, MPI_Comm comm = MPI_COMM_GEOS );
427 
428  template< typename T >
429  static int allGather( arrayView1d< T const > const & sendbuf,
430  array1d< T > & recvbuf,
431  MPI_Comm comm = MPI_COMM_GEOS );
432 
433  template< typename T >
434  static int allGatherv( arrayView1d< T const > const & sendbuf,
435  array1d< T > & recvbuf,
436  MPI_Comm comm = MPI_COMM_GEOS );
437 
446  template< typename T >
447  static T allReduce( T const & value, Reduction const op, MPI_Comm comm = MPI_COMM_GEOS );
448 
457  template< typename T >
458  static void allReduce( Span< T const > src, Span< T > dst, Reduction const op, MPI_Comm comm = MPI_COMM_GEOS );
459 
468  template< typename SRC_CONTAINER_TYPE, typename DST_CONTAINER_TYPE >
469  static void allReduce( SRC_CONTAINER_TYPE const & src, DST_CONTAINER_TYPE & dst, Reduction const op, MPI_Comm const comm = MPI_COMM_GEOS );
470 
480  template< typename SRC_CONTAINER_TYPE, typename DST_CONTAINER_TYPE >
481  static void allReduce( SRC_CONTAINER_TYPE const & src, DST_CONTAINER_TYPE & dst, int const count, Reduction const op, MPI_Comm const comm );
482 
492  template< typename FIRST, typename SECOND, PairReduction OP >
494  MPI_Comm comm = MPI_COMM_GEOS );
495 
506  template< typename FIRST, typename SECOND, typename CONTAINER, PairReduction OP >
507  static PairType< FIRST, SECOND > allReduce( CONTAINER const & pairs,
508  MPI_Comm comm = MPI_COMM_GEOS );
509 
519  template< typename T >
520  static int reduce( T const * sendbuf, T * recvbuf, int count, MPI_Op op, int root, MPI_Comm comm = MPI_COMM_GEOS );
521 
530  template< typename T >
531  static T reduce( T const & value, Reduction const op, int root, MPI_Comm comm = MPI_COMM_GEOS );
532 
541  template< typename T >
542  static void reduce( Span< T const > src, Span< T > dst, Reduction const op, int root, MPI_Comm comm = MPI_COMM_GEOS );
543 
544 
545  template< typename T >
546  static int scan( T const * sendbuf, T * recvbuf, int count, MPI_Op op, MPI_Comm comm = MPI_COMM_GEOS );
547 
548  template< typename T >
549  static int exscan( T const * sendbuf, T * recvbuf, int count, MPI_Op op, MPI_Comm comm = MPI_COMM_GEOS );
550 
559  template< typename T >
560  static int bcast( T * buffer, int count, int root, MPI_Comm comm = MPI_COMM_GEOS );
561 
562 
569  template< typename T >
570  static void broadcast( T & value, int srcRank = 0, MPI_Comm comm = MPI_COMM_GEOS );
571 
584  template< typename TS, typename TR >
585  static int gather( TS const * const sendbuf,
586  int sendcount,
587  TR * const recvbuf,
588  int recvcount,
589  int root,
590  MPI_Comm comm = MPI_COMM_GEOS );
591 
603  template< typename T, typename DST_CONTAINER,
604  typename = std::enable_if_t<
605  std::is_trivially_copyable_v< T > &&
606  std::is_same_v< decltype(std::declval< DST_CONTAINER >().size()), std::size_t > &&
607  std::is_same_v< decltype(std::declval< DST_CONTAINER >().data()), T * > > >
608  static int gather( T const & value,
609  DST_CONTAINER & destValuesBuffer,
610  int root,
611  MPI_Comm comm = MPI_COMM_GEOS );
612 
627  template< typename TS, typename TR >
628  static int gatherv( TS const * const sendbuf,
629  int sendcount,
630  TR * const recvbuf,
631  const int * recvcounts,
632  const int * displs,
633  int root,
634  MPI_Comm comm = MPI_COMM_GEOS );
635 
636 
649  template< typename TS, typename TR >
650  static int scatter( TS const * const sendbuf,
651  int sendcount,
652  TR * const recvbuf,
653  int recvcount,
654  int root,
655  MPI_Comm comm = MPI_COMM_GEOS );
656 
671  template< typename TS, typename TR >
672  static int scatterv( TS const * const sendbuf,
673  const int * sendcounts,
674  const int * displs,
675  TR * const recvbuf,
676  int recvcount,
677  int root,
678  MPI_Comm comm = MPI_COMM_GEOS );
679 
680 
681 
687  static MPI_Op getMpiOp( Reduction const op );
688 
689  template< typename T >
690  static int recv( array1d< T > & buf,
691  int MPI_PARAM( source ),
692  int tag,
693  MPI_Comm MPI_PARAM( comm ),
694  MPI_Status * MPI_PARAM( request ) );
695 
696  template< typename T >
697  static int iSend( arrayView1d< T > const & buf,
698  int MPI_PARAM( dest ),
699  int tag,
700  MPI_Comm MPI_PARAM( comm ),
701  MPI_Request * MPI_PARAM( request ) );
702 
713  template< typename T >
714  static int iRecv( T * const buf,
715  int count,
716  int source,
717  int tag,
718  MPI_Comm comm,
719  MPI_Request * request );
720 
730  template< typename T >
731  static int send( T const * const buf,
732  int count,
733  int dest,
734  int tag,
735  MPI_Comm comm );
736 
747  template< typename T >
748  static int iSend( T const * const buf,
749  int count,
750  int dest,
751  int tag,
752  MPI_Comm comm,
753  MPI_Request * request );
754 
762  template< typename U, typename T >
763  static U prefixSum( T const value, MPI_Comm comm = MPI_COMM_GEOS );
764 
770  template< typename T >
771  static T sum( T const & value, MPI_Comm comm = MPI_COMM_GEOS );
772 
779  template< typename T >
780  static void sum( Span< T const > src, Span< T > dst, MPI_Comm comm = MPI_COMM_GEOS );
781 
787  template< typename T >
788  static T min( T const & value, MPI_Comm comm = MPI_COMM_GEOS );
789 
796  template< typename T >
797  static void min( Span< T const > src, Span< T > dst, MPI_Comm comm = MPI_COMM_GEOS );
798 
805  template< typename FIRST, typename SECOND >
806  static PairType< FIRST, SECOND > min( PairType< FIRST, SECOND > const & pair, MPI_Comm comm = MPI_COMM_GEOS );
807 
814  template< typename FIRST, typename SECOND, typename CONTAINER >
815  static PairType< FIRST, SECOND > min( CONTAINER const & pairs, MPI_Comm comm = MPI_COMM_GEOS );
816 
822  template< typename T >
823  static T max( T const & value, MPI_Comm comm = MPI_COMM_GEOS );
824 
831  template< typename T >
832  static void max( Span< T const > src, Span< T > dst, MPI_Comm comm = MPI_COMM_GEOS );
833 
840  template< typename FIRST, typename SECOND >
841  static PairType< FIRST, SECOND > max( PairType< FIRST, SECOND > const & pair, MPI_Comm comm = MPI_COMM_GEOS );
842 
849  template< typename FIRST, typename SECOND, typename CONTAINER >
850  static PairType< FIRST, SECOND > max( CONTAINER const & pairs, MPI_Comm comm = MPI_COMM_GEOS );
851 
852 private:
853 
863  template< typename T >
864  static int allReduce( T const * sendbuf, T * recvbuf, int count, MPI_Op op, MPI_Comm comm = MPI_COMM_GEOS );
865 };
866 
867 namespace internal
868 {
869 
871 struct ManagedResources
872 {
873  // The list of managed MPI_Op instances
874  std::set< MPI_Op > m_mpiOps;
875 
876  // The list of managed MPI_Type instances
877  std::set< MPI_Datatype > m_mpiTypes;
878 
883  void finalize();
884 };
885 
890 ManagedResources & getManagedResources();
891 
892 template< typename T, typename ENABLE = void >
893 struct MpiTypeImpl {};
894 
895 #define ADD_MPI_TYPE_MAP( T, MPI_T ) \
896  template<> struct MpiTypeImpl< T > { static MPI_Datatype get() { return MPI_T; } }
897 
898 ADD_MPI_TYPE_MAP( float, MPI_FLOAT );
899 ADD_MPI_TYPE_MAP( double, MPI_DOUBLE );
900 
901 ADD_MPI_TYPE_MAP( char, MPI_CHAR );
902 ADD_MPI_TYPE_MAP( signed char, MPI_SIGNED_CHAR );
903 ADD_MPI_TYPE_MAP( unsigned char, MPI_UNSIGNED_CHAR );
904 
905 ADD_MPI_TYPE_MAP( int, MPI_INT );
906 ADD_MPI_TYPE_MAP( long int, MPI_LONG );
907 ADD_MPI_TYPE_MAP( long long int, MPI_LONG_LONG );
908 
909 ADD_MPI_TYPE_MAP( unsigned int, MPI_UNSIGNED );
910 ADD_MPI_TYPE_MAP( unsigned long int, MPI_UNSIGNED_LONG );
911 ADD_MPI_TYPE_MAP( unsigned long long int, MPI_UNSIGNED_LONG_LONG );
912 
913 #undef ADD_MPI_TYPE_MAP
914 
915 template< typename T >
916 struct MpiTypeImpl< T, std::enable_if_t< std::is_enum< T >::value > >
917 {
918  static MPI_Datatype get() { return MpiTypeImpl< std::underlying_type_t< T > >::get(); }
919 };
920 
921 template<>
922 struct MpiTypeImpl< bool * >
923 {
924  static MPI_Datatype get()
925  {
926  // Return the appropriate MPI_Datatype for bool*
927  return MPI_C_BOOL;
928  }
929 };
930 
931 
932 template< typename T >
933 MPI_Datatype getMpiType()
934 {
935  return MpiTypeImpl< T >::get();
936 }
937 
938 template< typename FIRST, typename SECOND >
939 MPI_Datatype getMpiPairType()
940 {
941  static_assert( "no default implementation, please add a template specialization and add it in the \"testMpiWrapper\" unit test." );
942  return {};
943 }
944 template<> MPI_Datatype getMpiPairType< int, int >();
945 template<> MPI_Datatype getMpiPairType< long int, int >();
946 template<> MPI_Datatype getMpiPairType< long int, long int >();
947 template<> MPI_Datatype getMpiPairType< long long int, long long int >();
948 template<> MPI_Datatype getMpiPairType< float, int >();
949 template<> MPI_Datatype getMpiPairType< double, int >();
950 template<> MPI_Datatype getMpiPairType< double, long int >();
951 template<> MPI_Datatype getMpiPairType< double, long long int >();
952 template<> MPI_Datatype getMpiPairType< double, double >();
953 
954 // It is advised to always use this custom operator for pairs as MPI_MAXLOC is not a true lexicographical comparator.
955 template< typename FIRST, typename SECOND, MpiWrapper::PairReduction OP >
956 MPI_Op getMpiPairReductionOp()
957 {
958  static auto const createOpHolder = [] () {
959  using PAIR_T = MpiWrapper::PairType< FIRST, SECOND >;
960 
961  auto const customOpFunc =
962  []( void * invec, void * inoutvec, int * len, MPI_Datatype * )
963  {
964  for( int i = 0; i < *len; ++i )
965  {
966  PAIR_T & in = static_cast< PAIR_T * >(invec)[i];
967  PAIR_T & inout = static_cast< PAIR_T * >(inoutvec)[i];
968  if constexpr ( OP == MpiWrapper::PairReduction::Min )
969  {
970  if( std::tie( in.first, in.second ) < std::tie( inout.first, inout.second ) )
971  inout = in;
972  }
973  else
974  {
975  if( std::tie( in.first, in.second ) > std::tie( inout.first, inout.second ) )
976  inout = in;
977  }
978  }
979  };
980 
981  MPI_Op mpiOp;
982  GEOS_ERROR_IF_NE( MPI_Op_create( customOpFunc, 1, &mpiOp ), MPI_SUCCESS );
983  // Resource registered to be destroyed at MpiWrapper::finalize().
984  internal::getManagedResources().m_mpiOps.emplace( mpiOp );
985  return mpiOp;
986  };
987  // Static storage to ensure the MPI operation is created only once and reused for all calls to this function.
988  static MPI_Op mpiOp{ createOpHolder() };
989  return mpiOp;
990 }
991 
992 }
993 
994 inline MPI_Op MpiWrapper::getMpiOp( Reduction const op )
995 {
996  switch( op )
997  {
998  case Reduction::Sum:
999  {
1000  return MPI_SUM;
1001  }
1002  case Reduction::Min:
1003  {
1004  return MPI_MIN;
1005  }
1006  case Reduction::Max:
1007  {
1008  return MPI_MAX;
1009  }
1010  case Reduction::Prod:
1011  {
1012  return MPI_PROD;
1013  }
1014  case Reduction::LogicalAnd:
1015  {
1016  return MPI_LAND;
1017  }
1018  case Reduction::LogicalOr:
1019  {
1020  return MPI_LOR;
1021  }
1022  default:
1023  GEOS_ERROR( "Unsupported reduction operation" );
1024  return MPI_NO_OP;
1025  }
1026 }
1027 
1028 template< typename CONTAINER, typename VALUE_T, typename >
1030 MpiWrapper::gatherBufferRank0( CONTAINER const & localBuffer )
1031 {
1032  integer const numRanks = MpiWrapper::commSize();
1033  integer const numLocalValues = static_cast< integer >(localBuffer.size());
1034 
1035  GatherResult< CONTAINER > gatherResult;
1036 
1037  if( MpiWrapper::commRank() == 0 )
1038  {
1039  gatherResult.counts.resize( numRanks );
1040  gatherResult.offsets.resize( numRanks );
1041  }
1042 
1043 
1044  MpiWrapper::gather( &numLocalValues, 1, gatherResult.counts.data(), 1, 0 );
1045 
1046  if( MpiWrapper::commRank() == 0 )
1047  {
1048  integer totalSize = 0;
1049  for( integer i = 0; i < numRanks; ++i )
1050  {
1051  gatherResult.offsets[i] = totalSize;
1052  totalSize += gatherResult.counts[i];
1053  }
1054  gatherResult.data.resize( totalSize );
1055  }
1056 
1057  MpiWrapper::gatherv( localBuffer.data(),
1058  numLocalValues,
1059  gatherResult.data.data(),
1060  gatherResult.counts.data(),
1061  gatherResult.offsets.data(),
1062  0 );
1063 
1064  return gatherResult;
1065 }
1066 
1067 template< typename T_SEND, typename T_RECV >
1068 int MpiWrapper::allgather( T_SEND const * const sendbuf,
1069  int sendcount,
1070  T_RECV * const recvbuf,
1071  int recvcount,
1072  MPI_Comm MPI_PARAM( comm ) )
1073 {
1074 #ifdef GEOS_USE_MPI
1075  return MPI_Allgather( sendbuf, sendcount, internal::getMpiType< T_SEND >(),
1076  recvbuf, recvcount, internal::getMpiType< T_RECV >(),
1077  comm );
1078 #else
1079  static_assert( std::is_same< T_SEND, T_RECV >::value,
1080  "MpiWrapper::allgather() for serial run requires send and receive buffers are of the same type" );
1081  GEOS_ERROR_IF_NE_MSG( sendcount, recvcount, "sendcount is not equal to recvcount." );
1082  std::copy( sendbuf, sendbuf + sendcount, recvbuf )
1083  return 0;
1084 #endif
1085 }
1086 
1087 template< typename T_SEND, typename T_RECV >
1088 int MpiWrapper::allgatherv( T_SEND const * const sendbuf,
1089  int sendcount,
1090  T_RECV * const recvbuf,
1091  int * recvcounts,
1092  int * displacements,
1093  MPI_Comm MPI_PARAM( comm ) )
1094 {
1095 #ifdef GEOS_USE_MPI
1096  return MPI_Allgatherv( sendbuf, sendcount, internal::getMpiType< T_SEND >(),
1097  recvbuf, recvcounts, displacements, internal::getMpiType< T_RECV >(),
1098  comm );
1099 #else
1100  static_assert( std::is_same< T_SEND, T_RECV >::value,
1101  "MpiWrapper::allgatherv() for serial run requires send and receive buffers are of the same type" );
1102  GEOS_ERROR_IF_NE_MSG( sendcount, recvcount, "sendcount is not equal to recvcount." );
1103  std::copy( sendbuf, sendbuf + sendcount, recvbuf )
1104  return 0;
1105 #endif
1106 }
1107 
1108 
1109 template< typename T >
1110 void MpiWrapper::allGather( T const myValue, array1d< T > & allValues, MPI_Comm MPI_PARAM( comm ) )
1111 {
1112 #ifdef GEOS_USE_MPI
1113  int const mpiSize = commSize( comm );
1114  allValues.resize( mpiSize );
1115 
1116  MPI_Datatype const MPI_TYPE = internal::getMpiType< T >();
1117 
1118  MPI_Allgather( &myValue, 1, MPI_TYPE, allValues.data(), 1, MPI_TYPE, comm );
1119 
1120 #else
1121  allValues.resize( 1 );
1122  allValues[0] = myValue;
1123 #endif
1124 }
1125 
1126 template< typename T >
1127 int MpiWrapper::allGather( arrayView1d< T const > const & sendValues,
1128  array1d< T > & allValues,
1129  MPI_Comm MPI_PARAM( comm ) )
1130 {
1131  int const sendSize = LvArray::integerConversion< int >( sendValues.size() );
1132 #ifdef GEOS_USE_MPI
1133  int const mpiSize = commSize( comm );
1134  allValues.resize( mpiSize * sendSize );
1135  return MPI_Allgather( sendValues.data(),
1136  sendSize,
1137  internal::getMpiType< T >(),
1138  allValues.data(),
1139  sendSize,
1140  internal::getMpiType< T >(),
1141  comm );
1142 
1143 #else
1144  allValues.resize( sendSize );
1145  for( localIndex a=0; a<sendSize; ++a )
1146  {
1147  allValues[a] = sendValues[a];
1148  }
1149  return 0;
1150 #endif
1151 }
1152 
1153 template< typename T >
1154 int MpiWrapper::allGatherv( arrayView1d< T const > const & sendValues,
1155  array1d< T > & allValues,
1156  MPI_Comm MPI_PARAM( comm ) )
1157 {
1158  int const sendSize = LvArray::integerConversion< int >( sendValues.size() );
1159 #ifdef GEOS_USE_MPI
1160  int const mpiSize = commSize( comm );
1161  array1d< int > counts;
1162  allGather( sendSize, counts, comm );
1163  array1d< int > displs( mpiSize + 1 );
1164  std::partial_sum( counts.begin(), counts.end(), displs.begin() + 1 );
1165  allValues.resize( displs.back() );
1166  return MPI_Allgatherv( sendValues.data(),
1167  sendSize,
1168  internal::getMpiType< T >(),
1169  allValues.data(),
1170  counts.data(),
1171  displs.data(),
1172  internal::getMpiType< T >(),
1173  comm );
1174 
1175 #else
1176  allValues.resize( sendSize );
1177  for( localIndex a=0; a<sendSize; ++a )
1178  {
1179  allValues[a] = sendValues[a];
1180  }
1181  return 0;
1182 #endif
1183 }
1184 
1185 template< typename T >
1186 int MpiWrapper::allReduce( T const * const sendbuf,
1187  T * const recvbuf,
1188  int const count,
1189  MPI_Op const MPI_PARAM( op ),
1190  MPI_Comm const MPI_PARAM( comm ) )
1191 {
1192 #ifdef GEOS_USE_MPI
1193  MPI_Datatype const mpiType = internal::getMpiType< T >();
1194  return MPI_Allreduce( sendbuf == recvbuf ? MPI_IN_PLACE : sendbuf, recvbuf, count, mpiType, op, comm );
1195 #else
1196  if( sendbuf != recvbuf )
1197  {
1198  memcpy( recvbuf, sendbuf, count * sizeof( T ) );
1199  }
1200  return 0;
1201 #endif
1202 }
1203 
1204 template< typename T >
1205 int MpiWrapper::reduce( T const * const sendbuf,
1206  T * const recvbuf,
1207  int const count,
1208  MPI_Op const MPI_PARAM( op ),
1209  int root,
1210  MPI_Comm const MPI_PARAM( comm ) )
1211 {
1212 #ifdef GEOS_USE_MPI
1213  MPI_Datatype const mpiType = internal::getMpiType< T >();
1214  return MPI_Reduce( sendbuf == recvbuf ? MPI_IN_PLACE : sendbuf, recvbuf, count, mpiType, op, root, comm );
1215 #else
1216  if( sendbuf != recvbuf )
1217  {
1218  memcpy( recvbuf, sendbuf, count * sizeof( T ) );
1219  }
1220  return 0;
1221 #endif
1222 }
1223 
1224 template< typename T >
1225 int MpiWrapper::scan( T const * const sendbuf,
1226  T * const recvbuf,
1227  int count,
1228  MPI_Op MPI_PARAM( op ),
1229  MPI_Comm MPI_PARAM( comm ) )
1230 {
1231 #ifdef GEOS_USE_MPI
1232  return MPI_Scan( sendbuf, recvbuf, count, internal::getMpiType< T >(), op, comm );
1233 #else
1234  memcpy( recvbuf, sendbuf, count*sizeof(T) );
1235  return 0;
1236 #endif
1237 }
1238 
1239 template< typename T >
1240 int MpiWrapper::exscan( T const * const MPI_PARAM( sendbuf ),
1241  T * const recvbuf,
1242  int count,
1243  MPI_Op MPI_PARAM( op ),
1244  MPI_Comm MPI_PARAM( comm ) )
1245 {
1246 #ifdef GEOS_USE_MPI
1247  return MPI_Exscan( sendbuf, recvbuf, count, internal::getMpiType< T >(), op, comm );
1248 #else
1249  memset( recvbuf, 0, count*sizeof(T) );
1250  return 0;
1251 #endif
1252 }
1253 
1254 template< typename T >
1255 int MpiWrapper::bcast( T * const MPI_PARAM( buffer ),
1256  int MPI_PARAM( count ),
1257  int MPI_PARAM( root ),
1258  MPI_Comm MPI_PARAM( comm ) )
1259 {
1260 #ifdef GEOS_USE_MPI
1261  return MPI_Bcast( buffer, count, internal::getMpiType< T >(), root, comm );
1262 #else
1263  return 0;
1264 #endif
1265 
1266 }
1267 
1268 template< typename T >
1269 void MpiWrapper::broadcast( T & MPI_PARAM( value ), int MPI_PARAM( srcRank ), MPI_Comm MPI_PARAM( comm ) )
1270 {
1271 #ifdef GEOS_USE_MPI
1272  MPI_Bcast( &value, 1, internal::getMpiType< T >(), srcRank, comm );
1273 #endif
1274 }
1275 
1276 template<>
1277 inline
1278 void MpiWrapper::broadcast< string >( string & MPI_PARAM( value ),
1279  int MPI_PARAM( srcRank ),
1280  MPI_Comm MPI_PARAM( comm ) )
1281 {
1282 #ifdef GEOS_USE_MPI
1283  int size = LvArray::integerConversion< int >( value.size() );
1284  broadcast( size, srcRank, comm );
1285  value.resize( size );
1286  MPI_Bcast( const_cast< char * >( value.data() ), size, internal::getMpiType< char >(), srcRank, comm );
1287 #endif
1288 }
1289 
1290 template< typename TS, typename TR >
1291 int MpiWrapper::gather( TS const * const sendbuf,
1292  int sendcount,
1293  TR * const recvbuf,
1294  int recvcount,
1295  int MPI_PARAM( root ),
1296  MPI_Comm MPI_PARAM( comm ) )
1297 {
1298 #ifdef GEOS_USE_MPI
1299  return MPI_Gather( sendbuf, sendcount, internal::getMpiType< TS >(),
1300  recvbuf, recvcount, internal::getMpiType< TR >(),
1301  root, comm );
1302 #else
1303  static_assert( std::is_same< TS, TR >::value,
1304  "MpiWrapper::gather() for serial run requires send and receive buffers are of the same type" );
1305  std::size_t const sendBufferSize = sendcount * sizeof(TS);
1306  std::size_t const recvBufferSize = recvcount * sizeof(TR);
1307  GEOS_ERROR_IF_NE_MSG( sendBufferSize, recvBufferSize, "size of send buffer and receive buffer are not equal" );
1308  memcpy( recvbuf, sendbuf, sendBufferSize );
1309  return 0;
1310 #endif
1311 }
1312 
1313 template< typename T, typename DST_CONTAINER, typename >
1314 int MpiWrapper::gather( T const & value,
1315  DST_CONTAINER & destValuesBuffer,
1316  int root,
1317  MPI_Comm MPI_PARAM( comm ) )
1318 {
1319  if( commRank() == 0 )
1320  GEOS_ERROR_IF_LT_MSG( destValuesBuffer.size(), size_t( commSize() ),
1321  "Receive buffer is not large enough to contain the values to receive." );
1322 #ifdef GEOS_USE_MPI
1323  return MPI_Gather( &value, sizeof( T ), internal::getMpiType< uint8_t >(),
1324  destValuesBuffer.data(), sizeof( T ), internal::getMpiType< uint8_t >(),
1325  root, comm );
1326 #else
1327  memcpy( destValuesBuffer.data(), &value, sendBufferSize );
1328  return 0;
1329 #endif
1330 }
1331 
1332 template< typename TS, typename TR >
1333 int MpiWrapper::gatherv( TS const * const sendbuf,
1334  int sendcount,
1335  TR * const recvbuf,
1336  const int * recvcounts,
1337  const int * MPI_PARAM( displs ),
1338  int MPI_PARAM( root ),
1339  MPI_Comm MPI_PARAM( comm ) )
1340 {
1341 #ifdef GEOS_USE_MPI
1342  return MPI_Gatherv( sendbuf, sendcount, internal::getMpiType< TS >(),
1343  recvbuf, recvcounts, displs, internal::getMpiType< TR >(),
1344  root, comm );
1345 #else
1346  static_assert( std::is_same< TS, TR >::value,
1347  "MpiWrapper::gather() for serial run requires send and receive buffers are of the same type" );
1348  std::size_t const sendBufferSize = sendcount * sizeof(TS);
1349  std::size_t const recvBufferSize = recvcounts[0] * sizeof(TR);
1350  GEOS_ERROR_IF_NE_MSG( sendBufferSize, recvBufferSize, "size of send buffer and receive buffer are not equal" );
1351  memcpy( recvbuf, sendbuf, sendBufferSize );
1352  return 0;
1353 #endif
1354 }
1355 
1356 
1357 template< typename TS, typename TR >
1358 int MpiWrapper::scatter( TS const * const sendbuf,
1359  int sendcount,
1360  TR * const recvbuf,
1361  int recvcount,
1362  int MPI_PARAM( root ),
1363  MPI_Comm MPI_PARAM( comm ))
1364 {
1365 #ifdef GEOS_USE_MPI
1366  return MPI_Scatter( sendbuf, sendcount, internal::getMpiType< TS >(),
1367  recvbuf, recvcount, internal::getMpiType< TR >(),
1368  root, comm );
1369 #else
1370  static_assert( std::is_same< TS, TR >::value,
1371  "MpiWrapper::scatter() for serial run requires send and receive buffers are of the same type" );
1372  std::size_t const sendBufferSize = sendcount * sizeof(TS);
1373  std::size_t const recvBufferSize = recvcount * sizeof(TR);
1374  GEOS_ERROR_IF_NE_MSG( sendBufferSize, recvBufferSize, "size of send buffer and receive buffer are not equal" );
1375  memcpy( recvbuf, sendbuf, sendBufferSize );
1376  return 0;
1377 #endif
1378 }
1379 
1380 template< typename TS, typename TR >
1381 int MpiWrapper::scatterv( TS const * const sendbuf,
1382  const int * sendcounts,
1383  const int * MPI_PARAM( displs ),
1384  TR * const recvbuf,
1385  int recvcount,
1386  int MPI_PARAM( root ),
1387  MPI_Comm MPI_PARAM( comm ))
1388 {
1389 #ifdef GEOS_USE_MPI
1390  return MPI_Scatterv( sendbuf, sendcounts, displs, internal::getMpiType< TS >(),
1391  recvbuf, recvcount, internal::getMpiType< TR >(),
1392  root, comm );
1393 #else
1394  static_assert( std::is_same< TS, TR >::value,
1395  "MpiWrapper::scatterv() for serial run requires send and receive buffers are of the same type" );
1396  std::size_t const sendBufferSize = sendcounts[0] * sizeof(TS);
1397  std::size_t const recvBufferSize = recvcount * sizeof(TR);
1398  GEOS_ERROR_IF_NE_MSG( sendBufferSize, recvBufferSize, "size of send buffer and receive buffer are not equal" );
1399  memcpy( recvbuf, sendbuf, sendBufferSize );
1400  return 0;
1401 #endif
1402 }
1403 
1404 
1405 
1406 template< typename T >
1407 int MpiWrapper::iRecv( T * const buf,
1408  int count,
1409  int MPI_PARAM( source ),
1410  int tag,
1411  MPI_Comm MPI_PARAM( comm ),
1412  MPI_Request * MPI_PARAM( request ) )
1413 {
1414 #ifdef GEOS_USE_MPI
1415  GEOS_ERROR_IF( (*request)!=MPI_REQUEST_NULL,
1416  "Attempting to use an MPI_Request that is still in use." );
1417  return MPI_Irecv( buf, count, internal::getMpiType< T >(), source, tag, comm, request );
1418 #else
1419  stdMap< int, std::pair< int, void * > > & pointerMap = getTagToPointersMap();
1420  stdMap< int, std::pair< int, void * > >::iterator iPointer = pointerMap.find( tag );
1421 
1422  if( iPointer==pointerMap.end() )
1423  {
1424  pointerMap.insert( {tag, {1, buf} } );
1425  }
1426  else
1427  {
1428  GEOS_ERROR_IF( iPointer->second.first != 0,
1429  "Tag does is assigned, but pointer was not set by iSend." );
1430  memcpy( buf, iPointer->second.second, count*sizeof(T) );
1431  pointerMap.erase( iPointer );
1432  }
1433  return 0;
1434 #endif
1435 }
1436 
1437 template< typename T >
1438 int MpiWrapper::recv( array1d< T > & buf,
1439  int MPI_PARAM( source ),
1440  int tag,
1441  MPI_Comm MPI_PARAM( comm ),
1442  MPI_Status * MPI_PARAM( request ) )
1443 {
1444 #ifdef GEOS_USE_MPI
1445  MPI_Status status;
1446  int count;
1447  MPI_Probe( source, tag, comm, &status );
1448  MPI_Get_count( &status, MPI_CHAR, &count );
1449 
1450  GEOS_ASSERT_EQ( count % sizeof( T ), 0 );
1451  buf.resize( count / sizeof( T ) );
1452 
1453  return MPI_Recv( reinterpret_cast< char * >( buf.data() ),
1454  count,
1455  MPI_CHAR,
1456  source,
1457  tag,
1458  comm,
1459  request );
1460 #else
1461  GEOS_ERROR( "Not implemented!" );
1462  return MPI_SUCCESS;
1463 #endif
1464 }
1465 
1466 template< typename T >
1467 int MpiWrapper::iSend( arrayView1d< T > const & buf,
1468  int MPI_PARAM( dest ),
1469  int tag,
1470  MPI_Comm MPI_PARAM( comm ),
1471  MPI_Request * MPI_PARAM( request ) )
1472 {
1473 #ifdef GEOS_USE_MPI
1474  GEOS_ERROR_IF( (*request)!=MPI_REQUEST_NULL,
1475  "Attempting to use an MPI_Request that is still in use." );
1476  return MPI_Isend( reinterpret_cast< void const * >( buf.data() ),
1477  buf.size() * sizeof( T ),
1478  MPI_CHAR,
1479  dest,
1480  tag,
1481  comm,
1482  request );
1483 #else
1484  GEOS_ERROR( "Not implemented." );
1485  return MPI_SUCCESS;
1486 #endif
1487 }
1488 
1489 template< typename T >
1490 int MpiWrapper::send( T const * const buf,
1491  int count,
1492  int dest,
1493  int tag,
1494  MPI_Comm comm )
1495 {
1496 #ifdef GEOS_USE_MPI
1497  return MPI_Send( buf, count, internal::getMpiType< T >(), dest, tag, comm );
1498 #else
1499  GEOS_ERROR( "Not implemented without MPI" );
1500 #endif
1501 }
1502 
1503 template< typename T >
1504 int MpiWrapper::iSend( T const * const buf,
1505  int count,
1506  int MPI_PARAM( dest ),
1507  int tag,
1508  MPI_Comm MPI_PARAM( comm ),
1509  MPI_Request * MPI_PARAM( request ) )
1510 {
1511 #ifdef GEOS_USE_MPI
1512  GEOS_ERROR_IF( (*request)!=MPI_REQUEST_NULL,
1513  "Attempting to use an MPI_Request that is still in use." );
1514  return MPI_Isend( buf, count, internal::getMpiType< T >(), dest, tag, comm, request );
1515 #else
1516  stdMap< int, std::pair< int, void * > > & pointerMap = getTagToPointersMap();
1517  stdMap< int, std::pair< int, void * > >::iterator iPointer = pointerMap.find( tag );
1518 
1519  if( iPointer==pointerMap.end() )
1520  {
1521  pointerMap.insert( {tag, {0, const_cast< T * >(buf)}
1522  } );
1523  }
1524  else
1525  {
1526  GEOS_ERROR_IF( iPointer->second.first != 1,
1527  "Tag does is assigned, but pointer was not set by iRecv." );
1528  memcpy( iPointer->second.second, buf, count*sizeof(T) );
1529  pointerMap.erase( iPointer );
1530  }
1531  return 0;
1532 #endif
1533 }
1534 
1535 template< typename U, typename T >
1536 U MpiWrapper::prefixSum( T const value, MPI_Comm comm )
1537 {
1538  U localResult;
1539 
1540 #ifdef GEOS_USE_MPI
1541  U const convertedValue = value;
1542  int const error = MPI_Exscan( &convertedValue, &localResult, 1, internal::getMpiType< U >(), MPI_SUM, comm );
1543  MPI_CHECK_ERROR( error );
1544 #endif
1545  if( commRank() == 0 )
1546  {
1547  localResult = 0;
1548  }
1549 
1550  return localResult;
1551 }
1552 
1553 
1554 template< typename T >
1555 T MpiWrapper::allReduce( T const & value, Reduction const op, MPI_Comm const comm )
1556 {
1557  T result;
1558  allReduce( &value, &result, 1, getMpiOp( op ), comm );
1559  return result;
1560 }
1561 
1562 template< typename T >
1563 void MpiWrapper::allReduce( Span< T const > const src, Span< T > const dst, Reduction const op, MPI_Comm const comm )
1564 {
1565  GEOS_ASSERT_EQ( src.size(), dst.size() );
1566  allReduce( src.data(), dst.data(), LvArray::integerConversion< int >( src.size() ), getMpiOp( op ), comm );
1567 }
1568 
1569 template< typename SRC_CONTAINER_TYPE, typename DST_CONTAINER_TYPE >
1570 void MpiWrapper::allReduce( SRC_CONTAINER_TYPE const & src, DST_CONTAINER_TYPE & dst, int const count, Reduction const op, MPI_Comm const comm )
1571 {
1572  static_assert( std::is_trivially_copyable< typename get_value_type< SRC_CONTAINER_TYPE >::type >::value,
1573  "The type in the source container must be trivially copyable." );
1574  static_assert( std::is_trivially_copyable< typename get_value_type< DST_CONTAINER_TYPE >::type >::value,
1575  "The type in the destination container must be trivially copyable." );
1576  static_assert( std::is_same< typename get_value_type< SRC_CONTAINER_TYPE >::type,
1578  "Source and destination containers must have the same value type." );
1579  GEOS_ASSERT_GE( src.size(), count );
1580  GEOS_ASSERT_GE( dst.size(), count );
1581  allReduce( src.data(), dst.data(), count, getMpiOp( op ), comm );
1582 }
1583 
1584 template< typename SRC_CONTAINER_TYPE, typename DST_CONTAINER_TYPE >
1585 void MpiWrapper::allReduce( SRC_CONTAINER_TYPE const & src, DST_CONTAINER_TYPE & dst, Reduction const op, MPI_Comm const comm )
1586 {
1587  static_assert( std::is_trivially_copyable< typename get_value_type< SRC_CONTAINER_TYPE >::type >::value,
1588  "The type in the source container must be trivially copyable." );
1589  static_assert( std::is_trivially_copyable< typename get_value_type< DST_CONTAINER_TYPE >::type >::value,
1590  "The type in the destination container must be trivially copyable." );
1591  static_assert( std::is_same< typename get_value_type< SRC_CONTAINER_TYPE >::type,
1593  "Source and destination containers must have the same value type." );
1594  GEOS_ASSERT_EQ( src.size(), dst.size() );
1595  allReduce( src.data(), dst.data(), LvArray::integerConversion< int >( src.size() ), getMpiOp( op ), comm );
1596 }
1597 
1598 template< typename T >
1599 T MpiWrapper::sum( T const & value, MPI_Comm comm )
1600 {
1601  return MpiWrapper::allReduce( value, Reduction::Sum, comm );
1602 }
1603 
1604 template< typename T >
1605 void MpiWrapper::sum( Span< T const > src, Span< T > dst, MPI_Comm comm )
1606 {
1607  MpiWrapper::allReduce( src, dst, Reduction::Sum, comm );
1608 }
1609 
1610 template< typename T >
1611 T MpiWrapper::min( T const & value, MPI_Comm comm )
1612 {
1613  return MpiWrapper::allReduce( value, Reduction::Min, comm );
1614 }
1615 
1616 template< typename T >
1617 void MpiWrapper::min( Span< T const > src, Span< T > dst, MPI_Comm comm )
1618 {
1619  MpiWrapper::allReduce( src, dst, Reduction::Min, comm );
1620 }
1621 
1622 template< typename T >
1623 T MpiWrapper::max( T const & value, MPI_Comm comm )
1624 {
1625  return MpiWrapper::allReduce( value, Reduction::Max, comm );
1626 }
1627 
1628 template< typename T >
1629 void MpiWrapper::max( Span< T const > src, Span< T > dst, MPI_Comm comm )
1630 {
1631  MpiWrapper::allReduce( src, dst, Reduction::Max, comm );
1632 }
1633 
1634 
1635 template< typename T >
1636 T MpiWrapper::reduce( T const & value, Reduction const op, int root, MPI_Comm const comm )
1637 {
1638  T result;
1639  reduce( &value, &result, 1, getMpiOp( op ), root, comm );
1640  return result;
1641 }
1642 
1643 template< typename T >
1644 void MpiWrapper::reduce( Span< T const > const src, Span< T > const dst, Reduction const op, int root, MPI_Comm const comm )
1645 {
1646  GEOS_ASSERT_EQ( src.size(), dst.size() );
1647  reduce( src.data(), dst.data(), LvArray::integerConversion< int >( src.size() ), getMpiOp( op ), root, comm );
1648 }
1649 
1650 template< typename FIRST, typename SECOND, MpiWrapper::PairReduction const OP >
1652 MpiWrapper::allReduce( PairType< FIRST, SECOND > const & localPair, MPI_Comm comm )
1653 {
1654 #ifdef GEOS_USE_MPI
1655  auto const type = internal::getMpiPairType< FIRST, SECOND >();
1656  auto const mpiOp = internal::getMpiPairReductionOp< FIRST, SECOND, OP >();
1657  PairType< FIRST, SECOND > pair{ localPair.first, localPair.second };
1658  MPI_Allreduce( MPI_IN_PLACE, &pair, 1, type, mpiOp, comm );
1659  return pair;
1660 #else
1661  return localPair;
1662 #endif
1663 }
1664 
1665 template< typename FIRST, typename SECOND, typename CONTAINER, MpiWrapper::PairReduction const OP >
1667 MpiWrapper::allReduce( CONTAINER const & pairs, MPI_Comm const comm )
1668 {
1669  using PAIR_T = PairType< FIRST, SECOND >;
1670  std::function< PAIR_T( PAIR_T, PAIR_T ) > const getMin = []( PAIR_T const & a, PAIR_T const & b ) {
1671  return ( std::tie( a.first, a.second ) < std::tie( b.first, b.second ) ) ? a : b;
1672  };
1673  std::function< PAIR_T( PAIR_T, PAIR_T ) > const getMax = []( PAIR_T const & a, PAIR_T const & b ) {
1674  return ( std::tie( a.first, a.second ) > std::tie( b.first, b.second ) ) ? a : b;
1675  };
1676  PAIR_T const defaultPair{
1677  OP == PairReduction::Min ? std::numeric_limits< FIRST >::max() : std::numeric_limits< FIRST >::lowest(),
1678  OP == PairReduction::Min ? std::numeric_limits< SECOND >::max() : std::numeric_limits< SECOND >::lowest()
1679  };
1680  // based on the operation, pair will be the minimum / maximum element (or defaultPair if pairs is empty)
1681  PAIR_T pair = std::accumulate( pairs.begin(), pairs.end(), defaultPair,
1682  OP == PairReduction::Min ? getMin : getMax );
1683  return allReduce< FIRST, SECOND, OP >( pair, comm );
1684 }
1685 
1686 template< typename FIRST, typename SECOND >
1688 { return allReduce< FIRST, SECOND, PairReduction::Min >( pair, comm ); }
1689 
1690 template< typename FIRST, typename SECOND, typename CONTAINER >
1691 MpiWrapper::PairType< FIRST, SECOND > MpiWrapper::min( CONTAINER const & pairs, MPI_Comm comm )
1692 { return allReduce< FIRST, SECOND, CONTAINER, PairReduction::Min >( pairs, comm ); }
1693 
1694 template< typename FIRST, typename SECOND >
1696 { return allReduce< FIRST, SECOND, PairReduction::Max >( pair, comm ); }
1697 
1698 template< typename FIRST, typename SECOND, typename CONTAINER >
1699 MpiWrapper::PairType< FIRST, SECOND > MpiWrapper::max( CONTAINER const & pairs, MPI_Comm comm )
1700 { return allReduce< FIRST, SECOND, CONTAINER, PairReduction::Max >( pairs, comm ); }
1701 
1702 } /* namespace geos */
1703 
1704 #endif /* GEOS_COMMON_MPIWRAPPER_HPP_ */
#define GEOS_ERROR(...)
Raise a hard error and terminate the program.
Definition: Logger.hpp:220
#define GEOS_ERROR_IF_LT_MSG(lhs, rhs,...)
Raise a hard error if one value compares less than the other.
Definition: Logger.hpp:493
#define GEOS_ERROR_IF(COND,...)
Conditionally raise a hard error and terminate the program.
Definition: Logger.hpp:211
#define GEOS_ERROR_IF_NE_MSG(lhs, rhs,...)
Raise a hard error if two values are not equal.
Definition: Logger.hpp:442
#define GEOS_ERROR_IF_NE(lhs, rhs)
Raise a hard error if two values are not equal.
Definition: Logger.hpp:449
#define GEOS_ASSERT_GE(lhs, rhs)
Assert that one value compares greater than or equal to the other in debug builds.
Definition: Logger.hpp:906
#define GEOS_ASSERT_EQ(lhs, rhs)
Assert that two values compare equal in debug builds.
Definition: Logger.hpp:855
Lightweight non-owning wrapper over a contiguous range of elements.
Definition: Span.hpp:42
constexpr T * data() const noexcept
Definition: Span.hpp:132
constexpr size_type size() const noexcept
Definition: Span.hpp:108
ArrayView< T, 1 > arrayView1d
Alias for 1D array view.
Definition: DataTypes.hpp:179
int MPI_COMM_GEOS
Global MPI communicator used by GEOSX.
GEOS_LOCALINDEX_TYPE localIndex
Local index type (for indexing objects within an MPI partition).
Definition: DataTypes.hpp:84
internal::StdMapWrapper< std::map< Key, T, Compare, Allocator >, USE_STD_CONTAINER_BOUNDS_CHECKING > stdMap
std::size_t size_t
Unsigned size type.
Definition: DataTypes.hpp:78
int integer
Signed integer type.
Definition: DataTypes.hpp:81
Array< T, 1 > array1d
Alias for 1D array.
Definition: DataTypes.hpp:175
std::string_view string_view
String type.
Definition: DataTypes.hpp:93
internal::StdVectorWrapper< T, Allocator, USE_STD_CONTAINER_BOUNDS_CHECKING > stdVector
Structure holding the result from all the gather operation.
Definition: MpiWrapper.hpp:341
static MPI_Op getMpiOp(Reduction const op)
Returns an MPI_Op associated with our strongly typed Reduction enum.
Definition: MpiWrapper.hpp:994
static int checkAll(int count, MPI_Request array_of_requests[], int *flag, MPI_Status array_of_statuses[])
static int allgatherv(T_SEND const *sendbuf, int sendcount, T_RECV *recvbuf, int *recvcounts, int *displacements, MPI_Comm comm=MPI_COMM_GEOS)
Strongly typed wrapper around MPI_Allgatherv.
static void gatherStringOnRank0(string_view str, std::function< void(string_view) > &&func)
Gather srting from all ranks to rank 0.
static int check(MPI_Request *request, int *flag, MPI_Status *status)
static int activeWaitAny(const int count, MPI_Request array_of_requests[], MPI_Status array_of_statuses[], std::function< MPI_Request(int) > func)
@ Max
Max pair first value.
@ Min
Min pair first value.
static int activeWaitSomeCompletePhase(const int participants, stdVector< std::tuple< MPI_Request *, MPI_Status *, std::function< MPI_Request(int) > > > const &phases)
static int iSend(T const *const buf, int count, int dest, int tag, MPI_Comm comm, MPI_Request *request)
Strongly typed wrapper around MPI_Isend()
static int bcast(T *buffer, int count, int root, MPI_Comm comm=MPI_COMM_GEOS)
Strongly typed wrapper around MPI_Bcast.
static void allGather(T const myValue, array1d< T > &allValues, MPI_Comm comm=MPI_COMM_GEOS)
Convenience function for MPI_Allgather.
static T max(T const &value, MPI_Comm comm=MPI_COMM_GEOS)
Convenience function for a MPI_Allreduce using a MPI_MAX operation.
static int allgather(T_SEND const *sendbuf, int sendcount, T_RECV *recvbuf, int recvcount, MPI_Comm comm=MPI_COMM_GEOS)
Strongly typed wrapper around MPI_Allgather.
static int activeWaitSome(const int count, MPI_Request array_of_requests[], MPI_Status array_of_statuses[], std::function< MPI_Request(int) > func)
static int send(T const *const buf, int count, int dest, int tag, MPI_Comm comm)
Strongly typed wrapper around MPI_Send()
static U prefixSum(T const value, MPI_Comm comm=MPI_COMM_GEOS)
Compute exclusive prefix sum and full sum.
static int scatter(TS const *const sendbuf, int sendcount, TR *const recvbuf, int recvcount, int root, MPI_Comm comm=MPI_COMM_GEOS)
Strongly typed wrapper around MPI_Scatter.
static int gather(T const &value, DST_CONTAINER &destValuesBuffer, int root, MPI_Comm comm=MPI_COMM_GEOS)
Strongly typed wrapper around MPI_Gather().
static T allReduce(T const &value, Reduction const op, MPI_Comm comm=MPI_COMM_GEOS)
Convenience wrapper for the MPI_Allreduce function.
static int checkAny(int count, MPI_Request array_of_requests[], int *idx, int *flag, MPI_Status array_of_statuses[])
static int gather(TS const *const sendbuf, int sendcount, TR *const recvbuf, int recvcount, int root, MPI_Comm comm=MPI_COMM_GEOS)
Strongly typed wrapper around MPI_Gather().
static int scatterv(TS const *const sendbuf, const int *sendcounts, const int *displs, TR *const recvbuf, int recvcount, int root, MPI_Comm comm=MPI_COMM_GEOS)
Strongly typed wrapper around MPI_Scatterv.
static int iRecv(T *const buf, int count, int source, int tag, MPI_Comm comm, MPI_Request *request)
Strongly typed wrapper around MPI_Irecv()
static T sum(T const &value, MPI_Comm comm=MPI_COMM_GEOS)
Convenience function for a MPI_Allreduce using a MPI_SUM operation.
static int activeWaitOrderedCompletePhase(const int participants, stdVector< std::tuple< MPI_Request *, MPI_Status *, std::function< MPI_Request(int) > > > const &phases)
static T min(T const &value, MPI_Comm comm=MPI_COMM_GEOS)
Convenience function for a MPI_Allreduce using a MPI_MIN operation.
static int nodeCommSize()
Compute the number of ranks allocated on the same node.
static int gatherv(TS const *const sendbuf, int sendcount, TR *const recvbuf, const int *recvcounts, const int *displs, int root, MPI_Comm comm=MPI_COMM_GEOS)
Strongly typed wrapper around MPI_Gatherv.
static void finalize()
Finalize the MPI environment and free MPI-managed resources. Please note that once called,...
static void broadcast(T &value, int srcRank=0, MPI_Comm comm=MPI_COMM_GEOS)
Convenience function for MPI_Broadcast.
static GatherResult< CONTAINER > gatherBufferRank0(CONTAINER const &localBuffer)
Gather buffers of varying sizes from all ranks to rank 0.
static int reduce(T const *sendbuf, T *recvbuf, int count, MPI_Op op, int root, MPI_Comm comm=MPI_COMM_GEOS)
Strongly typed wrapper around MPI_Reduce.
Trait to retrieve the value_type or ValueType of a type T.