Tpetra parallel linear algebra  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Tpetra_Details_PackTriples.hpp
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 
10 #ifndef TPETRA_DETAILS_PACKTRIPLES_HPP
11 #define TPETRA_DETAILS_PACKTRIPLES_HPP
12 
13 #include "TpetraCore_config.h"
14 #include "Teuchos_Comm.hpp"
15 #ifdef HAVE_TPETRACORE_MPI
18 #endif // HAVE_TPETRACORE_MPI
19 #include <ostream>
20 
21 namespace Tpetra {
22 namespace Details {
23 
24 //
25 // Search for "SKIP DOWN TO HERE" (omit quotes) for the "public"
26 // interface. I put "public" in quotes because it's public only for
27 // Tpetra developers, NOT for Tpetra users.
28 //
29 
30 #ifdef HAVE_TPETRACORE_MPI
31 
32 // It's not useful to pack or unpack if not using MPI. Thus, we only
33 // need to define these with MPI. For a non-MPI build, we just need
34 // some outer stub interface that throws an exception.
35 
36 int countPackTriplesCountMpi(MPI_Comm comm,
37  int& size,
38  std::ostream* errStrm = NULL);
39 
40 int packTriplesCountMpi(const int numEnt,
41  char outBuf[],
42  const int outBufSize,
43  int& outBufCurPos,
44  MPI_Comm comm,
45  std::ostream* errStrm = NULL);
46 
47 template <class ScalarType, class OrdinalType>
48 int countPackTriplesMpi(MPI_Datatype ordinalDt,
49  MPI_Datatype scalarDt,
50  const int numEnt,
51  MPI_Comm comm,
52  int& size,
53  std::ostream* errStrm = NULL) {
54  using std::endl;
55  int errCode = MPI_SUCCESS;
56 
57  int totalSize = 0; // return value
58 
59  // Count the global row and column indices.
60  {
61  int curSize = 0;
62  // We're packing two ordinals, the row resp. column index.
63  errCode = MPI_Pack_size(2, ordinalDt, comm, &curSize);
64  if (errCode != MPI_SUCCESS) {
65  if (errStrm != NULL) {
66  *errStrm << "countPackTripleMpi: MPI_Pack_size failed on "
67  "ordinalDt call"
68  << endl;
69  }
70  return errCode;
71  }
72  totalSize += curSize;
73  }
74  // Count the matrix value.
75  {
76  int curSize = 0;
77  errCode = MPI_Pack_size(1, scalarDt, comm, &curSize);
78  if (errCode != MPI_SUCCESS) {
79  if (errStrm != NULL) {
80  *errStrm << "countPackTripleMpi: MPI_Pack_size failed on "
81  "scalarDt call"
82  << endl;
83  }
84  return errCode;
85  }
86  totalSize += curSize; // one Scalar
87  }
88  totalSize *= numEnt; // all the entries we want to pack
89 
90  size = totalSize; // "commit" the result
91  return errCode;
92 }
93 
94 template <class ScalarType, class OrdinalType>
95 int packTripleMpi(const OrdinalType gblRowInd,
96  const OrdinalType gblColInd,
97  MPI_Datatype ordinalDt,
98  const ScalarType& val,
99  MPI_Datatype scalarDt,
100  char outBuf[],
101  const int outBufSize,
102  int& outBufCurPos,
103  MPI_Comm comm,
104  std::ostream* errStrm = NULL) {
105  using std::endl;
106  int errCode = MPI_SUCCESS;
107 
108  // Combine the two indices into a single MPI_Pack call.
109  OrdinalType inds[2] = {gblRowInd, gblColInd};
110  errCode = MPI_Pack(inds, 2, ordinalDt,
111  outBuf, outBufSize, &outBufCurPos, comm);
112  if (errCode != MPI_SUCCESS) {
113  if (errStrm != NULL) {
114  *errStrm << "packTripleMpi: MPI_Pack failed for indices i=" << gblRowInd
115  << ", j=" << gblColInd << ", where outBufSize=" << outBufSize
116  << " and outBufCurPos=" << outBufCurPos << "." << endl;
117  }
118  return errCode;
119  }
120  // mfh 17,20 Jan 2017: Some (generally older) MPI implementations
121  // want the first argument to be a pointer to nonconst, even though
122  // MPI_Pack does not modify that argument.
123  errCode = MPI_Pack(const_cast<ScalarType*>(&val), 1, scalarDt,
124  outBuf, outBufSize, &outBufCurPos, comm);
125  if (errCode != MPI_SUCCESS) {
126  if (errStrm != NULL) {
127  *errStrm << "packTripleMpi: MPI_Pack failed on val = " << val
128  << endl;
129  }
130  return errCode;
131  }
132  return errCode;
133 }
134 
135 template <class ScalarType, class OrdinalType>
136 int packTriplesMpi(const OrdinalType gblRowInds[],
137  const OrdinalType gblColInds[],
138  MPI_Datatype ordinalDt,
139  const ScalarType vals[],
140  MPI_Datatype scalarDt,
141  const int numEnt,
142  char outBuf[],
143  const int outBufSize,
144  int& outBufCurPos,
145  MPI_Comm comm,
146  std::ostream* errStrm = NULL) {
147  using std::endl;
148  int errCode = MPI_SUCCESS;
149 
150  for (int k = 0; k < numEnt; ++k) {
151  errCode = packTripleMpi(gblRowInds[k], gblColInds[k], ordinalDt,
152  vals[k], scalarDt, outBuf, outBufSize,
153  outBufCurPos, comm, errStrm);
154  if (errCode != MPI_SUCCESS) {
155  if (errStrm != NULL) {
156  *errStrm << "packTriplesMpi: packTripleMpi failed at entry k=" << k
157  << endl;
158  }
159  return errCode;
160  }
161  }
162  return errCode;
163 }
164 
165 template <class ScalarType, class OrdinalType>
166 int unpackTripleMpi(const char inBuf[],
167  const int inBufSize,
168  int& inBufCurPos,
169  OrdinalType& gblRowInd,
170  OrdinalType& gblColInd,
171  MPI_Datatype ordinalDt,
172  ScalarType& val,
173  MPI_Datatype scalarDt,
174  MPI_Comm comm,
175  std::ostream* errStrm = NULL) {
176  using std::endl;
177  int errCode = MPI_SUCCESS;
178 
179  // mfh 17 Jan 2017: Some (generally older) MPI implementations want
180  // the input buffer argument to be a pointer to nonconst, even
181  // though MPI_Unpack does not modify that argument.
182 
183  // Combine the two indices into a single MPI_Pack call.
184  OrdinalType inds[2] = {static_cast<OrdinalType>(0),
185  static_cast<OrdinalType>(0)};
186  errCode = MPI_Unpack(const_cast<char*>(inBuf), inBufSize, &inBufCurPos,
187  inds, 2, ordinalDt, comm);
188  if (errCode != MPI_SUCCESS) {
189  if (errStrm != NULL) {
190  *errStrm << "unpackTripleMpi: MPI_Unpack failed when unpacking indices: "
191  "inBufSize="
192  << inBufSize << ", inBufCurPos=" << inBufCurPos << endl;
193  }
194  return errCode;
195  }
196  gblRowInd = inds[0];
197  gblColInd = inds[1];
198 
199  // mfh 17 Jan 2017: Some (generally older) MPI implementations want
200  // the input buffer argument to be a pointer to nonconst, even
201  // though MPI_Unpack does not modify that argument.
202  errCode = MPI_Unpack(const_cast<char*>(inBuf), inBufSize, &inBufCurPos,
203  &val, 1, scalarDt, comm);
204  if (errCode != MPI_SUCCESS) {
205  if (errStrm != NULL) {
206  *errStrm << "unpackTripleMpi: MPI_Unpack failed when unpacking value: "
207  "inBufSize="
208  << inBufSize << ", inBufCurPos=" << inBufCurPos << endl;
209  }
210  return errCode;
211  }
212  return errCode;
213 }
214 
215 int unpackTriplesCountMpi(const char inBuf[],
216  const int inBufSize,
217  int& inBufCurPos,
218  int& numEnt,
219  MPI_Comm comm,
220  std::ostream* errStrm = NULL);
221 
222 template <class ScalarType, class OrdinalType>
223 int unpackTriplesMpi(const char inBuf[],
224  const int inBufSize,
225  int& inBufCurPos,
226  OrdinalType gblRowInds[],
227  OrdinalType gblColInds[],
228  MPI_Datatype ordinalDt,
229  ScalarType vals[],
230  MPI_Datatype scalarDt,
231  const int numEnt, // input arg, from unpackTriplesCountMpi
232  MPI_Comm comm,
233  std::ostream* errStrm = NULL) {
234  using std::endl;
235  int errCode = MPI_SUCCESS;
236 
237  for (int k = 0; k < numEnt; ++k) {
238  errCode = unpackTripleMpi(inBuf, inBufSize, inBufCurPos,
239  gblRowInds[k], gblColInds[k], ordinalDt,
240  vals[k], scalarDt, comm, errStrm);
241  if (errCode != MPI_SUCCESS) {
242  if (errStrm != NULL) {
243  *errStrm << "unpackTriplesMpi: packTripleMpi failed at entry k=" << k
244  << ": inBufSize=" << inBufSize
245  << ", inBufCurPos=" << inBufCurPos
246  << "." << endl;
247  }
248  return errCode;
249  }
250  }
251  return errCode;
252 }
253 
254 #endif // HAVE_TPETRACORE_MPI
255 
256 //
257 // SKIP DOWN TO HERE FOR "PUBLIC" INTERFACE
258 //
259 
280 int countPackTriplesCount(const ::Teuchos::Comm<int>& comm,
281  int& size,
282  std::ostream* errStrm = NULL);
283 
309 template <class ScalarType, class OrdinalType>
310 int countPackTriples(const int numEnt,
311  const ::Teuchos::Comm<int>& comm,
312  int& size, // output argument
313  std::ostream* errStrm = NULL) {
314 #ifdef HAVE_TPETRACORE_MPI
315  using ::Tpetra::Details::extractMpiCommFromTeuchos;
316  using ::Tpetra::Details::MpiTypeTraits;
317 
318  static_assert(MpiTypeTraits<ScalarType>::isSpecialized,
319  "countPackTriples: "
320  "ScalarType lacks an MpiTypeTraits specialization.");
321  static_assert(MpiTypeTraits<OrdinalType>::isSpecialized,
322  "countPackTriples: "
323  "OrdinalType lacks an MpiTypeTraits specialization.");
324 
325  MPI_Comm mpiComm = extractMpiCommFromTeuchos(comm);
326  MPI_Datatype ordinalDt = MpiTypeTraits<OrdinalType>::getType();
327  MPI_Datatype scalarDt = MpiTypeTraits<ScalarType>::getType();
328 
329  const int errCode =
330  countPackTriplesMpi<ScalarType, OrdinalType>(ordinalDt, scalarDt,
331  numEnt, mpiComm,
332  size, errStrm);
333  if (MpiTypeTraits<ScalarType>::needsFree) {
334  (void)MPI_Type_free(&scalarDt);
335  }
336  if (MpiTypeTraits<OrdinalType>::needsFree) {
337  (void)MPI_Type_free(&ordinalDt);
338  }
339  return errCode;
340 
341 #else // NOT HAVE_TPETRACORE_MPI
342  if (errStrm != NULL) {
343  *errStrm << "countPackTriples: Not implemented (no need; there's no need "
344  "to pack or unpack anything if there's only one process)."
345  << std::endl;
346  }
347  return -1;
348 #endif // HAVE_TPETRACORE_MPI
349 }
350 
376 int packTriplesCount(const int numEnt,
377  char outBuf[],
378  const int outBufSize,
379  int& outBufCurPos,
380  const ::Teuchos::Comm<int>& comm,
381  std::ostream* errStrm = NULL);
382 
408 template <class ScalarType, class OrdinalType>
409 int
410 #ifdef HAVE_TPETRACORE_MPI
411 packTriples(const OrdinalType gblRowInds[],
412  const OrdinalType gblColInds[],
413  const ScalarType vals[],
414  const int numEnt,
415  char outBuf[],
416  const int outBufSize,
417  int& outBufCurPos,
418  const ::Teuchos::Comm<int>& comm,
419  std::ostream* errStrm = NULL)
420 #else // NOT HAVE_TPETRACORE_MPI
421 packTriples(const OrdinalType /* gblRowInds */[],
422  const OrdinalType /* gblColInds */[],
423  const ScalarType /* vals */[],
424  const int /* numEnt */,
425  char /* outBuf */[],
426  const int /* outBufSize */,
427  int& /* outBufCurPos */,
428  const ::Teuchos::Comm<int>& /* comm */,
429  std::ostream* errStrm = NULL)
430 #endif // HAVE_TPETRACORE_MPI
431 {
432 #ifdef HAVE_TPETRACORE_MPI
433  using ::Tpetra::Details::extractMpiCommFromTeuchos;
434  using ::Tpetra::Details::MpiTypeTraits;
435 
436  static_assert(MpiTypeTraits<ScalarType>::isSpecialized,
437  "packTriples: "
438  "ScalarType lacks an MpiTypeTraits specialization.");
439  static_assert(MpiTypeTraits<OrdinalType>::isSpecialized,
440  "packTriples: "
441  "OrdinalType lacks an MpiTypeTraits specialization.");
442 
443  MPI_Comm mpiComm = extractMpiCommFromTeuchos(comm);
444  MPI_Datatype ordinalDt = MpiTypeTraits<OrdinalType>::getType();
445  MPI_Datatype scalarDt = MpiTypeTraits<ScalarType>::getType();
446 
447  const int errCode =
448  packTriplesMpi(gblRowInds, gblColInds, ordinalDt, vals, scalarDt,
449  numEnt, outBuf, outBufSize, outBufCurPos, mpiComm, errStrm);
450  if (MpiTypeTraits<ScalarType>::needsFree) {
451  (void)MPI_Type_free(&scalarDt);
452  }
453  if (MpiTypeTraits<OrdinalType>::needsFree) {
454  (void)MPI_Type_free(&ordinalDt);
455  }
456  return errCode;
457 
458 #else // NOT HAVE_TPETRACORE_MPI
459  if (errStrm != NULL) {
460  *errStrm << "packTriples: Not implemented (no need; there's no need to "
461  "pack or unpack anything if there's only one process)."
462  << std::endl;
463  }
464  return -1;
465 #endif // HAVE_TPETRACORE_MPI
466 }
467 
491 int unpackTriplesCount(const char inBuf[],
492  const int inBufSize,
493  int& inBufCurPos,
494  int& numEnt, // output argument!
495  const ::Teuchos::Comm<int>& comm,
496  std::ostream* errStrm = NULL);
497 
526 template <class ScalarType, class OrdinalType>
527 int
528 #ifdef HAVE_TPETRACORE_MPI
529 unpackTriples(const char inBuf[],
530  const int inBufSize,
531  int& inBufCurPos,
532  OrdinalType gblRowInds[],
533  OrdinalType gblColInds[],
534  ScalarType vals[],
535  const int numEnt,
536  const ::Teuchos::Comm<int>& comm,
537  std::ostream* errStrm = NULL)
538 #else // NOT HAVE_TPETRACORE_MPI
539 unpackTriples(const char /* inBuf */[],
540  const int /* inBufSize */,
541  int& /* inBufCurPos */,
542  OrdinalType /* gblRowInds */[],
543  OrdinalType /* gblColInds */[],
544  ScalarType /* vals */[],
545  const int /* numEnt */,
546  const ::Teuchos::Comm<int>& /* comm */,
547  std::ostream* errStrm = NULL)
548 #endif // HAVE_TPETRACORE_MPI
549 {
550 #ifdef HAVE_TPETRACORE_MPI
551  using ::Tpetra::Details::extractMpiCommFromTeuchos;
552  using ::Tpetra::Details::MpiTypeTraits;
553 
554  static_assert(MpiTypeTraits<ScalarType>::isSpecialized,
555  "unpackTriples: "
556  "ScalarType lacks an MpiTypeTraits specialization.");
557  static_assert(MpiTypeTraits<OrdinalType>::isSpecialized,
558  "unpackTriples: "
559  "OrdinalType lacks an MpiTypeTraits specialization.");
560 
561  MPI_Comm mpiComm = extractMpiCommFromTeuchos(comm);
562  MPI_Datatype ordinalDt = MpiTypeTraits<OrdinalType>::getType();
563  MPI_Datatype scalarDt = MpiTypeTraits<ScalarType>::getType();
564 
565  const int errCode =
566  unpackTriplesMpi(inBuf, inBufSize, inBufCurPos,
567  gblRowInds, gblColInds, ordinalDt,
568  vals, scalarDt, numEnt, mpiComm, errStrm);
569  if (MpiTypeTraits<ScalarType>::needsFree) {
570  (void)MPI_Type_free(&scalarDt);
571  }
572  if (MpiTypeTraits<OrdinalType>::needsFree) {
573  (void)MPI_Type_free(&ordinalDt);
574  }
575  return errCode;
576 
577 #else // NOT HAVE_TPETRACORE_MPI
578  if (errStrm != NULL) {
579  *errStrm << "unpackTriples: Not implemented (no need; there's no need to "
580  "pack or unpack anything if there's only one process)."
581  << std::endl;
582  }
583  return -1;
584 #endif // HAVE_TPETRACORE_MPI
585 }
586 
587 } // namespace Details
588 } // namespace Tpetra
589 
590 #endif // TPETRA_DETAILS_PACKTRIPLES_HPP
int packTriplesCount(const int, char[], const int, int &, const ::Teuchos::Comm< int > &, std::ostream *errStrm)
Pack the count (number) of matrix triples.
Declaration of Tpetra::Details::extractMpiCommFromTeuchos.
Add specializations of Teuchos::Details::MpiTypeTraits for Kokkos::complex&lt;float&gt; and Kokkos::complex...
int unpackTriplesCount(const char[], const int, int &, int &, const ::Teuchos::Comm< int > &, std::ostream *errStrm)
Unpack just the count of triples from the given input buffer.
int countPackTriplesCount(const ::Teuchos::Comm< int > &, int &size, std::ostream *errStrm)
Compute the buffer size required by packTriples for packing the number of matrix entries (&quot;triples&quot;)...
int countPackTriples(const int numEnt, const ::Teuchos::Comm< int > &comm, int &size, std::ostream *errStrm=NULL)
Compute the buffer size required by packTriples for packing numEnt number of (i,j,A(i,j)) matrix entries (&quot;triples&quot;).
int unpackTriples(const char[], const int, int &, OrdinalType[], OrdinalType[], ScalarType[], const int, const ::Teuchos::Comm< int > &, std::ostream *errStrm=NULL)
Unpack matrix entries (&quot;triples&quot; (i, j, A(i,j))) from the given input buffer.
int packTriples(const OrdinalType[], const OrdinalType[], const ScalarType[], const int, char[], const int, int &, const ::Teuchos::Comm< int > &, std::ostream *errStrm=NULL)
Pack matrix entries (&quot;triples&quot; (i, j, A(i,j))) into the given output buffer.