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