Tpetra parallel linear algebra Version of the Day
Loading...
Searching...
No Matches
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
14namespace Teuchos {
15namespace Details {
16namespace Impl {
17
28template<class T>
29MPI_Datatype
30computeKokkosComplexMpiDatatypeImpl (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
103MPI_Datatype
104computeKokkosComplexMpiDatatype (const ::Kokkos::complex<double>& z)
105{
106
107 return computeKokkosComplexMpiDatatypeImpl<double> (z);
108}
109
111MPI_Datatype
112computeKokkosComplexMpiDatatype (const ::Kokkos::complex<float>& z)
113{
114 return computeKokkosComplexMpiDatatypeImpl<float> (z);
115}
116
117} // namespace Impl
118
119MPI_Datatype
120MpiTypeTraits< ::Kokkos::complex<double> >::
121getType (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
135MPI_Datatype
136MpiTypeTraits< ::Kokkos::complex<double> >::
137getType ()
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
154MPI_Datatype
155MpiTypeTraits< ::Kokkos::complex<float> >::
156getType (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
170MPI_Datatype
171MpiTypeTraits< ::Kokkos::complex<float> >::
172getType ()
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<float> and Kokkos::complex...