Tpetra parallel linear algebra  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Tpetra_Details_MpiTypeTraits.cpp
1 // @HEADER
2 // *****************************************************************************
3 // Tpetra: Templated Linear Algebra Services Package
4 //
5 // Copyright 2008 NTESS and the Tpetra contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
11 
12 #ifdef HAVE_TPETRACORE_MPI
13 
14 namespace Teuchos {
15 namespace Details {
16 namespace Impl {
17 
28 template<class T>
29 MPI_Datatype
30 computeKokkosComplexMpiDatatypeImpl (const ::Kokkos::complex<T>& z)
31 {
32  static_assert (MpiTypeTraits<T>::isSpecialized, "This function only "
33  "works if MpiTypeTraits<T>::isSpecialized.");
34  static_assert (! MpiTypeTraits<T>::needsFree, "This function requires "
35  "! MpiTypeTraits<T>::needsFree, since otherwise it would "
36  "leak memory.");
37  // We assume here that every instance of T has the same
38  // MPI_Datatype, i.e., has the same binary representation.
39  MPI_Datatype innerDatatype = MpiTypeTraits<T>::getType (z.real ());
40  MPI_Datatype outerDatatype; // return value
41 
42  // If Kokkos::complex<T> has the same layout as T[2], then we can
43  // use a contiguous derived MPI_Datatype. This is likely the only
44  // code path that will execute. Contiguous types are likely more
45  // efficient for MPI to execute, and almost certainly more efficient
46  // for MPI to set up.
47  if (sizeof ( ::Kokkos::complex<T>) == 2 * sizeof (T)) {
48  (void) MPI_Type_contiguous (2, innerDatatype, &outerDatatype);
49  }
50  else { // must use the general struct approach
51  // I borrowed and adapted the code below from the MPICH
52  // documentation:
53  //
54  // www.mpich.org/static/docs/v3.1/www3/MPI_Type_struct.html
55  int blockLengths[3];
56  MPI_Aint arrayOfDisplacements[3];
57  MPI_Datatype arrayOfTypes[3];
58 
59  // See documentation of MyComplex (above) for explanation.
60  static_assert (sizeof (MyComplex<T>) == sizeof ( ::Kokkos::complex<T>),
61  "Attempt to construct a struct of the same size and layout "
62  "as Kokkos::complex<T> failed.");
63  ::Teuchos::Details::Impl::MyComplex<T> z2;
64 
65  // First entry in the struct.
66  blockLengths[0] = 1;
67  // Normally, &z2.re would equal &z2, but I'll be conservative and
68  // actually compute the offset, even though it's probably just 0.
69  //
70  // Need the cast to prevent the compiler complaining about
71  // subtracting addresses of different types.
72  arrayOfDisplacements[0] = reinterpret_cast<uintptr_t> (&z2.re) - reinterpret_cast<uintptr_t> (&z2);
73  arrayOfTypes[0] = innerDatatype;
74 
75  // Second entry in the struct.
76  blockLengths[1] = 1;
77  arrayOfDisplacements[1] = reinterpret_cast<uintptr_t> (&z2.im) - reinterpret_cast<uintptr_t> (&z2);
78  arrayOfTypes[1] = innerDatatype;
79 
80 #if MPI_VERSION < 2
81  // Upper bound of the struct.
82  blockLengths[2] = 1;
83  arrayOfDisplacements[2] = sizeof (MyComplex<T>);
84  arrayOfTypes[2] = MPI_UB; // "upper bound type"; signals end of struct
85 #endif // MPI_VERSION < 2
86 
87  // Define the MPI_Datatype.
88 #if MPI_VERSION < 2
89  (void) MPI_Type_struct (3, blockLengths, arrayOfDisplacements,
90  arrayOfTypes, &outerDatatype);
91 #else
92  // Don't include the upper bound with MPI_Type_create_struct.
93  (void) MPI_Type_create_struct (2, blockLengths, arrayOfDisplacements,
94  arrayOfTypes, &outerDatatype);
95 #endif // MPI_VERSION < 2
96  }
97 
98  MPI_Type_commit (&outerDatatype);
99  return outerDatatype;
100 }
101 
103 MPI_Datatype
104 computeKokkosComplexMpiDatatype (const ::Kokkos::complex<double>& z)
105 {
106 
107  return computeKokkosComplexMpiDatatypeImpl<double> (z);
108 }
109 
111 MPI_Datatype
112 computeKokkosComplexMpiDatatype (const ::Kokkos::complex<float>& z)
113 {
114  return computeKokkosComplexMpiDatatypeImpl<float> (z);
115 }
116 
117 } // namespace Impl
118 
119 MPI_Datatype
120 MpiTypeTraits< ::Kokkos::complex<double> >::
121 getType (const ::Kokkos::complex<double>& z)
122 {
123  if (hasMpi3) {
124 #if MPI_VERSION >= 3
125  return MPI_C_DOUBLE_COMPLEX; // requires MPI 2.?
126 #else
127  return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
128 #endif // MPI_VERSION >= 3
129  }
130  else { // ! hasMpi3
131  return Impl::computeKokkosComplexMpiDatatype (z);
132  }
133 }
134 
135 MPI_Datatype
136 MpiTypeTraits< ::Kokkos::complex<double> >::
137 getType ()
138 {
139  if (hasMpi3) {
140 #if MPI_VERSION >= 3
141  return MPI_C_DOUBLE_COMPLEX; // requires MPI 2.?
142 #else
143  return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
144 #endif // MPI_VERSION >= 3
145  }
146  else { // ! hasMpi3
147  // Values are arbitrary. The function just looks at the address
148  // offsets of the class fields, not their contents.
149  ::Kokkos::complex<double> z (3.0, 4.0);
150  return Impl::computeKokkosComplexMpiDatatype (z);
151  }
152 }
153 
154 MPI_Datatype
155 MpiTypeTraits< ::Kokkos::complex<float> >::
156 getType (const ::Kokkos::complex<float>& z)
157 {
158  if (hasMpi3) {
159 #if MPI_VERSION >= 3
160  return MPI_C_FLOAT_COMPLEX; // requires MPI 2.?
161 #else
162  return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
163 #endif // MPI_VERSION >= 3
164  }
165  else { // ! hasMpi3
166  return Impl::computeKokkosComplexMpiDatatype (z);
167  }
168 }
169 
170 MPI_Datatype
171 MpiTypeTraits< ::Kokkos::complex<float> >::
172 getType ()
173 {
174  if (hasMpi3) {
175 #if MPI_VERSION >= 3
176  return MPI_C_FLOAT_COMPLEX; // requires MPI 2.?
177 #else
178  return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
179 #endif // MPI_VERSION >= 3
180  }
181  else { // ! hasMpi3
182  // Values are arbitrary. The function just looks at the address
183  // offsets of the class fields, not their contents.
184  ::Kokkos::complex<float> z (3.0, 4.0);
185  return Impl::computeKokkosComplexMpiDatatype (z);
186  }
187 }
188 
189 } // namespace Details
190 } // namespace Teuchos
191 
192 
193 #endif // HAVE_TPETRACORE_MPI
Add specializations of Teuchos::Details::MpiTypeTraits for Kokkos::complex&lt;float&gt; and Kokkos::complex...