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 static_assert(MpiTypeTraits<T>::isSpecialized,
32 "This function only "
33 "works if MpiTypeTraits<T>::isSpecialized.");
34 static_assert(!MpiTypeTraits<T>::needsFree,
35 "This function requires "
36 "! MpiTypeTraits<T>::needsFree, since otherwise it would "
37 "leak memory.");
38 // We assume here that every instance of T has the same
39 // MPI_Datatype, i.e., has the same binary representation.
40 MPI_Datatype innerDatatype = MpiTypeTraits<T>::getType(z.real());
41 MPI_Datatype outerDatatype; // return value
42
43 // If Kokkos::complex<T> has the same layout as T[2], then we can
44 // use a contiguous derived MPI_Datatype. This is likely the only
45 // code path that will execute. Contiguous types are likely more
46 // efficient for MPI to execute, and almost certainly more efficient
47 // for MPI to set up.
48 if (sizeof(::Kokkos::complex<T>) == 2 * sizeof(T)) {
49 (void)MPI_Type_contiguous(2, innerDatatype, &outerDatatype);
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 return computeKokkosComplexMpiDatatypeImpl<double>(z);
106}
107
109MPI_Datatype
110computeKokkosComplexMpiDatatype(const ::Kokkos::complex<float>& z) {
111 return computeKokkosComplexMpiDatatypeImpl<float>(z);
112}
113
114} // namespace Impl
115
116MPI_Datatype
117MpiTypeTraits< ::Kokkos::complex<double> >::
118 getType(const ::Kokkos::complex<double>& z) {
119 if (hasMpi3) {
120#if MPI_VERSION >= 3
121 return MPI_C_DOUBLE_COMPLEX; // requires MPI 2.?
122#else
123 return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
124#endif // MPI_VERSION >= 3
125 } else { // ! hasMpi3
126 return Impl::computeKokkosComplexMpiDatatype(z);
127 }
128}
129
130MPI_Datatype
131MpiTypeTraits< ::Kokkos::complex<double> >::
132 getType() {
133 if (hasMpi3) {
134#if MPI_VERSION >= 3
135 return MPI_C_DOUBLE_COMPLEX; // requires MPI 2.?
136#else
137 return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
138#endif // MPI_VERSION >= 3
139 } else { // ! hasMpi3
140 // Values are arbitrary. The function just looks at the address
141 // offsets of the class fields, not their contents.
142 ::Kokkos::complex<double> z(3.0, 4.0);
143 return Impl::computeKokkosComplexMpiDatatype(z);
144 }
145}
146
147MPI_Datatype
148MpiTypeTraits< ::Kokkos::complex<float> >::
149 getType(const ::Kokkos::complex<float>& z) {
150 if (hasMpi3) {
151#if MPI_VERSION >= 3
152 return MPI_C_FLOAT_COMPLEX; // requires MPI 2.?
153#else
154 return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
155#endif // MPI_VERSION >= 3
156 } else { // ! hasMpi3
157 return Impl::computeKokkosComplexMpiDatatype(z);
158 }
159}
160
161MPI_Datatype
162MpiTypeTraits< ::Kokkos::complex<float> >::
163 getType() {
164 if (hasMpi3) {
165#if MPI_VERSION >= 3
166 return MPI_C_FLOAT_COMPLEX; // requires MPI 2.?
167#else
168 return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
169#endif // MPI_VERSION >= 3
170 } else { // ! hasMpi3
171 // Values are arbitrary. The function just looks at the address
172 // offsets of the class fields, not their contents.
173 ::Kokkos::complex<float> z(3.0, 4.0);
174 return Impl::computeKokkosComplexMpiDatatype(z);
175 }
176}
177
178} // namespace Details
179} // namespace Teuchos
180
181#endif // HAVE_TPETRACORE_MPI
Add specializations of Teuchos::Details::MpiTypeTraits for Kokkos::complex<float> and Kokkos::complex...
Implementation details of Tpetra.