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 /*
2 // @HEADER
3 // ***********************************************************************
4 //
5 // Tpetra: Templated Linear Algebra Services Package
6 // Copyright (2008) Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
39 //
40 // ************************************************************************
41 // @HEADER
42 */
43 
45 
46 #ifdef HAVE_TPETRACORE_MPI
47 
48 namespace Teuchos {
49 namespace Details {
50 namespace Impl {
51 
62 template<class T>
63 MPI_Datatype
64 computeKokkosComplexMpiDatatypeImpl (const ::Kokkos::complex<T>& z)
65 {
66  static_assert (MpiTypeTraits<T>::isSpecialized, "This function only "
67  "works if MpiTypeTraits<T>::isSpecialized.");
68  static_assert (! MpiTypeTraits<T>::needsFree, "This function requires "
69  "! MpiTypeTraits<T>::needsFree, since otherwise it would "
70  "leak memory.");
71  // We assume here that every instance of T has the same
72  // MPI_Datatype, i.e., has the same binary representation.
73  MPI_Datatype innerDatatype = MpiTypeTraits<T>::getType (z.real ());
74  MPI_Datatype outerDatatype; // return value
75 
76  // If Kokkos::complex<T> has the same layout as T[2], then we can
77  // use a contiguous derived MPI_Datatype. This is likely the only
78  // code path that will execute. Contiguous types are likely more
79  // efficient for MPI to execute, and almost certainly more efficient
80  // for MPI to set up.
81  if (sizeof ( ::Kokkos::complex<T>) == 2 * sizeof (T)) {
82  (void) MPI_Type_contiguous (2, innerDatatype, &outerDatatype);
83  }
84  else { // must use the general struct approach
85  // I borrowed and adapted the code below from the MPICH
86  // documentation:
87  //
88  // www.mpich.org/static/docs/v3.1/www3/MPI_Type_struct.html
89  int blockLengths[3];
90  MPI_Aint arrayOfDisplacements[3];
91  MPI_Datatype arrayOfTypes[3];
92 
93  // See documentation of MyComplex (above) for explanation.
94  static_assert (sizeof (MyComplex<T>) == sizeof ( ::Kokkos::complex<T>),
95  "Attempt to construct a struct of the same size and layout "
96  "as Kokkos::complex<T> failed.");
97  ::Teuchos::Details::Impl::MyComplex<T> z2;
98 
99  // First entry in the struct.
100  blockLengths[0] = 1;
101  // Normally, &z2.re would equal &z2, but I'll be conservative and
102  // actually compute the offset, even though it's probably just 0.
103  //
104  // Need the cast to prevent the compiler complaining about
105  // subtracting addresses of different types.
106  arrayOfDisplacements[0] = reinterpret_cast<uintptr_t> (&z2.re) - reinterpret_cast<uintptr_t> (&z2);
107  arrayOfTypes[0] = innerDatatype;
108 
109  // Second entry in the struct.
110  blockLengths[1] = 1;
111  arrayOfDisplacements[1] = reinterpret_cast<uintptr_t> (&z2.im) - reinterpret_cast<uintptr_t> (&z2);
112  arrayOfTypes[1] = innerDatatype;
113 
114 #if MPI_VERSION < 2
115  // Upper bound of the struct.
116  blockLengths[2] = 1;
117  arrayOfDisplacements[2] = sizeof (MyComplex<T>);
118  arrayOfTypes[2] = MPI_UB; // "upper bound type"; signals end of struct
119 #endif // MPI_VERSION < 2
120 
121  // Define the MPI_Datatype.
122 #if MPI_VERSION < 2
123  (void) MPI_Type_struct (3, blockLengths, arrayOfDisplacements,
124  arrayOfTypes, &outerDatatype);
125 #else
126  // Don't include the upper bound with MPI_Type_create_struct.
127  (void) MPI_Type_create_struct (2, blockLengths, arrayOfDisplacements,
128  arrayOfTypes, &outerDatatype);
129 #endif // MPI_VERSION < 2
130  }
131 
132  MPI_Type_commit (&outerDatatype);
133  return outerDatatype;
134 }
135 
137 MPI_Datatype
138 computeKokkosComplexMpiDatatype (const ::Kokkos::complex<double>& z)
139 {
140 
141  return computeKokkosComplexMpiDatatypeImpl<double> (z);
142 }
143 
145 MPI_Datatype
146 computeKokkosComplexMpiDatatype (const ::Kokkos::complex<float>& z)
147 {
148  return computeKokkosComplexMpiDatatypeImpl<float> (z);
149 }
150 
151 } // namespace Impl
152 
153 MPI_Datatype
154 MpiTypeTraits< ::Kokkos::complex<double> >::
155 getType (const ::Kokkos::complex<double>& z)
156 {
157  if (hasMpi3) {
158 #if MPI_VERSION >= 3
159  return MPI_C_DOUBLE_COMPLEX; // requires MPI 2.?
160 #else
161  return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
162 #endif // MPI_VERSION >= 3
163  }
164  else { // ! hasMpi3
165  return Impl::computeKokkosComplexMpiDatatype (z);
166  }
167 }
168 
169 MPI_Datatype
170 MpiTypeTraits< ::Kokkos::complex<double> >::
171 getType ()
172 {
173  if (hasMpi3) {
174 #if MPI_VERSION >= 3
175  return MPI_C_DOUBLE_COMPLEX; // requires MPI 2.?
176 #else
177  return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
178 #endif // MPI_VERSION >= 3
179  }
180  else { // ! hasMpi3
181  // Values are arbitrary. The function just looks at the address
182  // offsets of the class fields, not their contents.
183  ::Kokkos::complex<double> z (3.0, 4.0);
184  return Impl::computeKokkosComplexMpiDatatype (z);
185  }
186 }
187 
188 MPI_Datatype
189 MpiTypeTraits< ::Kokkos::complex<float> >::
190 getType (const ::Kokkos::complex<float>& z)
191 {
192  if (hasMpi3) {
193 #if MPI_VERSION >= 3
194  return MPI_C_FLOAT_COMPLEX; // requires MPI 2.?
195 #else
196  return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
197 #endif // MPI_VERSION >= 3
198  }
199  else { // ! hasMpi3
200  return Impl::computeKokkosComplexMpiDatatype (z);
201  }
202 }
203 
204 MPI_Datatype
205 MpiTypeTraits< ::Kokkos::complex<float> >::
206 getType ()
207 {
208  if (hasMpi3) {
209 #if MPI_VERSION >= 3
210  return MPI_C_FLOAT_COMPLEX; // requires MPI 2.?
211 #else
212  return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
213 #endif // MPI_VERSION >= 3
214  }
215  else { // ! hasMpi3
216  // Values are arbitrary. The function just looks at the address
217  // offsets of the class fields, not their contents.
218  ::Kokkos::complex<float> z (3.0, 4.0);
219  return Impl::computeKokkosComplexMpiDatatype (z);
220  }
221 }
222 
223 } // namespace Details
224 } // namespace Teuchos
225 
226 
227 #endif // HAVE_TPETRACORE_MPI
Add specializations of Teuchos::Details::MpiTypeTraits for Kokkos::complex&lt;float&gt; and Kokkos::complex...