Tpetra parallel linear algebra  Version of the Day
Tpetra_RowMatrix_def.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_ROWMATRIX_DEF_HPP
43 #define TPETRA_ROWMATRIX_DEF_HPP
44 
45 #include "Tpetra_CrsMatrix.hpp"
46 #include "Tpetra_Map.hpp"
47 #include "Tpetra_RowGraph.hpp"
48 
49 namespace Tpetra {
50 namespace Classes {
51 
52  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
54 
55  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
56  Teuchos::RCP<RowMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> >
58  add (const Scalar& alpha,
60  const Scalar& beta,
61  const Teuchos::RCP<const Map<LocalOrdinal, GlobalOrdinal, Node> >& domainMap,
62  const Teuchos::RCP<const Map<LocalOrdinal, GlobalOrdinal, Node> >& rangeMap,
63  const Teuchos::RCP<Teuchos::ParameterList>& params) const
64  {
65  using Teuchos::Array;
66  using Teuchos::ArrayRCP;
67  using Teuchos::ArrayView;
68  using Teuchos::ParameterList;
69  using Teuchos::RCP;
70  using Teuchos::rcp;
71  using Teuchos::rcp_implicit_cast;
72  using Teuchos::sublist;
73  typedef LocalOrdinal LO;
74  typedef GlobalOrdinal GO;
75  typedef Teuchos::ScalarTraits<Scalar> STS;
76  typedef Map<LO, GO, Node> map_type;
79 
80  const this_type& B = *this; // a convenient abbreviation
81 
82  // If the user didn't supply a domain or range Map, then try to
83  // get one from B first (if it has them), then from A (if it has
84  // them). If we don't have any domain or range Maps, scold the
85  // user.
86  RCP<const map_type> A_domainMap = A.getDomainMap ();
87  RCP<const map_type> A_rangeMap = A.getRangeMap ();
88  RCP<const map_type> B_domainMap = B.getDomainMap ();
89  RCP<const map_type> B_rangeMap = B.getRangeMap ();
90 
91  RCP<const map_type> theDomainMap = domainMap;
92  RCP<const map_type> theRangeMap = rangeMap;
93 
94  if (domainMap.is_null ()) {
95  if (B_domainMap.is_null ()) {
96  TEUCHOS_TEST_FOR_EXCEPTION(
97  A_domainMap.is_null (), std::invalid_argument,
98  "Tpetra::RowMatrix::add: If neither A nor B have a domain Map, "
99  "then you must supply a nonnull domain Map to this method.");
100  theDomainMap = A_domainMap;
101  } else {
102  theDomainMap = B_domainMap;
103  }
104  }
105  if (rangeMap.is_null ()) {
106  if (B_rangeMap.is_null ()) {
107  TEUCHOS_TEST_FOR_EXCEPTION(
108  A_rangeMap.is_null (), std::invalid_argument,
109  "Tpetra::RowMatrix::add: If neither A nor B have a range Map, "
110  "then you must supply a nonnull range Map to this method.");
111  theRangeMap = A_rangeMap;
112  } else {
113  theRangeMap = B_rangeMap;
114  }
115  }
116 
117 #ifdef HAVE_TPETRA_DEBUG
118  // In a debug build, check that A and B have matching domain and
119  // range Maps, if they have domain and range Maps at all. (If
120  // they aren't fill complete, then they may not yet have them.)
121  if (! A_domainMap.is_null () && ! A_rangeMap.is_null ()) {
122  if (! B_domainMap.is_null () && ! B_rangeMap.is_null ()) {
123  TEUCHOS_TEST_FOR_EXCEPTION(
124  ! B_domainMap->isSameAs (*A_domainMap), std::invalid_argument,
125  "Tpetra::RowMatrix::add: The input RowMatrix A must have a domain Map "
126  "which is the same as (isSameAs) this RowMatrix's domain Map.");
127  TEUCHOS_TEST_FOR_EXCEPTION(
128  ! B_rangeMap->isSameAs (*A_rangeMap), std::invalid_argument,
129  "Tpetra::RowMatrix::add: The input RowMatrix A must have a range Map "
130  "which is the same as (isSameAs) this RowMatrix's range Map.");
131  TEUCHOS_TEST_FOR_EXCEPTION(
132  ! domainMap.is_null () && ! domainMap->isSameAs (*B_domainMap),
133  std::invalid_argument,
134  "Tpetra::RowMatrix::add: The input domain Map must be the same as "
135  "(isSameAs) this RowMatrix's domain Map.");
136  TEUCHOS_TEST_FOR_EXCEPTION(
137  ! rangeMap.is_null () && ! rangeMap->isSameAs (*B_rangeMap),
138  std::invalid_argument,
139  "Tpetra::RowMatrix::add: The input range Map must be the same as "
140  "(isSameAs) this RowMatrix's range Map.");
141  }
142  }
143  else if (! B_domainMap.is_null () && ! B_rangeMap.is_null ()) {
144  TEUCHOS_TEST_FOR_EXCEPTION(
145  ! domainMap.is_null () && ! domainMap->isSameAs (*B_domainMap),
146  std::invalid_argument,
147  "Tpetra::RowMatrix::add: The input domain Map must be the same as "
148  "(isSameAs) this RowMatrix's domain Map.");
149  TEUCHOS_TEST_FOR_EXCEPTION(
150  ! rangeMap.is_null () && ! rangeMap->isSameAs (*B_rangeMap),
151  std::invalid_argument,
152  "Tpetra::RowMatrix::add: The input range Map must be the same as "
153  "(isSameAs) this RowMatrix's range Map.");
154  }
155  else {
156  TEUCHOS_TEST_FOR_EXCEPTION(
157  domainMap.is_null () || rangeMap.is_null (), std::invalid_argument,
158  "Tpetra::RowMatrix::add: If neither A nor B have a domain and range "
159  "Map, then you must supply a nonnull domain and range Map to this "
160  "method.");
161  }
162 #endif // HAVE_TPETRA_DEBUG
163 
164  // What parameters do we pass to C's constructor? Do we call
165  // fillComplete on C after filling it? And if so, what parameters
166  // do we pass to C's fillComplete call?
167  bool callFillComplete = true;
168  RCP<ParameterList> constructorSublist;
169  RCP<ParameterList> fillCompleteSublist;
170  if (! params.is_null ()) {
171  callFillComplete = params->get ("Call fillComplete", callFillComplete);
172  constructorSublist = sublist (params, "Constructor parameters");
173  fillCompleteSublist = sublist (params, "fillComplete parameters");
174  }
175 
176  RCP<const map_type> A_rowMap = A.getRowMap ();
177  RCP<const map_type> B_rowMap = B.getRowMap ();
178  RCP<const map_type> C_rowMap = B_rowMap; // see discussion in documentation
179  RCP<crs_matrix_type> C; // The result matrix.
180 
181  // If A and B's row Maps are the same, we can compute an upper
182  // bound on the number of entries in each row of C, before
183  // actually computing the sum. A reasonable upper bound is the
184  // sum of the two entry counts in each row. If we choose this as
185  // the actual per-row upper bound, we can use static profile.
186  if (A_rowMap->isSameAs (*B_rowMap)) {
187  const LO localNumRows = static_cast<LO> (A_rowMap->getNodeNumElements ());
188  ArrayRCP<size_t> C_maxNumEntriesPerRow (localNumRows, 0);
189 
190  // Get the number of entries in each row of A.
191  if (alpha != STS::zero ()) {
192  for (LO localRow = 0; localRow < localNumRows; ++localRow) {
193  const size_t A_numEntries = A.getNumEntriesInLocalRow (localRow);
194  C_maxNumEntriesPerRow[localRow] += A_numEntries;
195  }
196  }
197  // Get the number of entries in each row of B.
198  if (beta != STS::zero ()) {
199  for (LO localRow = 0; localRow < localNumRows; ++localRow) {
200  const size_t B_numEntries = B.getNumEntriesInLocalRow (localRow);
201  C_maxNumEntriesPerRow[localRow] += B_numEntries;
202  }
203  }
204  // Construct the result matrix C.
205  if (constructorSublist.is_null ()) {
206  C = rcp (new crs_matrix_type (C_rowMap, C_maxNumEntriesPerRow,
207  StaticProfile));
208  } else {
209  C = rcp (new crs_matrix_type (C_rowMap, C_maxNumEntriesPerRow,
210  StaticProfile, constructorSublist));
211  }
212  // Since A and B have the same row Maps, we could add them
213  // together all at once and merge values before we call
214  // insertGlobalValues. However, we don't really need to, since
215  // we've already allocated enough space in each row of C for C
216  // to do the merge itself.
217  }
218  else { // the row Maps of A and B are not the same
219  // Construct the result matrix C.
220  if (constructorSublist.is_null ()) {
221  C = rcp (new crs_matrix_type (C_rowMap, 0, DynamicProfile));
222  } else {
223  C = rcp (new crs_matrix_type (C_rowMap, 0, DynamicProfile,
224  constructorSublist));
225  }
226  }
227 
228 #ifdef HAVE_TPETRA_DEBUG
229  TEUCHOS_TEST_FOR_EXCEPTION(C.is_null (), std::logic_error,
230  "Tpetra::RowMatrix::add: C should not be null at this point. "
231  "Please report this bug to the Tpetra developers.");
232 #endif // HAVE_TPETRA_DEBUG
233  //
234  // Compute C = alpha*A + beta*B.
235  //
236  Array<GO> ind;
237  Array<Scalar> val;
238 
239  if (alpha != STS::zero ()) {
240  const LO A_localNumRows = static_cast<LO> (A_rowMap->getNodeNumElements ());
241  for (LO localRow = 0; localRow < A_localNumRows; ++localRow) {
242  size_t A_numEntries = A.getNumEntriesInLocalRow (localRow);
243  const GO globalRow = A_rowMap->getGlobalElement (localRow);
244  if (A_numEntries > static_cast<size_t> (ind.size ())) {
245  ind.resize (A_numEntries);
246  val.resize (A_numEntries);
247  }
248  ArrayView<GO> indView = ind (0, A_numEntries);
249  ArrayView<Scalar> valView = val (0, A_numEntries);
250  A.getGlobalRowCopy (globalRow, indView, valView, A_numEntries);
251 
252  if (alpha != STS::one ()) {
253  for (size_t k = 0; k < A_numEntries; ++k) {
254  valView[k] *= alpha;
255  }
256  }
257  C->insertGlobalValues (globalRow, indView, valView);
258  }
259  }
260 
261  if (beta != STS::zero ()) {
262  const LO B_localNumRows = static_cast<LO> (B_rowMap->getNodeNumElements ());
263  for (LO localRow = 0; localRow < B_localNumRows; ++localRow) {
264  size_t B_numEntries = B.getNumEntriesInLocalRow (localRow);
265  const GO globalRow = B_rowMap->getGlobalElement (localRow);
266  if (B_numEntries > static_cast<size_t> (ind.size ())) {
267  ind.resize (B_numEntries);
268  val.resize (B_numEntries);
269  }
270  ArrayView<GO> indView = ind (0, B_numEntries);
271  ArrayView<Scalar> valView = val (0, B_numEntries);
272  B.getGlobalRowCopy (globalRow, indView, valView, B_numEntries);
273 
274  if (beta != STS::one ()) {
275  for (size_t k = 0; k < B_numEntries; ++k) {
276  valView[k] *= beta;
277  }
278  }
279  C->insertGlobalValues (globalRow, indView, valView);
280  }
281  }
282 
283  if (callFillComplete) {
284  if (fillCompleteSublist.is_null ()) {
285  C->fillComplete (theDomainMap, theRangeMap);
286  } else {
287  C->fillComplete (theDomainMap, theRangeMap, fillCompleteSublist);
288  }
289  }
290 
291  return rcp_implicit_cast<this_type> (C);
292  }
293 
294 
295  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
296  void
298  pack (const Teuchos::ArrayView<const LocalOrdinal>& exportLIDs,
299  Teuchos::Array<char>& exports,
300  const Teuchos::ArrayView<size_t>& numPacketsPerLID,
301  size_t& constantNumPackets,
302  Distributor &distor) const
303  {
304 #ifdef HAVE_TPETRA_DEBUG
305  const char tfecfFuncName[] = "pack: ";
306  {
307  using Teuchos::reduceAll;
308  std::ostringstream msg;
309  int lclBad = 0;
310  try {
311  this->packImpl (exportLIDs, exports, numPacketsPerLID,
312  constantNumPackets, distor);
313  } catch (std::exception& e) {
314  lclBad = 1;
315  msg << e.what ();
316  }
317  int gblBad = 0;
318  const Teuchos::Comm<int>& comm = * (this->getComm ());
319  reduceAll<int, int> (comm, Teuchos::REDUCE_MAX,
320  lclBad, Teuchos::outArg (gblBad));
321  if (gblBad != 0) {
322  const int myRank = comm.getRank ();
323  const int numProcs = comm.getSize ();
324  for (int r = 0; r < numProcs; ++r) {
325  if (r == myRank && lclBad != 0) {
326  std::ostringstream os;
327  os << "Proc " << myRank << ": " << msg.str () << std::endl;
328  std::cerr << os.str ();
329  }
330  comm.barrier ();
331  comm.barrier ();
332  comm.barrier ();
333  }
334  TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
335  true, std::logic_error, "packImpl() threw an exception on one or "
336  "more participating processes.");
337  }
338  }
339 #else
340  this->packImpl (exportLIDs, exports, numPacketsPerLID,
341  constantNumPackets, distor);
342 #endif // HAVE_TPETRA_DEBUG
343  }
344 
345  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
346  void
348  allocatePackSpace (Teuchos::Array<char>& exports,
349  size_t& totalNumEntries,
350  const Teuchos::ArrayView<const LocalOrdinal>& exportLIDs) const
351  {
352  typedef LocalOrdinal LO;
353  typedef GlobalOrdinal GO;
354  typedef typename Teuchos::ArrayView<const LO>::size_type size_type;
355  //const char tfecfFuncName[] = "allocatePackSpace: ";
356  const size_type numExportLIDs = exportLIDs.size ();
357 
358  // Count the total number of entries to send.
359  totalNumEntries = 0;
360  for (size_type i = 0; i < numExportLIDs; ++i) {
361  const LO lclRow = exportLIDs[i];
362  size_t curNumEntries = this->getNumEntriesInLocalRow (lclRow);
363  // FIXME (mfh 25 Jan 2015) We should actually report invalid row
364  // indices as an error. Just consider them nonowned for now.
365  if (curNumEntries == Teuchos::OrdinalTraits<size_t>::invalid ()) {
366  curNumEntries = 0;
367  }
368  totalNumEntries += curNumEntries;
369  }
370 
371  // FIXME (mfh 24 Feb 2013) This code is only correct if
372  // sizeof(Scalar) is a meaningful representation of the amount of
373  // data in a Scalar instance. (LO and GO are always built-in
374  // integer types.)
375  //
376  // Allocate the exports array. It does NOT need padding for
377  // alignment, since we use memcpy to write to / read from send /
378  // receive buffers.
379  const size_t allocSize =
380  static_cast<size_t> (numExportLIDs) * sizeof (LO) +
381  totalNumEntries * (sizeof (Scalar) + sizeof (GO));
382  if (static_cast<size_t> (exports.size ()) < allocSize) {
383  exports.resize (allocSize);
384  }
385  }
386 
387  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
388  bool
389  RowMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
390  packRow (char* const numEntOut,
391  char* const valOut,
392  char* const indOut,
393  const size_t numEnt,
394  const LocalOrdinal lclRow) const
395  {
396  using Teuchos::Array;
397  using Teuchos::ArrayView;
398  typedef LocalOrdinal LO;
399  typedef GlobalOrdinal GO;
400  typedef Tpetra::Map<LO, GO, Node> map_type;
401 
402  const LO numEntLO = static_cast<LO> (numEnt);
403  memcpy (numEntOut, &numEntLO, sizeof (LO));
404 
405  if (this->supportsRowViews ()) {
406  if (this->isLocallyIndexed ()) {
407  // If the matrix is locally indexed on the calling process, we
408  // have to use its column Map (which it _must_ have in this
409  // case) to convert to global indices.
410  ArrayView<const LO> indIn;
411  ArrayView<const Scalar> valIn;
412  this->getLocalRowView (lclRow, indIn, valIn);
413  const map_type& colMap = * (this->getColMap ());
414  // Copy column indices one at a time, so that we don't need
415  // temporary storage.
416  for (size_t k = 0; k < numEnt; ++k) {
417  const GO gblIndIn = colMap.getGlobalElement (indIn[k]);
418  memcpy (indOut + k * sizeof (GO), &gblIndIn, sizeof (GO));
419  }
420  memcpy (valOut, valIn.getRawPtr (), numEnt * sizeof (Scalar));
421  }
422  else if (this->isGloballyIndexed ()) {
423  // If the matrix is globally indexed on the calling process,
424  // then we can use the column indices directly. However, we
425  // have to get the global row index. The calling process must
426  // have a row Map, since otherwise it shouldn't be participating
427  // in packing operations.
428  ArrayView<const GO> indIn;
429  ArrayView<const Scalar> valIn;
430  const map_type& rowMap = * (this->getRowMap ());
431  const GO gblRow = rowMap.getGlobalElement (lclRow);
432  this->getGlobalRowView (gblRow, indIn, valIn);
433  memcpy (indOut, indIn.getRawPtr (), numEnt * sizeof (GO));
434  memcpy (valOut, valIn.getRawPtr (), numEnt * sizeof (Scalar));
435  }
436  else {
437  if (numEnt != 0) {
438  return false;
439  }
440  }
441  }
442  else {
443  // FIXME (mfh 25 Jan 2015) Pass in valIn and indIn as scratch
444  // space, instead of allocating them on each call.
445  if (this->isLocallyIndexed ()) {
446  Array<LO> indIn (numEnt);
447  Array<Scalar> valIn (numEnt);
448  size_t theNumEnt = 0;
449  this->getLocalRowCopy (lclRow, indIn (), valIn (), theNumEnt);
450  if (theNumEnt != numEnt) {
451  return false;
452  }
453  const map_type& colMap = * (this->getColMap ());
454  // Copy column indices one at a time, so that we don't need
455  // temporary storage.
456  for (size_t k = 0; k < numEnt; ++k) {
457  const GO gblIndIn = colMap.getGlobalElement (indIn[k]);
458  memcpy (indOut + k * sizeof (GO), &gblIndIn, sizeof (GO));
459  }
460  memcpy (valOut, valIn.getRawPtr (), numEnt * sizeof (Scalar));
461  }
462  else if (this->isGloballyIndexed ()) {
463  Array<GO> indIn (numEnt);
464  Array<Scalar> valIn (numEnt);
465  const map_type& rowMap = * (this->getRowMap ());
466  const GO gblRow = rowMap.getGlobalElement (lclRow);
467  size_t theNumEnt = 0;
468  this->getGlobalRowCopy (gblRow, indIn, valIn, theNumEnt);
469  if (theNumEnt != numEnt) {
470  return false;
471  }
472  memcpy (indOut, indIn.getRawPtr (), numEnt * sizeof (GO));
473  memcpy (valOut, valIn.getRawPtr (), numEnt * sizeof (Scalar));
474  }
475  else {
476  if (numEnt != 0) {
477  return false;
478  }
479  }
480  }
481  return true;
482  }
483 
484  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
485  void
486  RowMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
487  packImpl (const Teuchos::ArrayView<const LocalOrdinal>& exportLIDs,
488  Teuchos::Array<char>& exports,
489  const Teuchos::ArrayView<size_t>& numPacketsPerLID,
490  size_t& constantNumPackets,
491  Distributor& distor) const
492  {
493  using Teuchos::Array;
494  using Teuchos::ArrayView;
495  using Teuchos::as;
496  using Teuchos::av_reinterpret_cast;
497  using Teuchos::RCP;
498  typedef LocalOrdinal LO;
499  typedef GlobalOrdinal GO;
500  typedef typename ArrayView<const LO>::size_type size_type;
501  const char tfecfFuncName[] = "packImpl: ";
502 
503  const size_type numExportLIDs = exportLIDs.size ();
504  TEUCHOS_TEST_FOR_EXCEPTION_CLASS_FUNC(
505  numExportLIDs != numPacketsPerLID.size (), std::invalid_argument,
506  "exportLIDs.size() = " << numExportLIDs << " != numPacketsPerLID.size()"
507  " = " << numPacketsPerLID.size () << ".");
508 
509  // Setting this to zero tells the caller to expect a possibly
510  // different ("nonconstant") number of packets per local index
511  // (i.e., a possibly different number of entries per row).
512  constantNumPackets = 0;
513 
514  // The pack buffer 'exports' enters this method possibly
515  // unallocated. Do the first two parts of "Count, allocate, fill,
516  // compute."
517  size_t totalNumEntries = 0;
518  allocatePackSpace (exports, totalNumEntries, exportLIDs);
519  const size_t bufSize = static_cast<size_t> (exports.size ());
520 
521  // Compute the number of "packets" (in this case, bytes) per
522  // export LID (in this case, local index of the row to send), and
523  // actually pack the data.
524  //
525  // FIXME (mfh 24 Feb 2013, 25 Jan 2015) This code is only correct
526  // if sizeof(Scalar) is a meaningful representation of the amount
527  // of data in a Scalar instance. (LO and GO are always built-in
528  // integer types.)
529 
530  // Variables for error reporting in the loop.
531  size_type firstBadIndex = 0; // only valid if outOfBounds == true.
532  size_t firstBadOffset = 0; // only valid if outOfBounds == true.
533  size_t firstBadNumBytes = 0; // only valid if outOfBounds == true.
534  bool outOfBounds = false;
535  bool packErr = false;
536 
537  char* const exportsRawPtr = exports.getRawPtr ();
538  size_t offset = 0; // current index into 'exports' array.
539  for (size_type i = 0; i < numExportLIDs; ++i) {
540  const LO lclRow = exportLIDs[i];
541  const size_t numEnt = this->getNumEntriesInLocalRow (lclRow);
542 
543  // Only pad this row if it has a nonzero number of entries.
544  if (numEnt == 0) {
545  numPacketsPerLID[i] = 0;
546  }
547  else {
548  char* const numEntBeg = exportsRawPtr + offset;
549  char* const numEntEnd = numEntBeg + sizeof (LO);
550  char* const valBeg = numEntEnd;
551  char* const valEnd = valBeg + numEnt * sizeof (Scalar);
552  char* const indBeg = valEnd;
553  const size_t numBytes = sizeof (LO) +
554  numEnt * (sizeof (Scalar) + sizeof (GO));
555  if (offset > bufSize || offset + numBytes > bufSize) {
556  firstBadIndex = i;
557  firstBadOffset = offset;
558  firstBadNumBytes = numBytes;
559  outOfBounds = true;
560  break;
561  }
562  packErr = ! packRow (numEntBeg, valBeg, indBeg, numEnt, lclRow);
563  if (packErr) {
564  firstBadIndex = i;
565  firstBadOffset = offset;
566  firstBadNumBytes = numBytes;
567  break;
568  }
569  // numPacketsPerLID[i] is the number of "packets" in the
570  // current local row i. Packet=char (really "byte") so use
571  // the number of bytes of the packed data for that row.
572  numPacketsPerLID[i] = numBytes;
573  offset += numBytes;
574  }
575  }
576 
577  // The point of these exceptions is to stop computation if the
578  // above checks found a bug. If HAVE_TPETRA_DEBUG is defined,
579  // Tpetra will do extra all-reduces to check for global
580  // consistency of the error state. Otherwise, throwing an
581  // exception here might cause deadlock, but we accept that as
582  // better than just continuing.
583  TEUCHOS_TEST_FOR_EXCEPTION(
584  outOfBounds, std::logic_error, "First invalid offset into 'exports' "
585  "pack buffer at index i = " << firstBadIndex << ". exportLIDs[i]: "
586  << exportLIDs[firstBadIndex] << ", bufSize: " << bufSize << ", offset: "
587  << firstBadOffset << ", numBytes: " << firstBadNumBytes << ".");
588  TEUCHOS_TEST_FOR_EXCEPTION(
589  packErr, std::logic_error, "First error in packRow() at index i = "
590  << firstBadIndex << ". exportLIDs[i]: " << exportLIDs[firstBadIndex]
591  << ", bufSize: " << bufSize << ", offset: " << firstBadOffset
592  << ", numBytes: " << firstBadNumBytes << ".");
593  }
594 
595  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
596  LocalOrdinal
598  getLocalRowViewRaw (const LocalOrdinal lclRow,
599  LocalOrdinal& numEnt,
600  const LocalOrdinal*& lclColInds,
601  const Scalar*& vals) const
602  {
603  // This is just the default implementation. Subclasses may want
604  // to implement this method in a more efficient way, e.g., to
605  // avoid creating Teuchos::ArrayView instances.
606  Teuchos::ArrayView<const LocalOrdinal> lclColInds_av;
607  Teuchos::ArrayView<const Scalar> vals_av;
608 
609  this->getLocalRowView (lclRow, lclColInds_av, vals_av);
610  numEnt = static_cast<LocalOrdinal> (lclColInds_av.size ());
611  if (numEnt == 0) {
612  lclColInds = NULL;
613  vals = NULL;
614  }
615  else {
616  lclColInds = lclColInds_av.getRawPtr ();
617  vals = vals_av.getRawPtr ();
618  }
619 
620  return static_cast<LocalOrdinal> (0);
621  }
622 
623 } // namespace Classes
624 } // namespace Tpetra
625 
626 //
627 // Explicit instantiation macro
628 //
629 // Must be expanded from within the Tpetra namespace!
630 //
631 
632 #define TPETRA_ROWMATRIX_INSTANT(SCALAR,LO,GO,NODE) \
633  namespace Classes { template class RowMatrix< SCALAR , LO , GO , NODE >; }
634 
635 
636 #endif // TPETRA_ROWMATRIX_DEF_HPP
637 
Tpetra::StaticProfile
Definition: Tpetra_ConfigDefs.hpp:131
Tpetra::Classes::RowMatrix::getGlobalRowCopy
virtual void getGlobalRowCopy(GlobalOrdinal GlobalRow, const Teuchos::ArrayView< GlobalOrdinal > &Indices, const Teuchos::ArrayView< Scalar > &Values, size_t &NumEntries) const =0
Get a copy of the given global row's entries.
Tpetra::Classes::RowMatrix::add
virtual Teuchos::RCP< RowMatrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > add(const Scalar &alpha, const RowMatrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A, const Scalar &beta, const Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > &domainMap=Teuchos::null, const Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > &rangeMap=Teuchos::null, const Teuchos::RCP< Teuchos::ParameterList > &params=Teuchos::null) const
Return a new RowMatrix which is the result of beta*this + alpha*A.
Definition: Tpetra_RowMatrix_def.hpp:58
Tpetra::Classes::Operator::getDomainMap
virtual Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > getDomainMap() const =0
The Map associated with the domain of this operator, which must be compatible with X....
Tpetra::DynamicProfile
Definition: Tpetra_ConfigDefs.hpp:132
Tpetra::Classes::RowMatrix::~RowMatrix
virtual ~RowMatrix()
Destructor (virtual for memory safety of derived classes).
Definition: Tpetra_RowMatrix_def.hpp:53
Tpetra::Classes::CrsMatrix
Sparse matrix that presents a row-oriented interface that lets users read or modify entries.
Definition: Tpetra_CrsMatrix_decl.hpp:424
Tpetra::Classes::RowMatrix::getRowMap
virtual Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > getRowMap() const =0
The Map that describes the distribution of rows over processes.
Tpetra::Classes::RowMatrix::getLocalRowViewRaw
virtual LocalOrdinal getLocalRowViewRaw(const LocalOrdinal lclRow, LocalOrdinal &numEnt, const LocalOrdinal *&lclColInds, const Scalar *&vals) const
Get a constant, nonpersisting, locally indexed view of the given row of the matrix,...
Definition: Tpetra_RowMatrix_def.hpp:598
Tpetra::Distributor
Sets up and executes a communication plan for a Tpetra DistObject.
Definition: Tpetra_Distributor.hpp:188
Tpetra::Classes::RowMatrix::pack
virtual void pack(const Teuchos::ArrayView< const LocalOrdinal > &exportLIDs, Teuchos::Array< char > &exports, const Teuchos::ArrayView< size_t > &numPacketsPerLID, size_t &constantNumPackets, Distributor &distor) const
Pack this object's data for an Import or Export.
Definition: Tpetra_RowMatrix_def.hpp:298
Tpetra::Classes::Map
A parallel distribution of indices over processes.
Definition: Tpetra_Map_decl.hpp:247
Tpetra::Classes::RowMatrix::getNumEntriesInLocalRow
virtual size_t getNumEntriesInLocalRow(LocalOrdinal localRow) const =0
The current number of entries on the calling process in the specified local row.
Tpetra::KokkosRefactor::Details::Impl::outOfBounds
KOKKOS_INLINE_FUNCTION bool outOfBounds(const IntegerType x, const IntegerType exclusiveUpperBound)
Is x out of bounds? That is, is x less than zero, or greater than or equal to the given exclusive upp...
Definition: Tpetra_KokkosRefactor_Details_MultiVectorDistObjectKernels.hpp:108
Tpetra
Namespace Tpetra contains the class and methods constituting the Tpetra library.
Tpetra::Classes::Operator::getRangeMap
virtual Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > getRangeMap() const =0
The Map associated with the range of this operator, which must be compatible with Y....
Tpetra::Classes::RowMatrix
A read-only, row-oriented interface to a sparse matrix.
Definition: Tpetra_RowMatrix_decl.hpp:85