1 // @HEADER
2 // ***********************************************************************
3 //
4 // Teuchos: Common Tools Package
5 // Copyright (2004) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ***********************************************************************
40 // @HEADER
41
42 #ifndef TEUCHOS_DETAILS_MPITYPETRAITS_HPP
43 #define TEUCHOS_DETAILS_MPITYPETRAITS_HPP
44
45 /// \file Teuchos_Details_MpiTypeTraits.hpp
46 /// \brief Declaration of Teuchos::Details::MpiTypeTraits (only if
47 /// building with MPI)
48
49 #include "Teuchos_config.h"
50
51 #ifdef HAVE_TEUCHOS_MPI
52
53 #include <mpi.h>
54 #include <complex>
55
56 namespace Teuchos {
57 namespace Details {
58
59 /// \class MpiTypeTraits
60 /// \brief Traits class mapping from type T to its MPI_Datatype
61 /// \tparam T The type being sent or received. T must be default
62 /// constructible. It must also be either one of C++'s built-in
63 /// types (like \c int or \c double), or a struct or "struct-like"
64 /// type like <tt>std::complex<double</tt>, for which sizeof(T)
65 /// correctly conveys the amount of data to send or receive.
66 template<class T>
67 class MpiTypeTraits {
68 public:
69 /// \brief Whether this class is specialized for T.
70 ///
71 /// If this class has <i>not</i> been specialized for T, then the
72 /// return value of getType (either the one-argument or
73 /// zero-argument version) is undefined.
74 static const bool isSpecialized = false;
75
76 /// \brief Whether you must call MPI_Type_free on the return value
77 /// of getType (both versions) after use.
78 ///
79 /// It is illegal to call MPI_Type_free on a built-in MPI_Datatype.
80 /// It is required to call MPI_Type_free on a non-built-in ("custom"
81 /// or "derived") MPI_Datatype after use. In the latter case, the
82 /// MPI standard says that you may call MPI_Type_free on an
83 /// MPI_Datatype as soon as you are done using the MPI_Datatype in
84 /// your code on that process, even if there is an outstanding
85 /// asynchronous operation on that process that uses the
86 /// MPI_Datatype.
87 ///
88 /// This applies to both the one-argument and the zero-argument
89 /// version of getType. If the return value of one needs freeing,
90 /// so must the return value of the other one. (IMPLEMENTERS:
91 /// Please make note of the previous sentence.)
92 static const bool needsFree = false;
93
94 /// \brief The MPI_Datatype corresponding to the given T instance.
95 ///
96 /// For more generality, this method requires passing in a T
97 /// instance. The method may or may not ignore this instance,
98 /// depending on the type T. The reason for passing in an instance
99 /// is that some MPI_Datatype constructors, e.g., MPI_Type_struct,
100 /// need actual offsets of the fields in an actual instance of T, in
101 /// order to construct the MPI_Datatype safely and portably. If T
102 /// has no default constructor, we have no way of doing so without
103 /// accepting a T instance.
104 ///
105 /// Specializations for T that do not need an instance of T in order
106 /// to construct the MPI_Datatype safely, may overload this method
107 /// not to require an instance of T. However, all specializations
108 /// must retain the overload that takes a T instance. This lets
109 /// users invoke this method in the same way for all types T.
getType(const T &)110 static MPI_Datatype getType (const T&) {
111 // In this default implementation, isSpecialized == false, so the
112 // return value of getType is undefined. We have to return
113 // something, so we return the predefined "invalid" MPI_Datatype,
114 // MPI_DATATYPE_NULL. Specializations of getType need to redefine
115 // this method to return something other than MPI_DATATYPE_NULL.
116 return MPI_DATATYPE_NULL;
117 }
118 };
119
120 //
121 // Specializations of MpiTypeTraits.
122 //
123
124 /// \brief Specialization for T = char.
125 ///
126 /// This requires MPI 1.2.
127 template<>
128 class MpiTypeTraits<char> {
129 public:
130 //! Whether this is a defined specialization of MpiTypeTraits (it is).
131 static const bool isSpecialized = true;
132
133 /// \brief Whether you must call MPI_Type_free on the return value
134 /// of getType (both versions) after use.
135 static const bool needsFree = false;
136
137 //! MPI_Datatype corresponding to the given T instance.
getType(const char &)138 static MPI_Datatype getType (const char&) {
139 return MPI_CHAR;
140 }
141
142 //! MPI_Datatype corresponding to the type T.
getType()143 static MPI_Datatype getType () {
144 return MPI_CHAR;
145 }
146 };
147
148 /// \brief Specialization for T = unsigned char.
149 ///
150 /// This requires MPI 1.2.
151 template<>
152 class MpiTypeTraits<unsigned char> {
153 public:
154 //! Whether this is a defined specialization of MpiTypeTraits (it is).
155 static const bool isSpecialized = true;
156
157 /// \brief Whether you must call MPI_Type_free on the return value
158 /// of getType (both versions) after use.
159 static const bool needsFree = false;
160
161 //! MPI_Datatype corresponding to the given T instance.
getType(const unsigned char &)162 static MPI_Datatype getType (const unsigned char&) {
163 return MPI_UNSIGNED_CHAR;
164 }
165
166 //! MPI_Datatype corresponding to the type T.
getType()167 static MPI_Datatype getType () {
168 return MPI_UNSIGNED_CHAR;
169 }
170 };
171
172 #if MPI_VERSION >= 2
173 /// \brief Specialization for T = signed char.
174 ///
175 /// This requires MPI 2.0.
176 template<>
177 class MpiTypeTraits<signed char> {
178 public:
179 //! Whether this is a defined specialization of MpiTypeTraits (it is).
180 static const bool isSpecialized = true;
181
182 /// \brief Whether you must call MPI_Type_free on the return value
183 /// of getType (both versions) after use.
184 static const bool needsFree = false;
185
186 //! MPI_Datatype corresponding to the given T instance.
getType(const signed char &)187 static MPI_Datatype getType (const signed char&) {
188 return MPI_SIGNED_CHAR;
189 }
190
191 //! MPI_Datatype corresponding to the type T.
getType()192 static MPI_Datatype getType () {
193 return MPI_SIGNED_CHAR;
194 }
195 };
196 #endif // MPI_VERSION >= 2
197
198 // mfh 09 Nov 2016: amb reports on 11 Nov 2014: "I am disabling these
199 // specializations for now. MPI_C_DOUBLE_COMPLEX is causing a problem
200 // in some builds. This code was effectively turned on only yesterday
201 // (10 Nov 2014) when TEUCHOS_HAVE_COMPLEX was corrected to be
202 // HAVE_TEUCHOS_COMPLEX, so evidently there are no users of these
203 // specializations."
204 //
205 // mfh 14 Nov 2016: my work-around for the above issue, is
206 // conservatively to assume that I need MPI_VERSION >= 3 for these
207 // types to exist. If I don't have MPI_VERSION >= 3, I create custom
208 // MPI_Datatype for these types.
209
210 namespace Impl {
211
212 /// \brief Struct for use in computeStdComplexMpiDatatype (see below).
213 ///
214 /// The actual real and imaginary fields in std::complex<T> are
215 /// private. While the instance methods real() and imag() return
216 /// references to those fields, it's not legal to take the addresses
217 /// of the return values of those methods ("invalid initialization"
218 /// errors, etc.). Thus, we construct another struct here which
219 /// should have exactly the same layout, and use it in the function
220 /// below.
221 template<class T>
222 struct MyComplex {
223 T re;
224 T im;
225 };
226
227 /// \brief Compute MPI_Datatype for instance of std::complex<T>.
228 ///
229 /// This function assumes the following:
230 /// <ul>
231 /// <li> <tt> MpiTypeTraits<T>::isSpecialized </tt> </li>
232 /// <li> <tt> ! MpiTypeTraits<T>::needsFree </tt>
233 /// <li> std::complex<T> has the same layout as
234 /// <tt>struct { T re; T im; };</tt> </li>
235 /// <li> Every instance of T has the same MPI_Datatype </li>
236 /// </ul>
237 template<class T>
238 MPI_Datatype
computeStdComplexMpiDatatype(const std::complex<T> & z)239 computeStdComplexMpiDatatype (const std::complex<T>& z)
240 {
241 #ifdef HAVE_TEUCHOSCORE_CXX11
242 static_assert (MpiTypeTraits<T>::isSpecialized, "This function only "
243 "works if MpiTypeTraits<T>::isSpecialized.");
244 static_assert (! MpiTypeTraits<T>::needsFree, "This function requires "
245 "! MpiTypeTraits<T>::needsFree, since otherwise it would "
246 "leak memory.");
247 #endif // HAVE_TEUCHOSCORE_CXX11
248
249 // We assume here that every instance of T has the same
250 // MPI_Datatype, i.e., has the same binary representation.
251 MPI_Datatype innerDatatype = MpiTypeTraits<T>::getType (z.real ());
252 MPI_Datatype outerDatatype; // return value
253
254 // If std::complex<T> has the same layout as T[2], then we can use a
255 // contiguous derived MPI_Datatype. This is likely the only code
256 // path that will execute. Contiguous types are likely more
257 // efficient for MPI to execute, and almost certainly more efficient
258 // for MPI to set up.
259 if (sizeof (std::complex<T>) == 2 * sizeof (T)) {
260 (void) MPI_Type_contiguous (2, innerDatatype, &outerDatatype);
261 }
262 else { // must use the general struct approach
263 // I borrowed and adapted the code below from the MPICH
264 // documentation:
265 //
266 // www.mpich.org/static/docs/v3.1/www3/MPI_Type_struct.html
267 int blockLengths[3];
268 MPI_Aint arrayOfDisplacements[3];
269 MPI_Datatype arrayOfTypes[3];
270
271 #ifdef HAVE_TEUCHOSCORE_CXX11
272 // See documentation of MyComplex (above) for explanation.
273 static_assert (sizeof (MyComplex<T>) == sizeof (std::complex<T>),
274 "Attempt to construct a struct of the same size and layout "
275 "as std::complex<T> failed.");
276 #endif // HAVE_TEUCHOSCORE_CXX11
277 MyComplex<T> z2;
278
279 // First entry in the struct.
280 blockLengths[0] = 1;
281 // Normally, &z2.re would equal &z2, but I'll be conservative and
282 // actually compute the offset, even though it's probably just 0.
283 //
284 // Need the cast to prevent the compiler complaining about
285 // subtracting addresses of different types.
286 arrayOfDisplacements[0] = reinterpret_cast<char*>(&z2.re) - reinterpret_cast<char*>(&z2);
287 arrayOfTypes[0] = innerDatatype;
288
289 // Second entry in the struct.
290 blockLengths[1] = 1;
291 arrayOfDisplacements[1] = reinterpret_cast<char*>(&z2.im) - reinterpret_cast<char*>(&z2);
292 arrayOfTypes[1] = innerDatatype;
293
294 #if MPI_VERSION < 2
295 // Upper bound of the struct.
296 blockLengths[2] = 1;
297 arrayOfDisplacements[2] = sizeof (MyComplex<T>);
298 arrayOfTypes[2] = MPI_UB; // "upper bound type"; signals end of struct
299 #endif // MPI_VERSION < 2
300
301 // Define the MPI_Datatype.
302 #if MPI_VERSION < 2
303 (void) MPI_Type_struct (3, blockLengths, arrayOfDisplacements,
304 arrayOfTypes, &outerDatatype);
305 #else
306 // Don't include the upper bound with MPI_Type_create_struct.
307 (void) MPI_Type_create_struct (2, blockLengths, arrayOfDisplacements,
308 arrayOfTypes, &outerDatatype);
309 #endif // MPI_VERSION < 2
310 }
311
312 MPI_Type_commit (&outerDatatype);
313 return outerDatatype;
314 }
315
316 } // namespace Impl
317
318
319 //! Specialization of MpiTypeTraits for std::complex<double>.
320 template<>
321 class MpiTypeTraits< std::complex<double> > {
322 private:
323 #if MPI_VERSION >= 3
324 static const bool hasMpi3 = true;
325 #else
326 static const bool hasMpi3 = false;
327 #endif // MPI_VERSION >= 3
328
329 public:
330 //! Whether this is a defined specialization of MpiTypeTraits (it is).
331 static const bool isSpecialized = true;
332
333 /// \brief Whether you must call MPI_Type_free on the return value
334 /// of getType (both versions) after use.
335 static const bool needsFree = ! hasMpi3;
336
337 //! MPI_Datatype corresponding to the given std::complex<double> instance.
getType(const std::complex<double> & z)338 static MPI_Datatype getType (const std::complex<double>& z) {
339 if (hasMpi3) {
340 #if MPI_VERSION >= 3
341 return MPI_C_DOUBLE_COMPLEX; // requires MPI 2.?
342 #else
343 return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
344 #endif // MPI_VERSION >= 3
345 }
346 else { // ! hasMpi3
347 return Impl::computeStdComplexMpiDatatype<double> (z);
348 }
349 }
350
351 //! MPI_Datatype corresponding to all std::complex<double> instances.
getType()352 static MPI_Datatype getType () {
353 if (hasMpi3) {
354 #if MPI_VERSION >= 3
355 return MPI_C_DOUBLE_COMPLEX; // requires MPI 2.?
356 #else
357 return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
358 #endif // MPI_VERSION >= 3
359 }
360 else { // ! hasMpi3
361 // Values are arbitrary. The function just looks at the address
362 // offsets of the class fields, not their contents.
363 std::complex<double> z (3.0, 4.0);
364 return Impl::computeStdComplexMpiDatatype<double> (z);
365 }
366 }
367 };
368
369 template<>
370 class MpiTypeTraits< std::complex<float> > {
371 private:
372 #if MPI_VERSION >= 3
373 static const bool hasMpi3 = true;
374 #else
375 static const bool hasMpi3 = false;
376 #endif // MPI_VERSION >= 3
377
378 public:
379 //! Whether this is a defined specialization of MpiTypeTraits (it is).
380 static const bool isSpecialized = true;
381
382 /// \brief Whether you must call MPI_Type_free on the return value
383 /// of getType (both versions) after use.
384 static const bool needsFree = ! hasMpi3;
385
386 //! MPI_Datatype corresponding to the given std::complex<float> instance.
getType(const std::complex<float> & z)387 static MPI_Datatype getType (const std::complex<float>& z) {
388 if (hasMpi3) {
389 #if MPI_VERSION >= 3
390 return MPI_C_FLOAT_COMPLEX; // requires MPI 2.?
391 #else
392 return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
393 #endif // MPI_VERSION >= 3
394 }
395 else { // ! hasMpi3
396 return Impl::computeStdComplexMpiDatatype<float> (z);
397 }
398 }
399
400 //! MPI_Datatype corresponding to all std::complex<float> instances.
getType()401 static MPI_Datatype getType () {
402 if (hasMpi3) {
403 #if MPI_VERSION >= 3
404 return MPI_C_FLOAT_COMPLEX; // requires MPI 2.?
405 #else
406 return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
407 #endif // MPI_VERSION >= 3
408 }
409 else { // ! hasMpi3
410 // Values are arbitrary. The function just looks at the address
411 // offsets of the class fields, not their contents.
412 std::complex<float> z (3.0, 4.0);
413 return Impl::computeStdComplexMpiDatatype<float> (z);
414 }
415 }
416 };
417
418 //! Specialization for T = double.
419 template<>
420 class MpiTypeTraits<double> {
421 public:
422 //! Whether this is a defined specialization of MpiTypeTraits (it is).
423 static const bool isSpecialized = true;
424
425 /// \brief Whether you must call MPI_Type_free on the return value
426 /// of getType (both versions) after use.
427 static const bool needsFree = false;
428
429 //! MPI_Datatype corresponding to the given T instance.
getType(const double &)430 static MPI_Datatype getType (const double&) {
431 return MPI_DOUBLE;
432 }
433
434 //! MPI_Datatype corresponding to the type T.
getType()435 static MPI_Datatype getType () {
436 return MPI_DOUBLE;
437 }
438 };
439
440 //! Specialization for T = float.
441 template<>
442 class MpiTypeTraits<float> {
443 public:
444 //! Whether this is a defined specialization of MpiTypeTraits (it is).
445 static const bool isSpecialized = true;
446
447 /// \brief Whether you must call MPI_Type_free on the return value
448 /// of getType (both versions) after use.
449 static const bool needsFree = false;
450
451 //! MPI_Datatype corresponding to the given T instance.
getType(const float &)452 static MPI_Datatype getType (const float&) {
453 return MPI_FLOAT;
454 }
455
456 //! MPI_Datatype corresponding to the type T.
getType()457 static MPI_Datatype getType () {
458 return MPI_FLOAT;
459 }
460 };
461
462 //! Specialization for T = long long.
463 template<>
464 class MpiTypeTraits<long long> {
465 public:
466 //! Whether this is a defined specialization of MpiTypeTraits (it is).
467 static const bool isSpecialized = true;
468
469 /// \brief Whether you must call MPI_Type_free on the return value
470 /// of getType (both versions) after use.
471 static const bool needsFree = false;
472
473 //! MPI_Datatype corresponding to the given T instance.
getType(const long long &)474 static MPI_Datatype getType (const long long&) {
475 return MPI_LONG_LONG; // synonym for MPI_LONG_LONG_INT in MPI 2.2
476 }
477
478 //! MPI_Datatype corresponding to the type T.
getType()479 static MPI_Datatype getType () {
480 return MPI_LONG_LONG;
481 }
482 };
483
484
485 #if MPI_VERSION >= 2
486 /// \brief Specialization for T = long long.
487 ///
488 /// This requires MPI 2.0.
489 template<>
490 class MpiTypeTraits<unsigned long long> {
491 public:
492 //! Whether this is a defined specialization of MpiTypeTraits (it is).
493 static const bool isSpecialized = true;
494
495 /// \brief Whether you must call MPI_Type_free on the return value
496 /// of getType (both versions) after use.
497 static const bool needsFree = false;
498
499 //! MPI_Datatype corresponding to the given T instance.
getType(const unsigned long long &)500 static MPI_Datatype getType (const unsigned long long&) {
501 return MPI_UNSIGNED_LONG_LONG;
502 }
503
504 //! MPI_Datatype corresponding to the type T.
getType()505 static MPI_Datatype getType () {
506 return MPI_UNSIGNED_LONG_LONG;
507 }
508 };
509 #endif // MPI_VERSION >= 2
510
511 //! Specialization for T = long.
512 template<>
513 class MpiTypeTraits<long> {
514 public:
515 //! Whether this is a defined specialization of MpiTypeTraits (it is).
516 static const bool isSpecialized = true;
517
518 /// \brief Whether you must call MPI_Type_free on the return value
519 /// of getType (both versions) after use.
520 static const bool needsFree = false;
521
522 //! MPI_Datatype corresponding to the given T instance.
getType(const long &)523 static MPI_Datatype getType (const long&) {
524 return MPI_LONG;
525 }
526
527 //! MPI_Datatype corresponding to the type T.
getType()528 static MPI_Datatype getType () {
529 return MPI_LONG;
530 }
531 };
532
533 //! Specialization for T = unsigned long.
534 template<>
535 class MpiTypeTraits<unsigned long> {
536 public:
537 //! Whether this is a defined specialization of MpiTypeTraits (it is).
538 static const bool isSpecialized = true;
539
540 /// \brief Whether you must call MPI_Type_free on the return value
541 /// of getType (both versions) after use.
542 static const bool needsFree = false;
543
544 //! MPI_Datatype corresponding to the given T instance.
getType(const unsigned long &)545 static MPI_Datatype getType (const unsigned long&) {
546 return MPI_UNSIGNED_LONG;
547 }
548
549 //! MPI_Datatype corresponding to the type T.
getType()550 static MPI_Datatype getType () {
551 return MPI_UNSIGNED_LONG;
552 }
553 };
554
555 //! Specialization for T = int.
556 template<>
557 class MpiTypeTraits<int> {
558 public:
559 //! Whether this is a defined specialization of MpiTypeTraits (it is).
560 static const bool isSpecialized = true;
561
562 /// \brief Whether you must call MPI_Type_free on the return value
563 /// of getType (both versions) after use.
564 static const bool needsFree = false;
565
566 //! MPI_Datatype corresponding to the given T instance.
getType(const int &)567 static MPI_Datatype getType (const int&) {
568 return MPI_INT;
569 }
570
571 //! MPI_Datatype corresponding to the type T.
getType()572 static MPI_Datatype getType () {
573 return MPI_INT;
574 }
575 };
576
577 //! Specialization for T = unsigned int.
578 template<>
579 class MpiTypeTraits<unsigned int> {
580 public:
581 //! Whether this is a defined specialization of MpiTypeTraits (it is).
582 static const bool isSpecialized = true;
583
584 /// \brief Whether you must call MPI_Type_free on the return value
585 /// of getType (both versions) after use.
586 static const bool needsFree = false;
587
588 //! MPI_Datatype corresponding to the given T instance.
getType(const unsigned int &)589 static MPI_Datatype getType (const unsigned int&) {
590 return MPI_UNSIGNED;
591 }
592
593 //! MPI_Datatype corresponding to the type T.
getType()594 static MPI_Datatype getType () {
595 return MPI_UNSIGNED;
596 }
597 };
598
599 //! Specialization for T = short.
600 template<>
601 class MpiTypeTraits<short> {
602 public:
603 //! Whether this is a defined specialization of MpiTypeTraits (it is).
604 static const bool isSpecialized = true;
605
606 /// \brief Whether you must call MPI_Type_free on the return value
607 /// of getType (both versions) after use.
608 static const bool needsFree = false;
609
610 //! MPI_Datatype corresponding to the given T instance.
getType(const short &)611 static MPI_Datatype getType (const short&) {
612 return MPI_SHORT;
613 }
614
615 //! MPI_Datatype corresponding to the type T.
getType()616 static MPI_Datatype getType () {
617 return MPI_SHORT;
618 }
619 };
620
621 //! Specialization for T = unsigned short.
622 template<>
623 class MpiTypeTraits<unsigned short> {
624 public:
625 //! Whether this is a defined specialization of MpiTypeTraits (it is).
626 static const bool isSpecialized = true;
627
628 /// \brief Whether you must call MPI_Type_free on the return value
629 /// of getType (both versions) after use.
630 static const bool needsFree = false;
631
632 //! MPI_Datatype corresponding to the given T instance.
getType(const unsigned short &)633 static MPI_Datatype getType (const unsigned short&) {
634 return MPI_UNSIGNED_SHORT;
635 }
636
637 //! MPI_Datatype corresponding to the type T.
getType()638 static MPI_Datatype getType () {
639 return MPI_UNSIGNED_SHORT;
640 }
641 };
642
643 } // namespace Details
644 } // namespace Teuchos
645
646 #endif // HAVE_TEUCHOS_MPI
647
648 #endif // TEUCHOS_DETAILS_MPITYPETRAITS_HPP
649
650