Tpetra parallel linear algebra  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Tpetra_Details_PackTriples.hpp
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Tpetra: Templated Linear Algebra Services Package
5 // Copyright (2008) Sandia Corporation
6 //
7 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
8 // the U.S. Government retains certain rights in this software.
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 TPETRA_DETAILS_PACKTRIPLES_HPP
43 #define TPETRA_DETAILS_PACKTRIPLES_HPP
44 
45 #include "TpetraCore_config.h"
46 #include "Teuchos_Comm.hpp"
47 #ifdef HAVE_TPETRACORE_MPI
50 #endif // HAVE_TPETRACORE_MPI
51 #include <ostream>
52 
53 namespace Tpetra {
54 namespace Details {
55 
56 //
57 // Search for "SKIP DOWN TO HERE" (omit quotes) for the "public"
58 // interface. I put "public" in quotes because it's public only for
59 // Tpetra developers, NOT for Tpetra users.
60 //
61 
62 #ifdef HAVE_TPETRACORE_MPI
63 
64 // It's not useful to pack or unpack if not using MPI. Thus, we only
65 // need to define these with MPI. For a non-MPI build, we just need
66 // some outer stub interface that throws an exception.
67 
68 int
69 countPackTriplesCountMpi (MPI_Comm comm,
70  int& size,
71  std::ostream* errStrm = NULL);
72 
73 int
74 packTriplesCountMpi (const int numEnt,
75  char outBuf[],
76  const int outBufSize,
77  int& outBufCurPos,
78  MPI_Comm comm,
79  std::ostream* errStrm = NULL);
80 
81 template<class ScalarType, class OrdinalType>
82 int
83 countPackTriplesMpi (MPI_Datatype ordinalDt,
84  MPI_Datatype scalarDt,
85  const int numEnt,
86  MPI_Comm comm,
87  int& size,
88  std::ostream* errStrm = NULL)
89 {
90  using std::endl;
91  int errCode = MPI_SUCCESS;
92 
93  int totalSize = 0; // return value
94 
95  // Count the global row and column indices.
96  {
97  int curSize = 0;
98  // We're packing two ordinals, the row resp. column index.
99  errCode = MPI_Pack_size (2, ordinalDt, comm, &curSize);
100  if (errCode != MPI_SUCCESS) {
101  if (errStrm != NULL) {
102  *errStrm << "countPackTripleMpi: MPI_Pack_size failed on "
103  "ordinalDt call" << endl;
104  }
105  return errCode;
106  }
107  totalSize += curSize;
108  }
109  // Count the matrix value.
110  {
111  int curSize = 0;
112  errCode = MPI_Pack_size (1, scalarDt, comm, &curSize);
113  if (errCode != MPI_SUCCESS) {
114  if (errStrm != NULL) {
115  *errStrm << "countPackTripleMpi: MPI_Pack_size failed on "
116  "scalarDt call" << endl;
117  }
118  return errCode;
119  }
120  totalSize += curSize; // one Scalar
121  }
122  totalSize *= numEnt; // all the entries we want to pack
123 
124  size = totalSize; // "commit" the result
125  return errCode;
126 }
127 
128 template<class ScalarType, class OrdinalType>
129 int
130 packTripleMpi (const OrdinalType gblRowInd,
131  const OrdinalType gblColInd,
132  MPI_Datatype ordinalDt,
133  const ScalarType& val,
134  MPI_Datatype scalarDt,
135  char outBuf[],
136  const int outBufSize,
137  int& outBufCurPos,
138  MPI_Comm comm,
139  std::ostream* errStrm = NULL)
140 {
141  using std::endl;
142  int errCode = MPI_SUCCESS;
143 
144  // Combine the two indices into a single MPI_Pack call.
145  OrdinalType inds[2] = {gblRowInd, gblColInd};
146  errCode = MPI_Pack (inds, 2, ordinalDt,
147  outBuf, outBufSize, &outBufCurPos, comm);
148  if (errCode != MPI_SUCCESS) {
149  if (errStrm != NULL) {
150  *errStrm << "packTripleMpi: MPI_Pack failed for indices i=" << gblRowInd
151  << ", j=" << gblColInd << ", where outBufSize=" << outBufSize
152  << " and outBufCurPos=" << outBufCurPos << "." << endl;
153  }
154  return errCode;
155  }
156  // mfh 17,20 Jan 2017: Some (generally older) MPI implementations
157  // want the first argument to be a pointer to nonconst, even though
158  // MPI_Pack does not modify that argument.
159  errCode = MPI_Pack (const_cast<ScalarType*> (&val), 1, scalarDt,
160  outBuf, outBufSize, &outBufCurPos, comm);
161  if (errCode != MPI_SUCCESS) {
162  if (errStrm != NULL) {
163  *errStrm << "packTripleMpi: MPI_Pack failed on val = " << val
164  << endl;
165  }
166  return errCode;
167  }
168  return errCode;
169 }
170 
171 template<class ScalarType, class OrdinalType>
172 int
173 packTriplesMpi (const OrdinalType gblRowInds[],
174  const OrdinalType gblColInds[],
175  MPI_Datatype ordinalDt,
176  const ScalarType vals[],
177  MPI_Datatype scalarDt,
178  const int numEnt,
179  char outBuf[],
180  const int outBufSize,
181  int& outBufCurPos,
182  MPI_Comm comm,
183  std::ostream* errStrm = NULL)
184 {
185  using std::endl;
186  int errCode = MPI_SUCCESS;
187 
188  for (int k = 0; k < numEnt; ++k) {
189  errCode = packTripleMpi (gblRowInds[k], gblColInds[k], ordinalDt,
190  vals[k], scalarDt, outBuf, outBufSize,
191  outBufCurPos, comm, errStrm);
192  if (errCode != MPI_SUCCESS) {
193  if (errStrm != NULL) {
194  *errStrm << "packTriplesMpi: packTripleMpi failed at entry k=" << k
195  << endl;
196  }
197  return errCode;
198  }
199  }
200  return errCode;
201 }
202 
203 template<class ScalarType, class OrdinalType>
204 int
205 unpackTripleMpi (const char inBuf[],
206  const int inBufSize,
207  int& inBufCurPos,
208  OrdinalType& gblRowInd,
209  OrdinalType& gblColInd,
210  MPI_Datatype ordinalDt,
211  ScalarType& val,
212  MPI_Datatype scalarDt,
213  MPI_Comm comm,
214  std::ostream* errStrm = NULL)
215 {
216  using std::endl;
217  int errCode = MPI_SUCCESS;
218 
219  // mfh 17 Jan 2017: Some (generally older) MPI implementations want
220  // the input buffer argument to be a pointer to nonconst, even
221  // though MPI_Unpack does not modify that argument.
222 
223  // Combine the two indices into a single MPI_Pack call.
224  OrdinalType inds[2] = {static_cast<OrdinalType> (0),
225  static_cast<OrdinalType> (0)};
226  errCode = MPI_Unpack (const_cast<char*> (inBuf), inBufSize, &inBufCurPos,
227  inds, 2, ordinalDt, comm);
228  if (errCode != MPI_SUCCESS) {
229  if (errStrm != NULL) {
230  *errStrm << "unpackTripleMpi: MPI_Unpack failed when unpacking indices: "
231  "inBufSize=" << inBufSize << ", inBufCurPos=" << inBufCurPos << endl;
232  }
233  return errCode;
234  }
235  gblRowInd = inds[0];
236  gblColInd = inds[1];
237 
238  // mfh 17 Jan 2017: Some (generally older) MPI implementations want
239  // the input buffer argument to be a pointer to nonconst, even
240  // though MPI_Unpack does not modify that argument.
241  errCode = MPI_Unpack (const_cast<char*> (inBuf), inBufSize, &inBufCurPos,
242  &val, 1, scalarDt, comm);
243  if (errCode != MPI_SUCCESS) {
244  if (errStrm != NULL) {
245  *errStrm << "unpackTripleMpi: MPI_Unpack failed when unpacking value: "
246  "inBufSize=" << inBufSize << ", inBufCurPos=" << inBufCurPos << endl;
247  }
248  return errCode;
249  }
250  return errCode;
251 }
252 
253 int
254 unpackTriplesCountMpi (const char inBuf[],
255  const int inBufSize,
256  int& inBufCurPos,
257  int& numEnt,
258  MPI_Comm comm,
259  std::ostream* errStrm = NULL);
260 
261 template<class ScalarType, class OrdinalType>
262 int
263 unpackTriplesMpi (const char inBuf[],
264  const int inBufSize,
265  int& inBufCurPos,
266  OrdinalType gblRowInds[],
267  OrdinalType gblColInds[],
268  MPI_Datatype ordinalDt,
269  ScalarType vals[],
270  MPI_Datatype scalarDt,
271  const int numEnt, // input arg, from unpackTriplesCountMpi
272  MPI_Comm comm,
273  std::ostream* errStrm = NULL)
274 {
275  using std::endl;
276  int errCode = MPI_SUCCESS;
277 
278  for (int k = 0; k < numEnt; ++k) {
279  errCode = unpackTripleMpi (inBuf, inBufSize, inBufCurPos,
280  gblRowInds[k], gblColInds[k], ordinalDt,
281  vals[k], scalarDt, comm, errStrm);
282  if (errCode != MPI_SUCCESS) {
283  if (errStrm != NULL) {
284  *errStrm << "unpackTriplesMpi: packTripleMpi failed at entry k=" << k
285  << ": inBufSize=" << inBufSize
286  << ", inBufCurPos=" << inBufCurPos
287  << "." << endl;
288  }
289  return errCode;
290  }
291  }
292  return errCode;
293 }
294 
295 #endif // HAVE_TPETRACORE_MPI
296 
297 //
298 // SKIP DOWN TO HERE FOR "PUBLIC" INTERFACE
299 //
300 
321 int
322 countPackTriplesCount (const ::Teuchos::Comm<int>& comm,
323  int& size,
324  std::ostream* errStrm = NULL);
325 
351 template<class ScalarType, class OrdinalType>
352 int
353 countPackTriples (const int numEnt,
354  const ::Teuchos::Comm<int>& comm,
355  int& size, // output argument
356  std::ostream* errStrm = NULL)
357 {
358 #ifdef HAVE_TPETRACORE_MPI
359  using ::Tpetra::Details::extractMpiCommFromTeuchos;
360  using ::Tpetra::Details::MpiTypeTraits;
361 
362  static_assert (MpiTypeTraits<ScalarType>::isSpecialized, "countPackTriples: "
363  "ScalarType lacks an MpiTypeTraits specialization.");
364  static_assert (MpiTypeTraits<OrdinalType>::isSpecialized, "countPackTriples: "
365  "OrdinalType lacks an MpiTypeTraits specialization.");
366 
367  MPI_Comm mpiComm = extractMpiCommFromTeuchos (comm);
368  MPI_Datatype ordinalDt = MpiTypeTraits<OrdinalType>::getType ();
369  MPI_Datatype scalarDt = MpiTypeTraits<ScalarType>::getType ();
370 
371  const int errCode =
372  countPackTriplesMpi<ScalarType, OrdinalType> (ordinalDt, scalarDt,
373  numEnt, mpiComm,
374  size, errStrm);
375  if (MpiTypeTraits<ScalarType>::needsFree) {
376  (void) MPI_Type_free (&scalarDt);
377  }
378  if (MpiTypeTraits<OrdinalType>::needsFree) {
379  (void) MPI_Type_free (&ordinalDt);
380  }
381  return errCode;
382 
383 #else // NOT HAVE_TPETRACORE_MPI
384  if (errStrm != NULL) {
385  *errStrm << "countPackTriples: Not implemented (no need; there's no need "
386  "to pack or unpack anything if there's only one process)." << std::endl;
387  }
388  return -1;
389 #endif // HAVE_TPETRACORE_MPI
390 }
391 
417 int
418 packTriplesCount (const int numEnt,
419  char outBuf[],
420  const int outBufSize,
421  int& outBufCurPos,
422  const ::Teuchos::Comm<int>& comm,
423  std::ostream* errStrm = NULL);
424 
450 template<class ScalarType, class OrdinalType>
451 int
452 #ifdef HAVE_TPETRACORE_MPI
453 packTriples (const OrdinalType gblRowInds[],
454  const OrdinalType gblColInds[],
455  const ScalarType vals[],
456  const int numEnt,
457  char outBuf[],
458  const int outBufSize,
459  int& outBufCurPos,
460  const ::Teuchos::Comm<int>& comm,
461  std::ostream* errStrm = NULL)
462 #else // NOT HAVE_TPETRACORE_MPI
463 packTriples (const OrdinalType /* gblRowInds */ [],
464  const OrdinalType /* gblColInds */ [],
465  const ScalarType /* vals */ [],
466  const int /* numEnt */,
467  char /* outBuf */ [],
468  const int /* outBufSize */,
469  int& /* outBufCurPos */,
470  const ::Teuchos::Comm<int>& /* comm */,
471  std::ostream* errStrm = NULL)
472 #endif // HAVE_TPETRACORE_MPI
473 {
474 #ifdef HAVE_TPETRACORE_MPI
475  using ::Tpetra::Details::extractMpiCommFromTeuchos;
476  using ::Tpetra::Details::MpiTypeTraits;
477 
478  static_assert (MpiTypeTraits<ScalarType>::isSpecialized, "packTriples: "
479  "ScalarType lacks an MpiTypeTraits specialization.");
480  static_assert (MpiTypeTraits<OrdinalType>::isSpecialized, "packTriples: "
481  "OrdinalType lacks an MpiTypeTraits specialization.");
482 
483  MPI_Comm mpiComm = extractMpiCommFromTeuchos (comm);
484  MPI_Datatype ordinalDt = MpiTypeTraits<OrdinalType>::getType ();
485  MPI_Datatype scalarDt = MpiTypeTraits<ScalarType>::getType ();
486 
487  const int errCode =
488  packTriplesMpi (gblRowInds, gblColInds, ordinalDt, vals, scalarDt,
489  numEnt, outBuf, outBufSize, outBufCurPos, mpiComm, errStrm);
490  if (MpiTypeTraits<ScalarType>::needsFree) {
491  (void) MPI_Type_free (&scalarDt);
492  }
493  if (MpiTypeTraits<OrdinalType>::needsFree) {
494  (void) MPI_Type_free (&ordinalDt);
495  }
496  return errCode;
497 
498 #else // NOT HAVE_TPETRACORE_MPI
499  if (errStrm != NULL) {
500  *errStrm << "packTriples: Not implemented (no need; there's no need to "
501  "pack or unpack anything if there's only one process)." << std::endl;
502  }
503  return -1;
504 #endif // HAVE_TPETRACORE_MPI
505 }
506 
530 int
531 unpackTriplesCount (const char inBuf[],
532  const int inBufSize,
533  int& inBufCurPos,
534  int& numEnt, // output argument!
535  const ::Teuchos::Comm<int>& comm,
536  std::ostream* errStrm = NULL);
537 
566 template<class ScalarType, class OrdinalType>
567 int
568 #ifdef HAVE_TPETRACORE_MPI
569 unpackTriples (const char inBuf[],
570  const int inBufSize,
571  int& inBufCurPos,
572  OrdinalType gblRowInds[],
573  OrdinalType gblColInds[],
574  ScalarType vals[],
575  const int numEnt,
576  const ::Teuchos::Comm<int>& comm,
577  std::ostream* errStrm = NULL)
578 #else // NOT HAVE_TPETRACORE_MPI
579 unpackTriples (const char /* inBuf */ [],
580  const int /* inBufSize */,
581  int& /* inBufCurPos */,
582  OrdinalType /* gblRowInds */ [],
583  OrdinalType /* gblColInds */ [],
584  ScalarType /* vals */ [],
585  const int /* numEnt */,
586  const ::Teuchos::Comm<int>& /* comm */,
587  std::ostream* errStrm = NULL)
588 #endif // HAVE_TPETRACORE_MPI
589 {
590 #ifdef HAVE_TPETRACORE_MPI
591  using ::Tpetra::Details::extractMpiCommFromTeuchos;
592  using ::Tpetra::Details::MpiTypeTraits;
593 
594  static_assert (MpiTypeTraits<ScalarType>::isSpecialized, "unpackTriples: "
595  "ScalarType lacks an MpiTypeTraits specialization.");
596  static_assert (MpiTypeTraits<OrdinalType>::isSpecialized, "unpackTriples: "
597  "OrdinalType lacks an MpiTypeTraits specialization.");
598 
599  MPI_Comm mpiComm = extractMpiCommFromTeuchos (comm);
600  MPI_Datatype ordinalDt = MpiTypeTraits<OrdinalType>::getType ();
601  MPI_Datatype scalarDt = MpiTypeTraits<ScalarType>::getType ();
602 
603  const int errCode =
604  unpackTriplesMpi (inBuf, inBufSize, inBufCurPos,
605  gblRowInds, gblColInds, ordinalDt,
606  vals, scalarDt, numEnt, mpiComm, errStrm);
607  if (MpiTypeTraits<ScalarType>::needsFree) {
608  (void) MPI_Type_free (&scalarDt);
609  }
610  if (MpiTypeTraits<OrdinalType>::needsFree) {
611  (void) MPI_Type_free (&ordinalDt);
612  }
613  return errCode;
614 
615 #else // NOT HAVE_TPETRACORE_MPI
616  if (errStrm != NULL) {
617  *errStrm << "unpackTriples: Not implemented (no need; there's no need to "
618  "pack or unpack anything if there's only one process)." << std::endl;
619  }
620  return -1;
621 #endif // HAVE_TPETRACORE_MPI
622 }
623 
624 } // namespace Details
625 } // namespace Tpetra
626 
627 #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.