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