Tpetra parallel linear algebra Version of the Day
Loading...
Searching...
No Matches
MatrixMarket_Tpetra.hpp
Go to the documentation of this file.
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 __MatrixMarket_Tpetra_hpp
43#define __MatrixMarket_Tpetra_hpp
44
57#include "Tpetra_CrsMatrix.hpp"
58#include "Tpetra_Operator.hpp"
59#include "Tpetra_Vector.hpp"
61#include "Teuchos_MatrixMarket_Raw_Adder.hpp"
62#include "Teuchos_MatrixMarket_Raw_Graph_Adder.hpp"
63#include "Teuchos_MatrixMarket_SymmetrizingAdder.hpp"
64#include "Teuchos_MatrixMarket_SymmetrizingGraphAdder.hpp"
65#include "Teuchos_MatrixMarket_assignScalar.hpp"
66#include "Teuchos_MatrixMarket_Banner.hpp"
67#include "Teuchos_MatrixMarket_CoordDataReader.hpp"
68#include "Teuchos_SetScientific.hpp"
69#include "Teuchos_TimeMonitor.hpp"
70
71extern "C" {
72#include "mmio_Tpetra.h"
73}
74#include "Tpetra_Distribution.hpp"
75
76
77#include <algorithm>
78#include <fstream>
79#include <iostream>
80#include <iterator>
81#include <vector>
82#include <stdexcept>
83#include <numeric>
84
85namespace Tpetra {
115 namespace MatrixMarket {
171 template<class SparseMatrixType>
172 class Reader {
173 public:
175 typedef SparseMatrixType sparse_matrix_type;
176 typedef Teuchos::RCP<sparse_matrix_type> sparse_matrix_ptr;
177
180 typedef typename SparseMatrixType::scalar_type scalar_type;
183 typedef typename SparseMatrixType::local_ordinal_type local_ordinal_type;
191 typedef typename SparseMatrixType::global_ordinal_type
194 typedef typename SparseMatrixType::node_type node_type;
195
200
202 typedef MultiVector<scalar_type,
206
208 typedef Vector<scalar_type,
212
213 typedef Teuchos::Comm<int> comm_type;
215
216
217 private:
223 typedef Teuchos::ArrayRCP<int>::size_type size_type;
224
235 static Teuchos::RCP<const map_type>
236 makeRangeMap (const Teuchos::RCP<const comm_type>& pComm,
237 const global_ordinal_type numRows)
238 {
239 // Return a conventional, uniformly partitioned, contiguous map.
240 return rcp (new map_type (static_cast<global_size_t> (numRows),
241 static_cast<global_ordinal_type> (0),
242 pComm, GloballyDistributed));
243 }
244
272 static Teuchos::RCP<const map_type>
273 makeRowMap (const Teuchos::RCP<const map_type>& pRowMap,
274 const Teuchos::RCP<const comm_type>& pComm,
275 const global_ordinal_type numRows)
276 {
277 // If the caller didn't provide a map, return a conventional,
278 // uniformly partitioned, contiguous map.
279 if (pRowMap.is_null ()) {
280 return rcp (new map_type (static_cast<global_size_t> (numRows),
281 static_cast<global_ordinal_type> (0),
282 pComm, GloballyDistributed));
283 }
284 else {
285 TEUCHOS_TEST_FOR_EXCEPTION
286 (! pRowMap->isDistributed () && pComm->getSize () > 1,
287 std::invalid_argument, "The specified row map is not distributed, "
288 "but the given communicator includes more than one process (in "
289 "fact, there are " << pComm->getSize () << " processes).");
290 TEUCHOS_TEST_FOR_EXCEPTION
291 (pRowMap->getComm () != pComm, std::invalid_argument,
292 "The specified row Map's communicator (pRowMap->getComm()) "
293 "differs from the given separately supplied communicator pComm.");
294 return pRowMap;
295 }
296 }
297
312 static Teuchos::RCP<const map_type>
313 makeDomainMap (const Teuchos::RCP<const map_type>& pRangeMap,
314 const global_ordinal_type numRows,
315 const global_ordinal_type numCols)
316 {
317 // Abbreviations so that the map creation call isn't too long.
318 typedef local_ordinal_type LO;
319 typedef global_ordinal_type GO;
320 typedef node_type NT;
321
322 if (numRows == numCols) {
323 return pRangeMap;
324 } else {
326 pRangeMap->getComm ());
327 }
328 }
329
402 static void
403 distribute (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
404 Teuchos::ArrayRCP<size_t>& myRowPtr,
405 Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
406 Teuchos::ArrayRCP<scalar_type>& myValues,
407 const Teuchos::RCP<const map_type>& pRowMap,
408 Teuchos::ArrayRCP<size_t>& numEntriesPerRow,
409 Teuchos::ArrayRCP<size_t>& rowPtr,
410 Teuchos::ArrayRCP<global_ordinal_type>& colInd,
411 Teuchos::ArrayRCP<scalar_type>& values,
412 const bool debug=false)
413 {
414 using Teuchos::arcp;
415 using Teuchos::ArrayRCP;
416 using Teuchos::ArrayView;
417 using Teuchos::as;
418 using Teuchos::Comm;
419 using Teuchos::CommRequest;
420 using Teuchos::null;
421 using Teuchos::RCP;
422 using Teuchos::receive;
423 using Teuchos::send;
424 using std::cerr;
425 using std::endl;
426
427 const bool extraDebug = false;
428 RCP<const comm_type> pComm = pRowMap->getComm ();
429 const int numProcs = pComm->getSize ();
430 const int myRank = pComm->getRank ();
431 const int rootRank = 0;
432
433 // Type abbreviations to make the code more concise.
434 typedef global_ordinal_type GO;
435
436 // List of the global indices of my rows. They may or may
437 // not be contiguous, and the row map need not be one-to-one.
438 ArrayView<const GO> myRows = pRowMap->getLocalElementList();
439 const size_type myNumRows = myRows.size();
440 TEUCHOS_TEST_FOR_EXCEPTION(static_cast<size_t>(myNumRows) !=
441 pRowMap->getLocalNumElements(),
442 std::logic_error,
443 "pRowMap->getLocalElementList().size() = "
444 << myNumRows
445 << " != pRowMap->getLocalNumElements() = "
446 << pRowMap->getLocalNumElements() << ". "
447 "Please report this bug to the Tpetra developers.");
448 TEUCHOS_TEST_FOR_EXCEPTION(myRank == 0 && numEntriesPerRow.size() < myNumRows,
449 std::logic_error,
450 "On Proc 0: numEntriesPerRow.size() = "
451 << numEntriesPerRow.size()
452 << " != pRowMap->getLocalElementList().size() = "
453 << myNumRows << ". Please report this bug to the "
454 "Tpetra developers.");
455
456 // Space for my proc's number of entries per row. Will be
457 // filled in below.
458 myNumEntriesPerRow = arcp<size_t> (myNumRows);
459
460 if (myRank != rootRank) {
461 // Tell the root how many rows we have. If we're sending
462 // none, then we don't have anything else to send, nor does
463 // the root have to receive anything else.
464 send (*pComm, myNumRows, rootRank);
465 if (myNumRows != 0) {
466 // Now send my rows' global indices. Hopefully the cast
467 // to int doesn't overflow. This is unlikely, since it
468 // should fit in a LO, even though it is a GO.
469 send (*pComm, static_cast<int> (myNumRows),
470 myRows.getRawPtr(), rootRank);
471
472 // I (this proc) don't care if my global row indices are
473 // contiguous, though the root proc does (since otherwise
474 // it needs to pack noncontiguous data into contiguous
475 // storage before sending). That's why we don't check
476 // for contiguousness here.
477
478 // Ask the root process for my part of the array of the
479 // number of entries per row.
480 receive (*pComm, rootRank,
481 static_cast<int> (myNumRows),
482 myNumEntriesPerRow.getRawPtr());
483
484 // Use the resulting array to figure out how many column
485 // indices and values I should ask from the root process.
486 const local_ordinal_type myNumEntries =
487 std::accumulate (myNumEntriesPerRow.begin(),
488 myNumEntriesPerRow.end(), 0);
489
490 // Make space for my entries of the sparse matrix. Note
491 // that they don't have to be sorted by row index.
492 // Iterating through all my rows requires computing a
493 // running sum over myNumEntriesPerRow.
494 myColInd = arcp<GO> (myNumEntries);
495 myValues = arcp<scalar_type> (myNumEntries);
496 if (myNumEntries > 0) {
497 // Ask for that many column indices and values, if
498 // there are any.
499 receive (*pComm, rootRank,
500 static_cast<int> (myNumEntries),
501 myColInd.getRawPtr());
502 receive (*pComm, rootRank,
503 static_cast<int> (myNumEntries),
504 myValues.getRawPtr());
505 }
506 } // If I own at least one row
507 } // If I am not the root processor
508 else { // I _am_ the root processor
509 if (debug) {
510 cerr << "-- Proc 0: Copying my data from global arrays" << endl;
511 }
512 // Proc 0 still needs to (allocate, if not done already)
513 // and fill its part of the matrix (my*).
514 for (size_type k = 0; k < myNumRows; ++k) {
515 const GO myCurRow = myRows[k];
516 const local_ordinal_type numEntriesInThisRow = numEntriesPerRow[myCurRow];
517 myNumEntriesPerRow[k] = numEntriesInThisRow;
518 }
519 if (extraDebug && debug) {
520 cerr << "Proc " << pRowMap->getComm ()->getRank ()
521 << ": myNumEntriesPerRow[0.." << (myNumRows-1) << "] = [";
522 for (size_type k = 0; k < myNumRows; ++k) {
523 cerr << myNumEntriesPerRow[k];
524 if (k < myNumRows-1) {
525 cerr << " ";
526 }
527 }
528 cerr << "]" << endl;
529 }
530 // The total number of matrix entries that my proc owns.
531 const local_ordinal_type myNumEntries =
532 std::accumulate (myNumEntriesPerRow.begin(),
533 myNumEntriesPerRow.end(), 0);
534 if (debug) {
535 cerr << "-- Proc 0: I own " << myNumRows << " rows and "
536 << myNumEntries << " entries" << endl;
537 }
538 myColInd = arcp<GO> (myNumEntries);
539 myValues = arcp<scalar_type> (myNumEntries);
540
541 // Copy Proc 0's part of the matrix into the my* arrays.
542 // It's important that myCurPos be updated _before_ k,
543 // otherwise myCurPos will get the wrong number of entries
544 // per row (it should be for the row in the just-completed
545 // iteration, not for the next iteration's row).
546 local_ordinal_type myCurPos = 0;
547 for (size_type k = 0; k < myNumRows;
548 myCurPos += myNumEntriesPerRow[k], ++k) {
549 const local_ordinal_type curNumEntries = myNumEntriesPerRow[k];
550 const GO myRow = myRows[k];
551 const size_t curPos = rowPtr[myRow];
552 // Only copy if there are entries to copy, in order not
553 // to construct empty ranges for the ArrayRCP views.
554 if (curNumEntries > 0) {
555 ArrayView<GO> colIndView = colInd (curPos, curNumEntries);
556 ArrayView<GO> myColIndView = myColInd (myCurPos, curNumEntries);
557 std::copy (colIndView.begin(), colIndView.end(),
558 myColIndView.begin());
559
560 ArrayView<scalar_type> valuesView =
561 values (curPos, curNumEntries);
562 ArrayView<scalar_type> myValuesView =
563 myValues (myCurPos, curNumEntries);
564 std::copy (valuesView.begin(), valuesView.end(),
565 myValuesView.begin());
566 }
567 }
568
569 // Proc 0 processes each other proc p in turn.
570 for (int p = 1; p < numProcs; ++p) {
571 if (debug) {
572 cerr << "-- Proc 0: Processing proc " << p << endl;
573 }
574
575 size_type theirNumRows = 0;
576 // Ask Proc p how many rows it has. If it doesn't
577 // have any, we can move on to the next proc. This
578 // has to be a standard receive so that we can avoid
579 // the degenerate case of sending zero data.
580 receive (*pComm, p, &theirNumRows);
581 if (debug) {
582 cerr << "-- Proc 0: Proc " << p << " owns "
583 << theirNumRows << " rows" << endl;
584 }
585 if (theirNumRows != 0) {
586 // Ask Proc p which rows it owns. The resulting global
587 // row indices are not guaranteed to be contiguous or
588 // sorted. Global row indices are themselves indices
589 // into the numEntriesPerRow array.
590 ArrayRCP<GO> theirRows = arcp<GO> (theirNumRows);
591 receive (*pComm, p, as<int> (theirNumRows),
592 theirRows.getRawPtr ());
593 // Extra test to make sure that the rows we received
594 // are all sensible. This is a good idea since we are
595 // going to use the global row indices we've received
596 // to index into the numEntriesPerRow array. Better to
597 // catch any bugs here and print a sensible error
598 // message, rather than segfault and print a cryptic
599 // error message.
600 {
601 const global_size_t numRows = pRowMap->getGlobalNumElements ();
602 const GO indexBase = pRowMap->getIndexBase ();
603 bool theirRowsValid = true;
604 for (size_type k = 0; k < theirNumRows; ++k) {
605 if (theirRows[k] < indexBase ||
606 as<global_size_t> (theirRows[k] - indexBase) >= numRows) {
607 theirRowsValid = false;
608 }
609 }
610 if (! theirRowsValid) {
611 TEUCHOS_TEST_FOR_EXCEPTION(
612 ! theirRowsValid, std::logic_error,
613 "Proc " << p << " has at least one invalid row index. "
614 "Here are all of them: " <<
615 Teuchos::toString (theirRows ()) << ". Valid row index "
616 "range (zero-based): [0, " << (numRows - 1) << "].");
617 }
618 }
619
620 // Perhaps we could save a little work if we check
621 // whether Proc p's row indices are contiguous. That
622 // would make lookups in the global data arrays
623 // faster. For now, we just implement the general
624 // case and don't prematurely optimize. (Remember
625 // that you're making Proc 0 read the whole file, so
626 // you've already lost scalability.)
627
628 // Compute the number of entries in each of Proc p's
629 // rows. (Proc p will compute its row pointer array
630 // on its own, after it gets the data from Proc 0.)
631 ArrayRCP<size_t> theirNumEntriesPerRow;
632 theirNumEntriesPerRow = arcp<size_t> (theirNumRows);
633 for (size_type k = 0; k < theirNumRows; ++k) {
634 theirNumEntriesPerRow[k] = numEntriesPerRow[theirRows[k]];
635 }
636
637 // Tell Proc p the number of entries in each of its
638 // rows. Hopefully the cast to int doesn't overflow.
639 // This is unlikely, since it should fit in a LO,
640 // even though it is a GO.
641 send (*pComm, static_cast<int> (theirNumRows),
642 theirNumEntriesPerRow.getRawPtr(), p);
643
644 // Figure out how many entries Proc p owns.
645 const local_ordinal_type theirNumEntries =
646 std::accumulate (theirNumEntriesPerRow.begin(),
647 theirNumEntriesPerRow.end(), 0);
648
649 if (debug) {
650 cerr << "-- Proc 0: Proc " << p << " owns "
651 << theirNumEntries << " entries" << endl;
652 }
653
654 // If there are no entries to send, then we're done
655 // with Proc p.
656 if (theirNumEntries == 0) {
657 continue;
658 }
659
660 // Construct (views of) proc p's column indices and
661 // values. Later, we might like to optimize for the
662 // (common) contiguous case, for which we don't need to
663 // copy data into separate "their*" arrays (we can just
664 // use contiguous views of the global arrays).
665 ArrayRCP<GO> theirColInd (theirNumEntries);
666 ArrayRCP<scalar_type> theirValues (theirNumEntries);
667 // Copy Proc p's part of the matrix into the their*
668 // arrays. It's important that theirCurPos be updated
669 // _before_ k, otherwise theirCurPos will get the wrong
670 // number of entries per row (it should be for the row
671 // in the just-completed iteration, not for the next
672 // iteration's row).
673 local_ordinal_type theirCurPos = 0;
674 for (size_type k = 0; k < theirNumRows;
675 theirCurPos += theirNumEntriesPerRow[k], k++) {
676 const local_ordinal_type curNumEntries = theirNumEntriesPerRow[k];
677 const GO theirRow = theirRows[k];
678 const local_ordinal_type curPos = rowPtr[theirRow];
679
680 // Only copy if there are entries to copy, in order
681 // not to construct empty ranges for the ArrayRCP
682 // views.
683 if (curNumEntries > 0) {
684 ArrayView<GO> colIndView =
685 colInd (curPos, curNumEntries);
686 ArrayView<GO> theirColIndView =
687 theirColInd (theirCurPos, curNumEntries);
688 std::copy (colIndView.begin(), colIndView.end(),
689 theirColIndView.begin());
690
691 ArrayView<scalar_type> valuesView =
692 values (curPos, curNumEntries);
693 ArrayView<scalar_type> theirValuesView =
694 theirValues (theirCurPos, curNumEntries);
695 std::copy (valuesView.begin(), valuesView.end(),
696 theirValuesView.begin());
697 }
698 }
699 // Send Proc p its column indices and values.
700 // Hopefully the cast to int doesn't overflow. This
701 // is unlikely, since it should fit in a LO, even
702 // though it is a GO.
703 send (*pComm, static_cast<int> (theirNumEntries),
704 theirColInd.getRawPtr(), p);
705 send (*pComm, static_cast<int> (theirNumEntries),
706 theirValues.getRawPtr(), p);
707
708 if (debug) {
709 cerr << "-- Proc 0: Finished with proc " << p << endl;
710 }
711 } // If proc p owns at least one row
712 } // For each proc p not the root proc 0
713 } // If I'm (not) the root proc 0
714
715 // Invalidate the input data to save space, since we don't
716 // need it anymore.
717 numEntriesPerRow = null;
718 rowPtr = null;
719 colInd = null;
720 values = null;
721
722 if (debug && myRank == 0) {
723 cerr << "-- Proc 0: About to fill in myRowPtr" << endl;
724 }
725
726 // Allocate and fill in myRowPtr (the row pointer array for
727 // my rank's rows). We delay this until the end because we
728 // don't need it to compute anything else in distribute().
729 // Each proc can do this work for itself, since it only needs
730 // myNumEntriesPerRow to do so.
731 myRowPtr = arcp<size_t> (myNumRows+1);
732 myRowPtr[0] = 0;
733 for (size_type k = 1; k < myNumRows+1; ++k) {
734 myRowPtr[k] = myRowPtr[k-1] + myNumEntriesPerRow[k-1];
735 }
736 if (extraDebug && debug) {
737 cerr << "Proc " << Teuchos::rank (*(pRowMap->getComm()))
738 << ": myRowPtr[0.." << myNumRows << "] = [";
739 for (size_type k = 0; k < myNumRows+1; ++k) {
740 cerr << myRowPtr[k];
741 if (k < myNumRows) {
742 cerr << " ";
743 }
744 }
745 cerr << "]" << endl << endl;
746 }
747
748 if (debug && myRank == 0) {
749 cerr << "-- Proc 0: Done with distribute" << endl;
750 }
751 }
752
766 static Teuchos::RCP<sparse_matrix_type>
767 makeMatrix (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
768 Teuchos::ArrayRCP<size_t>& myRowPtr,
769 Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
770 Teuchos::ArrayRCP<scalar_type>& myValues,
771 const Teuchos::RCP<const map_type>& pRowMap,
772 const Teuchos::RCP<const map_type>& pRangeMap,
773 const Teuchos::RCP<const map_type>& pDomainMap,
774 const bool callFillComplete = true)
775 {
776 using Teuchos::ArrayView;
777 using Teuchos::null;
778 using Teuchos::RCP;
779 using Teuchos::rcp;
780 using std::cerr;
781 using std::endl;
782 // Typedef to make certain type declarations shorter.
783 typedef global_ordinal_type GO;
784
785 // The row pointer array always has at least one entry, even
786 // if the matrix has zero rows. myNumEntriesPerRow, myColInd,
787 // and myValues would all be empty arrays in that degenerate
788 // case, but the row and domain maps would still be nonnull
789 // (though they would be trivial maps).
790 TEUCHOS_TEST_FOR_EXCEPTION(myRowPtr.is_null(), std::logic_error,
791 "makeMatrix: myRowPtr array is null. "
792 "Please report this bug to the Tpetra developers.");
793 TEUCHOS_TEST_FOR_EXCEPTION(pDomainMap.is_null(), std::logic_error,
794 "makeMatrix: domain map is null. "
795 "Please report this bug to the Tpetra developers.");
796 TEUCHOS_TEST_FOR_EXCEPTION(pRangeMap.is_null(), std::logic_error,
797 "makeMatrix: range map is null. "
798 "Please report this bug to the Tpetra developers.");
799 TEUCHOS_TEST_FOR_EXCEPTION(pRowMap.is_null(), std::logic_error,
800 "makeMatrix: row map is null. "
801 "Please report this bug to the Tpetra developers.");
802
803 // Construct the CrsMatrix, using the row map, with the
804 // constructor specifying the number of nonzeros for each row.
805 RCP<sparse_matrix_type> A =
806 rcp (new sparse_matrix_type (pRowMap, myNumEntriesPerRow ()));
807
808 // List of the global indices of my rows.
809 // They may or may not be contiguous.
810 ArrayView<const GO> myRows = pRowMap->getLocalElementList ();
811 const size_type myNumRows = myRows.size ();
812
813 // Add this processor's matrix entries to the CrsMatrix.
814 const GO indexBase = pRowMap->getIndexBase ();
815 for (size_type i = 0; i < myNumRows; ++i) {
816 const size_type myCurPos = myRowPtr[i];
817 const local_ordinal_type curNumEntries = myNumEntriesPerRow[i];
818 ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
819 ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
820
821 // Modify the column indices in place to have the right index base.
822 for (size_type k = 0; k < curNumEntries; ++k) {
823 curColInd[k] += indexBase;
824 }
825 // Avoid constructing empty views of ArrayRCP objects.
826 if (curNumEntries > 0) {
827 A->insertGlobalValues (myRows[i], curColInd, curValues);
828 }
829 }
830 // We've entered in all our matrix entries, so we can delete
831 // the original data. This will save memory when we call
832 // fillComplete(), so that we never keep more than two copies
833 // of the matrix's data in memory at once.
834 myNumEntriesPerRow = null;
835 myRowPtr = null;
836 myColInd = null;
837 myValues = null;
838
839 if (callFillComplete) {
840 A->fillComplete (pDomainMap, pRangeMap);
841 }
842 return A;
843 }
844
850 static Teuchos::RCP<sparse_matrix_type>
851 makeMatrix (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
852 Teuchos::ArrayRCP<size_t>& myRowPtr,
853 Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
854 Teuchos::ArrayRCP<scalar_type>& myValues,
855 const Teuchos::RCP<const map_type>& pRowMap,
856 const Teuchos::RCP<const map_type>& pRangeMap,
857 const Teuchos::RCP<const map_type>& pDomainMap,
858 const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
859 const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams)
860 {
861 using Teuchos::ArrayView;
862 using Teuchos::null;
863 using Teuchos::RCP;
864 using Teuchos::rcp;
865 using std::cerr;
866 using std::endl;
867 // Typedef to make certain type declarations shorter.
868 typedef global_ordinal_type GO;
869
870 // The row pointer array always has at least one entry, even
871 // if the matrix has zero rows. myNumEntriesPerRow, myColInd,
872 // and myValues would all be empty arrays in that degenerate
873 // case, but the row and domain maps would still be nonnull
874 // (though they would be trivial maps).
875 TEUCHOS_TEST_FOR_EXCEPTION(
876 myRowPtr.is_null(), std::logic_error,
877 "makeMatrix: myRowPtr array is null. "
878 "Please report this bug to the Tpetra developers.");
879 TEUCHOS_TEST_FOR_EXCEPTION(
880 pDomainMap.is_null(), std::logic_error,
881 "makeMatrix: domain map is null. "
882 "Please report this bug to the Tpetra developers.");
883 TEUCHOS_TEST_FOR_EXCEPTION(
884 pRangeMap.is_null(), std::logic_error,
885 "makeMatrix: range map is null. "
886 "Please report this bug to the Tpetra developers.");
887 TEUCHOS_TEST_FOR_EXCEPTION(
888 pRowMap.is_null(), std::logic_error,
889 "makeMatrix: row map is null. "
890 "Please report this bug to the Tpetra developers.");
891
892 // Construct the CrsMatrix, using the row map, with the
893 // constructor specifying the number of nonzeros for each row.
894 RCP<sparse_matrix_type> A =
895 rcp (new sparse_matrix_type (pRowMap, myNumEntriesPerRow(),
896 constructorParams));
897
898 // List of the global indices of my rows.
899 // They may or may not be contiguous.
900 ArrayView<const GO> myRows = pRowMap->getLocalElementList();
901 const size_type myNumRows = myRows.size();
902
903 // Add this processor's matrix entries to the CrsMatrix.
904 const GO indexBase = pRowMap->getIndexBase ();
905 for (size_type i = 0; i < myNumRows; ++i) {
906 const size_type myCurPos = myRowPtr[i];
907 const local_ordinal_type curNumEntries = myNumEntriesPerRow[i];
908 ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
909 ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
910
911 // Modify the column indices in place to have the right index base.
912 for (size_type k = 0; k < curNumEntries; ++k) {
913 curColInd[k] += indexBase;
914 }
915 if (curNumEntries > 0) {
916 A->insertGlobalValues (myRows[i], curColInd, curValues);
917 }
918 }
919 // We've entered in all our matrix entries, so we can delete
920 // the original data. This will save memory when we call
921 // fillComplete(), so that we never keep more than two copies
922 // of the matrix's data in memory at once.
923 myNumEntriesPerRow = null;
924 myRowPtr = null;
925 myColInd = null;
926 myValues = null;
927
928 A->fillComplete (pDomainMap, pRangeMap, fillCompleteParams);
929 return A;
930 }
931
936 static Teuchos::RCP<sparse_matrix_type>
937 makeMatrix (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
938 Teuchos::ArrayRCP<size_t>& myRowPtr,
939 Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
940 Teuchos::ArrayRCP<scalar_type>& myValues,
941 const Teuchos::RCP<const map_type>& rowMap,
942 Teuchos::RCP<const map_type>& colMap,
943 const Teuchos::RCP<const map_type>& domainMap,
944 const Teuchos::RCP<const map_type>& rangeMap,
945 const bool callFillComplete = true)
946 {
947 using Teuchos::ArrayView;
948 using Teuchos::as;
949 using Teuchos::null;
950 using Teuchos::RCP;
951 using Teuchos::rcp;
952 typedef global_ordinal_type GO;
953
954 // Construct the CrsMatrix.
955
956 RCP<sparse_matrix_type> A; // the matrix to return.
957 if (colMap.is_null ()) { // the user didn't provide a column Map
958 A = rcp (new sparse_matrix_type (rowMap, myNumEntriesPerRow));
959 } else { // the user provided a column Map
960 A = rcp (new sparse_matrix_type (rowMap, colMap, myNumEntriesPerRow));
961 }
962
963 // List of the global indices of my rows.
964 // They may or may not be contiguous.
965 ArrayView<const GO> myRows = rowMap->getLocalElementList ();
966 const size_type myNumRows = myRows.size ();
967
968 // Add this process' matrix entries to the CrsMatrix.
969 const GO indexBase = rowMap->getIndexBase ();
970 for (size_type i = 0; i < myNumRows; ++i) {
971 const size_type myCurPos = myRowPtr[i];
972 const size_type curNumEntries = as<size_type> (myNumEntriesPerRow[i]);
973 ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
974 ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
975
976 // Modify the column indices in place to have the right index base.
977 for (size_type k = 0; k < curNumEntries; ++k) {
978 curColInd[k] += indexBase;
979 }
980 if (curNumEntries > 0) {
981 A->insertGlobalValues (myRows[i], curColInd, curValues);
982 }
983 }
984 // We've entered in all our matrix entries, so we can delete
985 // the original data. This will save memory when we call
986 // fillComplete(), so that we never keep more than two copies
987 // of the matrix's data in memory at once.
988 myNumEntriesPerRow = null;
989 myRowPtr = null;
990 myColInd = null;
991 myValues = null;
992
993 if (callFillComplete) {
994 A->fillComplete (domainMap, rangeMap);
995 if (colMap.is_null ()) {
996 colMap = A->getColMap ();
997 }
998 }
999 return A;
1000 }
1001
1002 private:
1003
1020 static Teuchos::RCP<const Teuchos::MatrixMarket::Banner>
1021 readBanner (std::istream& in,
1022 size_t& lineNumber,
1023 const bool tolerant=false,
1024 const bool /* debug */=false,
1025 const bool isGraph=false)
1026 {
1027 using Teuchos::MatrixMarket::Banner;
1028 using Teuchos::RCP;
1029 using Teuchos::rcp;
1030 using std::cerr;
1031 using std::endl;
1032 typedef Teuchos::ScalarTraits<scalar_type> STS;
1033
1034 RCP<Banner> pBanner; // On output, if successful: the read-in Banner.
1035 std::string line; // If read from stream successful: the Banner line
1036
1037 // Try to read a line from the input stream.
1038 const bool readFailed = ! getline(in, line);
1039 TEUCHOS_TEST_FOR_EXCEPTION(readFailed, std::invalid_argument,
1040 "Failed to get Matrix Market banner line from input.");
1041
1042 // We read a line from the input stream.
1043 lineNumber++;
1044
1045 // Assume that the line we found is the Banner line.
1046 try {
1047 pBanner = rcp (new Banner (line, tolerant));
1048 } catch (std::exception& e) {
1049
1050 TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
1051 "Matrix Market banner line contains syntax error(s): "
1052 << e.what());
1053 }
1054
1055 TEUCHOS_TEST_FOR_EXCEPTION(pBanner->objectType() != "matrix",
1056 std::invalid_argument, "The Matrix Market file does not contain "
1057 "matrix data. Its Banner (first) line says that its object type is \""
1058 << pBanner->matrixType() << "\", rather than the required \"matrix\".");
1059
1060 // Validate the data type of the matrix, with respect to the
1061 // Scalar type of the CrsMatrix entries.
1062 TEUCHOS_TEST_FOR_EXCEPTION(
1063 ! STS::isComplex && pBanner->dataType() == "complex",
1064 std::invalid_argument,
1065 "The Matrix Market file contains complex-valued data, but you are "
1066 "trying to read it into a matrix containing entries of the real-"
1067 "valued Scalar type \""
1068 << Teuchos::TypeNameTraits<scalar_type>::name() << "\".");
1069 TEUCHOS_TEST_FOR_EXCEPTION(
1070 !isGraph &&
1071 pBanner->dataType() != "real" &&
1072 pBanner->dataType() != "complex" &&
1073 pBanner->dataType() != "integer",
1074 std::invalid_argument,
1075 "When reading Matrix Market data into a Tpetra::CrsMatrix, the "
1076 "Matrix Market file may not contain a \"pattern\" matrix. A "
1077 "pattern matrix is really just a graph with no weights. It "
1078 "should be stored in a CrsGraph, not a CrsMatrix.");
1079
1080 TEUCHOS_TEST_FOR_EXCEPTION(
1081 isGraph &&
1082 pBanner->dataType() != "pattern",
1083 std::invalid_argument,
1084 "When reading Matrix Market data into a Tpetra::CrsGraph, the "
1085 "Matrix Market file must contain a \"pattern\" matrix.");
1086
1087 return pBanner;
1088 }
1089
1112 static Teuchos::Tuple<global_ordinal_type, 3>
1113 readCoordDims (std::istream& in,
1114 size_t& lineNumber,
1115 const Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1116 const Teuchos::RCP<const comm_type>& pComm,
1117 const bool tolerant = false,
1118 const bool /* debug */ = false)
1119 {
1120 using Teuchos::MatrixMarket::readCoordinateDimensions;
1121 using Teuchos::Tuple;
1122
1123 // Packed coordinate matrix dimensions (numRows, numCols,
1124 // numNonzeros); computed on Rank 0 and broadcasted to all MPI
1125 // ranks.
1126 Tuple<global_ordinal_type, 3> dims;
1127
1128 // Read in the coordinate matrix dimensions from the input
1129 // stream. "success" tells us whether reading in the
1130 // coordinate matrix dimensions succeeded ("Guilty unless
1131 // proven innocent").
1132 bool success = false;
1133 if (pComm->getRank() == 0) {
1134 TEUCHOS_TEST_FOR_EXCEPTION(pBanner->matrixType() != "coordinate",
1135 std::invalid_argument, "The Tpetra::CrsMatrix Matrix Market reader "
1136 "only accepts \"coordinate\" (sparse) matrix data.");
1137 // Unpacked coordinate matrix dimensions
1138 global_ordinal_type numRows, numCols, numNonzeros;
1139 // Only MPI Rank 0 reads from the input stream
1140 success = readCoordinateDimensions (in, numRows, numCols,
1141 numNonzeros, lineNumber,
1142 tolerant);
1143 // Pack up the data into a Tuple so we can send them with
1144 // one broadcast instead of three.
1145 dims[0] = numRows;
1146 dims[1] = numCols;
1147 dims[2] = numNonzeros;
1148 }
1149 // Only Rank 0 did the reading, so it decides success.
1150 //
1151 // FIXME (mfh 02 Feb 2011) Teuchos::broadcast doesn't know how
1152 // to send bools. For now, we convert to/from int instead,
1153 // using the usual "true is 1, false is 0" encoding.
1154 {
1155 int the_success = success ? 1 : 0; // only matters on MPI Rank 0
1156 Teuchos::broadcast (*pComm, 0, &the_success);
1157 success = (the_success == 1);
1158 }
1159 if (success) {
1160 // Broadcast (numRows, numCols, numNonzeros) from Rank 0
1161 // to all the other MPI ranks.
1162 Teuchos::broadcast (*pComm, 0, dims);
1163 }
1164 else {
1165 // Perhaps in tolerant mode, we could set all the
1166 // dimensions to zero for now, and deduce correct
1167 // dimensions by reading all of the file's entries and
1168 // computing the max(row index) and max(column index).
1169 // However, for now we just error out in that case.
1170 TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
1171 "Error reading Matrix Market sparse matrix: failed to read "
1172 "coordinate matrix dimensions.");
1173 }
1174 return dims;
1175 }
1176
1187 typedef Teuchos::MatrixMarket::SymmetrizingAdder<Teuchos::MatrixMarket::Raw::Adder<scalar_type, global_ordinal_type> > adder_type;
1188
1189 typedef Teuchos::MatrixMarket::SymmetrizingGraphAdder<Teuchos::MatrixMarket::Raw::GraphAdder<global_ordinal_type> > graph_adder_type;
1190
1216 static Teuchos::RCP<adder_type>
1217 makeAdder (const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1218 Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1219 const Teuchos::Tuple<global_ordinal_type, 3>& dims,
1220 const bool tolerant=false,
1221 const bool debug=false)
1222 {
1223 if (pComm->getRank () == 0) {
1224 typedef Teuchos::MatrixMarket::Raw::Adder<scalar_type,
1226 raw_adder_type;
1227 Teuchos::RCP<raw_adder_type> pRaw =
1228 Teuchos::rcp (new raw_adder_type (dims[0], dims[1], dims[2],
1229 tolerant, debug));
1230 return Teuchos::rcp (new adder_type (pRaw, pBanner->symmType ()));
1231 }
1232 else {
1233 return Teuchos::null;
1234 }
1235 }
1236
1262 static Teuchos::RCP<graph_adder_type>
1263 makeGraphAdder (const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1264 Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1265 const Teuchos::Tuple<global_ordinal_type, 3>& dims,
1266 const bool tolerant=false,
1267 const bool debug=false)
1268 {
1269 if (pComm->getRank () == 0) {
1270 typedef Teuchos::MatrixMarket::Raw::GraphAdder<global_ordinal_type> raw_adder_type;
1271 Teuchos::RCP<raw_adder_type> pRaw =
1272 Teuchos::rcp (new raw_adder_type (dims[0], dims[1], dims[2],
1273 tolerant, debug));
1274 return Teuchos::rcp (new graph_adder_type (pRaw, pBanner->symmType ()));
1275 }
1276 else {
1277 return Teuchos::null;
1278 }
1279 }
1280
1282 static Teuchos::RCP<sparse_graph_type>
1283 readSparseGraphHelper (std::istream& in,
1284 const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1285 const Teuchos::RCP<const map_type>& rowMap,
1286 Teuchos::RCP<const map_type>& colMap,
1287 const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1288 const bool tolerant,
1289 const bool debug)
1290 {
1291 using Teuchos::MatrixMarket::Banner;
1292 using Teuchos::RCP;
1293 using Teuchos::ptr;
1294 using Teuchos::Tuple;
1295 using std::cerr;
1296 using std::endl;
1297
1298 const int myRank = pComm->getRank ();
1299 const int rootRank = 0;
1300
1301 // Current line number in the input stream. Various calls
1302 // will modify this depending on the number of lines that are
1303 // read from the input stream. Only Rank 0 modifies this.
1304 size_t lineNumber = 1;
1305
1306 if (debug && myRank == rootRank) {
1307 cerr << "Matrix Market reader: readGraph:" << endl
1308 << "-- Reading banner line" << endl;
1309 }
1310
1311 // The "Banner" tells you whether the input stream represents
1312 // a sparse matrix, the symmetry type of the matrix, and the
1313 // type of the data it contains.
1314 //
1315 // pBanner will only be nonnull on MPI Rank 0. It will be
1316 // null on all other MPI processes.
1317 RCP<const Banner> pBanner;
1318 {
1319 // We read and validate the Banner on Proc 0, but broadcast
1320 // the validation result to all processes.
1321 // Teuchos::broadcast doesn't currently work with bool, so
1322 // we use int (true -> 1, false -> 0).
1323 int bannerIsCorrect = 1;
1324 std::ostringstream errMsg;
1325
1326 if (myRank == rootRank) {
1327 // Read the Banner line from the input stream.
1328 try {
1329 pBanner = readBanner (in, lineNumber, tolerant, debug, true);
1330 }
1331 catch (std::exception& e) {
1332 errMsg << "Attempt to read the Matrix Market file's Banner line "
1333 "threw an exception: " << e.what();
1334 bannerIsCorrect = 0;
1335 }
1336
1337 if (bannerIsCorrect) {
1338 // Validate the Banner for the case of a sparse graph.
1339 // We validate on Proc 0, since it reads the Banner.
1340
1341 // In intolerant mode, the matrix type must be "coordinate".
1342 if (! tolerant && pBanner->matrixType() != "coordinate") {
1343 bannerIsCorrect = 0;
1344 errMsg << "The Matrix Market input file must contain a "
1345 "\"coordinate\"-format sparse graph in order to create a "
1346 "Tpetra::CrsGraph object from it, but the file's matrix "
1347 "type is \"" << pBanner->matrixType() << "\" instead.";
1348 }
1349 // In tolerant mode, we allow the matrix type to be
1350 // anything other than "array" (which would mean that
1351 // the file contains a dense matrix).
1352 if (tolerant && pBanner->matrixType() == "array") {
1353 bannerIsCorrect = 0;
1354 errMsg << "Matrix Market file must contain a \"coordinate\"-"
1355 "format sparse graph in order to create a Tpetra::CrsGraph "
1356 "object from it, but the file's matrix type is \"array\" "
1357 "instead. That probably means the file contains dense matrix "
1358 "data.";
1359 }
1360 }
1361 } // Proc 0: Done reading the Banner, hopefully successfully.
1362
1363 // Broadcast from Proc 0 whether the Banner was read correctly.
1364 broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
1365
1366 // If the Banner is invalid, all processes throw an
1367 // exception. Only Proc 0 gets the exception message, but
1368 // that's OK, since the main point is to "stop the world"
1369 // (rather than throw an exception on one process and leave
1370 // the others hanging).
1371 TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
1372 std::invalid_argument, errMsg.str ());
1373 } // Done reading the Banner line and broadcasting success.
1374 if (debug && myRank == rootRank) {
1375 cerr << "-- Reading dimensions line" << endl;
1376 }
1377
1378 // Read the graph dimensions from the Matrix Market metadata.
1379 // dims = (numRows, numCols, numEntries). Proc 0 does the
1380 // reading, but it broadcasts the results to all MPI
1381 // processes. Thus, readCoordDims() is a collective
1382 // operation. It does a collective check for correctness too.
1383 Tuple<global_ordinal_type, 3> dims =
1384 readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
1385
1386 if (debug && myRank == rootRank) {
1387 cerr << "-- Making Adder for collecting graph data" << endl;
1388 }
1389
1390 // "Adder" object for collecting all the sparse graph entries
1391 // from the input stream. This is only nonnull on Proc 0.
1392 // The Adder internally converts the one-based indices (native
1393 // Matrix Market format) into zero-based indices.
1394 RCP<graph_adder_type> pAdder =
1395 makeGraphAdder (pComm, pBanner, dims, tolerant, debug);
1396
1397 if (debug && myRank == rootRank) {
1398 cerr << "-- Reading graph data" << endl;
1399 }
1400 //
1401 // Read the graph entries from the input stream on Proc 0.
1402 //
1403 {
1404 // We use readSuccess to broadcast the results of the read
1405 // (succeeded or not) to all MPI processes. Since
1406 // Teuchos::broadcast doesn't currently know how to send
1407 // bools, we convert to int (true -> 1, false -> 0).
1408 int readSuccess = 1;
1409 std::ostringstream errMsg; // Exception message (only valid on Proc 0)
1410 if (myRank == rootRank) {
1411 try {
1412 // Reader for "coordinate" format sparse graph data.
1413 typedef Teuchos::MatrixMarket::CoordPatternReader<graph_adder_type,
1414 global_ordinal_type> reader_type;
1415 reader_type reader (pAdder);
1416
1417 // Read the sparse graph entries.
1418 std::pair<bool, std::vector<size_t> > results =
1419 reader.read (in, lineNumber, tolerant, debug);
1420 readSuccess = results.first ? 1 : 0;
1421 }
1422 catch (std::exception& e) {
1423 readSuccess = 0;
1424 errMsg << e.what();
1425 }
1426 }
1427 broadcast (*pComm, rootRank, ptr (&readSuccess));
1428
1429 // It would be nice to add a "verbose" flag, so that in
1430 // tolerant mode, we could log any bad line number(s) on
1431 // Proc 0. For now, we just throw if the read fails to
1432 // succeed.
1433 //
1434 // Question: If we're in tolerant mode, and if the read did
1435 // not succeed, should we attempt to call fillComplete()?
1436 TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
1437 "Failed to read the Matrix Market sparse graph file: "
1438 << errMsg.str());
1439 } // Done reading the graph entries (stored on Proc 0 for now)
1440
1441 if (debug && myRank == rootRank) {
1442 cerr << "-- Successfully read the Matrix Market data" << endl;
1443 }
1444
1445 // In tolerant mode, we need to rebroadcast the graph
1446 // dimensions, since they may be different after reading the
1447 // actual graph data. We only need to broadcast the number
1448 // of rows and columns. Only Rank 0 needs to know the actual
1449 // global number of entries, since (a) we need to merge
1450 // duplicates on Rank 0 first anyway, and (b) when we
1451 // distribute the entries, each rank other than Rank 0 will
1452 // only need to know how many entries it owns, not the total
1453 // number of entries.
1454 if (tolerant) {
1455 if (debug && myRank == rootRank) {
1456 cerr << "-- Tolerant mode: rebroadcasting graph dimensions"
1457 << endl
1458 << "----- Dimensions before: "
1459 << dims[0] << " x " << dims[1]
1460 << endl;
1461 }
1462 // Packed coordinate graph dimensions (numRows, numCols).
1463 Tuple<global_ordinal_type, 2> updatedDims;
1464 if (myRank == rootRank) {
1465 // If one or more bottom rows of the graph contain no
1466 // entries, then the Adder will report that the number
1467 // of rows is less than that specified in the
1468 // metadata. We allow this case, and favor the
1469 // metadata so that the zero row(s) will be included.
1470 updatedDims[0] =
1471 std::max (dims[0], pAdder->getAdder()->numRows());
1472 updatedDims[1] = pAdder->getAdder()->numCols();
1473 }
1474 broadcast (*pComm, rootRank, updatedDims);
1475 dims[0] = updatedDims[0];
1476 dims[1] = updatedDims[1];
1477 if (debug && myRank == rootRank) {
1478 cerr << "----- Dimensions after: " << dims[0] << " x "
1479 << dims[1] << endl;
1480 }
1481 }
1482 else {
1483 // In strict mode, we require that the graph's metadata and
1484 // its actual data agree, at least somewhat. In particular,
1485 // the number of rows must agree, since otherwise we cannot
1486 // distribute the graph correctly.
1487
1488 // Teuchos::broadcast() doesn't know how to broadcast bools,
1489 // so we use an int with the standard 1 == true, 0 == false
1490 // encoding.
1491 int dimsMatch = 1;
1492 if (myRank == rootRank) {
1493 // If one or more bottom rows of the graph contain no
1494 // entries, then the Adder will report that the number of
1495 // rows is less than that specified in the metadata. We
1496 // allow this case, and favor the metadata, but do not
1497 // allow the Adder to think there are more rows in the
1498 // graph than the metadata says.
1499 if (dims[0] < pAdder->getAdder ()->numRows ()) {
1500 dimsMatch = 0;
1501 }
1502 }
1503 broadcast (*pComm, 0, ptr (&dimsMatch));
1504 if (dimsMatch == 0) {
1505 // We're in an error state anyway, so we might as well
1506 // work a little harder to print an informative error
1507 // message.
1508 //
1509 // Broadcast the Adder's idea of the graph dimensions
1510 // from Proc 0 to all processes.
1511 Tuple<global_ordinal_type, 2> addersDims;
1512 if (myRank == rootRank) {
1513 addersDims[0] = pAdder->getAdder()->numRows();
1514 addersDims[1] = pAdder->getAdder()->numCols();
1515 }
1516 broadcast (*pComm, 0, addersDims);
1517 TEUCHOS_TEST_FOR_EXCEPTION(
1518 dimsMatch == 0, std::runtime_error,
1519 "The graph metadata says that the graph is " << dims[0] << " x "
1520 << dims[1] << ", but the actual data says that the graph is "
1521 << addersDims[0] << " x " << addersDims[1] << ". That means the "
1522 "data includes more rows than reported in the metadata. This "
1523 "is not allowed when parsing in strict mode. Parse the graph in "
1524 "tolerant mode to ignore the metadata when it disagrees with the "
1525 "data.");
1526 }
1527 } // Matrix dimensions (# rows, # cols, # entries) agree.
1528
1529 // Create a map describing a distribution where the root owns EVERYTHING
1530 RCP<map_type> proc0Map;
1531 global_ordinal_type indexBase;
1532 if(Teuchos::is_null(rowMap)) {
1533 indexBase = 0;
1534 }
1535 else {
1536 indexBase = rowMap->getIndexBase();
1537 }
1538 if(myRank == rootRank) {
1539 proc0Map = rcp(new map_type(dims[0],dims[0],indexBase,pComm));
1540 }
1541 else {
1542 proc0Map = rcp(new map_type(dims[0],0,indexBase,pComm));
1543 }
1544
1545 // Create the graph where the root owns EVERYTHING
1546 std::map<global_ordinal_type, size_t> numEntriesPerRow_map;
1547 if (myRank == rootRank) {
1548 const auto& entries = pAdder()->getAdder()->getEntries();
1549 // This will count duplicates, but it's better than dense.
1550 // An even better approach would use a classic algorithm,
1551 // likely in Saad's old textbook, for converting COO (entries)
1552 // to CSR (the local part of the sparse matrix data structure).
1553 for (const auto& entry : entries) {
1554 const global_ordinal_type gblRow = entry.rowIndex () + indexBase;
1555 ++numEntriesPerRow_map[gblRow];
1556 }
1557 }
1558
1559 Teuchos::Array<size_t> numEntriesPerRow (proc0Map->getLocalNumElements ());
1560 for (const auto& ent : numEntriesPerRow_map) {
1561 const local_ordinal_type lclRow = proc0Map->getLocalElement (ent.first);
1562 numEntriesPerRow[lclRow] = ent.second;
1563 }
1564 // Free anything we don't need before allocating the graph.
1565 // Swapping with an empty data structure is the standard idiom
1566 // for freeing memory used by Standard Library containers.
1567 // (Just resizing to 0 doesn't promise to free memory.)
1568 {
1569 std::map<global_ordinal_type, size_t> empty_map;
1570 std::swap (numEntriesPerRow_map, empty_map);
1571 }
1572
1573 RCP<sparse_graph_type> proc0Graph =
1574 rcp(new sparse_graph_type(proc0Map,numEntriesPerRow (),
1575 constructorParams));
1576 if(myRank == rootRank) {
1577 typedef Teuchos::MatrixMarket::Raw::GraphElement<global_ordinal_type> element_type;
1578
1579 // Get the entries
1580 const std::vector<element_type>& entries =
1581 pAdder->getAdder()->getEntries();
1582
1583 // Insert them one at a time
1584 for(size_t curPos=0; curPos<entries.size(); curPos++) {
1585 const element_type& curEntry = entries[curPos];
1586 const global_ordinal_type curRow = curEntry.rowIndex()+indexBase;
1587 const global_ordinal_type curCol = curEntry.colIndex()+indexBase;
1588 Teuchos::ArrayView<const global_ordinal_type> colView(&curCol,1);
1589 proc0Graph->insertGlobalIndices(curRow,colView);
1590 }
1591 }
1592 proc0Graph->fillComplete();
1593
1594 RCP<sparse_graph_type> distGraph;
1595 if(Teuchos::is_null(rowMap))
1596 {
1597 // Create a map describing the distribution we actually want
1598 RCP<map_type> distMap =
1599 rcp(new map_type(dims[0],0,pComm,GloballyDistributed));
1600
1601 // Create the graph with that distribution too
1602 distGraph = rcp(new sparse_graph_type(distMap,colMap,0,constructorParams));
1603
1604 // Create an importer/exporter/vandelay to redistribute the graph
1605 typedef Import<local_ordinal_type, global_ordinal_type, node_type> import_type;
1606 import_type importer (proc0Map, distMap);
1607
1608 // Import the data
1609 distGraph->doImport(*proc0Graph,importer,INSERT);
1610 }
1611 else {
1612 distGraph = rcp(new sparse_graph_type(rowMap,colMap,0,constructorParams));
1613
1614 // Create an importer/exporter/vandelay to redistribute the graph
1615 typedef Import<local_ordinal_type, global_ordinal_type, node_type> import_type;
1616 import_type importer (proc0Map, rowMap);
1617
1618 // Import the data
1619 distGraph->doImport(*proc0Graph,importer,INSERT);
1620 }
1621
1622 return distGraph;
1623 }
1624
1625 public:
1649 static Teuchos::RCP<sparse_graph_type>
1650 readSparseGraphFile (const std::string& filename,
1651 const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
1652 const bool callFillComplete=true,
1653 const bool tolerant=false,
1654 const bool debug=false)
1655 {
1656 using Teuchos::broadcast;
1657 using Teuchos::outArg;
1658
1659 // Only open the file on Process 0. Test carefully to make
1660 // sure that the file opened successfully (and broadcast that
1661 // result to all processes to prevent a hang on exception
1662 // throw), since it's a common mistake to misspell a filename.
1663 std::ifstream in;
1664 int opened = 0;
1665 if (comm->getRank () == 0) {
1666 try {
1667 in.open (filename.c_str ());
1668 opened = in.is_open();
1669 }
1670 catch (...) {
1671 opened = 0;
1672 }
1673 }
1674 broadcast<int, int> (*comm, 0, outArg (opened));
1675 TEUCHOS_TEST_FOR_EXCEPTION
1676 (opened == 0, std::runtime_error, "readSparseGraphFile: "
1677 "Failed to open file \"" << filename << "\" on Process 0.");
1678 return readSparseGraph (in, comm,
1679 callFillComplete,
1680 tolerant, debug);
1681 // We can rely on the destructor of the input stream to close
1682 // the file on scope exit, even if readSparseGraph() throws an
1683 // exception.
1684 }
1685
1686
1715 static Teuchos::RCP<sparse_graph_type>
1716 readSparseGraphFile (const std::string& filename,
1717 const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1718 const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1719 const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
1720 const bool tolerant=false,
1721 const bool debug=false)
1722 {
1723 using Teuchos::broadcast;
1724 using Teuchos::outArg;
1725
1726 // Only open the file on Process 0. Test carefully to make
1727 // sure that the file opened successfully (and broadcast that
1728 // result to all processes to prevent a hang on exception
1729 // throw), since it's a common mistake to misspell a filename.
1730 std::ifstream in;
1731 int opened = 0;
1732 if (pComm->getRank () == 0) {
1733 try {
1734 in.open (filename.c_str ());
1735 opened = in.is_open();
1736 }
1737 catch (...) {
1738 opened = 0;
1739 }
1740 }
1741 broadcast<int, int> (*pComm, 0, outArg (opened));
1742 TEUCHOS_TEST_FOR_EXCEPTION
1743 (opened == 0, std::runtime_error, "readSparseGraphFile: "
1744 "Failed to open file \"" << filename << "\" on Process 0.");
1745 if (pComm->getRank () == 0) { // only open the input file on Process 0
1746 in.open (filename.c_str ());
1747 }
1748 return readSparseGraph (in, pComm,
1749 constructorParams,
1750 fillCompleteParams, tolerant, debug);
1751 // We can rely on the destructor of the input stream to close
1752 // the file on scope exit, even if readSparseGraph() throws an
1753 // exception.
1754 }
1755
1756
1794 static Teuchos::RCP<sparse_graph_type>
1795 readSparseGraphFile (const std::string& filename,
1796 const Teuchos::RCP<const map_type>& rowMap,
1797 Teuchos::RCP<const map_type>& colMap,
1798 const Teuchos::RCP<const map_type>& domainMap,
1799 const Teuchos::RCP<const map_type>& rangeMap,
1800 const bool callFillComplete=true,
1801 const bool tolerant=false,
1802 const bool debug=false)
1803 {
1804 using Teuchos::broadcast;
1805 using Teuchos::Comm;
1806 using Teuchos::outArg;
1807 using Teuchos::RCP;
1808
1809 TEUCHOS_TEST_FOR_EXCEPTION
1810 (rowMap.is_null (), std::invalid_argument,
1811 "Input rowMap must be nonnull.");
1812 RCP<const Comm<int> > comm = rowMap->getComm ();
1813 if (comm.is_null ()) {
1814 // If the input communicator is null on some process, then
1815 // that process does not participate in the collective.
1816 return Teuchos::null;
1817 }
1818
1819 // Only open the file on Process 0. Test carefully to make
1820 // sure that the file opened successfully (and broadcast that
1821 // result to all processes to prevent a hang on exception
1822 // throw), since it's a common mistake to misspell a filename.
1823 std::ifstream in;
1824 int opened = 0;
1825 if (comm->getRank () == 0) {
1826 try {
1827 in.open (filename.c_str ());
1828 opened = in.is_open();
1829 }
1830 catch (...) {
1831 opened = 0;
1832 }
1833 }
1834 broadcast<int, int> (*comm, 0, outArg (opened));
1835 TEUCHOS_TEST_FOR_EXCEPTION
1836 (opened == 0, std::runtime_error, "readSparseGraphFile: "
1837 "Failed to open file \"" << filename << "\" on Process 0.");
1838 return readSparseGraph (in, rowMap, colMap, domainMap, rangeMap,
1839 callFillComplete, tolerant, debug);
1840 }
1841
1867 static Teuchos::RCP<sparse_graph_type>
1868 readSparseGraph (std::istream& in,
1869 const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1870 const bool callFillComplete=true,
1871 const bool tolerant=false,
1872 const bool debug=false)
1873 {
1874 Teuchos::RCP<const map_type> fakeRowMap;
1875 Teuchos::RCP<const map_type> fakeColMap;
1876 Teuchos::RCP<Teuchos::ParameterList> fakeCtorParams;
1877
1878 Teuchos::RCP<sparse_graph_type> graph =
1879 readSparseGraphHelper (in, pComm,
1880 fakeRowMap, fakeColMap,
1881 fakeCtorParams, tolerant, debug);
1882 if (callFillComplete) {
1883 graph->fillComplete ();
1884 }
1885 return graph;
1886 }
1887
1888
1918 static Teuchos::RCP<sparse_graph_type>
1919 readSparseGraph (std::istream& in,
1920 const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1921 const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1922 const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
1923 const bool tolerant=false,
1924 const bool debug=false)
1925 {
1926 Teuchos::RCP<const map_type> fakeRowMap;
1927 Teuchos::RCP<const map_type> fakeColMap;
1928 Teuchos::RCP<sparse_graph_type> graph =
1929 readSparseGraphHelper (in, pComm,
1930 fakeRowMap, fakeColMap,
1931 constructorParams, tolerant, debug);
1932 graph->fillComplete (fillCompleteParams);
1933 return graph;
1934 }
1935
1936
1977 static Teuchos::RCP<sparse_graph_type>
1978 readSparseGraph (std::istream& in,
1979 const Teuchos::RCP<const map_type>& rowMap,
1980 Teuchos::RCP<const map_type>& colMap,
1981 const Teuchos::RCP<const map_type>& domainMap,
1982 const Teuchos::RCP<const map_type>& rangeMap,
1983 const bool callFillComplete=true,
1984 const bool tolerant=false,
1985 const bool debug=false)
1986 {
1987 Teuchos::RCP<sparse_graph_type> graph =
1988 readSparseGraphHelper (in, rowMap->getComm (),
1989 rowMap, colMap, Teuchos::null, tolerant,
1990 debug);
1991 if (callFillComplete) {
1992 graph->fillComplete (domainMap, rangeMap);
1993 }
1994 return graph;
1995 }
1996
1997#include "MatrixMarket_TpetraNew.hpp"
1998
2022 static Teuchos::RCP<sparse_matrix_type>
2023 readSparseFile (const std::string& filename,
2024 const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2025 const bool callFillComplete=true,
2026 const bool tolerant=false,
2027 const bool debug=false)
2028 {
2029 const int myRank = pComm->getRank ();
2030 std::ifstream in;
2031
2032 // Only open the file on Rank 0.
2033 if (myRank == 0) {
2034 in.open (filename.c_str ());
2035 }
2036 // FIXME (mfh 16 Jun 2015) Do a broadcast to make sure that
2037 // opening the file succeeded, before continuing. That will
2038 // avoid hangs if the read doesn't work. On the other hand,
2039 // readSparse could do that too, by checking the status of the
2040 // std::ostream.
2041
2042 return readSparse (in, pComm, callFillComplete, tolerant, debug);
2043 // We can rely on the destructor of the input stream to close
2044 // the file on scope exit, even if readSparse() throws an
2045 // exception.
2046 }
2047
2048
2077 static Teuchos::RCP<sparse_matrix_type>
2078 readSparseFile (const std::string& filename,
2079 const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2080 const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
2081 const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
2082 const bool tolerant=false,
2083 const bool debug=false)
2084 {
2085 std::ifstream in;
2086 if (pComm->getRank () == 0) { // only open on Process 0
2087 in.open (filename.c_str ());
2088 }
2089 return readSparse (in, pComm, constructorParams,
2090 fillCompleteParams, tolerant, debug);
2091 }
2092
2093
2131 static Teuchos::RCP<sparse_matrix_type>
2132 readSparseFile (const std::string& filename,
2133 const Teuchos::RCP<const map_type>& rowMap,
2134 Teuchos::RCP<const map_type>& colMap,
2135 const Teuchos::RCP<const map_type>& domainMap,
2136 const Teuchos::RCP<const map_type>& rangeMap,
2137 const bool callFillComplete=true,
2138 const bool tolerant=false,
2139 const bool debug=false)
2140 {
2141 using Teuchos::broadcast;
2142 using Teuchos::Comm;
2143 using Teuchos::outArg;
2144 using Teuchos::RCP;
2145
2146 TEUCHOS_TEST_FOR_EXCEPTION(
2147 rowMap.is_null (), std::invalid_argument,
2148 "Row Map must be nonnull.");
2149
2150 RCP<const Comm<int> > comm = rowMap->getComm ();
2151 const int myRank = comm->getRank ();
2152
2153 // Only open the file on Process 0. Test carefully to make
2154 // sure that the file opened successfully (and broadcast that
2155 // result to all processes to prevent a hang on exception
2156 // throw), since it's a common mistake to misspell a filename.
2157 std::ifstream in;
2158 int opened = 0;
2159 if (myRank == 0) {
2160 try {
2161 in.open (filename.c_str ());
2162 opened = in.is_open();
2163 }
2164 catch (...) {
2165 opened = 0;
2166 }
2167 }
2168 broadcast<int, int> (*comm, 0, outArg (opened));
2169 TEUCHOS_TEST_FOR_EXCEPTION(
2170 opened == 0, std::runtime_error,
2171 "readSparseFile: Failed to open file \"" << filename << "\" on "
2172 "Process 0.");
2173 return readSparse (in, rowMap, colMap, domainMap, rangeMap,
2174 callFillComplete, tolerant, debug);
2175 }
2176
2202 static Teuchos::RCP<sparse_matrix_type>
2203 readSparse (std::istream& in,
2204 const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2205 const bool callFillComplete=true,
2206 const bool tolerant=false,
2207 const bool debug=false)
2208 {
2209 using Teuchos::MatrixMarket::Banner;
2210 using Teuchos::arcp;
2211 using Teuchos::ArrayRCP;
2212 using Teuchos::broadcast;
2213 using Teuchos::null;
2214 using Teuchos::ptr;
2215 using Teuchos::RCP;
2216 using Teuchos::REDUCE_MAX;
2217 using Teuchos::reduceAll;
2218 using Teuchos::Tuple;
2219 using std::cerr;
2220 using std::endl;
2221 typedef Teuchos::ScalarTraits<scalar_type> STS;
2222
2223 const bool extraDebug = false;
2224 const int myRank = pComm->getRank ();
2225 const int rootRank = 0;
2226
2227 // Current line number in the input stream. Various calls
2228 // will modify this depending on the number of lines that are
2229 // read from the input stream. Only Rank 0 modifies this.
2230 size_t lineNumber = 1;
2231
2232 if (debug && myRank == rootRank) {
2233 cerr << "Matrix Market reader: readSparse:" << endl
2234 << "-- Reading banner line" << endl;
2235 }
2236
2237 // The "Banner" tells you whether the input stream represents
2238 // a sparse matrix, the symmetry type of the matrix, and the
2239 // type of the data it contains.
2240 //
2241 // pBanner will only be nonnull on MPI Rank 0. It will be
2242 // null on all other MPI processes.
2243 RCP<const Banner> pBanner;
2244 {
2245 // We read and validate the Banner on Proc 0, but broadcast
2246 // the validation result to all processes.
2247 // Teuchos::broadcast doesn't currently work with bool, so
2248 // we use int (true -> 1, false -> 0).
2249 int bannerIsCorrect = 1;
2250 std::ostringstream errMsg;
2251
2252 if (myRank == rootRank) {
2253 // Read the Banner line from the input stream.
2254 try {
2255 pBanner = readBanner (in, lineNumber, tolerant, debug);
2256 }
2257 catch (std::exception& e) {
2258 errMsg << "Attempt to read the Matrix Market file's Banner line "
2259 "threw an exception: " << e.what();
2260 bannerIsCorrect = 0;
2261 }
2262
2263 if (bannerIsCorrect) {
2264 // Validate the Banner for the case of a sparse matrix.
2265 // We validate on Proc 0, since it reads the Banner.
2266
2267 // In intolerant mode, the matrix type must be "coordinate".
2268 if (! tolerant && pBanner->matrixType() != "coordinate") {
2269 bannerIsCorrect = 0;
2270 errMsg << "The Matrix Market input file must contain a "
2271 "\"coordinate\"-format sparse matrix in order to create a "
2272 "Tpetra::CrsMatrix object from it, but the file's matrix "
2273 "type is \"" << pBanner->matrixType() << "\" instead.";
2274 }
2275 // In tolerant mode, we allow the matrix type to be
2276 // anything other than "array" (which would mean that
2277 // the file contains a dense matrix).
2278 if (tolerant && pBanner->matrixType() == "array") {
2279 bannerIsCorrect = 0;
2280 errMsg << "Matrix Market file must contain a \"coordinate\"-"
2281 "format sparse matrix in order to create a Tpetra::CrsMatrix "
2282 "object from it, but the file's matrix type is \"array\" "
2283 "instead. That probably means the file contains dense matrix "
2284 "data.";
2285 }
2286 }
2287 } // Proc 0: Done reading the Banner, hopefully successfully.
2288
2289 // Broadcast from Proc 0 whether the Banner was read correctly.
2290 broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
2291
2292 // If the Banner is invalid, all processes throw an
2293 // exception. Only Proc 0 gets the exception message, but
2294 // that's OK, since the main point is to "stop the world"
2295 // (rather than throw an exception on one process and leave
2296 // the others hanging).
2297 TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
2298 std::invalid_argument, errMsg.str ());
2299 } // Done reading the Banner line and broadcasting success.
2300 if (debug && myRank == rootRank) {
2301 cerr << "-- Reading dimensions line" << endl;
2302 }
2303
2304 // Read the matrix dimensions from the Matrix Market metadata.
2305 // dims = (numRows, numCols, numEntries). Proc 0 does the
2306 // reading, but it broadcasts the results to all MPI
2307 // processes. Thus, readCoordDims() is a collective
2308 // operation. It does a collective check for correctness too.
2309 Tuple<global_ordinal_type, 3> dims =
2310 readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
2311
2312 if (debug && myRank == rootRank) {
2313 cerr << "-- Making Adder for collecting matrix data" << endl;
2314 }
2315
2316 // "Adder" object for collecting all the sparse matrix entries
2317 // from the input stream. This is only nonnull on Proc 0.
2318 RCP<adder_type> pAdder =
2319 makeAdder (pComm, pBanner, dims, tolerant, debug);
2320
2321 if (debug && myRank == rootRank) {
2322 cerr << "-- Reading matrix data" << endl;
2323 }
2324 //
2325 // Read the matrix entries from the input stream on Proc 0.
2326 //
2327 {
2328 // We use readSuccess to broadcast the results of the read
2329 // (succeeded or not) to all MPI processes. Since
2330 // Teuchos::broadcast doesn't currently know how to send
2331 // bools, we convert to int (true -> 1, false -> 0).
2332 int readSuccess = 1;
2333 std::ostringstream errMsg; // Exception message (only valid on Proc 0)
2334 if (myRank == rootRank) {
2335 try {
2336 // Reader for "coordinate" format sparse matrix data.
2337 typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
2338 global_ordinal_type, scalar_type, STS::isComplex> reader_type;
2339 reader_type reader (pAdder);
2340
2341 // Read the sparse matrix entries.
2342 std::pair<bool, std::vector<size_t> > results =
2343 reader.read (in, lineNumber, tolerant, debug);
2344 readSuccess = results.first ? 1 : 0;
2345 }
2346 catch (std::exception& e) {
2347 readSuccess = 0;
2348 errMsg << e.what();
2349 }
2350 }
2351 broadcast (*pComm, rootRank, ptr (&readSuccess));
2352
2353 // It would be nice to add a "verbose" flag, so that in
2354 // tolerant mode, we could log any bad line number(s) on
2355 // Proc 0. For now, we just throw if the read fails to
2356 // succeed.
2357 //
2358 // Question: If we're in tolerant mode, and if the read did
2359 // not succeed, should we attempt to call fillComplete()?
2360 TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
2361 "Failed to read the Matrix Market sparse matrix file: "
2362 << errMsg.str());
2363 } // Done reading the matrix entries (stored on Proc 0 for now)
2364
2365 if (debug && myRank == rootRank) {
2366 cerr << "-- Successfully read the Matrix Market data" << endl;
2367 }
2368
2369 // In tolerant mode, we need to rebroadcast the matrix
2370 // dimensions, since they may be different after reading the
2371 // actual matrix data. We only need to broadcast the number
2372 // of rows and columns. Only Rank 0 needs to know the actual
2373 // global number of entries, since (a) we need to merge
2374 // duplicates on Rank 0 first anyway, and (b) when we
2375 // distribute the entries, each rank other than Rank 0 will
2376 // only need to know how many entries it owns, not the total
2377 // number of entries.
2378 if (tolerant) {
2379 if (debug && myRank == rootRank) {
2380 cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
2381 << endl
2382 << "----- Dimensions before: "
2383 << dims[0] << " x " << dims[1]
2384 << endl;
2385 }
2386 // Packed coordinate matrix dimensions (numRows, numCols).
2387 Tuple<global_ordinal_type, 2> updatedDims;
2388 if (myRank == rootRank) {
2389 // If one or more bottom rows of the matrix contain no
2390 // entries, then the Adder will report that the number
2391 // of rows is less than that specified in the
2392 // metadata. We allow this case, and favor the
2393 // metadata so that the zero row(s) will be included.
2394 updatedDims[0] =
2395 std::max (dims[0], pAdder->getAdder()->numRows());
2396 updatedDims[1] = pAdder->getAdder()->numCols();
2397 }
2398 broadcast (*pComm, rootRank, updatedDims);
2399 dims[0] = updatedDims[0];
2400 dims[1] = updatedDims[1];
2401 if (debug && myRank == rootRank) {
2402 cerr << "----- Dimensions after: " << dims[0] << " x "
2403 << dims[1] << endl;
2404 }
2405 }
2406 else {
2407 // In strict mode, we require that the matrix's metadata and
2408 // its actual data agree, at least somewhat. In particular,
2409 // the number of rows must agree, since otherwise we cannot
2410 // distribute the matrix correctly.
2411
2412 // Teuchos::broadcast() doesn't know how to broadcast bools,
2413 // so we use an int with the standard 1 == true, 0 == false
2414 // encoding.
2415 int dimsMatch = 1;
2416 if (myRank == rootRank) {
2417 // If one or more bottom rows of the matrix contain no
2418 // entries, then the Adder will report that the number of
2419 // rows is less than that specified in the metadata. We
2420 // allow this case, and favor the metadata, but do not
2421 // allow the Adder to think there are more rows in the
2422 // matrix than the metadata says.
2423 if (dims[0] < pAdder->getAdder ()->numRows ()) {
2424 dimsMatch = 0;
2425 }
2426 }
2427 broadcast (*pComm, 0, ptr (&dimsMatch));
2428 if (dimsMatch == 0) {
2429 // We're in an error state anyway, so we might as well
2430 // work a little harder to print an informative error
2431 // message.
2432 //
2433 // Broadcast the Adder's idea of the matrix dimensions
2434 // from Proc 0 to all processes.
2435 Tuple<global_ordinal_type, 2> addersDims;
2436 if (myRank == rootRank) {
2437 addersDims[0] = pAdder->getAdder()->numRows();
2438 addersDims[1] = pAdder->getAdder()->numCols();
2439 }
2440 broadcast (*pComm, 0, addersDims);
2441 TEUCHOS_TEST_FOR_EXCEPTION(
2442 dimsMatch == 0, std::runtime_error,
2443 "The matrix metadata says that the matrix is " << dims[0] << " x "
2444 << dims[1] << ", but the actual data says that the matrix is "
2445 << addersDims[0] << " x " << addersDims[1] << ". That means the "
2446 "data includes more rows than reported in the metadata. This "
2447 "is not allowed when parsing in strict mode. Parse the matrix in "
2448 "tolerant mode to ignore the metadata when it disagrees with the "
2449 "data.");
2450 }
2451 } // Matrix dimensions (# rows, # cols, # entries) agree.
2452
2453 if (debug && myRank == rootRank) {
2454 cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
2455 }
2456
2457 // Now that we've read in all the matrix entries from the
2458 // input stream into the adder on Proc 0, post-process them
2459 // into CSR format (still on Proc 0). This will facilitate
2460 // distributing them to all the processors.
2461 //
2462 // These arrays represent the global matrix data as a CSR
2463 // matrix (with numEntriesPerRow as redundant but convenient
2464 // metadata, since it's computable from rowPtr and vice
2465 // versa). They are valid only on Proc 0.
2466 ArrayRCP<size_t> numEntriesPerRow;
2467 ArrayRCP<size_t> rowPtr;
2468 ArrayRCP<global_ordinal_type> colInd;
2469 ArrayRCP<scalar_type> values;
2470
2471 // Proc 0 first merges duplicate entries, and then converts
2472 // the coordinate-format matrix data to CSR.
2473 {
2474 int mergeAndConvertSucceeded = 1;
2475 std::ostringstream errMsg;
2476
2477 if (myRank == rootRank) {
2478 try {
2479 typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,
2480 global_ordinal_type> element_type;
2481
2482 // Number of rows in the matrix. If we are in tolerant
2483 // mode, we've already synchronized dims with the actual
2484 // matrix data. If in strict mode, we should use dims
2485 // (as read from the file's metadata) rather than the
2486 // matrix data to determine the dimensions. (The matrix
2487 // data will claim fewer rows than the metadata, if one
2488 // or more rows have no entries stored in the file.)
2489 const size_type numRows = dims[0];
2490
2491 // Additively merge duplicate matrix entries.
2492 pAdder->getAdder()->merge ();
2493
2494 // Get a temporary const view of the merged matrix entries.
2495 const std::vector<element_type>& entries =
2496 pAdder->getAdder()->getEntries();
2497
2498 // Number of matrix entries (after merging).
2499 const size_t numEntries = (size_t)entries.size();
2500
2501 if (debug) {
2502 cerr << "----- Proc 0: Matrix has numRows=" << numRows
2503 << " rows and numEntries=" << numEntries
2504 << " entries." << endl;
2505 }
2506
2507 // Make space for the CSR matrix data. Converting to
2508 // CSR is easier if we fill numEntriesPerRow with zeros
2509 // at first.
2510 numEntriesPerRow = arcp<size_t> (numRows);
2511 std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
2512 rowPtr = arcp<size_t> (numRows+1);
2513 std::fill (rowPtr.begin(), rowPtr.end(), 0);
2514 colInd = arcp<global_ordinal_type> (numEntries);
2515 values = arcp<scalar_type> (numEntries);
2516
2517 // Convert from array-of-structs coordinate format to CSR
2518 // (compressed sparse row) format.
2519 global_ordinal_type prvRow = 0;
2520 size_t curPos = 0;
2521 rowPtr[0] = 0;
2522 for (curPos = 0; curPos < numEntries; ++curPos) {
2523 const element_type& curEntry = entries[curPos];
2524 const global_ordinal_type curRow = curEntry.rowIndex();
2525 TEUCHOS_TEST_FOR_EXCEPTION(
2526 curRow < prvRow, std::logic_error,
2527 "Row indices are out of order, even though they are supposed "
2528 "to be sorted. curRow = " << curRow << ", prvRow = "
2529 << prvRow << ", at curPos = " << curPos << ". Please report "
2530 "this bug to the Tpetra developers.");
2531 if (curRow > prvRow) {
2532 for (global_ordinal_type r = prvRow+1; r <= curRow; ++r) {
2533 rowPtr[r] = curPos;
2534 }
2535 prvRow = curRow;
2536 }
2537 numEntriesPerRow[curRow]++;
2538 colInd[curPos] = curEntry.colIndex();
2539 values[curPos] = curEntry.value();
2540 }
2541 // rowPtr has one more entry than numEntriesPerRow. The
2542 // last entry of rowPtr is the number of entries in
2543 // colInd and values.
2544 rowPtr[numRows] = numEntries;
2545 } // Finished conversion to CSR format
2546 catch (std::exception& e) {
2547 mergeAndConvertSucceeded = 0;
2548 errMsg << "Failed to merge sparse matrix entries and convert to "
2549 "CSR format: " << e.what();
2550 }
2551
2552 if (debug && mergeAndConvertSucceeded) {
2553 // Number of rows in the matrix.
2554 const size_type numRows = dims[0];
2555 const size_type maxToDisplay = 100;
2556
2557 cerr << "----- Proc 0: numEntriesPerRow[0.."
2558 << (numEntriesPerRow.size()-1) << "] ";
2559 if (numRows > maxToDisplay) {
2560 cerr << "(only showing first and last few entries) ";
2561 }
2562 cerr << "= [";
2563 if (numRows > 0) {
2564 if (numRows > maxToDisplay) {
2565 for (size_type k = 0; k < 2; ++k) {
2566 cerr << numEntriesPerRow[k] << " ";
2567 }
2568 cerr << "... ";
2569 for (size_type k = numRows-2; k < numRows-1; ++k) {
2570 cerr << numEntriesPerRow[k] << " ";
2571 }
2572 }
2573 else {
2574 for (size_type k = 0; k < numRows-1; ++k) {
2575 cerr << numEntriesPerRow[k] << " ";
2576 }
2577 }
2578 cerr << numEntriesPerRow[numRows-1];
2579 } // numRows > 0
2580 cerr << "]" << endl;
2581
2582 cerr << "----- Proc 0: rowPtr ";
2583 if (numRows > maxToDisplay) {
2584 cerr << "(only showing first and last few entries) ";
2585 }
2586 cerr << "= [";
2587 if (numRows > maxToDisplay) {
2588 for (size_type k = 0; k < 2; ++k) {
2589 cerr << rowPtr[k] << " ";
2590 }
2591 cerr << "... ";
2592 for (size_type k = numRows-2; k < numRows; ++k) {
2593 cerr << rowPtr[k] << " ";
2594 }
2595 }
2596 else {
2597 for (size_type k = 0; k < numRows; ++k) {
2598 cerr << rowPtr[k] << " ";
2599 }
2600 }
2601 cerr << rowPtr[numRows] << "]" << endl;
2602 }
2603 } // if myRank == rootRank
2604 } // Done converting sparse matrix data to CSR format
2605
2606 // Now we're done with the Adder, so we can release the
2607 // reference ("free" it) to save space. This only actually
2608 // does anything on Rank 0, since pAdder is null on all the
2609 // other MPI processes.
2610 pAdder = null;
2611
2612 if (debug && myRank == rootRank) {
2613 cerr << "-- Making range, domain, and row maps" << endl;
2614 }
2615
2616 // Make the maps that describe the matrix's range and domain,
2617 // and the distribution of its rows. Creating a Map is a
2618 // collective operation, so we don't have to do a broadcast of
2619 // a success Boolean.
2620 RCP<const map_type> pRangeMap = makeRangeMap (pComm, dims[0]);
2621 RCP<const map_type> pDomainMap =
2622 makeDomainMap (pRangeMap, dims[0], dims[1]);
2623 RCP<const map_type> pRowMap = makeRowMap (null, pComm, dims[0]);
2624
2625 if (debug && myRank == rootRank) {
2626 cerr << "-- Distributing the matrix data" << endl;
2627 }
2628
2629 // Distribute the matrix data. Each processor has to add the
2630 // rows that it owns. If you try to make Proc 0 call
2631 // insertGlobalValues() for _all_ the rows, not just those it
2632 // owns, then fillComplete() will compute the number of
2633 // columns incorrectly. That's why Proc 0 has to distribute
2634 // the matrix data and why we make all the processors (not
2635 // just Proc 0) call insertGlobalValues() on their own data.
2636 //
2637 // These arrays represent each processor's part of the matrix
2638 // data, in "CSR" format (sort of, since the row indices might
2639 // not be contiguous).
2640 ArrayRCP<size_t> myNumEntriesPerRow;
2641 ArrayRCP<size_t> myRowPtr;
2642 ArrayRCP<global_ordinal_type> myColInd;
2643 ArrayRCP<scalar_type> myValues;
2644 // Distribute the matrix data. This is a collective operation.
2645 distribute (myNumEntriesPerRow, myRowPtr, myColInd, myValues, pRowMap,
2646 numEntriesPerRow, rowPtr, colInd, values, debug);
2647
2648 if (debug && myRank == rootRank) {
2649 cerr << "-- Inserting matrix entries on each processor";
2650 if (callFillComplete) {
2651 cerr << " and calling fillComplete()";
2652 }
2653 cerr << endl;
2654 }
2655 // Each processor inserts its part of the matrix data, and
2656 // then they all call fillComplete(). This method invalidates
2657 // the my* distributed matrix data before calling
2658 // fillComplete(), in order to save space. In general, we
2659 // never store more than two copies of the matrix's entries in
2660 // memory at once, which is no worse than what Tpetra
2661 // promises.
2662 RCP<sparse_matrix_type> pMatrix =
2663 makeMatrix (myNumEntriesPerRow, myRowPtr, myColInd, myValues,
2664 pRowMap, pRangeMap, pDomainMap, callFillComplete);
2665 // Only use a reduce-all in debug mode to check if pMatrix is
2666 // null. Otherwise, just throw an exception. We never expect
2667 // a null pointer here, so we can save a communication.
2668 if (debug) {
2669 int localIsNull = pMatrix.is_null () ? 1 : 0;
2670 int globalIsNull = 0;
2671 reduceAll (*pComm, REDUCE_MAX, localIsNull, ptr (&globalIsNull));
2672 TEUCHOS_TEST_FOR_EXCEPTION(globalIsNull != 0, std::logic_error,
2673 "Reader::makeMatrix() returned a null pointer on at least one "
2674 "process. Please report this bug to the Tpetra developers.");
2675 }
2676 else {
2677 TEUCHOS_TEST_FOR_EXCEPTION(pMatrix.is_null(), std::logic_error,
2678 "Reader::makeMatrix() returned a null pointer. "
2679 "Please report this bug to the Tpetra developers.");
2680 }
2681
2682 // We can't get the dimensions of the matrix until after
2683 // fillComplete() is called. Thus, we can't do the sanity
2684 // check (dimensions read from the Matrix Market data,
2685 // vs. dimensions reported by the CrsMatrix) unless the user
2686 // asked makeMatrix() to call fillComplete().
2687 //
2688 // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
2689 // what one might think it does, so you have to ask the range
2690 // resp. domain map for the number of rows resp. columns.
2691 if (callFillComplete) {
2692 const int numProcs = pComm->getSize ();
2693
2694 if (extraDebug && debug) {
2695 const global_size_t globalNumRows =
2696 pRangeMap->getGlobalNumElements ();
2697 const global_size_t globalNumCols =
2698 pDomainMap->getGlobalNumElements ();
2699 if (myRank == rootRank) {
2700 cerr << "-- Matrix is "
2701 << globalNumRows << " x " << globalNumCols
2702 << " with " << pMatrix->getGlobalNumEntries()
2703 << " entries, and index base "
2704 << pMatrix->getIndexBase() << "." << endl;
2705 }
2706 pComm->barrier ();
2707 for (int p = 0; p < numProcs; ++p) {
2708 if (myRank == p) {
2709 cerr << "-- Proc " << p << " owns "
2710 << pMatrix->getLocalNumCols() << " columns, and "
2711 << pMatrix->getLocalNumEntries() << " entries." << endl;
2712 }
2713 pComm->barrier ();
2714 }
2715 } // if (extraDebug && debug)
2716 } // if (callFillComplete)
2717
2718 if (debug && myRank == rootRank) {
2719 cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
2720 << endl;
2721 }
2722 return pMatrix;
2723 }
2724
2725
2754 static Teuchos::RCP<sparse_matrix_type>
2755 readSparse (std::istream& in,
2756 const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2757 const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
2758 const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
2759 const bool tolerant=false,
2760 const bool debug=false)
2761 {
2762 using Teuchos::MatrixMarket::Banner;
2763 using Teuchos::arcp;
2764 using Teuchos::ArrayRCP;
2765 using Teuchos::broadcast;
2766 using Teuchos::null;
2767 using Teuchos::ptr;
2768 using Teuchos::RCP;
2769 using Teuchos::reduceAll;
2770 using Teuchos::Tuple;
2771 using std::cerr;
2772 using std::endl;
2773 typedef Teuchos::ScalarTraits<scalar_type> STS;
2774
2775 const bool extraDebug = false;
2776 const int myRank = pComm->getRank ();
2777 const int rootRank = 0;
2778
2779 // Current line number in the input stream. Various calls
2780 // will modify this depending on the number of lines that are
2781 // read from the input stream. Only Rank 0 modifies this.
2782 size_t lineNumber = 1;
2783
2784 if (debug && myRank == rootRank) {
2785 cerr << "Matrix Market reader: readSparse:" << endl
2786 << "-- Reading banner line" << endl;
2787 }
2788
2789 // The "Banner" tells you whether the input stream represents
2790 // a sparse matrix, the symmetry type of the matrix, and the
2791 // type of the data it contains.
2792 //
2793 // pBanner will only be nonnull on MPI Rank 0. It will be
2794 // null on all other MPI processes.
2795 RCP<const Banner> pBanner;
2796 {
2797 // We read and validate the Banner on Proc 0, but broadcast
2798 // the validation result to all processes.
2799 // Teuchos::broadcast doesn't currently work with bool, so
2800 // we use int (true -> 1, false -> 0).
2801 int bannerIsCorrect = 1;
2802 std::ostringstream errMsg;
2803
2804 if (myRank == rootRank) {
2805 // Read the Banner line from the input stream.
2806 try {
2807 pBanner = readBanner (in, lineNumber, tolerant, debug);
2808 }
2809 catch (std::exception& e) {
2810 errMsg << "Attempt to read the Matrix Market file's Banner line "
2811 "threw an exception: " << e.what();
2812 bannerIsCorrect = 0;
2813 }
2814
2815 if (bannerIsCorrect) {
2816 // Validate the Banner for the case of a sparse matrix.
2817 // We validate on Proc 0, since it reads the Banner.
2818
2819 // In intolerant mode, the matrix type must be "coordinate".
2820 if (! tolerant && pBanner->matrixType() != "coordinate") {
2821 bannerIsCorrect = 0;
2822 errMsg << "The Matrix Market input file must contain a "
2823 "\"coordinate\"-format sparse matrix in order to create a "
2824 "Tpetra::CrsMatrix object from it, but the file's matrix "
2825 "type is \"" << pBanner->matrixType() << "\" instead.";
2826 }
2827 // In tolerant mode, we allow the matrix type to be
2828 // anything other than "array" (which would mean that
2829 // the file contains a dense matrix).
2830 if (tolerant && pBanner->matrixType() == "array") {
2831 bannerIsCorrect = 0;
2832 errMsg << "Matrix Market file must contain a \"coordinate\"-"
2833 "format sparse matrix in order to create a Tpetra::CrsMatrix "
2834 "object from it, but the file's matrix type is \"array\" "
2835 "instead. That probably means the file contains dense matrix "
2836 "data.";
2837 }
2838 }
2839 } // Proc 0: Done reading the Banner, hopefully successfully.
2840
2841 // Broadcast from Proc 0 whether the Banner was read correctly.
2842 broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
2843
2844 // If the Banner is invalid, all processes throw an
2845 // exception. Only Proc 0 gets the exception message, but
2846 // that's OK, since the main point is to "stop the world"
2847 // (rather than throw an exception on one process and leave
2848 // the others hanging).
2849 TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
2850 std::invalid_argument, errMsg.str ());
2851 } // Done reading the Banner line and broadcasting success.
2852 if (debug && myRank == rootRank) {
2853 cerr << "-- Reading dimensions line" << endl;
2854 }
2855
2856 // Read the matrix dimensions from the Matrix Market metadata.
2857 // dims = (numRows, numCols, numEntries). Proc 0 does the
2858 // reading, but it broadcasts the results to all MPI
2859 // processes. Thus, readCoordDims() is a collective
2860 // operation. It does a collective check for correctness too.
2861 Tuple<global_ordinal_type, 3> dims =
2862 readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
2863
2864 if (debug && myRank == rootRank) {
2865 cerr << "-- Making Adder for collecting matrix data" << endl;
2866 }
2867
2868 // "Adder" object for collecting all the sparse matrix entries
2869 // from the input stream. This is only nonnull on Proc 0.
2870 RCP<adder_type> pAdder =
2871 makeAdder (pComm, pBanner, dims, tolerant, debug);
2872
2873 if (debug && myRank == rootRank) {
2874 cerr << "-- Reading matrix data" << endl;
2875 }
2876 //
2877 // Read the matrix entries from the input stream on Proc 0.
2878 //
2879 {
2880 // We use readSuccess to broadcast the results of the read
2881 // (succeeded or not) to all MPI processes. Since
2882 // Teuchos::broadcast doesn't currently know how to send
2883 // bools, we convert to int (true -> 1, false -> 0).
2884 int readSuccess = 1;
2885 std::ostringstream errMsg; // Exception message (only valid on Proc 0)
2886 if (myRank == rootRank) {
2887 try {
2888 // Reader for "coordinate" format sparse matrix data.
2889 typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
2890 global_ordinal_type, scalar_type, STS::isComplex> reader_type;
2891 reader_type reader (pAdder);
2892
2893 // Read the sparse matrix entries.
2894 std::pair<bool, std::vector<size_t> > results =
2895 reader.read (in, lineNumber, tolerant, debug);
2896 readSuccess = results.first ? 1 : 0;
2897 }
2898 catch (std::exception& e) {
2899 readSuccess = 0;
2900 errMsg << e.what();
2901 }
2902 }
2903 broadcast (*pComm, rootRank, ptr (&readSuccess));
2904
2905 // It would be nice to add a "verbose" flag, so that in
2906 // tolerant mode, we could log any bad line number(s) on
2907 // Proc 0. For now, we just throw if the read fails to
2908 // succeed.
2909 //
2910 // Question: If we're in tolerant mode, and if the read did
2911 // not succeed, should we attempt to call fillComplete()?
2912 TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
2913 "Failed to read the Matrix Market sparse matrix file: "
2914 << errMsg.str());
2915 } // Done reading the matrix entries (stored on Proc 0 for now)
2916
2917 if (debug && myRank == rootRank) {
2918 cerr << "-- Successfully read the Matrix Market data" << endl;
2919 }
2920
2921 // In tolerant mode, we need to rebroadcast the matrix
2922 // dimensions, since they may be different after reading the
2923 // actual matrix data. We only need to broadcast the number
2924 // of rows and columns. Only Rank 0 needs to know the actual
2925 // global number of entries, since (a) we need to merge
2926 // duplicates on Rank 0 first anyway, and (b) when we
2927 // distribute the entries, each rank other than Rank 0 will
2928 // only need to know how many entries it owns, not the total
2929 // number of entries.
2930 if (tolerant) {
2931 if (debug && myRank == rootRank) {
2932 cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
2933 << endl
2934 << "----- Dimensions before: "
2935 << dims[0] << " x " << dims[1]
2936 << endl;
2937 }
2938 // Packed coordinate matrix dimensions (numRows, numCols).
2939 Tuple<global_ordinal_type, 2> updatedDims;
2940 if (myRank == rootRank) {
2941 // If one or more bottom rows of the matrix contain no
2942 // entries, then the Adder will report that the number
2943 // of rows is less than that specified in the
2944 // metadata. We allow this case, and favor the
2945 // metadata so that the zero row(s) will be included.
2946 updatedDims[0] =
2947 std::max (dims[0], pAdder->getAdder()->numRows());
2948 updatedDims[1] = pAdder->getAdder()->numCols();
2949 }
2950 broadcast (*pComm, rootRank, updatedDims);
2951 dims[0] = updatedDims[0];
2952 dims[1] = updatedDims[1];
2953 if (debug && myRank == rootRank) {
2954 cerr << "----- Dimensions after: " << dims[0] << " x "
2955 << dims[1] << endl;
2956 }
2957 }
2958 else {
2959 // In strict mode, we require that the matrix's metadata and
2960 // its actual data agree, at least somewhat. In particular,
2961 // the number of rows must agree, since otherwise we cannot
2962 // distribute the matrix correctly.
2963
2964 // Teuchos::broadcast() doesn't know how to broadcast bools,
2965 // so we use an int with the standard 1 == true, 0 == false
2966 // encoding.
2967 int dimsMatch = 1;
2968 if (myRank == rootRank) {
2969 // If one or more bottom rows of the matrix contain no
2970 // entries, then the Adder will report that the number of
2971 // rows is less than that specified in the metadata. We
2972 // allow this case, and favor the metadata, but do not
2973 // allow the Adder to think there are more rows in the
2974 // matrix than the metadata says.
2975 if (dims[0] < pAdder->getAdder ()->numRows ()) {
2976 dimsMatch = 0;
2977 }
2978 }
2979 broadcast (*pComm, 0, ptr (&dimsMatch));
2980 if (dimsMatch == 0) {
2981 // We're in an error state anyway, so we might as well
2982 // work a little harder to print an informative error
2983 // message.
2984 //
2985 // Broadcast the Adder's idea of the matrix dimensions
2986 // from Proc 0 to all processes.
2987 Tuple<global_ordinal_type, 2> addersDims;
2988 if (myRank == rootRank) {
2989 addersDims[0] = pAdder->getAdder()->numRows();
2990 addersDims[1] = pAdder->getAdder()->numCols();
2991 }
2992 broadcast (*pComm, 0, addersDims);
2993 TEUCHOS_TEST_FOR_EXCEPTION(
2994 dimsMatch == 0, std::runtime_error,
2995 "The matrix metadata says that the matrix is " << dims[0] << " x "
2996 << dims[1] << ", but the actual data says that the matrix is "
2997 << addersDims[0] << " x " << addersDims[1] << ". That means the "
2998 "data includes more rows than reported in the metadata. This "
2999 "is not allowed when parsing in strict mode. Parse the matrix in "
3000 "tolerant mode to ignore the metadata when it disagrees with the "
3001 "data.");
3002 }
3003 } // Matrix dimensions (# rows, # cols, # entries) agree.
3004
3005 if (debug && myRank == rootRank) {
3006 cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
3007 }
3008
3009 // Now that we've read in all the matrix entries from the
3010 // input stream into the adder on Proc 0, post-process them
3011 // into CSR format (still on Proc 0). This will facilitate
3012 // distributing them to all the processors.
3013 //
3014 // These arrays represent the global matrix data as a CSR
3015 // matrix (with numEntriesPerRow as redundant but convenient
3016 // metadata, since it's computable from rowPtr and vice
3017 // versa). They are valid only on Proc 0.
3018 ArrayRCP<size_t> numEntriesPerRow;
3019 ArrayRCP<size_t> rowPtr;
3020 ArrayRCP<global_ordinal_type> colInd;
3021 ArrayRCP<scalar_type> values;
3022
3023 // Proc 0 first merges duplicate entries, and then converts
3024 // the coordinate-format matrix data to CSR.
3025 {
3026 int mergeAndConvertSucceeded = 1;
3027 std::ostringstream errMsg;
3028
3029 if (myRank == rootRank) {
3030 try {
3031 typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,
3032 global_ordinal_type> element_type;
3033
3034 // Number of rows in the matrix. If we are in tolerant
3035 // mode, we've already synchronized dims with the actual
3036 // matrix data. If in strict mode, we should use dims
3037 // (as read from the file's metadata) rather than the
3038 // matrix data to determine the dimensions. (The matrix
3039 // data will claim fewer rows than the metadata, if one
3040 // or more rows have no entries stored in the file.)
3041 const size_type numRows = dims[0];
3042
3043 // Additively merge duplicate matrix entries.
3044 pAdder->getAdder()->merge ();
3045
3046 // Get a temporary const view of the merged matrix entries.
3047 const std::vector<element_type>& entries =
3048 pAdder->getAdder()->getEntries();
3049
3050 // Number of matrix entries (after merging).
3051 const size_t numEntries = (size_t)entries.size();
3052
3053 if (debug) {
3054 cerr << "----- Proc 0: Matrix has numRows=" << numRows
3055 << " rows and numEntries=" << numEntries
3056 << " entries." << endl;
3057 }
3058
3059 // Make space for the CSR matrix data. Converting to
3060 // CSR is easier if we fill numEntriesPerRow with zeros
3061 // at first.
3062 numEntriesPerRow = arcp<size_t> (numRows);
3063 std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
3064 rowPtr = arcp<size_t> (numRows+1);
3065 std::fill (rowPtr.begin(), rowPtr.end(), 0);
3066 colInd = arcp<global_ordinal_type> (numEntries);
3067 values = arcp<scalar_type> (numEntries);
3068
3069 // Convert from array-of-structs coordinate format to CSR
3070 // (compressed sparse row) format.
3071 global_ordinal_type prvRow = 0;
3072 size_t curPos = 0;
3073 rowPtr[0] = 0;
3074 for (curPos = 0; curPos < numEntries; ++curPos) {
3075 const element_type& curEntry = entries[curPos];
3076 const global_ordinal_type curRow = curEntry.rowIndex();
3077 TEUCHOS_TEST_FOR_EXCEPTION(
3078 curRow < prvRow, std::logic_error,
3079 "Row indices are out of order, even though they are supposed "
3080 "to be sorted. curRow = " << curRow << ", prvRow = "
3081 << prvRow << ", at curPos = " << curPos << ". Please report "
3082 "this bug to the Tpetra developers.");
3083 if (curRow > prvRow) {
3084 for (global_ordinal_type r = prvRow+1; r <= curRow; ++r) {
3085 rowPtr[r] = curPos;
3086 }
3087 prvRow = curRow;
3088 }
3089 numEntriesPerRow[curRow]++;
3090 colInd[curPos] = curEntry.colIndex();
3091 values[curPos] = curEntry.value();
3092 }
3093 // rowPtr has one more entry than numEntriesPerRow. The
3094 // last entry of rowPtr is the number of entries in
3095 // colInd and values.
3096 rowPtr[numRows] = numEntries;
3097 } // Finished conversion to CSR format
3098 catch (std::exception& e) {
3099 mergeAndConvertSucceeded = 0;
3100 errMsg << "Failed to merge sparse matrix entries and convert to "
3101 "CSR format: " << e.what();
3102 }
3103
3104 if (debug && mergeAndConvertSucceeded) {
3105 // Number of rows in the matrix.
3106 const size_type numRows = dims[0];
3107 const size_type maxToDisplay = 100;
3108
3109 cerr << "----- Proc 0: numEntriesPerRow[0.."
3110 << (numEntriesPerRow.size()-1) << "] ";
3111 if (numRows > maxToDisplay) {
3112 cerr << "(only showing first and last few entries) ";
3113 }
3114 cerr << "= [";
3115 if (numRows > 0) {
3116 if (numRows > maxToDisplay) {
3117 for (size_type k = 0; k < 2; ++k) {
3118 cerr << numEntriesPerRow[k] << " ";
3119 }
3120 cerr << "... ";
3121 for (size_type k = numRows-2; k < numRows-1; ++k) {
3122 cerr << numEntriesPerRow[k] << " ";
3123 }
3124 }
3125 else {
3126 for (size_type k = 0; k < numRows-1; ++k) {
3127 cerr << numEntriesPerRow[k] << " ";
3128 }
3129 }
3130 cerr << numEntriesPerRow[numRows-1];
3131 } // numRows > 0
3132 cerr << "]" << endl;
3133
3134 cerr << "----- Proc 0: rowPtr ";
3135 if (numRows > maxToDisplay) {
3136 cerr << "(only showing first and last few entries) ";
3137 }
3138 cerr << "= [";
3139 if (numRows > maxToDisplay) {
3140 for (size_type k = 0; k < 2; ++k) {
3141 cerr << rowPtr[k] << " ";
3142 }
3143 cerr << "... ";
3144 for (size_type k = numRows-2; k < numRows; ++k) {
3145 cerr << rowPtr[k] << " ";
3146 }
3147 }
3148 else {
3149 for (size_type k = 0; k < numRows; ++k) {
3150 cerr << rowPtr[k] << " ";
3151 }
3152 }
3153 cerr << rowPtr[numRows] << "]" << endl;
3154 }
3155 } // if myRank == rootRank
3156 } // Done converting sparse matrix data to CSR format
3157
3158 // Now we're done with the Adder, so we can release the
3159 // reference ("free" it) to save space. This only actually
3160 // does anything on Rank 0, since pAdder is null on all the
3161 // other MPI processes.
3162 pAdder = null;
3163
3164 if (debug && myRank == rootRank) {
3165 cerr << "-- Making range, domain, and row maps" << endl;
3166 }
3167
3168 // Make the maps that describe the matrix's range and domain,
3169 // and the distribution of its rows. Creating a Map is a
3170 // collective operation, so we don't have to do a broadcast of
3171 // a success Boolean.
3172 RCP<const map_type> pRangeMap = makeRangeMap (pComm, dims[0]);
3173 RCP<const map_type> pDomainMap =
3174 makeDomainMap (pRangeMap, dims[0], dims[1]);
3175 RCP<const map_type> pRowMap = makeRowMap (null, pComm, dims[0]);
3176
3177 if (debug && myRank == rootRank) {
3178 cerr << "-- Distributing the matrix data" << endl;
3179 }
3180
3181 // Distribute the matrix data. Each processor has to add the
3182 // rows that it owns. If you try to make Proc 0 call
3183 // insertGlobalValues() for _all_ the rows, not just those it
3184 // owns, then fillComplete() will compute the number of
3185 // columns incorrectly. That's why Proc 0 has to distribute
3186 // the matrix data and why we make all the processors (not
3187 // just Proc 0) call insertGlobalValues() on their own data.
3188 //
3189 // These arrays represent each processor's part of the matrix
3190 // data, in "CSR" format (sort of, since the row indices might
3191 // not be contiguous).
3192 ArrayRCP<size_t> myNumEntriesPerRow;
3193 ArrayRCP<size_t> myRowPtr;
3194 ArrayRCP<global_ordinal_type> myColInd;
3195 ArrayRCP<scalar_type> myValues;
3196 // Distribute the matrix data. This is a collective operation.
3197 distribute (myNumEntriesPerRow, myRowPtr, myColInd, myValues, pRowMap,
3198 numEntriesPerRow, rowPtr, colInd, values, debug);
3199
3200 if (debug && myRank == rootRank) {
3201 cerr << "-- Inserting matrix entries on each process "
3202 "and calling fillComplete()" << endl;
3203 }
3204 // Each processor inserts its part of the matrix data, and
3205 // then they all call fillComplete(). This method invalidates
3206 // the my* distributed matrix data before calling
3207 // fillComplete(), in order to save space. In general, we
3208 // never store more than two copies of the matrix's entries in
3209 // memory at once, which is no worse than what Tpetra
3210 // promises.
3211 Teuchos::RCP<sparse_matrix_type> pMatrix =
3212 makeMatrix (myNumEntriesPerRow, myRowPtr, myColInd, myValues,
3213 pRowMap, pRangeMap, pDomainMap, constructorParams,
3214 fillCompleteParams);
3215 // Only use a reduce-all in debug mode to check if pMatrix is
3216 // null. Otherwise, just throw an exception. We never expect
3217 // a null pointer here, so we can save a communication.
3218 if (debug) {
3219 int localIsNull = pMatrix.is_null () ? 1 : 0;
3220 int globalIsNull = 0;
3221 reduceAll (*pComm, Teuchos::REDUCE_MAX, localIsNull, ptr (&globalIsNull));
3222 TEUCHOS_TEST_FOR_EXCEPTION(globalIsNull != 0, std::logic_error,
3223 "Reader::makeMatrix() returned a null pointer on at least one "
3224 "process. Please report this bug to the Tpetra developers.");
3225 }
3226 else {
3227 TEUCHOS_TEST_FOR_EXCEPTION(pMatrix.is_null(), std::logic_error,
3228 "Reader::makeMatrix() returned a null pointer. "
3229 "Please report this bug to the Tpetra developers.");
3230 }
3231
3232 // Sanity check for dimensions (read from the Matrix Market
3233 // data, vs. dimensions reported by the CrsMatrix).
3234 //
3235 // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
3236 // what one might think it does, so you have to ask the range
3237 // resp. domain map for the number of rows resp. columns.
3238 if (extraDebug && debug) {
3239 const int numProcs = pComm->getSize ();
3240 const global_size_t globalNumRows =
3241 pRangeMap->getGlobalNumElements();
3242 const global_size_t globalNumCols =
3243 pDomainMap->getGlobalNumElements();
3244 if (myRank == rootRank) {
3245 cerr << "-- Matrix is "
3246 << globalNumRows << " x " << globalNumCols
3247 << " with " << pMatrix->getGlobalNumEntries()
3248 << " entries, and index base "
3249 << pMatrix->getIndexBase() << "." << endl;
3250 }
3251 pComm->barrier ();
3252 for (int p = 0; p < numProcs; ++p) {
3253 if (myRank == p) {
3254 cerr << "-- Proc " << p << " owns "
3255 << pMatrix->getLocalNumCols() << " columns, and "
3256 << pMatrix->getLocalNumEntries() << " entries." << endl;
3257 }
3258 pComm->barrier ();
3259 }
3260 } // if (extraDebug && debug)
3261
3262 if (debug && myRank == rootRank) {
3263 cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
3264 << endl;
3265 }
3266 return pMatrix;
3267 }
3268
3269
3310 static Teuchos::RCP<sparse_matrix_type>
3311 readSparse (std::istream& in,
3312 const Teuchos::RCP<const map_type>& rowMap,
3313 Teuchos::RCP<const map_type>& colMap,
3314 const Teuchos::RCP<const map_type>& domainMap,
3315 const Teuchos::RCP<const map_type>& rangeMap,
3316 const bool callFillComplete=true,
3317 const bool tolerant=false,
3318 const bool debug=false)
3319 {
3320 using Teuchos::MatrixMarket::Banner;
3321 using Teuchos::arcp;
3322 using Teuchos::ArrayRCP;
3323 using Teuchos::ArrayView;
3324 using Teuchos::as;
3325 using Teuchos::broadcast;
3326 using Teuchos::Comm;
3327 using Teuchos::null;
3328 using Teuchos::ptr;
3329 using Teuchos::RCP;
3330 using Teuchos::reduceAll;
3331 using Teuchos::Tuple;
3332 using std::cerr;
3333 using std::endl;
3334 typedef Teuchos::ScalarTraits<scalar_type> STS;
3335
3336 RCP<const Comm<int> > pComm = rowMap->getComm ();
3337 const int myRank = pComm->getRank ();
3338 const int rootRank = 0;
3339 const bool extraDebug = false;
3340
3341 // Fast checks for invalid input. We can't check other
3342 // attributes of the Maps until we've read in the matrix
3343 // dimensions.
3344 TEUCHOS_TEST_FOR_EXCEPTION(
3345 rowMap.is_null (), std::invalid_argument,
3346 "Row Map must be nonnull.");
3347 TEUCHOS_TEST_FOR_EXCEPTION(
3348 rangeMap.is_null (), std::invalid_argument,
3349 "Range Map must be nonnull.");
3350 TEUCHOS_TEST_FOR_EXCEPTION(
3351 domainMap.is_null (), std::invalid_argument,
3352 "Domain Map must be nonnull.");
3353 TEUCHOS_TEST_FOR_EXCEPTION(
3354 rowMap->getComm().getRawPtr() != pComm.getRawPtr(),
3355 std::invalid_argument,
3356 "The specified row Map's communicator (rowMap->getComm())"
3357 "differs from the given separately supplied communicator pComm.");
3358 TEUCHOS_TEST_FOR_EXCEPTION(
3359 domainMap->getComm().getRawPtr() != pComm.getRawPtr(),
3360 std::invalid_argument,
3361 "The specified domain Map's communicator (domainMap->getComm())"
3362 "differs from the given separately supplied communicator pComm.");
3363 TEUCHOS_TEST_FOR_EXCEPTION(
3364 rangeMap->getComm().getRawPtr() != pComm.getRawPtr(),
3365 std::invalid_argument,
3366 "The specified range Map's communicator (rangeMap->getComm())"
3367 "differs from the given separately supplied communicator pComm.");
3368
3369 // Current line number in the input stream. Various calls
3370 // will modify this depending on the number of lines that are
3371 // read from the input stream. Only Rank 0 modifies this.
3372 size_t lineNumber = 1;
3373
3374 if (debug && myRank == rootRank) {
3375 cerr << "Matrix Market reader: readSparse:" << endl
3376 << "-- Reading banner line" << endl;
3377 }
3378
3379 // The "Banner" tells you whether the input stream represents
3380 // a sparse matrix, the symmetry type of the matrix, and the
3381 // type of the data it contains.
3382 //
3383 // pBanner will only be nonnull on MPI Rank 0. It will be
3384 // null on all other MPI processes.
3385 RCP<const Banner> pBanner;
3386 {
3387 // We read and validate the Banner on Proc 0, but broadcast
3388 // the validation result to all processes.
3389 // Teuchos::broadcast doesn't currently work with bool, so
3390 // we use int (true -> 1, false -> 0).
3391 int bannerIsCorrect = 1;
3392 std::ostringstream errMsg;
3393
3394 if (myRank == rootRank) {
3395 // Read the Banner line from the input stream.
3396 try {
3397 pBanner = readBanner (in, lineNumber, tolerant, debug);
3398 }
3399 catch (std::exception& e) {
3400 errMsg << "Attempt to read the Matrix Market file's Banner line "
3401 "threw an exception: " << e.what();
3402 bannerIsCorrect = 0;
3403 }
3404
3405 if (bannerIsCorrect) {
3406 // Validate the Banner for the case of a sparse matrix.
3407 // We validate on Proc 0, since it reads the Banner.
3408
3409 // In intolerant mode, the matrix type must be "coordinate".
3410 if (! tolerant && pBanner->matrixType() != "coordinate") {
3411 bannerIsCorrect = 0;
3412 errMsg << "The Matrix Market input file must contain a "
3413 "\"coordinate\"-format sparse matrix in order to create a "
3414 "Tpetra::CrsMatrix object from it, but the file's matrix "
3415 "type is \"" << pBanner->matrixType() << "\" instead.";
3416 }
3417 // In tolerant mode, we allow the matrix type to be
3418 // anything other than "array" (which would mean that
3419 // the file contains a dense matrix).
3420 if (tolerant && pBanner->matrixType() == "array") {
3421 bannerIsCorrect = 0;
3422 errMsg << "Matrix Market file must contain a \"coordinate\"-"
3423 "format sparse matrix in order to create a Tpetra::CrsMatrix "
3424 "object from it, but the file's matrix type is \"array\" "
3425 "instead. That probably means the file contains dense matrix "
3426 "data.";
3427 }
3428 }
3429 } // Proc 0: Done reading the Banner, hopefully successfully.
3430
3431 // Broadcast from Proc 0 whether the Banner was read correctly.
3432 broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
3433
3434 // If the Banner is invalid, all processes throw an
3435 // exception. Only Proc 0 gets the exception message, but
3436 // that's OK, since the main point is to "stop the world"
3437 // (rather than throw an exception on one process and leave
3438 // the others hanging).
3439 TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
3440 std::invalid_argument, errMsg.str ());
3441 } // Done reading the Banner line and broadcasting success.
3442 if (debug && myRank == rootRank) {
3443 cerr << "-- Reading dimensions line" << endl;
3444 }
3445
3446 // Read the matrix dimensions from the Matrix Market metadata.
3447 // dims = (numRows, numCols, numEntries). Proc 0 does the
3448 // reading, but it broadcasts the results to all MPI
3449 // processes. Thus, readCoordDims() is a collective
3450 // operation. It does a collective check for correctness too.
3451 Tuple<global_ordinal_type, 3> dims =
3452 readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
3453
3454 if (debug && myRank == rootRank) {
3455 cerr << "-- Making Adder for collecting matrix data" << endl;
3456 }
3457
3458 // "Adder" object for collecting all the sparse matrix entries
3459 // from the input stream. This is only nonnull on Proc 0.
3460 // The Adder internally converts the one-based indices (native
3461 // Matrix Market format) into zero-based indices.
3462 RCP<adder_type> pAdder =
3463 makeAdder (pComm, pBanner, dims, tolerant, debug);
3464
3465 if (debug && myRank == rootRank) {
3466 cerr << "-- Reading matrix data" << endl;
3467 }
3468 //
3469 // Read the matrix entries from the input stream on Proc 0.
3470 //
3471 {
3472 // We use readSuccess to broadcast the results of the read
3473 // (succeeded or not) to all MPI processes. Since
3474 // Teuchos::broadcast doesn't currently know how to send
3475 // bools, we convert to int (true -> 1, false -> 0).
3476 int readSuccess = 1;
3477 std::ostringstream errMsg; // Exception message (only valid on Proc 0)
3478 if (myRank == rootRank) {
3479 try {
3480 // Reader for "coordinate" format sparse matrix data.
3481 typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
3482 global_ordinal_type, scalar_type, STS::isComplex> reader_type;
3483 reader_type reader (pAdder);
3484
3485 // Read the sparse matrix entries.
3486 std::pair<bool, std::vector<size_t> > results =
3487 reader.read (in, lineNumber, tolerant, debug);
3488 readSuccess = results.first ? 1 : 0;
3489 }
3490 catch (std::exception& e) {
3491 readSuccess = 0;
3492 errMsg << e.what();
3493 }
3494 }
3495 broadcast (*pComm, rootRank, ptr (&readSuccess));
3496
3497 // It would be nice to add a "verbose" flag, so that in
3498 // tolerant mode, we could log any bad line number(s) on
3499 // Proc 0. For now, we just throw if the read fails to
3500 // succeed.
3501 //
3502 // Question: If we're in tolerant mode, and if the read did
3503 // not succeed, should we attempt to call fillComplete()?
3504 TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
3505 "Failed to read the Matrix Market sparse matrix file: "
3506 << errMsg.str());
3507 } // Done reading the matrix entries (stored on Proc 0 for now)
3508
3509 if (debug && myRank == rootRank) {
3510 cerr << "-- Successfully read the Matrix Market data" << endl;
3511 }
3512
3513 // In tolerant mode, we need to rebroadcast the matrix
3514 // dimensions, since they may be different after reading the
3515 // actual matrix data. We only need to broadcast the number
3516 // of rows and columns. Only Rank 0 needs to know the actual
3517 // global number of entries, since (a) we need to merge
3518 // duplicates on Rank 0 first anyway, and (b) when we
3519 // distribute the entries, each rank other than Rank 0 will
3520 // only need to know how many entries it owns, not the total
3521 // number of entries.
3522 if (tolerant) {
3523 if (debug && myRank == rootRank) {
3524 cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
3525 << endl
3526 << "----- Dimensions before: "
3527 << dims[0] << " x " << dims[1]
3528 << endl;
3529 }
3530 // Packed coordinate matrix dimensions (numRows, numCols).
3531 Tuple<global_ordinal_type, 2> updatedDims;
3532 if (myRank == rootRank) {
3533 // If one or more bottom rows of the matrix contain no
3534 // entries, then the Adder will report that the number
3535 // of rows is less than that specified in the
3536 // metadata. We allow this case, and favor the
3537 // metadata so that the zero row(s) will be included.
3538 updatedDims[0] =
3539 std::max (dims[0], pAdder->getAdder()->numRows());
3540 updatedDims[1] = pAdder->getAdder()->numCols();
3541 }
3542 broadcast (*pComm, rootRank, updatedDims);
3543 dims[0] = updatedDims[0];
3544 dims[1] = updatedDims[1];
3545 if (debug && myRank == rootRank) {
3546 cerr << "----- Dimensions after: " << dims[0] << " x "
3547 << dims[1] << endl;
3548 }
3549 }
3550 else {
3551 // In strict mode, we require that the matrix's metadata and
3552 // its actual data agree, at least somewhat. In particular,
3553 // the number of rows must agree, since otherwise we cannot
3554 // distribute the matrix correctly.
3555
3556 // Teuchos::broadcast() doesn't know how to broadcast bools,
3557 // so we use an int with the standard 1 == true, 0 == false
3558 // encoding.
3559 int dimsMatch = 1;
3560 if (myRank == rootRank) {
3561 // If one or more bottom rows of the matrix contain no
3562 // entries, then the Adder will report that the number of
3563 // rows is less than that specified in the metadata. We
3564 // allow this case, and favor the metadata, but do not
3565 // allow the Adder to think there are more rows in the
3566 // matrix than the metadata says.
3567 if (dims[0] < pAdder->getAdder ()->numRows ()) {
3568 dimsMatch = 0;
3569 }
3570 }
3571 broadcast (*pComm, 0, ptr (&dimsMatch));
3572 if (dimsMatch == 0) {
3573 // We're in an error state anyway, so we might as well
3574 // work a little harder to print an informative error
3575 // message.
3576 //
3577 // Broadcast the Adder's idea of the matrix dimensions
3578 // from Proc 0 to all processes.
3579 Tuple<global_ordinal_type, 2> addersDims;
3580 if (myRank == rootRank) {
3581 addersDims[0] = pAdder->getAdder()->numRows();
3582 addersDims[1] = pAdder->getAdder()->numCols();
3583 }
3584 broadcast (*pComm, 0, addersDims);
3585 TEUCHOS_TEST_FOR_EXCEPTION(
3586 dimsMatch == 0, std::runtime_error,
3587 "The matrix metadata says that the matrix is " << dims[0] << " x "
3588 << dims[1] << ", but the actual data says that the matrix is "
3589 << addersDims[0] << " x " << addersDims[1] << ". That means the "
3590 "data includes more rows than reported in the metadata. This "
3591 "is not allowed when parsing in strict mode. Parse the matrix in "
3592 "tolerant mode to ignore the metadata when it disagrees with the "
3593 "data.");
3594 }
3595 } // Matrix dimensions (# rows, # cols, # entries) agree.
3596
3597 if (debug && myRank == rootRank) {
3598 cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
3599 }
3600
3601 // Now that we've read in all the matrix entries from the
3602 // input stream into the adder on Proc 0, post-process them
3603 // into CSR format (still on Proc 0). This will facilitate
3604 // distributing them to all the processors.
3605 //
3606 // These arrays represent the global matrix data as a CSR
3607 // matrix (with numEntriesPerRow as redundant but convenient
3608 // metadata, since it's computable from rowPtr and vice
3609 // versa). They are valid only on Proc 0.
3610 ArrayRCP<size_t> numEntriesPerRow;
3611 ArrayRCP<size_t> rowPtr;
3612 ArrayRCP<global_ordinal_type> colInd;
3613 ArrayRCP<scalar_type> values;
3614
3615 // Proc 0 first merges duplicate entries, and then converts
3616 // the coordinate-format matrix data to CSR.
3617 {
3618 int mergeAndConvertSucceeded = 1;
3619 std::ostringstream errMsg;
3620
3621 if (myRank == rootRank) {
3622 try {
3623 typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,
3624 global_ordinal_type> element_type;
3625
3626 // Number of rows in the matrix. If we are in tolerant
3627 // mode, we've already synchronized dims with the actual
3628 // matrix data. If in strict mode, we should use dims
3629 // (as read from the file's metadata) rather than the
3630 // matrix data to determine the dimensions. (The matrix
3631 // data will claim fewer rows than the metadata, if one
3632 // or more rows have no entries stored in the file.)
3633 const size_type numRows = dims[0];
3634
3635 // Additively merge duplicate matrix entries.
3636 pAdder->getAdder()->merge ();
3637
3638 // Get a temporary const view of the merged matrix entries.
3639 const std::vector<element_type>& entries =
3640 pAdder->getAdder()->getEntries();
3641
3642 // Number of matrix entries (after merging).
3643 const size_t numEntries = (size_t)entries.size();
3644
3645 if (debug) {
3646 cerr << "----- Proc 0: Matrix has numRows=" << numRows
3647 << " rows and numEntries=" << numEntries
3648 << " entries." << endl;
3649 }
3650
3651 // Make space for the CSR matrix data. Converting to
3652 // CSR is easier if we fill numEntriesPerRow with zeros
3653 // at first.
3654 numEntriesPerRow = arcp<size_t> (numRows);
3655 std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
3656 rowPtr = arcp<size_t> (numRows+1);
3657 std::fill (rowPtr.begin(), rowPtr.end(), 0);
3658 colInd = arcp<global_ordinal_type> (numEntries);
3659 values = arcp<scalar_type> (numEntries);
3660
3661 // Convert from array-of-structs coordinate format to CSR
3662 // (compressed sparse row) format.
3663 global_ordinal_type prvRow = 0;
3664 size_t curPos = 0;
3665 rowPtr[0] = 0;
3666 for (curPos = 0; curPos < numEntries; ++curPos) {
3667 const element_type& curEntry = entries[curPos];
3668 const global_ordinal_type curRow = curEntry.rowIndex();
3669 TEUCHOS_TEST_FOR_EXCEPTION(
3670 curRow < prvRow, std::logic_error,
3671 "Row indices are out of order, even though they are supposed "
3672 "to be sorted. curRow = " << curRow << ", prvRow = "
3673 << prvRow << ", at curPos = " << curPos << ". Please report "
3674 "this bug to the Tpetra developers.");
3675 if (curRow > prvRow) {
3676 prvRow = curRow;
3677 }
3678 numEntriesPerRow[curRow]++;
3679 colInd[curPos] = curEntry.colIndex();
3680 values[curPos] = curEntry.value();
3681 }
3682
3683 rowPtr[0] = 0;
3684 for (global_ordinal_type row = 1; row <= numRows; ++row) {
3685 rowPtr[row] = numEntriesPerRow[row-1] + rowPtr[row-1];
3686 }
3687 } // Finished conversion to CSR format
3688 catch (std::exception& e) {
3689 mergeAndConvertSucceeded = 0;
3690 errMsg << "Failed to merge sparse matrix entries and convert to "
3691 "CSR format: " << e.what();
3692 }
3693
3694 if (debug && mergeAndConvertSucceeded) {
3695 // Number of rows in the matrix.
3696 const size_type numRows = dims[0];
3697 const size_type maxToDisplay = 100;
3698
3699 cerr << "----- Proc 0: numEntriesPerRow[0.."
3700 << (numEntriesPerRow.size()-1) << "] ";
3701 if (numRows > maxToDisplay) {
3702 cerr << "(only showing first and last few entries) ";
3703 }
3704 cerr << "= [";
3705 if (numRows > 0) {
3706 if (numRows > maxToDisplay) {
3707 for (size_type k = 0; k < 2; ++k) {
3708 cerr << numEntriesPerRow[k] << " ";
3709 }
3710 cerr << "... ";
3711 for (size_type k = numRows-2; k < numRows-1; ++k) {
3712 cerr << numEntriesPerRow[k] << " ";
3713 }
3714 }
3715 else {
3716 for (size_type k = 0; k < numRows-1; ++k) {
3717 cerr << numEntriesPerRow[k] << " ";
3718 }
3719 }
3720 cerr << numEntriesPerRow[numRows-1];
3721 } // numRows > 0
3722 cerr << "]" << endl;
3723
3724 cerr << "----- Proc 0: rowPtr ";
3725 if (numRows > maxToDisplay) {
3726 cerr << "(only showing first and last few entries) ";
3727 }
3728 cerr << "= [";
3729 if (numRows > maxToDisplay) {
3730 for (size_type k = 0; k < 2; ++k) {
3731 cerr << rowPtr[k] << " ";
3732 }
3733 cerr << "... ";
3734 for (size_type k = numRows-2; k < numRows; ++k) {
3735 cerr << rowPtr[k] << " ";
3736 }
3737 }
3738 else {
3739 for (size_type k = 0; k < numRows; ++k) {
3740 cerr << rowPtr[k] << " ";
3741 }
3742 }
3743 cerr << rowPtr[numRows] << "]" << endl;
3744
3745 cerr << "----- Proc 0: colInd = [";
3746 for (size_t k = 0; k < rowPtr[numRows]; ++k) {
3747 cerr << colInd[k] << " ";
3748 }
3749 cerr << "]" << endl;
3750 }
3751 } // if myRank == rootRank
3752 } // Done converting sparse matrix data to CSR format
3753
3754 // Now we're done with the Adder, so we can release the
3755 // reference ("free" it) to save space. This only actually
3756 // does anything on Rank 0, since pAdder is null on all the
3757 // other MPI processes.
3758 pAdder = null;
3759
3760 // Verify details of the Maps. Don't count the global number
3761 // of entries in the row Map, since that number doesn't
3762 // correctly count overlap.
3763 if (debug && myRank == rootRank) {
3764 cerr << "-- Verifying Maps" << endl;
3765 }
3766 TEUCHOS_TEST_FOR_EXCEPTION(
3767 as<global_size_t> (dims[0]) != rangeMap->getGlobalNumElements(),
3768 std::invalid_argument,
3769 "The range Map has " << rangeMap->getGlobalNumElements ()
3770 << " entries, but the matrix has a global number of rows " << dims[0]
3771 << ".");
3772 TEUCHOS_TEST_FOR_EXCEPTION(
3773 as<global_size_t> (dims[1]) != domainMap->getGlobalNumElements (),
3774 std::invalid_argument,
3775 "The domain Map has " << domainMap->getGlobalNumElements ()
3776 << " entries, but the matrix has a global number of columns "
3777 << dims[1] << ".");
3778
3779 // Create a row Map which is entirely owned on Proc 0.
3780 RCP<Teuchos::FancyOStream> err = debug ?
3781 Teuchos::getFancyOStream (Teuchos::rcpFromRef (cerr)) : null;
3782
3783 RCP<const map_type> gatherRowMap = Details::computeGatherMap (rowMap, err, debug);
3784 ArrayView<const global_ordinal_type> myRows =
3785 gatherRowMap->getLocalElementList ();
3786 const size_type myNumRows = myRows.size ();
3787 const global_ordinal_type indexBase = gatherRowMap->getIndexBase ();
3788
3789 ArrayRCP<size_t> gatherNumEntriesPerRow = arcp<size_t>(myNumRows);
3790 for (size_type i_ = 0; i_ < myNumRows; i_++) {
3791 gatherNumEntriesPerRow[i_] = numEntriesPerRow[myRows[i_]-indexBase];
3792 }
3793
3794 // Create a matrix using this Map, and fill in on Proc 0. We
3795 // know how many entries there are in each row, so we can use
3796 // static profile.
3797 RCP<sparse_matrix_type> A_proc0 =
3798 rcp (new sparse_matrix_type (gatherRowMap, gatherNumEntriesPerRow()));
3799 if (myRank == rootRank) {
3800 if (debug) {
3801 cerr << "-- Proc 0: Filling gather matrix" << endl;
3802 }
3803 if (debug) {
3804 cerr << "---- Rows: " << Teuchos::toString (myRows) << endl;
3805 }
3806
3807 // Add Proc 0's matrix entries to the CrsMatrix.
3808 for (size_type i_ = 0; i_ < myNumRows; ++i_) {
3809 size_type i = myRows[i_] - indexBase;
3810
3811 const size_type curPos = as<size_type> (rowPtr[i]);
3812 const local_ordinal_type curNumEntries = numEntriesPerRow[i];
3813 ArrayView<global_ordinal_type> curColInd =
3814 colInd.view (curPos, curNumEntries);
3815 ArrayView<scalar_type> curValues =
3816 values.view (curPos, curNumEntries);
3817
3818 // Modify the column indices in place to have the right index base.
3819 for (size_type k = 0; k < curNumEntries; ++k) {
3820 curColInd[k] += indexBase;
3821 }
3822 if (debug) {
3823 cerr << "------ Columns: " << Teuchos::toString (curColInd) << endl;
3824 cerr << "------ Values: " << Teuchos::toString (curValues) << endl;
3825 }
3826 // Avoid constructing empty views of ArrayRCP objects.
3827 if (curNumEntries > 0) {
3828 A_proc0->insertGlobalValues (myRows[i_], curColInd, curValues);
3829 }
3830 }
3831 // Now we can save space by deallocating numEntriesPerRow,
3832 // rowPtr, colInd, and values, since we've already put those
3833 // data in the matrix.
3834 numEntriesPerRow = null;
3835 rowPtr = null;
3836 colInd = null;
3837 values = null;
3838 } // if myRank == rootRank
3839
3840 RCP<sparse_matrix_type> A;
3842 export_type exp (gatherRowMap, rowMap);
3843
3844 // Communicate the precise number of nonzeros per row, which was already
3845 // calculated above.
3846 typedef local_ordinal_type LO;
3847 typedef global_ordinal_type GO;
3849 mv_type_go target_nnzPerRow(rowMap,1);
3850 mv_type_go source_nnzPerRow(gatherRowMap,1);
3851 Teuchos::ArrayRCP<GO> srcData = source_nnzPerRow.getDataNonConst(0);
3852 for (int i=0; i<myNumRows; i++)
3853 srcData[i] = gatherNumEntriesPerRow[i];
3854 srcData = Teuchos::null;
3855 target_nnzPerRow.doExport(source_nnzPerRow,exp,Tpetra::INSERT);
3856 Teuchos::ArrayRCP<GO> targetData = target_nnzPerRow.getDataNonConst(0);
3857 ArrayRCP<size_t> targetData_size_t = arcp<size_t>(targetData.size());
3858 for (int i=0; i<targetData.size(); i++)
3859 targetData_size_t[i] = targetData[i];
3860
3861 if (colMap.is_null ()) {
3862 A = rcp (new sparse_matrix_type (rowMap, targetData_size_t()));
3863 } else {
3864 A = rcp (new sparse_matrix_type (rowMap, colMap, targetData_size_t()));
3865 }
3866 A->doExport (*A_proc0, exp, INSERT);
3867 if (callFillComplete) {
3868 A->fillComplete (domainMap, rangeMap);
3869 }
3870
3871 // We can't get the dimensions of the matrix until after
3872 // fillComplete() is called. Thus, we can't do the sanity
3873 // check (dimensions read from the Matrix Market data,
3874 // vs. dimensions reported by the CrsMatrix) unless the user
3875 // asked us to call fillComplete().
3876 //
3877 // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
3878 // what one might think it does, so you have to ask the range
3879 // resp. domain map for the number of rows resp. columns.
3880 if (callFillComplete) {
3881 const int numProcs = pComm->getSize ();
3882
3883 if (extraDebug && debug) {
3884 const global_size_t globalNumRows = rangeMap->getGlobalNumElements ();
3885 const global_size_t globalNumCols = domainMap->getGlobalNumElements ();
3886 if (myRank == rootRank) {
3887 cerr << "-- Matrix is "
3888 << globalNumRows << " x " << globalNumCols
3889 << " with " << A->getGlobalNumEntries()
3890 << " entries, and index base "
3891 << A->getIndexBase() << "." << endl;
3892 }
3893 pComm->barrier ();
3894 for (int p = 0; p < numProcs; ++p) {
3895 if (myRank == p) {
3896 cerr << "-- Proc " << p << " owns "
3897 << A->getLocalNumCols() << " columns, and "
3898 << A->getLocalNumEntries() << " entries." << endl;
3899 }
3900 pComm->barrier ();
3901 }
3902 } // if (extraDebug && debug)
3903 } // if (callFillComplete)
3904
3905 if (debug && myRank == rootRank) {
3906 cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
3907 << endl;
3908 }
3909 return A;
3910 }
3911
3941 static Teuchos::RCP<multivector_type>
3942 readDenseFile (const std::string& filename,
3943 const Teuchos::RCP<const comm_type>& comm,
3944 Teuchos::RCP<const map_type>& map,
3945 const bool tolerant=false,
3946 const bool debug=false,
3947 const bool binary=false)
3948 {
3949 using Teuchos::broadcast;
3950 using Teuchos::outArg;
3951
3952 std::ifstream in;
3953 int opened = 0;
3954 if (comm->getRank() == 0) {
3955 try {
3956 if (!binary)
3957 in.open (filename.c_str ());
3958 else
3959 in.open (filename.c_str (), std::ios::binary);
3960 opened = in.is_open();
3961 }
3962 catch (...) {
3963 opened = 0;
3964 }
3965 }
3966 broadcast<int, int> (*comm, 0, outArg (opened));
3967 TEUCHOS_TEST_FOR_EXCEPTION(
3968 opened == 0, std::runtime_error,
3969 "readDenseFile: Failed to open file \"" << filename << "\" on "
3970 "Process 0.");
3971 return readDense (in, comm, map, tolerant, debug, binary);
3972 }
3973
3974
4004 static Teuchos::RCP<vector_type>
4005 readVectorFile (const std::string& filename,
4006 const Teuchos::RCP<const comm_type>& comm,
4007 Teuchos::RCP<const map_type>& map,
4008 const bool tolerant=false,
4009 const bool debug=false)
4010 {
4011 using Teuchos::broadcast;
4012 using Teuchos::outArg;
4013
4014 std::ifstream in;
4015 int opened = 0;
4016 if (comm->getRank() == 0) {
4017 try {
4018 in.open (filename.c_str ());
4019 opened = in.is_open();
4020 }
4021 catch (...) {
4022 opened = 0;
4023 }
4024 }
4025 broadcast<int, int> (*comm, 0, outArg (opened));
4026 TEUCHOS_TEST_FOR_EXCEPTION(
4027 opened == 0, std::runtime_error,
4028 "readVectorFile: Failed to open file \"" << filename << "\" on "
4029 "Process 0.");
4030 return readVector (in, comm, map, tolerant, debug);
4031 }
4032
4033
4101
4102 static Teuchos::RCP<multivector_type>
4103 readDense (std::istream& in,
4104 const Teuchos::RCP<const comm_type>& comm,
4105 Teuchos::RCP<const map_type>& map,
4106 const bool tolerant=false,
4107 const bool debug=false,
4108 const bool binary=false)
4109 {
4110 Teuchos::RCP<Teuchos::FancyOStream> err =
4111 Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
4112 return readDenseImpl<scalar_type> (in, comm, map, err, tolerant, debug, binary);
4113 }
4114
4115
4117 static Teuchos::RCP<vector_type>
4118 readVector (std::istream& in,
4119 const Teuchos::RCP<const comm_type>& comm,
4120 Teuchos::RCP<const map_type>& map,
4121 const bool tolerant=false,
4122 const bool debug=false)
4123 {
4124 Teuchos::RCP<Teuchos::FancyOStream> err =
4125 Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
4126 return readVectorImpl<scalar_type> (in, comm, map, err, tolerant, debug);
4127 }
4128
4129
4151 static Teuchos::RCP<const map_type>
4152 readMapFile (const std::string& filename,
4153 const Teuchos::RCP<const comm_type>& comm,
4154 const bool tolerant=false,
4155 const bool debug=false,
4156 const bool binary=false)
4157 {
4158 using Teuchos::inOutArg;
4159 using Teuchos::broadcast;
4160 std::ifstream in;
4161
4162 int success = 1;
4163 if (comm->getRank () == 0) { // Only open the file on Proc 0.
4164 if (binary)
4165 in.open (filename.c_str (), std::ios::binary);
4166 else
4167 in.open (filename.c_str ()); // Destructor closes safely
4168 if (! in) {
4169 success = 0;
4170 }
4171 }
4172 broadcast<int, int> (*comm, 0, inOutArg (success));
4173 TEUCHOS_TEST_FOR_EXCEPTION(
4174 success == 0, std::runtime_error,
4175 "Tpetra::MatrixMarket::Reader::readMapFile: "
4176 "Failed to read file \"" << filename << "\" on Process 0.");
4177 return readMap (in, comm, tolerant, debug, binary);
4178 }
4179
4180
4181 private:
4182 template<class MultiVectorScalarType>
4183 static Teuchos::RCP<Tpetra::MultiVector<MultiVectorScalarType,
4186 node_type> >
4187 readDenseImpl (std::istream& in,
4188 const Teuchos::RCP<const comm_type>& comm,
4189 Teuchos::RCP<const map_type>& map,
4190 const Teuchos::RCP<Teuchos::FancyOStream>& err,
4191 const bool tolerant=false,
4192 const bool debug=false,
4193 const bool binary=false)
4194 {
4195 using Teuchos::MatrixMarket::Banner;
4196 using Teuchos::MatrixMarket::checkCommentLine;
4197 using Teuchos::ArrayRCP;
4198 using Teuchos::as;
4199 using Teuchos::broadcast;
4200 using Teuchos::outArg;
4201 using Teuchos::RCP;
4202 using Teuchos::Tuple;
4203 using std::endl;
4204 typedef MultiVectorScalarType ST;
4205 typedef local_ordinal_type LO;
4206 typedef global_ordinal_type GO;
4207 typedef node_type NT;
4208 typedef Teuchos::ScalarTraits<ST> STS;
4209 typedef typename STS::magnitudeType MT;
4210 typedef Teuchos::ScalarTraits<MT> STM;
4212
4213 // Rank 0 is the only (MPI) process allowed to read from the
4214 // input stream.
4215 const int myRank = comm->getRank ();
4216
4217 if (! err.is_null ()) {
4218 err->pushTab ();
4219 }
4220 if (debug) {
4221 *err << myRank << ": readDenseImpl" << endl;
4222 }
4223 if (! err.is_null ()) {
4224 err->pushTab ();
4225 }
4226
4227 // mfh 17 Feb 2013: It's not strictly necessary that the Comm
4228 // instances be identical and that the Node instances be
4229 // identical. The essential condition is more complicated to
4230 // test and isn't the same for all Node types. Thus, we just
4231 // leave it up to the user.
4232
4233 // // If map is nonnull, check the precondition that its
4234 // // communicator resp. node equal comm resp. node. Checking
4235 // // now avoids doing a lot of file reading before we detect the
4236 // // violated precondition.
4237 // TEUCHOS_TEST_FOR_EXCEPTION(
4238 // ! map.is_null() && (map->getComm() != comm || map->getNode () != node,
4239 // std::invalid_argument, "If you supply a nonnull Map, the Map's "
4240 // "communicator and node must equal the supplied communicator resp. "
4241 // "node.");
4242
4243 // Process 0 will read in the matrix dimensions from the file,
4244 // and broadcast them to all ranks in the given communicator.
4245 // There are only 2 dimensions in the matrix, but we use the
4246 // third element of the Tuple to encode the banner's reported
4247 // data type: "real" == 0, "complex" == 1, and "integer" == 0
4248 // (same as "real"). We don't allow pattern matrices (i.e.,
4249 // graphs) since they only make sense for sparse data.
4250 Tuple<GO, 3> dims;
4251 dims[0] = 0;
4252 dims[1] = 0;
4253 dims[2] = 0;
4254
4255 // Current line number in the input stream. Only valid on
4256 // Proc 0. Various calls will modify this depending on the
4257 // number of lines that are read from the input stream.
4258 size_t lineNumber = 1;
4259
4260 // Capture errors and their messages on Proc 0.
4261 std::ostringstream exMsg;
4262 int localBannerReadSuccess = 1;
4263 int localDimsReadSuccess = 1;
4264
4265 // Only Proc 0 gets to read matrix data from the input stream.
4266 if (myRank == 0) {
4267 if (! binary) {
4268 if (debug) {
4269 *err << myRank << ": readDenseImpl: Reading banner line (dense)" << endl;
4270 }
4271
4272 // The "Banner" tells you whether the input stream
4273 // represents a dense matrix, the symmetry type of the
4274 // matrix, and the type of the data it contains.
4275 RCP<const Banner> pBanner;
4276 try {
4277 pBanner = readBanner (in, lineNumber, tolerant, debug);
4278 } catch (std::exception& e) {
4279 exMsg << e.what ();
4280 localBannerReadSuccess = 0;
4281 }
4282 // Make sure the input stream is the right kind of data.
4283 if (localBannerReadSuccess) {
4284 if (pBanner->matrixType () != "array") {
4285 exMsg << "The Matrix Market file does not contain dense matrix "
4286 "data. Its banner (first) line says that its matrix type is \""
4287 << pBanner->matrixType () << "\", rather that the required "
4288 "\"array\".";
4289 localBannerReadSuccess = 0;
4290 } else if (pBanner->dataType() == "pattern") {
4291 exMsg << "The Matrix Market file's banner (first) "
4292 "line claims that the matrix's data type is \"pattern\". This does "
4293 "not make sense for a dense matrix, yet the file reports the matrix "
4294 "as dense. The only valid data types for a dense matrix are "
4295 "\"real\", \"complex\", and \"integer\".";
4296 localBannerReadSuccess = 0;
4297 } else {
4298 // Encode the data type reported by the Banner as the
4299 // third element of the dimensions Tuple.
4300 dims[2] = encodeDataType (pBanner->dataType ());
4301 }
4302 } // if we successfully read the banner line
4303
4304 // At this point, we've successfully read the banner line.
4305 // Now read the dimensions line.
4306 if (localBannerReadSuccess) {
4307 if (debug) {
4308 *err << myRank << ": readDenseImpl: Reading dimensions line (dense)" << endl;
4309 }
4310 // Keep reading lines from the input stream until we find
4311 // a non-comment line, or until we run out of lines. The
4312 // latter is an error, since every "array" format Matrix
4313 // Market file must have a dimensions line after the
4314 // banner (even if the matrix has zero rows or columns, or
4315 // zero entries).
4316 std::string line;
4317 bool commentLine = true;
4318
4319 while (commentLine) {
4320 // Test whether it is even valid to read from the input
4321 // stream wrapping the line.
4322 if (in.eof () || in.fail ()) {
4323 exMsg << "Unable to get array dimensions line (at all) from line "
4324 << lineNumber << " of input stream. The input stream "
4325 << "claims that it is "
4326 << (in.eof() ? "at end-of-file." : "in a failed state.");
4327 localDimsReadSuccess = 0;
4328 } else {
4329 // Try to get the next line from the input stream.
4330 if (getline (in, line)) {
4331 ++lineNumber; // We did actually read a line.
4332 }
4333 // Is the current line a comment line? Ignore start
4334 // and size; they are only useful for reading the
4335 // actual matrix entries. (We could use them here as
4336 // an optimization, but we've chosen not to.)
4337 size_t start = 0, size = 0;
4338 commentLine = checkCommentLine (line, start, size, lineNumber, tolerant);
4339 } // whether we failed to read the line at all
4340 } // while the line we just read is a comment line
4341
4342 //
4343 // Get <numRows> <numCols> from the line we just read.
4344 //
4345 std::istringstream istr (line);
4346
4347 // Test whether it is even valid to read from the input
4348 // stream wrapping the line.
4349 if (istr.eof () || istr.fail ()) {
4350 exMsg << "Unable to read any data from line " << lineNumber
4351 << " of input; the line should contain the matrix dimensions "
4352 << "\"<numRows> <numCols>\".";
4353 localDimsReadSuccess = 0;
4354 } else { // It's valid to read from the line.
4355 GO theNumRows = 0;
4356 istr >> theNumRows; // Read in the number of rows.
4357 if (istr.fail ()) {
4358 exMsg << "Failed to get number of rows from line "
4359 << lineNumber << " of input; the line should contains the "
4360 << "matrix dimensions \"<numRows> <numCols>\".";
4361 localDimsReadSuccess = 0;
4362 } else { // We successfully read the number of rows
4363 dims[0] = theNumRows; // Save the number of rows
4364 if (istr.eof ()) { // Do we still have data to read?
4365 exMsg << "No more data after number of rows on line "
4366 << lineNumber << " of input; the line should contain the "
4367 << "matrix dimensions \"<numRows> <numCols>\".";
4368 localDimsReadSuccess = 0;
4369 } else { // Still data left to read; read in number of columns.
4370 GO theNumCols = 0;
4371 istr >> theNumCols; // Read in the number of columns
4372 if (istr.fail ()) {
4373 exMsg << "Failed to get number of columns from line "
4374 << lineNumber << " of input; the line should contain "
4375 << "the matrix dimensions \"<numRows> <numCols>\".";
4376 localDimsReadSuccess = 0;
4377 } else { // We successfully read the number of columns
4378 dims[1] = theNumCols; // Save the number of columns
4379 } // if istr.fail ()
4380 } // if istr.eof ()
4381 } // if we read the number of rows
4382 } // if the input stream wrapping the dims line was (in)valid
4383 } // if we successfully read the banner line
4384 } // not in binary format
4385 else { // in binary format
4386 global_size_t numRows, numCols;
4387 in.read(reinterpret_cast<char*>(&numRows), sizeof(numRows));
4388 in.read(reinterpret_cast<char*>(&numCols), sizeof(numCols));
4389 dims[0] = Teuchos::as<GO>(numRows);
4390 dims[1] = Teuchos::as<GO>(numCols);
4391 if ((typeid(ST) == typeid(double)) || Teuchos::ScalarTraits<ST>::isOrdinal) {
4392 dims[2] = 0;
4393 } else if (Teuchos::ScalarTraits<ST>::isComplex) {
4394 dims[2] = 1;
4395 } else {
4396 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
4397 "Unrecognized Matrix Market data type. "
4398 "We should never get here. "
4399 "Please report this bug to the Tpetra developers.");
4400 }
4401 localDimsReadSuccess = true;
4402 localDimsReadSuccess = true;
4403 } // in binary format
4404 } // if (myRank == 0)
4405
4406 // Broadcast the matrix dimensions, the encoded data type, and
4407 // whether or not Proc 0 succeeded in reading the banner and
4408 // dimensions.
4409 Tuple<GO, 5> bannerDimsReadResult;
4410 if (myRank == 0) {
4411 bannerDimsReadResult[0] = dims[0]; // numRows
4412 bannerDimsReadResult[1] = dims[1]; // numCols
4413 bannerDimsReadResult[2] = dims[2]; // encoded data type
4414 bannerDimsReadResult[3] = localBannerReadSuccess;
4415 bannerDimsReadResult[4] = localDimsReadSuccess;
4416 }
4417 // Broadcast matrix dimensions and the encoded data type from
4418 // Proc 0 to all the MPI processes.
4419 broadcast (*comm, 0, bannerDimsReadResult);
4420
4421 TEUCHOS_TEST_FOR_EXCEPTION(
4422 bannerDimsReadResult[3] == 0, std::runtime_error,
4423 "Failed to read banner line: " << exMsg.str ());
4424 TEUCHOS_TEST_FOR_EXCEPTION(
4425 bannerDimsReadResult[4] == 0, std::runtime_error,
4426 "Failed to read matrix dimensions line: " << exMsg.str ());
4427 if (myRank != 0) {
4428 dims[0] = bannerDimsReadResult[0];
4429 dims[1] = bannerDimsReadResult[1];
4430 dims[2] = bannerDimsReadResult[2];
4431 }
4432
4433 // Tpetra objects want the matrix dimensions in these types.
4434 const global_size_t numRows = static_cast<global_size_t> (dims[0]);
4435 const size_t numCols = static_cast<size_t> (dims[1]);
4436
4437 // Make a "Proc 0 owns everything" Map that we will use to
4438 // read in the multivector entries in the correct order on
4439 // Proc 0. This must be a collective
4440 RCP<const map_type> proc0Map; // "Proc 0 owns everything" Map
4441 if (map.is_null ()) {
4442 // The user didn't supply a Map. Make a contiguous
4443 // distributed Map for them, using the read-in multivector
4444 // dimensions.
4445 map = createUniformContigMapWithNode<LO, GO, NT> (numRows, comm);
4446 const size_t localNumRows = (myRank == 0) ? numRows : 0;
4447 // At this point, map exists and has a nonnull node.
4448 proc0Map = createContigMapWithNode<LO, GO, NT> (numRows, localNumRows,
4449 comm);
4450 }
4451 else { // The user supplied a Map.
4452 proc0Map = Details::computeGatherMap<map_type> (map, err, debug);
4453 }
4454
4455 // Make a multivector X owned entirely by Proc 0.
4456 RCP<MV> X = createMultiVector<ST, LO, GO, NT> (proc0Map, numCols);
4457
4458 //
4459 // On Proc 0, read the Matrix Market data from the input
4460 // stream into the multivector X.
4461 //
4462 int localReadDataSuccess = 1;
4463 if (myRank == 0) {
4464 if (! binary) {
4465 try {
4466 if (debug) {
4467 *err << myRank << ": readDenseImpl: Reading matrix data (dense)"
4468 << endl;
4469 }
4470
4471 // Make sure that we can get a 1-D view of X.
4472 TEUCHOS_TEST_FOR_EXCEPTION(
4473 ! X->isConstantStride (), std::logic_error,
4474 "Can't get a 1-D view of the entries of the MultiVector X on "
4475 "Process 0, because the stride between the columns of X is not "
4476 "constant. This shouldn't happen because we just created X and "
4477 "haven't filled it in yet. Please report this bug to the Tpetra "
4478 "developers.");
4479
4480 // Get a writeable 1-D view of the entries of X. Rank 0
4481 // owns all of them. The view will expire at the end of
4482 // scope, so (if necessary) it will be written back to X
4483 // at this time.
4484 ArrayRCP<ST> X_view = X->get1dViewNonConst ();
4485 TEUCHOS_TEST_FOR_EXCEPTION(
4486 as<global_size_t> (X_view.size ()) < numRows * numCols,
4487 std::logic_error,
4488 "The view of X has size " << X_view.size() << " which is not enough to "
4489 "accommodate the expected number of entries numRows*numCols = "
4490 << numRows << "*" << numCols << " = " << numRows*numCols << ". "
4491 "Please report this bug to the Tpetra developers.");
4492 const size_t stride = X->getStride ();
4493
4494 // The third element of the dimensions Tuple encodes the data
4495 // type reported by the Banner: "real" == 0, "complex" == 1,
4496 // "integer" == 0 (same as "real"), "pattern" == 2. We do not
4497 // allow dense matrices to be pattern matrices, so dims[2] ==
4498 // 0 or 1. We've already checked for this above.
4499 const bool isComplex = (dims[2] == 1);
4500 size_type count = 0, curRow = 0, curCol = 0;
4501
4502 std::string line;
4503 while (getline (in, line)) {
4504 ++lineNumber;
4505 // Is the current line a comment line? If it's not,
4506 // line.substr(start,size) contains the data.
4507 size_t start = 0, size = 0;
4508 const bool commentLine =
4509 checkCommentLine (line, start, size, lineNumber, tolerant);
4510 if (! commentLine) {
4511 // Make sure we have room in which to put the new matrix
4512 // entry. We check this only after checking for a
4513 // comment line, because there may be one or more
4514 // comment lines at the end of the file. In tolerant
4515 // mode, we simply ignore any extra data.
4516 if (count >= X_view.size()) {
4517 if (tolerant) {
4518 break;
4519 }
4520 else {
4521 TEUCHOS_TEST_FOR_EXCEPTION(
4522 count >= X_view.size(),
4523 std::runtime_error,
4524 "The Matrix Market input stream has more data in it than "
4525 "its metadata reported. Current line number is "
4526 << lineNumber << ".");
4527 }
4528 }
4529
4530 // mfh 19 Dec 2012: Ignore everything up to the initial
4531 // colon. writeDense() has the option to print out the
4532 // global row index in front of each entry, followed by
4533 // a colon and space.
4534 {
4535 const size_t pos = line.substr (start, size).find (':');
4536 if (pos != std::string::npos) {
4537 start = pos+1;
4538 }
4539 }
4540 std::istringstream istr (line.substr (start, size));
4541 // Does the line contain anything at all? Can we
4542 // safely read from the input stream wrapping the
4543 // line?
4544 if (istr.eof() || istr.fail()) {
4545 // In tolerant mode, simply ignore the line.
4546 if (tolerant) {
4547 break;
4548 }
4549 // We repeat the full test here so the exception
4550 // message is more informative.
4551 TEUCHOS_TEST_FOR_EXCEPTION(
4552 ! tolerant && (istr.eof() || istr.fail()),
4553 std::runtime_error,
4554 "Line " << lineNumber << " of the Matrix Market file is "
4555 "empty, or we cannot read from it for some other reason.");
4556 }
4557 // Current matrix entry to read in.
4558 ST val = STS::zero();
4559 // Real and imaginary parts of the current matrix entry.
4560 // The imaginary part is zero if the matrix is real-valued.
4561 MT real = STM::zero(), imag = STM::zero();
4562
4563 // isComplex refers to the input stream's data, not to
4564 // the scalar type S. It's OK to read real-valued
4565 // data into a matrix storing complex-valued data; in
4566 // that case, all entries' imaginary parts are zero.
4567 if (isComplex) {
4568 // STS::real() and STS::imag() return a copy of
4569 // their respective components, not a writeable
4570 // reference. Otherwise we could just assign to
4571 // them using the istream extraction operator (>>).
4572 // That's why we have separate magnitude type "real"
4573 // and "imag" variables.
4574
4575 // Attempt to read the real part of the current entry.
4576 istr >> real;
4577 if (istr.fail()) {
4578 TEUCHOS_TEST_FOR_EXCEPTION(
4579 ! tolerant && istr.eof(), std::runtime_error,
4580 "Failed to get the real part of a complex-valued matrix "
4581 "entry from line " << lineNumber << " of the Matrix Market "
4582 "file.");
4583 // In tolerant mode, just skip bad lines.
4584 if (tolerant) {
4585 break;
4586 }
4587 } else if (istr.eof()) {
4588 TEUCHOS_TEST_FOR_EXCEPTION(
4589 ! tolerant && istr.eof(), std::runtime_error,
4590 "Missing imaginary part of a complex-valued matrix entry "
4591 "on line " << lineNumber << " of the Matrix Market file.");
4592 // In tolerant mode, let any missing imaginary part be 0.
4593 } else {
4594 // Attempt to read the imaginary part of the current
4595 // matrix entry.
4596 istr >> imag;
4597 TEUCHOS_TEST_FOR_EXCEPTION(
4598 ! tolerant && istr.fail(), std::runtime_error,
4599 "Failed to get the imaginary part of a complex-valued "
4600 "matrix entry from line " << lineNumber << " of the "
4601 "Matrix Market file.");
4602 // In tolerant mode, let any missing or corrupted
4603 // imaginary part be 0.
4604 }
4605 } else { // Matrix Market file contains real-valued data.
4606 // Attempt to read the current matrix entry.
4607 istr >> real;
4608 TEUCHOS_TEST_FOR_EXCEPTION(
4609 ! tolerant && istr.fail(), std::runtime_error,
4610 "Failed to get a real-valued matrix entry from line "
4611 << lineNumber << " of the Matrix Market file.");
4612 // In tolerant mode, simply ignore the line if
4613 // we failed to read a matrix entry.
4614 if (istr.fail() && tolerant) {
4615 break;
4616 }
4617 }
4618 // In tolerant mode, we simply let pass through whatever
4619 // data we got.
4620 TEUCHOS_TEST_FOR_EXCEPTION(
4621 ! tolerant && istr.fail(), std::runtime_error,
4622 "Failed to read matrix data from line " << lineNumber
4623 << " of the Matrix Market file.");
4624
4625 // Assign val = ST(real, imag).
4626 Teuchos::MatrixMarket::details::assignScalar<ST> (val, real, imag);
4627
4628 curRow = count % numRows;
4629 curCol = count / numRows;
4630 X_view[curRow + curCol*stride] = val;
4631 ++count;
4632 } // if not a comment line
4633 } // while there are still lines in the file, get the next one
4634
4635 TEUCHOS_TEST_FOR_EXCEPTION(
4636 ! tolerant && static_cast<global_size_t> (count) < numRows * numCols,
4637 std::runtime_error,
4638 "The Matrix Market metadata reports that the dense matrix is "
4639 << numRows << " x " << numCols << ", and thus has "
4640 << numRows*numCols << " total entries, but we only found " << count
4641 << " entr" << (count == 1 ? "y" : "ies") << " in the file.");
4642 } catch (std::exception& e) {
4643 exMsg << e.what ();
4644 localReadDataSuccess = 0;
4645 }
4646 } // not binary file
4647 else {
4648 if (debug) {
4649 *err << myRank << ": readDenseImpl: Reading matrix data (dense)"
4650 << endl;
4651 }
4652
4653 // Make sure that we can get a 1-D view of X.
4654 TEUCHOS_TEST_FOR_EXCEPTION(
4655 ! X->isConstantStride (), std::logic_error,
4656 "Can't get a 1-D view of the entries of the MultiVector X on "
4657 "Process 0, because the stride between the columns of X is not "
4658 "constant. This shouldn't happen because we just created X and "
4659 "haven't filled it in yet. Please report this bug to the Tpetra "
4660 "developers.");
4661
4662 // Get a writeable 1-D view of the entries of X. Rank 0
4663 // owns all of them. The view will expire at the end of
4664 // scope, so (if necessary) it will be written back to X
4665 // at this time.
4666 auto X_view = X->getLocalViewHost (Access::OverwriteAll);
4667
4668 TEUCHOS_TEST_FOR_EXCEPTION(
4669 as<global_size_t> (X_view.extent(0)) < numRows,
4670 std::logic_error,
4671 "The view of X has " << X_view.extent(0) << " rows which is not enough to "
4672 "accommodate the expected number of entries numRows = "
4673 << numRows << ". "
4674 "Please report this bug to the Tpetra developers.");
4675 TEUCHOS_TEST_FOR_EXCEPTION(
4676 as<global_size_t> (X_view.extent(1)) < numCols,
4677 std::logic_error,
4678 "The view of X has " << X_view.extent(1) << " colums which is not enough to "
4679 "accommodate the expected number of entries numRows = "
4680 << numCols << ". "
4681 "Please report this bug to the Tpetra developers.");
4682
4683 for (size_t curRow = 0; curRow < numRows; ++curRow) {
4684 for (size_t curCol = 0; curCol < numCols; ++curCol) {
4685 if (Teuchos::ScalarTraits<ST>::isOrdinal){
4686 global_size_t val;
4687 in.read(reinterpret_cast<char*>(&val), sizeof(val));
4688 X_view(curRow, curCol) = val;
4689 } else {
4690 double val;
4691 in.read(reinterpret_cast<char*>(&val), sizeof(val));
4692 X_view(curRow, curCol) = val;
4693 }
4694 }
4695 }
4696 } // binary
4697 } // if (myRank == 0)
4698
4699 if (debug) {
4700 *err << myRank << ": readDenseImpl: done reading data" << endl;
4701 }
4702
4703 // Synchronize on whether Proc 0 successfully read the data.
4704 int globalReadDataSuccess = localReadDataSuccess;
4705 broadcast (*comm, 0, outArg (globalReadDataSuccess));
4706 TEUCHOS_TEST_FOR_EXCEPTION(
4707 globalReadDataSuccess == 0, std::runtime_error,
4708 "Failed to read the multivector's data: " << exMsg.str ());
4709
4710 // If there's only one MPI process and the user didn't supply
4711 // a Map (i.e., pMap is null), we're done. Set pMap to the
4712 // Map used to distribute X, and return X.
4713 if (comm->getSize () == 1 && map.is_null ()) {
4714 map = proc0Map;
4715 if (! err.is_null ()) {
4716 err->popTab ();
4717 }
4718 if (debug) {
4719 *err << myRank << ": readDenseImpl: done" << endl;
4720 }
4721 if (! err.is_null ()) {
4722 err->popTab ();
4723 }
4724 return X;
4725 }
4726
4727 if (debug) {
4728 *err << myRank << ": readDenseImpl: Creating target MV" << endl;
4729 }
4730
4731 // Make a multivector Y with the distributed map pMap.
4732 RCP<MV> Y = createMultiVector<ST, LO, GO, NT> (map, numCols);
4733
4734 if (debug) {
4735 *err << myRank << ": readDenseImpl: Creating Export" << endl;
4736 }
4737
4738 // Make an Export object that will export X to Y. First
4739 // argument is the source map, second argument is the target
4740 // map.
4741 Export<LO, GO, NT> exporter (proc0Map, map, err);
4742
4743 if (debug) {
4744 *err << myRank << ": readDenseImpl: Exporting" << endl;
4745 }
4746 // Export X into Y.
4747 Y->doExport (*X, exporter, INSERT);
4748
4749 if (! err.is_null ()) {
4750 err->popTab ();
4751 }
4752 if (debug) {
4753 *err << myRank << ": readDenseImpl: done" << endl;
4754 }
4755 if (! err.is_null ()) {
4756 err->popTab ();
4757 }
4758
4759 // Y is distributed over all process(es) in the communicator.
4760 return Y;
4761 }
4762
4763
4764 template<class VectorScalarType>
4765 static Teuchos::RCP<Tpetra::Vector<VectorScalarType,
4768 node_type> >
4769 readVectorImpl (std::istream& in,
4770 const Teuchos::RCP<const comm_type>& comm,
4771 Teuchos::RCP<const map_type>& map,
4772 const Teuchos::RCP<Teuchos::FancyOStream>& err,
4773 const bool tolerant=false,
4774 const bool debug=false)
4775 {
4776 using Teuchos::MatrixMarket::Banner;
4777 using Teuchos::MatrixMarket::checkCommentLine;
4778 using Teuchos::as;
4779 using Teuchos::broadcast;
4780 using Teuchos::outArg;
4781 using Teuchos::RCP;
4782 using Teuchos::Tuple;
4783 using std::endl;
4784 typedef VectorScalarType ST;
4785 typedef local_ordinal_type LO;
4786 typedef global_ordinal_type GO;
4787 typedef node_type NT;
4788 typedef Teuchos::ScalarTraits<ST> STS;
4789 typedef typename STS::magnitudeType MT;
4790 typedef Teuchos::ScalarTraits<MT> STM;
4791 typedef Tpetra::Vector<ST, LO, GO, NT> MV;
4792
4793 // Rank 0 is the only (MPI) process allowed to read from the
4794 // input stream.
4795 const int myRank = comm->getRank ();
4796
4797 if (! err.is_null ()) {
4798 err->pushTab ();
4799 }
4800 if (debug) {
4801 *err << myRank << ": readVectorImpl" << endl;
4802 }
4803 if (! err.is_null ()) {
4804 err->pushTab ();
4805 }
4806
4807 // mfh 17 Feb 2013: It's not strictly necessary that the Comm
4808 // instances be identical and that the Node instances be
4809 // identical. The essential condition is more complicated to
4810 // test and isn't the same for all Node types. Thus, we just
4811 // leave it up to the user.
4812
4813 // // If map is nonnull, check the precondition that its
4814 // // communicator resp. node equal comm resp. node. Checking
4815 // // now avoids doing a lot of file reading before we detect the
4816 // // violated precondition.
4817 // TEUCHOS_TEST_FOR_EXCEPTION(
4818 // ! map.is_null() && (map->getComm() != comm || map->getNode () != node,
4819 // std::invalid_argument, "If you supply a nonnull Map, the Map's "
4820 // "communicator and node must equal the supplied communicator resp. "
4821 // "node.");
4822
4823 // Process 0 will read in the matrix dimensions from the file,
4824 // and broadcast them to all ranks in the given communicator.
4825 // There are only 2 dimensions in the matrix, but we use the
4826 // third element of the Tuple to encode the banner's reported
4827 // data type: "real" == 0, "complex" == 1, and "integer" == 0
4828 // (same as "real"). We don't allow pattern matrices (i.e.,
4829 // graphs) since they only make sense for sparse data.
4830 Tuple<GO, 3> dims;
4831 dims[0] = 0;
4832 dims[1] = 0;
4833
4834 // Current line number in the input stream. Only valid on
4835 // Proc 0. Various calls will modify this depending on the
4836 // number of lines that are read from the input stream.
4837 size_t lineNumber = 1;
4838
4839 // Capture errors and their messages on Proc 0.
4840 std::ostringstream exMsg;
4841 int localBannerReadSuccess = 1;
4842 int localDimsReadSuccess = 1;
4843
4844 // Only Proc 0 gets to read matrix data from the input stream.
4845 if (myRank == 0) {
4846 if (debug) {
4847 *err << myRank << ": readVectorImpl: Reading banner line (dense)" << endl;
4848 }
4849
4850 // The "Banner" tells you whether the input stream
4851 // represents a dense matrix, the symmetry type of the
4852 // matrix, and the type of the data it contains.
4853 RCP<const Banner> pBanner;
4854 try {
4855 pBanner = readBanner (in, lineNumber, tolerant, debug);
4856 } catch (std::exception& e) {
4857 exMsg << e.what ();
4858 localBannerReadSuccess = 0;
4859 }
4860 // Make sure the input stream is the right kind of data.
4861 if (localBannerReadSuccess) {
4862 if (pBanner->matrixType () != "array") {
4863 exMsg << "The Matrix Market file does not contain dense matrix "
4864 "data. Its banner (first) line says that its matrix type is \""
4865 << pBanner->matrixType () << "\", rather that the required "
4866 "\"array\".";
4867 localBannerReadSuccess = 0;
4868 } else if (pBanner->dataType() == "pattern") {
4869 exMsg << "The Matrix Market file's banner (first) "
4870 "line claims that the matrix's data type is \"pattern\". This does "
4871 "not make sense for a dense matrix, yet the file reports the matrix "
4872 "as dense. The only valid data types for a dense matrix are "
4873 "\"real\", \"complex\", and \"integer\".";
4874 localBannerReadSuccess = 0;
4875 } else {
4876 // Encode the data type reported by the Banner as the
4877 // third element of the dimensions Tuple.
4878 dims[2] = encodeDataType (pBanner->dataType ());
4879 }
4880 } // if we successfully read the banner line
4881
4882 // At this point, we've successfully read the banner line.
4883 // Now read the dimensions line.
4884 if (localBannerReadSuccess) {
4885 if (debug) {
4886 *err << myRank << ": readVectorImpl: Reading dimensions line (dense)" << endl;
4887 }
4888 // Keep reading lines from the input stream until we find
4889 // a non-comment line, or until we run out of lines. The
4890 // latter is an error, since every "array" format Matrix
4891 // Market file must have a dimensions line after the
4892 // banner (even if the matrix has zero rows or columns, or
4893 // zero entries).
4894 std::string line;
4895 bool commentLine = true;
4896
4897 while (commentLine) {
4898 // Test whether it is even valid to read from the input
4899 // stream wrapping the line.
4900 if (in.eof () || in.fail ()) {
4901 exMsg << "Unable to get array dimensions line (at all) from line "
4902 << lineNumber << " of input stream. The input stream "
4903 << "claims that it is "
4904 << (in.eof() ? "at end-of-file." : "in a failed state.");
4905 localDimsReadSuccess = 0;
4906 } else {
4907 // Try to get the next line from the input stream.
4908 if (getline (in, line)) {
4909 ++lineNumber; // We did actually read a line.
4910 }
4911 // Is the current line a comment line? Ignore start
4912 // and size; they are only useful for reading the
4913 // actual matrix entries. (We could use them here as
4914 // an optimization, but we've chosen not to.)
4915 size_t start = 0, size = 0;
4916 commentLine = checkCommentLine (line, start, size, lineNumber, tolerant);
4917 } // whether we failed to read the line at all
4918 } // while the line we just read is a comment line
4919
4920 //
4921 // Get <numRows> <numCols> from the line we just read.
4922 //
4923 std::istringstream istr (line);
4924
4925 // Test whether it is even valid to read from the input
4926 // stream wrapping the line.
4927 if (istr.eof () || istr.fail ()) {
4928 exMsg << "Unable to read any data from line " << lineNumber
4929 << " of input; the line should contain the matrix dimensions "
4930 << "\"<numRows> <numCols>\".";
4931 localDimsReadSuccess = 0;
4932 } else { // It's valid to read from the line.
4933 GO theNumRows = 0;
4934 istr >> theNumRows; // Read in the number of rows.
4935 if (istr.fail ()) {
4936 exMsg << "Failed to get number of rows from line "
4937 << lineNumber << " of input; the line should contains the "
4938 << "matrix dimensions \"<numRows> <numCols>\".";
4939 localDimsReadSuccess = 0;
4940 } else { // We successfully read the number of rows
4941 dims[0] = theNumRows; // Save the number of rows
4942 if (istr.eof ()) { // Do we still have data to read?
4943 exMsg << "No more data after number of rows on line "
4944 << lineNumber << " of input; the line should contain the "
4945 << "matrix dimensions \"<numRows> <numCols>\".";
4946 localDimsReadSuccess = 0;
4947 } else { // Still data left to read; read in number of columns.
4948 GO theNumCols = 0;
4949 istr >> theNumCols; // Read in the number of columns
4950 if (istr.fail ()) {
4951 exMsg << "Failed to get number of columns from line "
4952 << lineNumber << " of input; the line should contain "
4953 << "the matrix dimensions \"<numRows> <numCols>\".";
4954 localDimsReadSuccess = 0;
4955 } else { // We successfully read the number of columns
4956 dims[1] = theNumCols; // Save the number of columns
4957 } // if istr.fail ()
4958 } // if istr.eof ()
4959 } // if we read the number of rows
4960 } // if the input stream wrapping the dims line was (in)valid
4961 } // if we successfully read the banner line
4962 } // if (myRank == 0)
4963
4964 // Check if file has a Vector
4965 if (dims[1]!=1) {
4966 exMsg << "File does not contain a 1D Vector";
4967 localDimsReadSuccess = 0;
4968 }
4969
4970 // Broadcast the matrix dimensions, the encoded data type, and
4971 // whether or not Proc 0 succeeded in reading the banner and
4972 // dimensions.
4973 Tuple<GO, 5> bannerDimsReadResult;
4974 if (myRank == 0) {
4975 bannerDimsReadResult[0] = dims[0]; // numRows
4976 bannerDimsReadResult[1] = dims[1]; // numCols
4977 bannerDimsReadResult[2] = dims[2]; // encoded data type
4978 bannerDimsReadResult[3] = localBannerReadSuccess;
4979 bannerDimsReadResult[4] = localDimsReadSuccess;
4980 }
4981
4982 // Broadcast matrix dimensions and the encoded data type from
4983 // Proc 0 to all the MPI processes.
4984 broadcast (*comm, 0, bannerDimsReadResult);
4985
4986 TEUCHOS_TEST_FOR_EXCEPTION(
4987 bannerDimsReadResult[3] == 0, std::runtime_error,
4988 "Failed to read banner line: " << exMsg.str ());
4989 TEUCHOS_TEST_FOR_EXCEPTION(
4990 bannerDimsReadResult[4] == 0, std::runtime_error,
4991 "Failed to read matrix dimensions line: " << exMsg.str ());
4992 if (myRank != 0) {
4993 dims[0] = bannerDimsReadResult[0];
4994 dims[1] = bannerDimsReadResult[1];
4995 dims[2] = bannerDimsReadResult[2];
4996 }
4997
4998 // Tpetra objects want the matrix dimensions in these types.
4999 const global_size_t numRows = static_cast<global_size_t> (dims[0]);
5000 const size_t numCols = static_cast<size_t> (dims[1]);
5001
5002 // Make a "Proc 0 owns everything" Map that we will use to
5003 // read in the multivector entries in the correct order on
5004 // Proc 0. This must be a collective
5005 RCP<const map_type> proc0Map; // "Proc 0 owns everything" Map
5006 if (map.is_null ()) {
5007 // The user didn't supply a Map. Make a contiguous
5008 // distributed Map for them, using the read-in multivector
5009 // dimensions.
5010 map = createUniformContigMapWithNode<LO, GO, NT> (numRows, comm);
5011 const size_t localNumRows = (myRank == 0) ? numRows : 0;
5012 // At this point, map exists and has a nonnull node.
5013 proc0Map = createContigMapWithNode<LO, GO, NT> (numRows, localNumRows,
5014 comm);
5015 }
5016 else { // The user supplied a Map.
5017 proc0Map = Details::computeGatherMap<map_type> (map, err, debug);
5018 }
5019
5020 // Make a multivector X owned entirely by Proc 0.
5021 RCP<MV> X = createVector<ST, LO, GO, NT> (proc0Map);
5022
5023 //
5024 // On Proc 0, read the Matrix Market data from the input
5025 // stream into the multivector X.
5026 //
5027 int localReadDataSuccess = 1;
5028 if (myRank == 0) {
5029 try {
5030 if (debug) {
5031 *err << myRank << ": readVectorImpl: Reading matrix data (dense)"
5032 << endl;
5033 }
5034
5035 // Make sure that we can get a 1-D view of X.
5036 TEUCHOS_TEST_FOR_EXCEPTION(
5037 ! X->isConstantStride (), std::logic_error,
5038 "Can't get a 1-D view of the entries of the MultiVector X on "
5039 "Process 0, because the stride between the columns of X is not "
5040 "constant. This shouldn't happen because we just created X and "
5041 "haven't filled it in yet. Please report this bug to the Tpetra "
5042 "developers.");
5043
5044 // Get a writeable 1-D view of the entries of X. Rank 0
5045 // owns all of them. The view will expire at the end of
5046 // scope, so (if necessary) it will be written back to X
5047 // at this time.
5048 Teuchos::ArrayRCP<ST> X_view = X->get1dViewNonConst ();
5049 TEUCHOS_TEST_FOR_EXCEPTION(
5050 as<global_size_t> (X_view.size ()) < numRows * numCols,
5051 std::logic_error,
5052 "The view of X has size " << X_view << " which is not enough to "
5053 "accommodate the expected number of entries numRows*numCols = "
5054 << numRows << "*" << numCols << " = " << numRows*numCols << ". "
5055 "Please report this bug to the Tpetra developers.");
5056 const size_t stride = X->getStride ();
5057
5058 // The third element of the dimensions Tuple encodes the data
5059 // type reported by the Banner: "real" == 0, "complex" == 1,
5060 // "integer" == 0 (same as "real"), "pattern" == 2. We do not
5061 // allow dense matrices to be pattern matrices, so dims[2] ==
5062 // 0 or 1. We've already checked for this above.
5063 const bool isComplex = (dims[2] == 1);
5064 size_type count = 0, curRow = 0, curCol = 0;
5065
5066 std::string line;
5067 while (getline (in, line)) {
5068 ++lineNumber;
5069 // Is the current line a comment line? If it's not,
5070 // line.substr(start,size) contains the data.
5071 size_t start = 0, size = 0;
5072 const bool commentLine =
5073 checkCommentLine (line, start, size, lineNumber, tolerant);
5074 if (! commentLine) {
5075 // Make sure we have room in which to put the new matrix
5076 // entry. We check this only after checking for a
5077 // comment line, because there may be one or more
5078 // comment lines at the end of the file. In tolerant
5079 // mode, we simply ignore any extra data.
5080 if (count >= X_view.size()) {
5081 if (tolerant) {
5082 break;
5083 }
5084 else {
5085 TEUCHOS_TEST_FOR_EXCEPTION(
5086 count >= X_view.size(),
5087 std::runtime_error,
5088 "The Matrix Market input stream has more data in it than "
5089 "its metadata reported. Current line number is "
5090 << lineNumber << ".");
5091 }
5092 }
5093
5094 // mfh 19 Dec 2012: Ignore everything up to the initial
5095 // colon. writeDense() has the option to print out the
5096 // global row index in front of each entry, followed by
5097 // a colon and space.
5098 {
5099 const size_t pos = line.substr (start, size).find (':');
5100 if (pos != std::string::npos) {
5101 start = pos+1;
5102 }
5103 }
5104 std::istringstream istr (line.substr (start, size));
5105 // Does the line contain anything at all? Can we
5106 // safely read from the input stream wrapping the
5107 // line?
5108 if (istr.eof() || istr.fail()) {
5109 // In tolerant mode, simply ignore the line.
5110 if (tolerant) {
5111 break;
5112 }
5113 // We repeat the full test here so the exception
5114 // message is more informative.
5115 TEUCHOS_TEST_FOR_EXCEPTION(
5116 ! tolerant && (istr.eof() || istr.fail()),
5117 std::runtime_error,
5118 "Line " << lineNumber << " of the Matrix Market file is "
5119 "empty, or we cannot read from it for some other reason.");
5120 }
5121 // Current matrix entry to read in.
5122 ST val = STS::zero();
5123 // Real and imaginary parts of the current matrix entry.
5124 // The imaginary part is zero if the matrix is real-valued.
5125 MT real = STM::zero(), imag = STM::zero();
5126
5127 // isComplex refers to the input stream's data, not to
5128 // the scalar type S. It's OK to read real-valued
5129 // data into a matrix storing complex-valued data; in
5130 // that case, all entries' imaginary parts are zero.
5131 if (isComplex) {
5132 // STS::real() and STS::imag() return a copy of
5133 // their respective components, not a writeable
5134 // reference. Otherwise we could just assign to
5135 // them using the istream extraction operator (>>).
5136 // That's why we have separate magnitude type "real"
5137 // and "imag" variables.
5138
5139 // Attempt to read the real part of the current entry.
5140 istr >> real;
5141 if (istr.fail()) {
5142 TEUCHOS_TEST_FOR_EXCEPTION(
5143 ! tolerant && istr.eof(), std::runtime_error,
5144 "Failed to get the real part of a complex-valued matrix "
5145 "entry from line " << lineNumber << " of the Matrix Market "
5146 "file.");
5147 // In tolerant mode, just skip bad lines.
5148 if (tolerant) {
5149 break;
5150 }
5151 } else if (istr.eof()) {
5152 TEUCHOS_TEST_FOR_EXCEPTION(
5153 ! tolerant && istr.eof(), std::runtime_error,
5154 "Missing imaginary part of a complex-valued matrix entry "
5155 "on line " << lineNumber << " of the Matrix Market file.");
5156 // In tolerant mode, let any missing imaginary part be 0.
5157 } else {
5158 // Attempt to read the imaginary part of the current
5159 // matrix entry.
5160 istr >> imag;
5161 TEUCHOS_TEST_FOR_EXCEPTION(
5162 ! tolerant && istr.fail(), std::runtime_error,
5163 "Failed to get the imaginary part of a complex-valued "
5164 "matrix entry from line " << lineNumber << " of the "
5165 "Matrix Market file.");
5166 // In tolerant mode, let any missing or corrupted
5167 // imaginary part be 0.
5168 }
5169 } else { // Matrix Market file contains real-valued data.
5170 // Attempt to read the current matrix entry.
5171 istr >> real;
5172 TEUCHOS_TEST_FOR_EXCEPTION(
5173 ! tolerant && istr.fail(), std::runtime_error,
5174 "Failed to get a real-valued matrix entry from line "
5175 << lineNumber << " of the Matrix Market file.");
5176 // In tolerant mode, simply ignore the line if
5177 // we failed to read a matrix entry.
5178 if (istr.fail() && tolerant) {
5179 break;
5180 }
5181 }
5182 // In tolerant mode, we simply let pass through whatever
5183 // data we got.
5184 TEUCHOS_TEST_FOR_EXCEPTION(
5185 ! tolerant && istr.fail(), std::runtime_error,
5186 "Failed to read matrix data from line " << lineNumber
5187 << " of the Matrix Market file.");
5188
5189 // Assign val = ST(real, imag).
5190 Teuchos::MatrixMarket::details::assignScalar<ST> (val, real, imag);
5191
5192 curRow = count % numRows;
5193 curCol = count / numRows;
5194 X_view[curRow + curCol*stride] = val;
5195 ++count;
5196 } // if not a comment line
5197 } // while there are still lines in the file, get the next one
5198
5199 TEUCHOS_TEST_FOR_EXCEPTION(
5200 ! tolerant && static_cast<global_size_t> (count) < numRows * numCols,
5201 std::runtime_error,
5202 "The Matrix Market metadata reports that the dense matrix is "
5203 << numRows << " x " << numCols << ", and thus has "
5204 << numRows*numCols << " total entries, but we only found " << count
5205 << " entr" << (count == 1 ? "y" : "ies") << " in the file.");
5206 } catch (std::exception& e) {
5207 exMsg << e.what ();
5208 localReadDataSuccess = 0;
5209 }
5210 } // if (myRank == 0)
5211
5212 if (debug) {
5213 *err << myRank << ": readVectorImpl: done reading data" << endl;
5214 }
5215
5216 // Synchronize on whether Proc 0 successfully read the data.
5217 int globalReadDataSuccess = localReadDataSuccess;
5218 broadcast (*comm, 0, outArg (globalReadDataSuccess));
5219 TEUCHOS_TEST_FOR_EXCEPTION(
5220 globalReadDataSuccess == 0, std::runtime_error,
5221 "Failed to read the multivector's data: " << exMsg.str ());
5222
5223 // If there's only one MPI process and the user didn't supply
5224 // a Map (i.e., pMap is null), we're done. Set pMap to the
5225 // Map used to distribute X, and return X.
5226 if (comm->getSize () == 1 && map.is_null ()) {
5227 map = proc0Map;
5228 if (! err.is_null ()) {
5229 err->popTab ();
5230 }
5231 if (debug) {
5232 *err << myRank << ": readVectorImpl: done" << endl;
5233 }
5234 if (! err.is_null ()) {
5235 err->popTab ();
5236 }
5237 return X;
5238 }
5239
5240 if (debug) {
5241 *err << myRank << ": readVectorImpl: Creating target MV" << endl;
5242 }
5243
5244 // Make a multivector Y with the distributed map pMap.
5245 RCP<MV> Y = createVector<ST, LO, GO, NT> (map);
5246
5247 if (debug) {
5248 *err << myRank << ": readVectorImpl: Creating Export" << endl;
5249 }
5250
5251 // Make an Export object that will export X to Y. First
5252 // argument is the source map, second argument is the target
5253 // map.
5254 Export<LO, GO, NT> exporter (proc0Map, map, err);
5255
5256 if (debug) {
5257 *err << myRank << ": readVectorImpl: Exporting" << endl;
5258 }
5259 // Export X into Y.
5260 Y->doExport (*X, exporter, INSERT);
5261
5262 if (! err.is_null ()) {
5263 err->popTab ();
5264 }
5265 if (debug) {
5266 *err << myRank << ": readVectorImpl: done" << endl;
5267 }
5268 if (! err.is_null ()) {
5269 err->popTab ();
5270 }
5271
5272 // Y is distributed over all process(es) in the communicator.
5273 return Y;
5274 }
5275
5276 public:
5297 static Teuchos::RCP<const map_type>
5298 readMap (std::istream& in,
5299 const Teuchos::RCP<const comm_type>& comm,
5300 const bool tolerant=false,
5301 const bool debug=false,
5302 const bool binary=false)
5303 {
5304 Teuchos::RCP<Teuchos::FancyOStream> err =
5305 Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
5306 return readMap (in, comm, err, tolerant, debug, binary);
5307 }
5308
5309
5336 static Teuchos::RCP<const map_type>
5337 readMap (std::istream& in,
5338 const Teuchos::RCP<const comm_type>& comm,
5339 const Teuchos::RCP<Teuchos::FancyOStream>& err,
5340 const bool tolerant=false,
5341 const bool debug=false,
5342 const bool binary=false)
5343 {
5344 using Teuchos::arcp;
5345 using Teuchos::Array;
5346 using Teuchos::ArrayRCP;
5347 using Teuchos::as;
5348 using Teuchos::broadcast;
5349 using Teuchos::Comm;
5350 using Teuchos::CommRequest;
5351 using Teuchos::inOutArg;
5352 using Teuchos::ireceive;
5353 using Teuchos::outArg;
5354 using Teuchos::RCP;
5355 using Teuchos::receive;
5356 using Teuchos::reduceAll;
5357 using Teuchos::REDUCE_MIN;
5358 using Teuchos::isend;
5359 using Teuchos::SerialComm;
5360 using Teuchos::toString;
5361 using Teuchos::wait;
5362 using std::endl;
5363 typedef Tpetra::global_size_t GST;
5364 typedef ptrdiff_t int_type; // Can hold int and GO
5365 typedef local_ordinal_type LO;
5366 typedef global_ordinal_type GO;
5367 typedef node_type NT;
5369
5370 const int numProcs = comm->getSize ();
5371 const int myRank = comm->getRank ();
5372
5373 if (err.is_null ()) {
5374 err->pushTab ();
5375 }
5376 if (debug) {
5377 std::ostringstream os;
5378 os << myRank << ": readMap: " << endl;
5379 *err << os.str ();
5380 }
5381 if (err.is_null ()) {
5382 err->pushTab ();
5383 }
5384
5385 // Tag for receive-size / send-size messages. writeMap used
5386 // tags 1337 and 1338; we count up from there.
5387 const int sizeTag = 1339;
5388 // Tag for receive-data / send-data messages.
5389 const int dataTag = 1340;
5390
5391 // These are for sends on Process 0, and for receives on all
5392 // other processes. sizeReq is for the {receive,send}-size
5393 // message, and dataReq is for the message containing the
5394 // actual GIDs to belong to the receiving process.
5395 RCP<CommRequest<int> > sizeReq;
5396 RCP<CommRequest<int> > dataReq;
5397
5398 // Each process will have to receive the number of GIDs to
5399 // expect. Thus, we can post the receives now, and cancel
5400 // them if something should go wrong in the meantime.
5401 ArrayRCP<int_type> numGidsToRecv (1);
5402 numGidsToRecv[0] = 0;
5403 if (myRank != 0) {
5404 sizeReq = ireceive<int, int_type> (numGidsToRecv, 0, sizeTag, *comm);
5405 }
5406
5407 int readSuccess = 1;
5408 std::ostringstream exMsg;
5409 RCP<MV> data; // Will only be valid on Proc 0
5410 if (myRank == 0) {
5411 // If we want to reuse readDenseImpl, we have to make a
5412 // communicator that only contains Proc 0. Otherwise,
5413 // readDenseImpl will redistribute the data to all
5414 // processes. While we eventually want that, neither we nor
5415 // readDenseImpl know the correct Map to use at the moment.
5416 // That depends on the second column of the multivector.
5417 RCP<const Comm<int> > proc0Comm (new SerialComm<int> ());
5418 try {
5419 RCP<const map_type> dataMap;
5420 // This is currently the only place where we use the
5421 // 'tolerant' argument. Later, if we want to be clever,
5422 // we could have tolerant mode allow PIDs out of order.
5423 data = readDenseImpl<GO> (in, proc0Comm, dataMap, err, tolerant, debug, binary);
5424 (void) dataMap; // Silence "unused" warnings
5425 if (data.is_null ()) {
5426 readSuccess = 0;
5427 exMsg << "readDenseImpl() returned null." << endl;
5428 }
5429 } catch (std::exception& e) {
5430 readSuccess = 0;
5431 exMsg << e.what () << endl;
5432 }
5433 }
5434
5435 // Map from PID to all the GIDs for that PID.
5436 // Only populated on Process 0.
5437 std::map<int, Array<GO> > pid2gids;
5438
5439 // The index base must be the global minimum GID.
5440 // We will compute this on Process 0 and broadcast,
5441 // so that all processes can set up the Map.
5442 int_type globalNumGIDs = 0;
5443
5444 // The index base must be the global minimum GID.
5445 // We will compute this on Process 0 and broadcast,
5446 // so that all processes can set up the Map.
5447 GO indexBase = 0;
5448
5449 // Process 0: If the above read of the MultiVector succeeded,
5450 // extract the GIDs and PIDs into pid2gids, and find the
5451 // global min GID.
5452 if (myRank == 0 && readSuccess == 1) {
5453 if (data->getNumVectors () == 2) { // Map format 1.0
5454 ArrayRCP<const GO> GIDs = data->getData (0);
5455 ArrayRCP<const GO> PIDs = data->getData (1); // convert to int
5456 globalNumGIDs = GIDs.size ();
5457
5458 // Start computing the global min GID, while collecting
5459 // the GIDs for each PID.
5460 if (globalNumGIDs > 0) {
5461 const int pid = static_cast<int> (PIDs[0]);
5462
5463 if (pid < 0 || pid >= numProcs) {
5464 readSuccess = 0;
5465 exMsg << "Tpetra::MatrixMarket::readMap: "
5466 << "Encountered invalid PID " << pid << "." << endl;
5467 }
5468 else {
5469 const GO gid = GIDs[0];
5470 pid2gids[pid].push_back (gid);
5471 indexBase = gid; // the current min GID
5472 }
5473 }
5474 if (readSuccess == 1) {
5475 // Collect the rest of the GIDs for each PID, and compute
5476 // the global min GID.
5477 for (size_type k = 1; k < globalNumGIDs; ++k) {
5478 const int pid = static_cast<int> (PIDs[k]);
5479 if (pid < 0 || pid >= numProcs) {
5480 readSuccess = 0;
5481 exMsg << "Tpetra::MatrixMarket::readMap: "
5482 << "Encountered invalid PID " << pid << "." << endl;
5483 }
5484 else {
5485 const int_type gid = GIDs[k];
5486 pid2gids[pid].push_back (gid);
5487 if (gid < indexBase) {
5488 indexBase = gid; // the current min GID
5489 }
5490 }
5491 }
5492 }
5493 }
5494 else if (data->getNumVectors () == 1) { // Map format 2.0
5495 if (data->getGlobalLength () % 2 != static_cast<GST> (0)) {
5496 readSuccess = 0;
5497 exMsg << "Tpetra::MatrixMarket::readMap: Input data has the "
5498 "wrong format (for Map format 2.0). The global number of rows "
5499 "in the MultiVector must be even (divisible by 2)." << endl;
5500 }
5501 else {
5502 ArrayRCP<const GO> theData = data->getData (0);
5503 globalNumGIDs = static_cast<GO> (data->getGlobalLength ()) /
5504 static_cast<GO> (2);
5505
5506 // Start computing the global min GID, while
5507 // collecting the GIDs for each PID.
5508 if (globalNumGIDs > 0) {
5509 const int pid = static_cast<int> (theData[1]);
5510 if (pid < 0 || pid >= numProcs) {
5511 readSuccess = 0;
5512 exMsg << "Tpetra::MatrixMarket::readMap: "
5513 << "Encountered invalid PID " << pid << "." << endl;
5514 }
5515 else {
5516 const GO gid = theData[0];
5517 pid2gids[pid].push_back (gid);
5518 indexBase = gid; // the current min GID
5519 }
5520 }
5521 // Collect the rest of the GIDs for each PID, and
5522 // compute the global min GID.
5523 for (int_type k = 1; k < globalNumGIDs; ++k) {
5524 const int pid = static_cast<int> (theData[2*k + 1]);
5525 if (pid < 0 || pid >= numProcs) {
5526 readSuccess = 0;
5527 exMsg << "Tpetra::MatrixMarket::readMap: "
5528 << "Encountered invalid PID " << pid << "." << endl;
5529 }
5530 else {
5531 const GO gid = theData[2*k];
5532 pid2gids[pid].push_back (gid);
5533 if (gid < indexBase) {
5534 indexBase = gid; // the current min GID
5535 }
5536 }
5537 } // for each GID
5538 } // if the amount of data is correct
5539 }
5540 else {
5541 readSuccess = 0;
5542 exMsg << "Tpetra::MatrixMarket::readMap: Input data must have "
5543 "either 1 column (for the new Map format 2.0) or 2 columns (for "
5544 "the old Map format 1.0).";
5545 }
5546 } // myRank is zero
5547
5548 // Broadcast the indexBase, the global number of GIDs, and the
5549 // current success status. Use int_type for all of these.
5550 {
5551 int_type readResults[3];
5552 readResults[0] = static_cast<int_type> (indexBase);
5553 readResults[1] = static_cast<int_type> (globalNumGIDs);
5554 readResults[2] = static_cast<int_type> (readSuccess);
5555 broadcast<int, int_type> (*comm, 0, 3, readResults);
5556
5557 indexBase = static_cast<GO> (readResults[0]);
5558 globalNumGIDs = static_cast<int_type> (readResults[1]);
5559 readSuccess = static_cast<int> (readResults[2]);
5560 }
5561
5562 // Unwinding the stack will invoke sizeReq's destructor, which
5563 // will cancel the receive-size request on all processes that
5564 // posted it.
5565 TEUCHOS_TEST_FOR_EXCEPTION(
5566 readSuccess != 1, std::runtime_error,
5567 "Tpetra::MatrixMarket::readMap: Reading the Map failed with the "
5568 "following exception message: " << exMsg.str ());
5569
5570 if (myRank == 0) {
5571 // Proc 0: Send each process' number of GIDs to that process.
5572 for (int p = 1; p < numProcs; ++p) {
5573 ArrayRCP<int_type> numGidsToSend (1);
5574
5575 auto it = pid2gids.find (p);
5576 if (it == pid2gids.end ()) {
5577 numGidsToSend[0] = 0;
5578 } else {
5579 numGidsToSend[0] = it->second.size ();
5580 }
5581 sizeReq = isend<int, int_type> (numGidsToSend, p, sizeTag, *comm);
5582 wait<int> (*comm, outArg (sizeReq));
5583 }
5584 }
5585 else {
5586 // Wait on the receive-size message to finish.
5587 wait<int> (*comm, outArg (sizeReq));
5588 }
5589
5590 // Allocate / get the array for my GIDs.
5591 // Only Process 0 will have its actual GIDs at this point.
5592 ArrayRCP<GO> myGids;
5593 int_type myNumGids = 0;
5594 if (myRank == 0) {
5595 GO* myGidsRaw = NULL;
5596
5597 typename std::map<int, Array<GO> >::iterator it = pid2gids.find (0);
5598 if (it != pid2gids.end ()) {
5599 myGidsRaw = it->second.getRawPtr ();
5600 myNumGids = it->second.size ();
5601 // Nonowning ArrayRCP just views the Array.
5602 myGids = arcp<GO> (myGidsRaw, 0, myNumGids, false);
5603 }
5604 }
5605 else { // myRank != 0
5606 myNumGids = numGidsToRecv[0];
5607 myGids = arcp<GO> (myNumGids);
5608 }
5609
5610 if (myRank != 0) {
5611 // Post receive for data, now that we know how much data we
5612 // will receive. Only post receive if my process actually
5613 // has nonzero GIDs.
5614 if (myNumGids > 0) {
5615 dataReq = ireceive<int, GO> (myGids, 0, dataTag, *comm);
5616 }
5617 }
5618
5619 for (int p = 1; p < numProcs; ++p) {
5620 if (myRank == 0) {
5621 ArrayRCP<GO> sendGids; // to send to Process p
5622 GO* sendGidsRaw = NULL;
5623 int_type numSendGids = 0;
5624
5625 typename std::map<int, Array<GO> >::iterator it = pid2gids.find (p);
5626 if (it != pid2gids.end ()) {
5627 numSendGids = it->second.size ();
5628 sendGidsRaw = it->second.getRawPtr ();
5629 sendGids = arcp<GO> (sendGidsRaw, 0, numSendGids, false);
5630 }
5631 // Only send if that process actually has nonzero GIDs.
5632 if (numSendGids > 0) {
5633 dataReq = isend<int, GO> (sendGids, p, dataTag, *comm);
5634 }
5635 wait<int> (*comm, outArg (dataReq));
5636 }
5637 else if (myRank == p) {
5638 // Wait on my receive of GIDs to finish.
5639 wait<int> (*comm, outArg (dataReq));
5640 }
5641 } // for each process rank p in 1, 2, ..., numProcs-1
5642
5643 if (debug) {
5644 std::ostringstream os;
5645 os << myRank << ": readMap: creating Map" << endl;
5646 *err << os.str ();
5647 }
5648 const GST INVALID = Teuchos::OrdinalTraits<GST>::invalid ();
5649 RCP<const map_type> newMap;
5650
5651 // Create the Map; test whether the constructor threw. This
5652 // avoids deadlock and makes error reporting more readable.
5653
5654 int lclSuccess = 1;
5655 int gblSuccess = 0; // output argument
5656 std::ostringstream errStrm;
5657 try {
5658 newMap = rcp (new map_type (INVALID, myGids (), indexBase, comm));
5659 }
5660 catch (std::exception& e) {
5661 lclSuccess = 0;
5662 errStrm << "Process " << comm->getRank () << " threw an exception: "
5663 << e.what () << std::endl;
5664 }
5665 catch (...) {
5666 lclSuccess = 0;
5667 errStrm << "Process " << comm->getRank () << " threw an exception "
5668 "not a subclass of std::exception" << std::endl;
5669 }
5670 Teuchos::reduceAll<int, int> (*comm, Teuchos::REDUCE_MIN,
5671 lclSuccess, Teuchos::outArg (gblSuccess));
5672 if (gblSuccess != 1) {
5673 Tpetra::Details::gathervPrint (std::cerr, errStrm.str (), *comm);
5674 }
5675 TEUCHOS_TEST_FOR_EXCEPTION(gblSuccess != 1, std::runtime_error, "Map constructor failed!");
5676
5677 if (err.is_null ()) {
5678 err->popTab ();
5679 }
5680 if (debug) {
5681 std::ostringstream os;
5682 os << myRank << ": readMap: done" << endl;
5683 *err << os.str ();
5684 }
5685 if (err.is_null ()) {
5686 err->popTab ();
5687 }
5688 return newMap;
5689 }
5690
5691
5692 private:
5693
5704 static int
5705 encodeDataType (const std::string& dataType)
5706 {
5707 if (dataType == "real" || dataType == "integer") {
5708 return 0;
5709 } else if (dataType == "complex") {
5710 return 1;
5711 } else if (dataType == "pattern") {
5712 return 2;
5713 } else {
5714 // We should never get here, since Banner validates the
5715 // reported data type and ensures it is one of the accepted
5716 // values.
5717 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
5718 "Unrecognized Matrix Market data type \"" << dataType
5719 << "\". We should never get here. "
5720 "Please report this bug to the Tpetra developers.");
5721 }
5722 }
5723
5724 public:
5725
5755 static Teuchos::RCP<sparse_matrix_type>
5756 readSparsePerRank (const std::string& filename_prefix,
5757 const std::string& filename_suffix,
5758 const Teuchos::RCP<const map_type>& rowMap,
5759 Teuchos::RCP<const map_type>& colMap,
5760 const Teuchos::RCP<const map_type>& domainMap,
5761 const Teuchos::RCP<const map_type>& rangeMap,
5762 const bool callFillComplete=true,
5763 const bool tolerant=false,
5764 const int ranksToReadAtOnce=8,
5765 const bool debug=false)
5766 {
5767 using ST = scalar_type;
5768 using LO = local_ordinal_type;
5769 using GO = global_ordinal_type;
5770 using STS = typename Teuchos::ScalarTraits<ST>;
5771 using Teuchos::RCP;
5772 using Teuchos::ArrayRCP;
5773 using Teuchos::arcp;
5774 using Teuchos::rcp;
5775
5776 // Sanity Checks
5777 // Fast checks for invalid input. We can't check other
5778 // attributes of the Maps until we've read in the matrix
5779 // dimensions.
5780 TEUCHOS_TEST_FOR_EXCEPTION(
5781 rowMap.is_null (), std::invalid_argument,
5782 "Row Map must be nonnull.");
5783 Teuchos::RCP<const Teuchos::Comm<int> > comm = rowMap->getComm();
5784 TEUCHOS_TEST_FOR_EXCEPTION
5785 (comm.is_null (), std::invalid_argument,
5786 "The input row map's communicator (Teuchos::Comm object) is null.");
5787 TEUCHOS_TEST_FOR_EXCEPTION(
5788 rangeMap.is_null (), std::invalid_argument,
5789 "Range Map must be nonnull.");
5790 TEUCHOS_TEST_FOR_EXCEPTION(
5791 domainMap.is_null (), std::invalid_argument,
5792 "Domain Map must be nonnull.");
5793 TEUCHOS_TEST_FOR_EXCEPTION(
5794 domainMap->getComm().getRawPtr() != comm.getRawPtr(),
5795 std::invalid_argument,
5796 "The specified domain Map's communicator (domainMap->getComm())"
5797 "differs from row Map's communicator");
5798 TEUCHOS_TEST_FOR_EXCEPTION(
5799 rangeMap->getComm().getRawPtr() != comm.getRawPtr(),
5800 std::invalid_argument,
5801 "The specified range Map's communicator (rangeMap->getComm())"
5802 "differs from row Map's communicator");
5803
5804 // Setup
5805 const int myRank = comm->getRank();
5806 const int numProc = comm->getSize();
5807 std::string filename = filename_prefix + std::to_string(myRank) + filename_suffix;
5808
5809 // Bounds check the writing limits
5810 int rank_limit = std::min(std::max(ranksToReadAtOnce,1),numProc);
5811
5812 // Data structures for constructor
5813 ArrayRCP<size_t> numEntriesPerRow;
5814 ArrayRCP<size_t> rowPtr;
5815 ArrayRCP<global_ordinal_type> colInd;
5816 ArrayRCP<scalar_type> values;
5817 std::ostringstream errMsg;
5818
5820 // Start the reading of the banners to get
5821 // local row / nnz counts and then read the
5822 // data. We'll pack everything into big ol'
5823 // rowptr/colind/values ArrayRCPs
5824 bool success = true;
5825 int bannerIsCorrect = 1, readSuccess = 1;
5826 LO numRows, numCols, numNonzeros;
5827 for(int base_rank = 0; base_rank < numProc; base_rank += rank_limit) {
5828 int stop = std::min(base_rank+rank_limit,numProc);
5829
5830 // Is my rank in this batch?
5831 if(base_rank <= myRank && myRank < stop) {
5832 // My turn to read
5833 std::ifstream in(filename);
5834 using Teuchos::MatrixMarket::Banner;
5835 size_t lineNumber = 1;
5836 RCP<const Banner> pBanner;
5837 try {
5838 pBanner = readBanner (in, lineNumber, tolerant, debug);
5839 }
5840 catch (std::exception& e) {
5841 errMsg << "Attempt to read the Matrix Market file's Banner line "
5842 "threw an exception: " << e.what();
5843 bannerIsCorrect = 0;
5844 }
5845 if (bannerIsCorrect) {
5846 // Validate the Banner for the case of a sparse matrix.
5847 // We validate on Proc 0, since it reads the Banner.
5848
5849 // In intolerant mode, the matrix type must be "coordinate".
5850 if (! tolerant && pBanner->matrixType() != "coordinate") {
5851 bannerIsCorrect = 0;
5852 errMsg << "The Matrix Market input file must contain a "
5853 "\"coordinate\"-format sparse matrix in order to create a "
5854 "Tpetra::CrsMatrix object from it, but the file's matrix "
5855 "type is \"" << pBanner->matrixType() << "\" instead.";
5856 }
5857 // In tolerant mode, we allow the matrix type to be
5858 // anything other than "array" (which would mean that
5859 // the file contains a dense matrix).
5860 if (tolerant && pBanner->matrixType() == "array") {
5861 bannerIsCorrect = 0;
5862 errMsg << "Matrix Market file must contain a \"coordinate\"-"
5863 "format sparse matrix in order to create a Tpetra::CrsMatrix "
5864 "object from it, but the file's matrix type is \"array\" "
5865 "instead. That probably means the file contains dense matrix "
5866 "data.";
5867 }
5868 }
5869
5870 // Unpacked coordinate matrix dimensions
5871 using Teuchos::MatrixMarket::readCoordinateDimensions;
5872 success = readCoordinateDimensions (in, numRows, numCols,
5873 numNonzeros, lineNumber,
5874 tolerant);
5875
5876 // Sanity checking of headers
5877 TEUCHOS_TEST_FOR_EXCEPTION(numRows != (LO)rowMap->getLocalNumElements(), std::invalid_argument,
5878 "# rows in file does not match rowmap.");
5879 TEUCHOS_TEST_FOR_EXCEPTION(!colMap.is_null() && numCols != (LO)colMap->getLocalNumElements(), std::invalid_argument,
5880 "# rows in file does not match colmap.");
5881
5882
5883 // Read the data
5884 typedef Teuchos::MatrixMarket::Raw::Adder<scalar_type,global_ordinal_type> raw_adder_type;
5885 bool tolerant_required = true;
5886 Teuchos::RCP<raw_adder_type> pRaw =
5887 Teuchos::rcp (new raw_adder_type (numRows,numCols,numNonzeros,tolerant_required,debug));
5888 RCP<adder_type> pAdder = Teuchos::rcp (new adder_type (pRaw, pBanner->symmType ()));
5889
5890 if (debug) {
5891 std::cerr << "-- Reading matrix data" << std::endl;
5892 }
5893
5894 try {
5895 // Reader for "coordinate" format sparse matrix data.
5896 typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
5897 global_ordinal_type, scalar_type, STS::isComplex> reader_type;
5898 reader_type reader (pAdder);
5899
5900 // Read the sparse matrix entries.
5901 std::pair<bool, std::vector<size_t> > results = reader.read (in, lineNumber, tolerant_required, debug);
5902
5903
5904 readSuccess = results.first ? 1 : 0;
5905 }
5906 catch (std::exception& e) {
5907 readSuccess = 0;
5908 errMsg << e.what();
5909 }
5910
5912 // Create the CSR Arrays
5913 typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,global_ordinal_type> element_type;
5914
5915 // Additively merge duplicate matrix entries.
5916 pAdder->getAdder()->merge ();
5917
5918 // Get a temporary const view of the merged matrix entries.
5919 const std::vector<element_type>& entries = pAdder->getAdder()->getEntries();
5920
5921 // Number of matrix entries (after merging).
5922 const size_t numEntries = (size_t)entries.size();
5923
5924 if (debug) {
5925 std::cerr << "----- Proc "<<myRank<<": Matrix has numRows=" << numRows
5926 << " rows and numEntries=" << numEntries
5927 << " entries." << std::endl;
5928 }
5929
5930
5931 // Make space for the CSR matrix data. Converting to
5932 // CSR is easier if we fill numEntriesPerRow with zeros
5933 // at first.
5934 numEntriesPerRow = arcp<size_t> (numRows);
5935 std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
5936 rowPtr = arcp<size_t> (numRows+1);
5937 std::fill (rowPtr.begin(), rowPtr.end(), 0);
5938 colInd = arcp<global_ordinal_type> (numEntries);
5939 values = arcp<scalar_type> (numEntries);
5940
5941 // Convert from array-of-structs coordinate format to CSR
5942 // (compressed sparse row) format.
5943 global_ordinal_type l_prvRow = 0;
5944 size_t curPos = 0;
5945 LO INVALID = Teuchos::OrdinalTraits<LO>::invalid();
5946 rowPtr[0] = 0;
5947 LO indexBase = rowMap->getIndexBase();
5948 for (curPos = 0; curPos < numEntries; ++curPos) {
5949 const element_type& curEntry = entries[curPos];
5950 const global_ordinal_type curRow = curEntry.rowIndex() + indexBase;
5951 LO l_curRow = rowMap->getLocalElement(curRow);
5952
5953
5954 TEUCHOS_TEST_FOR_EXCEPTION(l_curRow == INVALID,std::logic_error,
5955 "Current global row "<< curRow << " is invalid.");
5956
5957 TEUCHOS_TEST_FOR_EXCEPTION(l_curRow < l_prvRow, std::logic_error,
5958 "Row indices are out of order, even though they are supposed "
5959 "to be sorted. curRow = " << l_curRow << ", prvRow = "
5960 << l_prvRow << ", at curPos = " << curPos << ". Please report "
5961 "this bug to the Tpetra developers.");
5962 if (l_curRow > l_prvRow) {
5963 for (LO r = l_prvRow+1; r <= l_curRow; ++r) {
5964 rowPtr[r] = curPos;
5965 }
5966 l_prvRow = l_curRow;
5967 }
5968 numEntriesPerRow[l_curRow]++;
5969 colInd[curPos] = curEntry.colIndex() + indexBase;
5970 values[curPos] = curEntry.value();
5971
5972 }
5973 // rowPtr has one more entry than numEntriesPerRow. The
5974 // last entry of rowPtr is the number of entries in
5975 // colInd and values.
5976 rowPtr[numRows] = numEntries;
5977
5978 }// end base_rank <= myRank < stop
5979
5980 // Barrier between batches to keep the filesystem happy
5981 comm->barrier();
5982
5983 }//end outer rank loop
5984
5985
5986 // Call the matrix constructor and fill. This isn't particularly efficient
5987 RCP<sparse_matrix_type> A;
5988 if(colMap.is_null()) {
5989 A=rcp(new sparse_matrix_type(rowMap,numEntriesPerRow()));
5990 for(size_t i=0; i<rowMap->getLocalNumElements(); i++) {
5991 GO g_row = rowMap->getGlobalElement(i);
5992 size_t start = rowPtr[i];
5993 size_t size = rowPtr[i+1] - rowPtr[i];
5994 if(size>0) {
5995 A->insertGlobalValues(g_row,size,&values[start],&colInd[start]);
5996 }
5997 }
5998 }
5999 else {
6000 throw std::runtime_error("Reading with a column map is not yet implemented");
6001 }
6002 RCP<const map_type> myDomainMap = domainMap.is_null() ? rowMap : domainMap;
6003 RCP<const map_type> myRangeMap = rangeMap.is_null() ? rowMap : rangeMap;
6004
6005 A->fillComplete(myDomainMap,myRangeMap);
6006
6007 if(!readSuccess)
6008 success = false;
6009 TEUCHOS_TEST_FOR_EXCEPTION(success == false, std::runtime_error,
6010 "Read failed.");
6011
6012 return A;
6013 }// end readSparsePerRank
6014
6015
6016 }; // class Reader
6017
6046 template<class SparseMatrixType>
6047 class Writer {
6048 public:
6050 typedef SparseMatrixType sparse_matrix_type;
6051 typedef Teuchos::RCP<sparse_matrix_type> sparse_matrix_ptr;
6052
6054 typedef typename SparseMatrixType::scalar_type scalar_type;
6056 typedef typename SparseMatrixType::local_ordinal_type local_ordinal_type;
6062 typedef typename SparseMatrixType::global_ordinal_type global_ordinal_type;
6064 typedef typename SparseMatrixType::node_type node_type;
6065
6067 typedef MultiVector<scalar_type,
6075
6078
6110 static void
6111 writeSparseFile (const std::string& filename,
6112 const sparse_matrix_type& matrix,
6113 const std::string& matrixName,
6114 const std::string& matrixDescription,
6115 const bool debug=false)
6116 {
6117 Teuchos::RCP<const Teuchos::Comm<int> > comm = matrix.getComm ();
6118 TEUCHOS_TEST_FOR_EXCEPTION
6119 (comm.is_null (), std::invalid_argument,
6120 "The input matrix's communicator (Teuchos::Comm object) is null.");
6121 const int myRank = comm->getRank ();
6122 std::ofstream out;
6123
6124 // Only open the file on Rank 0.
6125 if (myRank == 0) {
6126 out.open (filename.c_str ());
6127 }
6128 writeSparse (out, matrix, matrixName, matrixDescription, debug);
6129 // We can rely on the destructor of the output stream to close
6130 // the file on scope exit, even if writeSparse() throws an
6131 // exception.
6132 }
6133
6135 static void
6136 writeSparseFile (const std::string& filename,
6137 const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6138 const std::string& matrixName,
6139 const std::string& matrixDescription,
6140 const bool debug=false)
6141 {
6142 TEUCHOS_TEST_FOR_EXCEPTION
6143 (pMatrix.is_null (), std::invalid_argument,
6144 "The input matrix is null.");
6145 writeSparseFile (filename, *pMatrix, matrixName,
6146 matrixDescription, debug);
6147 }
6148
6168 static void
6169 writeSparseFile (const std::string& filename,
6170 const sparse_matrix_type& matrix,
6171 const bool debug=false)
6172 {
6173 writeSparseFile (filename, matrix, "", "", debug);
6174 }
6175
6177 static void
6178 writeSparseFile (const std::string& filename,
6179 const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6180 const bool debug=false)
6181 {
6182 writeSparseFile (filename, *pMatrix, "", "", debug);
6183 }
6184
6215 static void
6216 writeSparse (std::ostream& out,
6217 const sparse_matrix_type& matrix,
6218 const std::string& matrixName,
6219 const std::string& matrixDescription,
6220 const bool debug=false)
6221 {
6222 using Teuchos::ArrayView;
6223 using Teuchos::Comm;
6224 using Teuchos::FancyOStream;
6225 using Teuchos::getFancyOStream;
6226 using Teuchos::null;
6227 using Teuchos::RCP;
6228 using Teuchos::rcpFromRef;
6229 using std::cerr;
6230 using std::endl;
6231 using ST = scalar_type;
6232 using LO = local_ordinal_type;
6233 using GO = global_ordinal_type;
6234 using STS = typename Teuchos::ScalarTraits<ST>;
6235
6236 // Make the output stream write floating-point numbers in
6237 // scientific notation. It will politely put the output
6238 // stream back to its state on input, when this scope
6239 // terminates.
6240 Teuchos::SetScientific<ST> sci (out);
6241
6242 // Get the matrix's communicator.
6243 RCP<const Comm<int> > comm = matrix.getComm ();
6244 TEUCHOS_TEST_FOR_EXCEPTION(
6245 comm.is_null (), std::invalid_argument,
6246 "The input matrix's communicator (Teuchos::Comm object) is null.");
6247 const int myRank = comm->getRank ();
6248
6249 // Optionally, make a stream for debugging output.
6250 RCP<FancyOStream> err =
6251 debug ? getFancyOStream (rcpFromRef (std::cerr)) : null;
6252 if (debug) {
6253 std::ostringstream os;
6254 os << myRank << ": writeSparse" << endl;
6255 *err << os.str ();
6256 comm->barrier ();
6257 os << "-- " << myRank << ": past barrier" << endl;
6258 *err << os.str ();
6259 }
6260
6261 // Whether to print debugging output to stderr.
6262 const bool debugPrint = debug && myRank == 0;
6263
6264 RCP<const map_type> rowMap = matrix.getRowMap ();
6265 RCP<const map_type> colMap = matrix.getColMap ();
6266 RCP<const map_type> domainMap = matrix.getDomainMap ();
6267 RCP<const map_type> rangeMap = matrix.getRangeMap ();
6268
6269 const global_size_t numRows = rangeMap->getGlobalNumElements ();
6270 const global_size_t numCols = domainMap->getGlobalNumElements ();
6271
6272 if (debug && myRank == 0) {
6273 std::ostringstream os;
6274 os << "-- Input sparse matrix is:"
6275 << "---- " << numRows << " x " << numCols << endl
6276 << "---- "
6277 << (matrix.isGloballyIndexed() ? "Globally" : "Locally")
6278 << " indexed." << endl
6279 << "---- Its row map has " << rowMap->getGlobalNumElements ()
6280 << " elements." << endl
6281 << "---- Its col map has " << colMap->getGlobalNumElements ()
6282 << " elements." << endl;
6283 *err << os.str ();
6284 }
6285 // Make the "gather" row map, where Proc 0 owns all rows and
6286 // the other procs own no rows.
6287 const size_t localNumRows = (myRank == 0) ? numRows : 0;
6288 if (debug) {
6289 std::ostringstream os;
6290 os << "-- " << myRank << ": making gatherRowMap" << endl;
6291 *err << os.str ();
6292 }
6293 RCP<const map_type> gatherRowMap =
6294 Details::computeGatherMap (rowMap, err, debug);
6295
6296 // Since the matrix may in general be non-square, we need to
6297 // make a column map as well. In this case, the column map
6298 // contains all the columns of the original matrix, because we
6299 // are gathering the whole matrix onto Proc 0. We call
6300 // computeGatherMap to preserve the original order of column
6301 // indices over all the processes.
6302 const size_t localNumCols = (myRank == 0) ? numCols : 0;
6303 RCP<const map_type> gatherColMap =
6304 Details::computeGatherMap (colMap, err, debug);
6305
6306 // Current map is the source map, gather map is the target map.
6308 import_type importer (rowMap, gatherRowMap);
6309
6310 // Create a new CrsMatrix to hold the result of the import.
6311 // The constructor needs a column map as well as a row map,
6312 // for the case that the matrix is not square.
6313 RCP<sparse_matrix_type> newMatrix =
6314 rcp (new sparse_matrix_type (gatherRowMap, gatherColMap,
6315 static_cast<size_t> (0)));
6316 // Import the sparse matrix onto Proc 0.
6317 newMatrix->doImport (matrix, importer, INSERT);
6318
6319 // fillComplete() needs the domain and range maps for the case
6320 // that the matrix is not square.
6321 {
6322 RCP<const map_type> gatherDomainMap =
6323 rcp (new map_type (numCols, localNumCols,
6324 domainMap->getIndexBase (),
6325 comm));
6326 RCP<const map_type> gatherRangeMap =
6327 rcp (new map_type (numRows, localNumRows,
6328 rangeMap->getIndexBase (),
6329 comm));
6330 newMatrix->fillComplete (gatherDomainMap, gatherRangeMap);
6331 }
6332
6333 if (debugPrint) {
6334 cerr << "-- Output sparse matrix is:"
6335 << "---- " << newMatrix->getRangeMap ()->getGlobalNumElements ()
6336 << " x "
6337 << newMatrix->getDomainMap ()->getGlobalNumElements ()
6338 << " with "
6339 << newMatrix->getGlobalNumEntries () << " entries;" << endl
6340 << "---- "
6341 << (newMatrix->isGloballyIndexed () ? "Globally" : "Locally")
6342 << " indexed." << endl
6343 << "---- Its row map has "
6344 << newMatrix->getRowMap ()->getGlobalNumElements ()
6345 << " elements, with index base "
6346 << newMatrix->getRowMap ()->getIndexBase () << "." << endl
6347 << "---- Its col map has "
6348 << newMatrix->getColMap ()->getGlobalNumElements ()
6349 << " elements, with index base "
6350 << newMatrix->getColMap ()->getIndexBase () << "." << endl
6351 << "---- Element count of output matrix's column Map may differ "
6352 << "from that of the input matrix's column Map, if some columns "
6353 << "of the matrix contain no entries." << endl;
6354 }
6355
6356 //
6357 // Print the metadata and the matrix entries on Rank 0.
6358 //
6359 if (myRank == 0) {
6360 // Print the Matrix Market banner line. CrsMatrix stores
6361 // data nonsymmetrically ("general"). This implies that
6362 // readSparse() on a symmetrically stored input file,
6363 // followed by writeSparse() on the resulting sparse matrix,
6364 // will result in an output file with a different banner
6365 // line than the original input file.
6366 out << "%%MatrixMarket matrix coordinate "
6367 << (STS::isComplex ? "complex" : "real")
6368 << " general" << endl;
6369
6370 // Print comments (the matrix name and / or description).
6371 if (matrixName != "") {
6372 printAsComment (out, matrixName);
6373 }
6374 if (matrixDescription != "") {
6375 printAsComment (out, matrixDescription);
6376 }
6377
6378 // Print the Matrix Market header (# rows, # columns, #
6379 // nonzeros). Use the range resp. domain map for the number
6380 // of rows resp. columns, since Tpetra::CrsMatrix uses the
6381 // column map for the number of columns. That only
6382 // corresponds to the "linear-algebraic" number of columns
6383 // when the column map is uniquely owned (a.k.a. one-to-one),
6384 // which only happens if the matrix is (block) diagonal.
6385 out << newMatrix->getRangeMap ()->getGlobalNumElements () << " "
6386 << newMatrix->getDomainMap ()->getGlobalNumElements () << " "
6387 << newMatrix->getGlobalNumEntries () << endl;
6388
6389 // The Matrix Market format expects one-based row and column
6390 // indices. We'll convert the indices on output from
6391 // whatever index base they use to one-based indices.
6392 const GO rowIndexBase = gatherRowMap->getIndexBase ();
6393 const GO colIndexBase = newMatrix->getColMap()->getIndexBase ();
6394 //
6395 // Print the entries of the matrix.
6396 //
6397 // newMatrix can never be globally indexed, since we called
6398 // fillComplete() on it. We include code for both cases
6399 // (globally or locally indexed) just in case that ever
6400 // changes.
6401 if (newMatrix->isGloballyIndexed()) {
6402 // We know that the "gather" row Map is contiguous, so we
6403 // don't need to get the list of GIDs.
6404 const GO minAllGlobalIndex = gatherRowMap->getMinAllGlobalIndex ();
6405 const GO maxAllGlobalIndex = gatherRowMap->getMaxAllGlobalIndex ();
6406 for (GO globalRowIndex = minAllGlobalIndex;
6407 globalRowIndex <= maxAllGlobalIndex; // inclusive range
6408 ++globalRowIndex) {
6409 typename sparse_matrix_type::global_inds_host_view_type ind;
6410 typename sparse_matrix_type::values_host_view_type val;
6411 newMatrix->getGlobalRowView (globalRowIndex, ind, val);
6412 for (size_t ii = 0; ii < ind.extent(0); ii++) {
6413 const GO globalColIndex = ind(ii);
6414 // Convert row and column indices to 1-based.
6415 // This works because the global index type is signed.
6416 out << (globalRowIndex + 1 - rowIndexBase) << " "
6417 << (globalColIndex + 1 - colIndexBase) << " ";
6418 if (STS::isComplex) {
6419 out << STS::real (val(ii)) << " " << STS::imag (val(ii));
6420 } else {
6421 out << val(ii);
6422 }
6423 out << endl;
6424 } // For each entry in the current row
6425 } // For each row of the "gather" matrix
6426 }
6427 else { // newMatrix is locally indexed
6428 using OTG = Teuchos::OrdinalTraits<GO>;
6429 for (LO localRowIndex = gatherRowMap->getMinLocalIndex();
6430 localRowIndex <= gatherRowMap->getMaxLocalIndex();
6431 ++localRowIndex) {
6432 // Convert from local to global row index.
6433 const GO globalRowIndex =
6434 gatherRowMap->getGlobalElement (localRowIndex);
6435 TEUCHOS_TEST_FOR_EXCEPTION(
6436 globalRowIndex == OTG::invalid(), std::logic_error,
6437 "Failed to convert the supposed local row index "
6438 << localRowIndex << " into a global row index. "
6439 "Please report this bug to the Tpetra developers.");
6440 typename sparse_matrix_type::local_inds_host_view_type ind;
6441 typename sparse_matrix_type::values_host_view_type val;
6442 newMatrix->getLocalRowView (localRowIndex, ind, val);
6443 for (size_t ii = 0; ii < ind.extent(0); ii++) {
6444 // Convert the column index from local to global.
6445 const GO globalColIndex =
6446 newMatrix->getColMap()->getGlobalElement (ind(ii));
6447 TEUCHOS_TEST_FOR_EXCEPTION(
6448 globalColIndex == OTG::invalid(), std::logic_error,
6449 "On local row " << localRowIndex << " of the sparse matrix: "
6450 "Failed to convert the supposed local column index "
6451 << ind(ii) << " into a global column index. Please report "
6452 "this bug to the Tpetra developers.");
6453 // Convert row and column indices to 1-based.
6454 // This works because the global index type is signed.
6455 out << (globalRowIndex + 1 - rowIndexBase) << " "
6456 << (globalColIndex + 1 - colIndexBase) << " ";
6457 if (STS::isComplex) {
6458 out << STS::real (val(ii)) << " " << STS::imag (val(ii));
6459 } else {
6460 out << val(ii);
6461 }
6462 out << endl;
6463 } // For each entry in the current row
6464 } // For each row of the "gather" matrix
6465 } // Whether the "gather" matrix is locally or globally indexed
6466 } // If my process' rank is 0
6467 }
6468
6470 static void
6471 writeSparse (std::ostream& out,
6472 const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6473 const std::string& matrixName,
6474 const std::string& matrixDescription,
6475 const bool debug=false)
6476 {
6477 TEUCHOS_TEST_FOR_EXCEPTION
6478 (pMatrix.is_null (), std::invalid_argument,
6479 "The input matrix is null.");
6480 writeSparse (out, *pMatrix, matrixName, matrixDescription, debug);
6481 }
6482
6513 static void
6514 writeSparseGraph (std::ostream& out,
6515 const crs_graph_type& graph,
6516 const std::string& graphName,
6517 const std::string& graphDescription,
6518 const bool debug=false)
6519 {
6520 using Teuchos::ArrayView;
6521 using Teuchos::Comm;
6522 using Teuchos::FancyOStream;
6523 using Teuchos::getFancyOStream;
6524 using Teuchos::null;
6525 using Teuchos::RCP;
6526 using Teuchos::rcpFromRef;
6527 using std::cerr;
6528 using std::endl;
6529 typedef local_ordinal_type LO;
6530 typedef global_ordinal_type GO;
6531
6532 // Get the graph's communicator. Processes on which the
6533 // graph's Map or communicator is null don't participate in
6534 // this operation. This function shouldn't even be called on
6535 // those processes.
6536 auto rowMap = graph.getRowMap ();
6537 if (rowMap.is_null ()) {
6538 return;
6539 }
6540 auto comm = rowMap->getComm ();
6541 if (comm.is_null ()) {
6542 return;
6543 }
6544 const int myRank = comm->getRank ();
6545
6546 // Optionally, make a stream for debugging output.
6547 RCP<FancyOStream> err =
6548 debug ? getFancyOStream (rcpFromRef (std::cerr)) : null;
6549 if (debug) {
6550 std::ostringstream os;
6551 os << myRank << ": writeSparseGraph" << endl;
6552 *err << os.str ();
6553 comm->barrier ();
6554 os << "-- " << myRank << ": past barrier" << endl;
6555 *err << os.str ();
6556 }
6557
6558 // Whether to print debugging output to stderr.
6559 const bool debugPrint = debug && myRank == 0;
6560
6561 // We've already gotten the rowMap above.
6562 auto colMap = graph.getColMap ();
6563 auto domainMap = graph.getDomainMap ();
6564 auto rangeMap = graph.getRangeMap ();
6565
6566 const global_size_t numRows = rangeMap->getGlobalNumElements ();
6567 const global_size_t numCols = domainMap->getGlobalNumElements ();
6568
6569 if (debug && myRank == 0) {
6570 std::ostringstream os;
6571 os << "-- Input sparse graph is:"
6572 << "---- " << numRows << " x " << numCols << " with "
6573 << graph.getGlobalNumEntries () << " entries;" << endl
6574 << "---- "
6575 << (graph.isGloballyIndexed () ? "Globally" : "Locally")
6576 << " indexed." << endl
6577 << "---- Its row Map has " << rowMap->getGlobalNumElements ()
6578 << " elements." << endl
6579 << "---- Its col Map has " << colMap->getGlobalNumElements ()
6580 << " elements." << endl;
6581 *err << os.str ();
6582 }
6583 // Make the "gather" row map, where Proc 0 owns all rows and
6584 // the other procs own no rows.
6585 const size_t localNumRows = (myRank == 0) ? numRows : 0;
6586 if (debug) {
6587 std::ostringstream os;
6588 os << "-- " << myRank << ": making gatherRowMap" << endl;
6589 *err << os.str ();
6590 }
6591 auto gatherRowMap = Details::computeGatherMap (rowMap, err, debug);
6592
6593 // Since the graph may in general be non-square, we need to
6594 // make a column map as well. In this case, the column map
6595 // contains all the columns of the original graph, because we
6596 // are gathering the whole graph onto Proc 0. We call
6597 // computeGatherMap to preserve the original order of column
6598 // indices over all the processes.
6599 const size_t localNumCols = (myRank == 0) ? numCols : 0;
6600 auto gatherColMap = Details::computeGatherMap (colMap, err, debug);
6601
6602 // Current map is the source map, gather map is the target map.
6603 Import<LO, GO, node_type> importer (rowMap, gatherRowMap);
6604
6605 // Create a new CrsGraph to hold the result of the import.
6606 // The constructor needs a column map as well as a row map,
6607 // for the case that the graph is not square.
6608 crs_graph_type newGraph (gatherRowMap, gatherColMap,
6609 static_cast<size_t> (0));
6610 // Import the sparse graph onto Proc 0.
6611 newGraph.doImport (graph, importer, INSERT);
6612
6613 // fillComplete() needs the domain and range maps for the case
6614 // that the graph is not square.
6615 {
6616 RCP<const map_type> gatherDomainMap =
6617 rcp (new map_type (numCols, localNumCols,
6618 domainMap->getIndexBase (),
6619 comm));
6620 RCP<const map_type> gatherRangeMap =
6621 rcp (new map_type (numRows, localNumRows,
6622 rangeMap->getIndexBase (),
6623 comm));
6624 newGraph.fillComplete (gatherDomainMap, gatherRangeMap);
6625 }
6626
6627 if (debugPrint) {
6628 cerr << "-- Output sparse graph is:"
6629 << "---- " << newGraph.getRangeMap ()->getGlobalNumElements ()
6630 << " x "
6631 << newGraph.getDomainMap ()->getGlobalNumElements ()
6632 << " with "
6633 << newGraph.getGlobalNumEntries () << " entries;" << endl
6634 << "---- "
6635 << (newGraph.isGloballyIndexed () ? "Globally" : "Locally")
6636 << " indexed." << endl
6637 << "---- Its row map has "
6638 << newGraph.getRowMap ()->getGlobalNumElements ()
6639 << " elements, with index base "
6640 << newGraph.getRowMap ()->getIndexBase () << "." << endl
6641 << "---- Its col map has "
6642 << newGraph.getColMap ()->getGlobalNumElements ()
6643 << " elements, with index base "
6644 << newGraph.getColMap ()->getIndexBase () << "." << endl
6645 << "---- Element count of output graph's column Map may differ "
6646 << "from that of the input matrix's column Map, if some columns "
6647 << "of the matrix contain no entries." << endl;
6648 }
6649
6650 //
6651 // Print the metadata and the graph entries on Process 0 of
6652 // the graph's communicator.
6653 //
6654 if (myRank == 0) {
6655 // Print the Matrix Market banner line. CrsGraph stores
6656 // data nonsymmetrically ("general"). This implies that
6657 // readSparseGraph() on a symmetrically stored input file,
6658 // followed by writeSparseGraph() on the resulting sparse
6659 // graph, will result in an output file with a different
6660 // banner line than the original input file.
6661 out << "%%MatrixMarket matrix coordinate pattern general" << endl;
6662
6663 // Print comments (the graph name and / or description).
6664 if (graphName != "") {
6665 printAsComment (out, graphName);
6666 }
6667 if (graphDescription != "") {
6668 printAsComment (out, graphDescription);
6669 }
6670
6671 // Print the Matrix Market header (# rows, # columns, #
6672 // stored entries). Use the range resp. domain map for the
6673 // number of rows resp. columns, since Tpetra::CrsGraph uses
6674 // the column map for the number of columns. That only
6675 // corresponds to the "linear-algebraic" number of columns
6676 // when the column map is uniquely owned
6677 // (a.k.a. one-to-one), which only happens if the graph is
6678 // block diagonal (one block per process).
6679 out << newGraph.getRangeMap ()->getGlobalNumElements () << " "
6680 << newGraph.getDomainMap ()->getGlobalNumElements () << " "
6681 << newGraph.getGlobalNumEntries () << endl;
6682
6683 // The Matrix Market format expects one-based row and column
6684 // indices. We'll convert the indices on output from
6685 // whatever index base they use to one-based indices.
6686 const GO rowIndexBase = gatherRowMap->getIndexBase ();
6687 const GO colIndexBase = newGraph.getColMap()->getIndexBase ();
6688 //
6689 // Print the entries of the graph.
6690 //
6691 // newGraph can never be globally indexed, since we called
6692 // fillComplete() on it. We include code for both cases
6693 // (globally or locally indexed) just in case that ever
6694 // changes.
6695 if (newGraph.isGloballyIndexed ()) {
6696 // We know that the "gather" row Map is contiguous, so we
6697 // don't need to get the list of GIDs.
6698 const GO minAllGlobalIndex = gatherRowMap->getMinAllGlobalIndex ();
6699 const GO maxAllGlobalIndex = gatherRowMap->getMaxAllGlobalIndex ();
6700 for (GO globalRowIndex = minAllGlobalIndex;
6701 globalRowIndex <= maxAllGlobalIndex; // inclusive range
6702 ++globalRowIndex) {
6703 typename crs_graph_type::global_inds_host_view_type ind;
6704 newGraph.getGlobalRowView (globalRowIndex, ind);
6705 for (size_t ii = 0; ii < ind.extent(0); ii++) {
6706 const GO globalColIndex = ind(ii);
6707 // Convert row and column indices to 1-based.
6708 // This works because the global index type is signed.
6709 out << (globalRowIndex + 1 - rowIndexBase) << " "
6710 << (globalColIndex + 1 - colIndexBase) << " ";
6711 out << endl;
6712 } // For each entry in the current row
6713 } // For each row of the "gather" graph
6714 }
6715 else { // newGraph is locally indexed
6716 typedef Teuchos::OrdinalTraits<GO> OTG;
6717 for (LO localRowIndex = gatherRowMap->getMinLocalIndex ();
6718 localRowIndex <= gatherRowMap->getMaxLocalIndex ();
6719 ++localRowIndex) {
6720 // Convert from local to global row index.
6721 const GO globalRowIndex =
6722 gatherRowMap->getGlobalElement (localRowIndex);
6723 TEUCHOS_TEST_FOR_EXCEPTION
6724 (globalRowIndex == OTG::invalid (), std::logic_error, "Failed "
6725 "to convert the supposed local row index " << localRowIndex <<
6726 " into a global row index. Please report this bug to the "
6727 "Tpetra developers.");
6728 typename crs_graph_type::local_inds_host_view_type ind;
6729 newGraph.getLocalRowView (localRowIndex, ind);
6730 for (size_t ii = 0; ii < ind.extent(0); ii++) {
6731 // Convert the column index from local to global.
6732 const GO globalColIndex =
6733 newGraph.getColMap ()->getGlobalElement (ind(ii));
6734 TEUCHOS_TEST_FOR_EXCEPTION(
6735 globalColIndex == OTG::invalid(), std::logic_error,
6736 "On local row " << localRowIndex << " of the sparse graph: "
6737 "Failed to convert the supposed local column index "
6738 << ind(ii) << " into a global column index. Please report "
6739 "this bug to the Tpetra developers.");
6740 // Convert row and column indices to 1-based.
6741 // This works because the global index type is signed.
6742 out << (globalRowIndex + 1 - rowIndexBase) << " "
6743 << (globalColIndex + 1 - colIndexBase) << " ";
6744 out << endl;
6745 } // For each entry in the current row
6746 } // For each row of the "gather" graph
6747 } // Whether the "gather" graph is locally or globally indexed
6748 } // If my process' rank is 0
6749 }
6750
6756 static void
6757 writeSparseGraph (std::ostream& out,
6758 const crs_graph_type& graph,
6759 const bool debug=false)
6760 {
6761 writeSparseGraph (out, graph, "", "", debug);
6762 }
6763
6798 static void
6799 writeSparseGraphFile (const std::string& filename,
6800 const crs_graph_type& graph,
6801 const std::string& graphName,
6802 const std::string& graphDescription,
6803 const bool debug=false)
6804 {
6805 auto comm = graph.getComm ();
6806 if (comm.is_null ()) {
6807 // Processes on which the communicator is null shouldn't
6808 // even call this function. The convention is that
6809 // processes on which the object's communicator is null do
6810 // not participate in collective operations involving the
6811 // object.
6812 return;
6813 }
6814 const int myRank = comm->getRank ();
6815 std::ofstream out;
6816
6817 // Only open the file on Process 0.
6818 if (myRank == 0) {
6819 out.open (filename.c_str ());
6820 }
6821 writeSparseGraph (out, graph, graphName, graphDescription, debug);
6822 // We can rely on the destructor of the output stream to close
6823 // the file on scope exit, even if writeSparseGraph() throws
6824 // an exception.
6825 }
6826
6831 static void
6832 writeSparseGraphFile (const std::string& filename,
6833 const crs_graph_type& graph,
6834 const bool debug=false)
6835 {
6836 writeSparseGraphFile (filename, graph, "", "", debug);
6837 }
6838
6847 static void
6848 writeSparseGraphFile (const std::string& filename,
6849 const Teuchos::RCP<const crs_graph_type>& pGraph,
6850 const std::string& graphName,
6851 const std::string& graphDescription,
6852 const bool debug=false)
6853 {
6854 writeSparseGraphFile (filename, *pGraph, graphName, graphDescription, debug);
6855 }
6856
6866 static void
6867 writeSparseGraphFile (const std::string& filename,
6868 const Teuchos::RCP<const crs_graph_type>& pGraph,
6869 const bool debug=false)
6870 {
6871 writeSparseGraphFile (filename, *pGraph, "", "", debug);
6872 }
6873
6896 static void
6897 writeSparse (std::ostream& out,
6898 const sparse_matrix_type& matrix,
6899 const bool debug=false)
6900 {
6901 writeSparse (out, matrix, "", "", debug);
6902 }
6903
6905 static void
6906 writeSparse (std::ostream& out,
6907 const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6908 const bool debug=false)
6909 {
6910 writeSparse (out, *pMatrix, "", "", debug);
6911 }
6912
6941 static void
6942 writeDenseFile (const std::string& filename,
6943 const multivector_type& X,
6944 const std::string& matrixName,
6945 const std::string& matrixDescription,
6946 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6947 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6948 {
6949 const int myRank = X.getMap ().is_null () ? 0 :
6950 (X.getMap ()->getComm ().is_null () ? 0 :
6951 X.getMap ()->getComm ()->getRank ());
6952 std::ofstream out;
6953
6954 if (myRank == 0) { // Only open the file on Process 0.
6955 out.open (filename.c_str());
6956 }
6957
6958 writeDense (out, X, matrixName, matrixDescription, err, dbg);
6959 // We can rely on the destructor of the output stream to close
6960 // the file on scope exit, even if writeDense() throws an
6961 // exception.
6962 }
6963
6969 static void
6970 writeDenseFile (const std::string& filename,
6971 const Teuchos::RCP<const multivector_type>& X,
6972 const std::string& matrixName,
6973 const std::string& matrixDescription,
6974 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6975 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6976 {
6977 TEUCHOS_TEST_FOR_EXCEPTION(
6978 X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
6979 "writeDenseFile: The input MultiVector X is null.");
6980 writeDenseFile (filename, *X, matrixName, matrixDescription, err, dbg);
6981 }
6982
6988 static void
6989 writeDenseFile (const std::string& filename,
6990 const multivector_type& X,
6991 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6992 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6993 {
6994 writeDenseFile (filename, X, "", "", err, dbg);
6995 }
6996
7002 static void
7003 writeDenseFile (const std::string& filename,
7004 const Teuchos::RCP<const multivector_type>& X,
7005 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7006 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7007 {
7008 TEUCHOS_TEST_FOR_EXCEPTION(
7009 X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
7010 "writeDenseFile: The input MultiVector X is null.");
7011 writeDenseFile (filename, *X, err, dbg);
7012 }
7013
7014
7045 static void
7046 writeDense (std::ostream& out,
7047 const multivector_type& X,
7048 const std::string& matrixName,
7049 const std::string& matrixDescription,
7050 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7051 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7052 {
7053 using Teuchos::Comm;
7054 using Teuchos::outArg;
7055 using Teuchos::REDUCE_MAX;
7056 using Teuchos::reduceAll;
7057 using Teuchos::RCP;
7058 using std::endl;
7059
7060 RCP<const Comm<int> > comm = X.getMap ().is_null () ?
7061 Teuchos::null : X.getMap ()->getComm ();
7062 const int myRank = comm.is_null () ? 0 : comm->getRank ();
7063
7064 // If the caller provides a nonnull debug output stream, we
7065 // print debugging output to it. This is a local thing; we
7066 // don't have to check across processes.
7067 const bool debug = ! dbg.is_null ();
7068 if (debug) {
7069 dbg->pushTab ();
7070 std::ostringstream os;
7071 os << myRank << ": writeDense" << endl;
7072 *dbg << os.str ();
7073 dbg->pushTab ();
7074 }
7075 // Print the Matrix Market header.
7076 writeDenseHeader (out, X, matrixName, matrixDescription, err, dbg);
7077
7078 // Print each column one at a time. This is a (perhaps)
7079 // temporary fix for Bug 6288.
7080 const size_t numVecs = X.getNumVectors ();
7081 for (size_t j = 0; j < numVecs; ++j) {
7082 writeDenseColumn (out, * (X.getVector (j)), err, dbg);
7083 }
7084
7085 if (debug) {
7086 dbg->popTab ();
7087 std::ostringstream os;
7088 os << myRank << ": writeDense: Done" << endl;
7089 *dbg << os.str ();
7090 dbg->popTab ();
7091 }
7092 }
7093
7094 private:
7095
7121 static void
7122 writeDenseHeader (std::ostream& out,
7123 const multivector_type& X,
7124 const std::string& matrixName,
7125 const std::string& matrixDescription,
7126 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7127 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7128 {
7129 using Teuchos::Comm;
7130 using Teuchos::outArg;
7131 using Teuchos::RCP;
7132 using Teuchos::REDUCE_MAX;
7133 using Teuchos::reduceAll;
7134 using std::endl;
7135 typedef Teuchos::ScalarTraits<scalar_type> STS;
7136 const char prefix[] = "Tpetra::MatrixMarket::writeDenseHeader: ";
7137
7138 RCP<const Comm<int> > comm = X.getMap ().is_null () ?
7139 Teuchos::null : X.getMap ()->getComm ();
7140 const int myRank = comm.is_null () ? 0 : comm->getRank ();
7141 int lclErr = 0; // whether this MPI process has seen an error
7142 int gblErr = 0; // whether we know if some MPI process has seen an error
7143
7144 // If the caller provides a nonnull debug output stream, we
7145 // print debugging output to it. This is a local thing; we
7146 // don't have to check across processes.
7147 const bool debug = ! dbg.is_null ();
7148
7149 if (debug) {
7150 dbg->pushTab ();
7151 std::ostringstream os;
7152 os << myRank << ": writeDenseHeader" << endl;
7153 *dbg << os.str ();
7154 dbg->pushTab ();
7155 }
7156
7157 //
7158 // Process 0: Write the MatrixMarket header.
7159 //
7160 if (myRank == 0) {
7161 try {
7162 // Print the Matrix Market header. MultiVector stores data
7163 // nonsymmetrically, hence "general" in the banner line.
7164 // Print first to a temporary string output stream, and then
7165 // write it to the main output stream, so that at least the
7166 // header output has transactional semantics. We can't
7167 // guarantee transactional semantics for the whole output,
7168 // since that would not be memory scalable. (This could be
7169 // done in the file system by using a temporary file; we
7170 // don't do this, but users could.)
7171 std::ostringstream hdr;
7172 {
7173 std::string dataType;
7174 if (STS::isComplex) {
7175 dataType = "complex";
7176 } else if (STS::isOrdinal) {
7177 dataType = "integer";
7178 } else {
7179 dataType = "real";
7180 }
7181 hdr << "%%MatrixMarket matrix array " << dataType << " general"
7182 << endl;
7183 }
7184
7185 // Print comments (the matrix name and / or description).
7186 if (matrixName != "") {
7187 printAsComment (hdr, matrixName);
7188 }
7189 if (matrixDescription != "") {
7190 printAsComment (hdr, matrixDescription);
7191 }
7192 // Print the Matrix Market dimensions header for dense matrices.
7193 hdr << X.getGlobalLength () << " " << X.getNumVectors () << endl;
7194
7195 // Write the MatrixMarket header to the output stream.
7196 out << hdr.str ();
7197 } catch (std::exception& e) {
7198 if (! err.is_null ()) {
7199 *err << prefix << "While writing the Matrix Market header, "
7200 "Process 0 threw an exception: " << e.what () << endl;
7201 }
7202 lclErr = 1;
7203 }
7204 } // if I am Process 0
7205
7206 // Establish global agreement on the error state. It wouldn't
7207 // be good for other processes to keep going, if Process 0
7208 // finds out that it can't write to the given output stream.
7209 reduceAll<int, int> (*comm, REDUCE_MAX, lclErr, outArg (gblErr));
7210 TEUCHOS_TEST_FOR_EXCEPTION(
7211 gblErr == 1, std::runtime_error, prefix << "Some error occurred "
7212 "which prevented this method from completing.");
7213
7214 if (debug) {
7215 dbg->popTab ();
7216 *dbg << myRank << ": writeDenseHeader: Done" << endl;
7217 dbg->popTab ();
7218 }
7219 }
7220
7238 static void
7239 writeDenseColumn (std::ostream& out,
7240 const multivector_type& X,
7241 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7242 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7243 {
7244 using Teuchos::arcp;
7245 using Teuchos::Array;
7246 using Teuchos::ArrayRCP;
7247 using Teuchos::ArrayView;
7248 using Teuchos::Comm;
7249 using Teuchos::CommRequest;
7250 using Teuchos::ireceive;
7251 using Teuchos::isend;
7252 using Teuchos::outArg;
7253 using Teuchos::REDUCE_MAX;
7254 using Teuchos::reduceAll;
7255 using Teuchos::RCP;
7256 using Teuchos::TypeNameTraits;
7257 using Teuchos::wait;
7258 using std::endl;
7259 typedef Teuchos::ScalarTraits<scalar_type> STS;
7260
7261 const Comm<int>& comm = * (X.getMap ()->getComm ());
7262 const int myRank = comm.getRank ();
7263 const int numProcs = comm.getSize ();
7264 int lclErr = 0; // whether this MPI process has seen an error
7265 int gblErr = 0; // whether we know if some MPI process has seen an error
7266
7267 // If the caller provides a nonnull debug output stream, we
7268 // print debugging output to it. This is a local thing; we
7269 // don't have to check across processes.
7270 const bool debug = ! dbg.is_null ();
7271
7272 if (debug) {
7273 dbg->pushTab ();
7274 std::ostringstream os;
7275 os << myRank << ": writeDenseColumn" << endl;
7276 *dbg << os.str ();
7277 dbg->pushTab ();
7278 }
7279
7280 // Make the output stream write floating-point numbers in
7281 // scientific notation. It will politely put the output
7282 // stream back to its state on input, when this scope
7283 // terminates.
7284 Teuchos::SetScientific<scalar_type> sci (out);
7285
7286 const size_t myNumRows = X.getLocalLength ();
7287 const size_t numCols = X.getNumVectors ();
7288 // Use a different tag for the "size" messages than for the
7289 // "data" messages, in order to help us debug any mix-ups.
7290 const int sizeTag = 1337;
7291 const int dataTag = 1338;
7292
7293 // Process 0 pipelines nonblocking receives with file output.
7294 //
7295 // Constraints:
7296 // - Process 0 can't post a receive for another process'
7297 // actual data, until it posts and waits on the receive
7298 // from that process with the amount of data to receive.
7299 // (We could just post receives with a max data size, but
7300 // I feel uncomfortable about that.)
7301 // - The C++ standard library doesn't allow nonblocking
7302 // output to an std::ostream. (Thus, we have to start a
7303 // receive or send before starting the write, and hope
7304 // that MPI completes it in the background.)
7305 //
7306 // Process 0: Post receive-size receives from Processes 1 and 2.
7307 // Process 1: Post send-size send to Process 0.
7308 // Process 2: Post send-size send to Process 0.
7309 //
7310 // All processes: Pack my entries.
7311 //
7312 // Process 1:
7313 // - Post send-data send to Process 0.
7314 // - Wait on my send-size send to Process 0.
7315 //
7316 // Process 0:
7317 // - Print MatrixMarket header.
7318 // - Print my entries.
7319 // - Wait on receive-size receive from Process 1.
7320 // - Post receive-data receive from Process 1.
7321 //
7322 // For each process p = 1, 2, ... numProcs-1:
7323 // If I am Process 0:
7324 // - Post receive-size receive from Process p + 2
7325 // - Wait on receive-size receive from Process p + 1
7326 // - Post receive-data receive from Process p + 1
7327 // - Wait on receive-data receive from Process p
7328 // - Write data from Process p.
7329 // Else if I am Process p:
7330 // - Wait on my send-data send.
7331 // Else if I am Process p+1:
7332 // - Post send-data send to Process 0.
7333 // - Wait on my send-size send.
7334 // Else if I am Process p+2:
7335 // - Post send-size send to Process 0.
7336 //
7337 // Pipelining has three goals here:
7338 // 1. Overlap communication (the receives) with file I/O
7339 // 2. Give Process 0 a chance to prepost some receives,
7340 // before sends show up, by packing local data before
7341 // posting sends
7342 // 3. Don't post _all_ receives or _all_ sends, because that
7343 // wouldn't be memory scalable. (Just because we can't
7344 // see how much memory MPI consumes, doesn't mean that it
7345 // doesn't consume any!)
7346
7347 // These are used on every process. sendReqSize[0] holds the
7348 // number of rows on this process, and sendReqBuf holds this
7349 // process' data. Process 0 packs into sendReqBuf, but
7350 // doesn't send; it only uses that for printing. All other
7351 // processes send both of these to Process 0.
7352 RCP<CommRequest<int> > sendReqSize, sendReqData;
7353
7354 // These are used only on Process 0, for received data. Keep
7355 // 3 of each, and treat the arrays as circular buffers. When
7356 // receiving from Process p, the corresponding array index
7357 // here is p % 3.
7358 Array<ArrayRCP<size_t> > recvSizeBufs (3);
7359 Array<ArrayRCP<scalar_type> > recvDataBufs (3);
7360 Array<RCP<CommRequest<int> > > recvSizeReqs (3);
7361 Array<RCP<CommRequest<int> > > recvDataReqs (3);
7362
7363 // Buffer for nonblocking send of the "send size."
7364 ArrayRCP<size_t> sendDataSize (1);
7365 sendDataSize[0] = myNumRows;
7366
7367 if (myRank == 0) {
7368 if (debug) {
7369 std::ostringstream os;
7370 os << myRank << ": Post receive-size receives from "
7371 "Procs 1 and 2: tag = " << sizeTag << endl;
7372 *dbg << os.str ();
7373 }
7374 // Process 0: Post receive-size receives from Processes 1 and 2.
7375 recvSizeBufs[0].resize (1);
7376 // Set these three to an invalid value as a flag. If we
7377 // don't get these messages, then the invalid value will
7378 // remain, so we can test for it.
7379 (recvSizeBufs[0])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
7380 recvSizeBufs[1].resize (1);
7381 (recvSizeBufs[1])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
7382 recvSizeBufs[2].resize (1);
7383 (recvSizeBufs[2])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
7384 if (numProcs > 1) {
7385 recvSizeReqs[1] =
7386 ireceive<int, size_t> (recvSizeBufs[1], 1, sizeTag, comm);
7387 }
7388 if (numProcs > 2) {
7389 recvSizeReqs[2] =
7390 ireceive<int, size_t> (recvSizeBufs[2], 2, sizeTag, comm);
7391 }
7392 }
7393 else if (myRank == 1 || myRank == 2) {
7394 if (debug) {
7395 std::ostringstream os;
7396 os << myRank << ": Post send-size send: size = "
7397 << sendDataSize[0] << ", tag = " << sizeTag << endl;
7398 *dbg << os.str ();
7399 }
7400 // Prime the pipeline by having Processes 1 and 2 start
7401 // their send-size sends. We don't want _all_ the processes
7402 // to start their send-size sends, because that wouldn't be
7403 // memory scalable.
7404 sendReqSize = isend<int, size_t> (sendDataSize, 0, sizeTag, comm);
7405 }
7406 else {
7407 if (debug) {
7408 std::ostringstream os;
7409 os << myRank << ": Not posting my send-size send yet" << endl;
7410 *dbg << os.str ();
7411 }
7412 }
7413
7414 //
7415 // Pack my entries, in column-major order.
7416 //
7417 if (debug) {
7418 std::ostringstream os;
7419 os << myRank << ": Pack my entries" << endl;
7420 *dbg << os.str ();
7421 }
7422 ArrayRCP<scalar_type> sendDataBuf;
7423 try {
7424 sendDataBuf = arcp<scalar_type> (myNumRows * numCols);
7425 X.get1dCopy (sendDataBuf (), myNumRows);
7426 }
7427 catch (std::exception& e) {
7428 lclErr = 1;
7429 if (! err.is_null ()) {
7430 std::ostringstream os;
7431 os << "Process " << myRank << ": Attempt to pack my MultiVector "
7432 "entries threw an exception: " << e.what () << endl;
7433 *err << os.str ();
7434 }
7435 }
7436 if (debug) {
7437 std::ostringstream os;
7438 os << myRank << ": Done packing my entries" << endl;
7439 *dbg << os.str ();
7440 }
7441
7442 //
7443 // Process 1: post send-data send to Process 0.
7444 //
7445 if (myRank == 1) {
7446 if (debug) {
7447 *dbg << myRank << ": Post send-data send: tag = " << dataTag
7448 << endl;
7449 }
7450 sendReqData = isend<int, scalar_type> (sendDataBuf, 0, dataTag, comm);
7451 }
7452
7453 //
7454 // Process 0: Write my entries.
7455 //
7456 if (myRank == 0) {
7457 if (debug) {
7458 std::ostringstream os;
7459 os << myRank << ": Write my entries" << endl;
7460 *dbg << os.str ();
7461 }
7462
7463 // Write Process 0's data to the output stream.
7464 // Matrix Market prints dense matrices in column-major order.
7465 const size_t printNumRows = myNumRows;
7466 ArrayView<const scalar_type> printData = sendDataBuf ();
7467 const size_t printStride = printNumRows;
7468 if (static_cast<size_t> (printData.size ()) < printStride * numCols) {
7469 lclErr = 1;
7470 if (! err.is_null ()) {
7471 std::ostringstream os;
7472 os << "Process " << myRank << ": My MultiVector data's size "
7473 << printData.size () << " does not match my local dimensions "
7474 << printStride << " x " << numCols << "." << endl;
7475 *err << os.str ();
7476 }
7477 }
7478 else {
7479 // Matrix Market dense format wants one number per line.
7480 // It wants each complex number as two real numbers (real
7481 // resp. imaginary parts) with a space between.
7482 for (size_t col = 0; col < numCols; ++col) {
7483 for (size_t row = 0; row < printNumRows; ++row) {
7484 if (STS::isComplex) {
7485 out << STS::real (printData[row + col * printStride]) << " "
7486 << STS::imag (printData[row + col * printStride]) << endl;
7487 } else {
7488 out << printData[row + col * printStride] << endl;
7489 }
7490 }
7491 }
7492 }
7493 }
7494
7495 if (myRank == 0) {
7496 // Wait on receive-size receive from Process 1.
7497 const int recvRank = 1;
7498 const int circBufInd = recvRank % 3;
7499 if (debug) {
7500 std::ostringstream os;
7501 os << myRank << ": Wait on receive-size receive from Process "
7502 << recvRank << endl;
7503 *dbg << os.str ();
7504 }
7505 if (numProcs > 1) {
7506 wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7507
7508 // We received the number of rows of data. (The data
7509 // come in two columns.)
7510 size_t recvNumRows = (recvSizeBufs[circBufInd])[0];
7511 if (recvNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7512 lclErr = 1;
7513 if (! err.is_null ()) {
7514 std::ostringstream os;
7515 os << myRank << ": Result of receive-size receive from Process "
7516 << recvRank << " is Teuchos::OrdinalTraits<size_t>::invalid() "
7517 << "= " << Teuchos::OrdinalTraits<size_t>::invalid () << ". "
7518 "This should never happen, and suggests that the receive never "
7519 "got posted. Please report this bug to the Tpetra developers."
7520 << endl;
7521 *err << os.str ();
7522 }
7523
7524 // If we're going to continue after error, set the
7525 // number of rows to receive to a reasonable size. This
7526 // may cause MPI_ERR_TRUNCATE if the sending process is
7527 // sending more than 0 rows, but that's better than MPI
7528 // overflowing due to the huge positive value that is
7529 // Teuchos::OrdinalTraits<size_t>::invalid().
7530 recvNumRows = 0;
7531 }
7532
7533 // Post receive-data receive from Process 1.
7534 recvDataBufs[circBufInd].resize (recvNumRows * numCols);
7535 if (debug) {
7536 std::ostringstream os;
7537 os << myRank << ": Post receive-data receive from Process "
7538 << recvRank << ": tag = " << dataTag << ", buffer size = "
7539 << recvDataBufs[circBufInd].size () << endl;
7540 *dbg << os.str ();
7541 }
7542 if (! recvSizeReqs[circBufInd].is_null ()) {
7543 lclErr = 1;
7544 if (! err.is_null ()) {
7545 std::ostringstream os;
7546 os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7547 "null, before posting the receive-data receive from Process "
7548 << recvRank << ". This should never happen. Please report "
7549 "this bug to the Tpetra developers." << endl;
7550 *err << os.str ();
7551 }
7552 }
7553 recvDataReqs[circBufInd] =
7554 ireceive<int, scalar_type> (recvDataBufs[circBufInd],
7555 recvRank, dataTag, comm);
7556 } // numProcs > 1
7557 }
7558 else if (myRank == 1) {
7559 // Wait on my send-size send.
7560 if (debug) {
7561 std::ostringstream os;
7562 os << myRank << ": Wait on my send-size send" << endl;
7563 *dbg << os.str ();
7564 }
7565 wait<int> (comm, outArg (sendReqSize));
7566 }
7567
7568 //
7569 // Pipeline loop
7570 //
7571 for (int p = 1; p < numProcs; ++p) {
7572 if (myRank == 0) {
7573 if (p + 2 < numProcs) {
7574 // Post receive-size receive from Process p + 2.
7575 const int recvRank = p + 2;
7576 const int circBufInd = recvRank % 3;
7577 if (debug) {
7578 std::ostringstream os;
7579 os << myRank << ": Post receive-size receive from Process "
7580 << recvRank << ": tag = " << sizeTag << endl;
7581 *dbg << os.str ();
7582 }
7583 if (! recvSizeReqs[circBufInd].is_null ()) {
7584 lclErr = 1;
7585 if (! err.is_null ()) {
7586 std::ostringstream os;
7587 os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7588 << "null, for the receive-size receive from Process "
7589 << recvRank << "! This may mean that this process never "
7590 << "finished waiting for the receive from Process "
7591 << (recvRank - 3) << "." << endl;
7592 *err << os.str ();
7593 }
7594 }
7595 recvSizeReqs[circBufInd] =
7596 ireceive<int, size_t> (recvSizeBufs[circBufInd],
7597 recvRank, sizeTag, comm);
7598 }
7599
7600 if (p + 1 < numProcs) {
7601 const int recvRank = p + 1;
7602 const int circBufInd = recvRank % 3;
7603
7604 // Wait on receive-size receive from Process p + 1.
7605 if (debug) {
7606 std::ostringstream os;
7607 os << myRank << ": Wait on receive-size receive from Process "
7608 << recvRank << endl;
7609 *dbg << os.str ();
7610 }
7611 wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7612
7613 // We received the number of rows of data. (The data
7614 // come in two columns.)
7615 size_t recvNumRows = (recvSizeBufs[circBufInd])[0];
7616 if (recvNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7617 lclErr = 1;
7618 if (! err.is_null ()) {
7619 std::ostringstream os;
7620 os << myRank << ": Result of receive-size receive from Process "
7621 << recvRank << " is Teuchos::OrdinalTraits<size_t>::invalid() "
7622 << "= " << Teuchos::OrdinalTraits<size_t>::invalid () << ". "
7623 "This should never happen, and suggests that the receive never "
7624 "got posted. Please report this bug to the Tpetra developers."
7625 << endl;
7626 *err << os.str ();
7627 }
7628 // If we're going to continue after error, set the
7629 // number of rows to receive to a reasonable size.
7630 // This may cause MPI_ERR_TRUNCATE if the sending
7631 // process sends more than 0 rows, but that's better
7632 // than MPI overflowing due to the huge positive value
7633 // Teuchos::OrdinalTraits<size_t>::invalid().
7634 recvNumRows = 0;
7635 }
7636
7637 // Post receive-data receive from Process p + 1.
7638 recvDataBufs[circBufInd].resize (recvNumRows * numCols);
7639 if (debug) {
7640 std::ostringstream os;
7641 os << myRank << ": Post receive-data receive from Process "
7642 << recvRank << ": tag = " << dataTag << ", buffer size = "
7643 << recvDataBufs[circBufInd].size () << endl;
7644 *dbg << os.str ();
7645 }
7646 if (! recvDataReqs[circBufInd].is_null ()) {
7647 lclErr = 1;
7648 if (! err.is_null ()) {
7649 std::ostringstream os;
7650 os << myRank << ": recvDataReqs[" << circBufInd << "] is not "
7651 << "null, for the receive-data receive from Process "
7652 << recvRank << "! This may mean that this process never "
7653 << "finished waiting for the receive from Process "
7654 << (recvRank - 3) << "." << endl;
7655 *err << os.str ();
7656 }
7657 }
7658 recvDataReqs[circBufInd] =
7659 ireceive<int, scalar_type> (recvDataBufs[circBufInd],
7660 recvRank, dataTag, comm);
7661 }
7662
7663 // Wait on receive-data receive from Process p.
7664 const int recvRank = p;
7665 const int circBufInd = recvRank % 3;
7666 if (debug) {
7667 std::ostringstream os;
7668 os << myRank << ": Wait on receive-data receive from Process "
7669 << recvRank << endl;
7670 *dbg << os.str ();
7671 }
7672 wait<int> (comm, outArg (recvDataReqs[circBufInd]));
7673
7674 // Write Process p's data. Number of rows lives in
7675 // recvSizeBufs[circBufInd], and the actual data live in
7676 // recvDataBufs[circBufInd]. Do this after posting receives,
7677 // in order to expose overlap of comm. with file I/O.
7678 if (debug) {
7679 std::ostringstream os;
7680 os << myRank << ": Write entries from Process " << recvRank
7681 << endl;
7682 *dbg << os.str () << endl;
7683 }
7684 size_t printNumRows = (recvSizeBufs[circBufInd])[0];
7685 if (printNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7686 lclErr = 1;
7687 if (! err.is_null ()) {
7688 std::ostringstream os;
7689 os << myRank << ": Result of receive-size receive from Process "
7690 << recvRank << " was Teuchos::OrdinalTraits<size_t>::"
7691 "invalid() = " << Teuchos::OrdinalTraits<size_t>::invalid ()
7692 << ". This should never happen, and suggests that its "
7693 "receive-size receive was never posted. "
7694 "Please report this bug to the Tpetra developers." << endl;
7695 *err << os.str ();
7696 }
7697 // If we're going to continue after error, set the
7698 // number of rows to print to a reasonable size.
7699 printNumRows = 0;
7700 }
7701 if (printNumRows > 0 && recvDataBufs[circBufInd].is_null ()) {
7702 lclErr = 1;
7703 if (! err.is_null ()) {
7704 std::ostringstream os;
7705 os << myRank << ": Result of receive-size receive from Proc "
7706 << recvRank << " was " << printNumRows << " > 0, but "
7707 "recvDataBufs[" << circBufInd << "] is null. This should "
7708 "never happen. Please report this bug to the Tpetra "
7709 "developers." << endl;
7710 *err << os.str ();
7711 }
7712 // If we're going to continue after error, set the
7713 // number of rows to print to a reasonable size.
7714 printNumRows = 0;
7715 }
7716
7717 // Write the received data to the output stream.
7718 // Matrix Market prints dense matrices in column-major order.
7719 ArrayView<const scalar_type> printData = (recvDataBufs[circBufInd]) ();
7720 const size_t printStride = printNumRows;
7721 // Matrix Market dense format wants one number per line.
7722 // It wants each complex number as two real numbers (real
7723 // resp. imaginary parts) with a space between.
7724 for (size_t col = 0; col < numCols; ++col) {
7725 for (size_t row = 0; row < printNumRows; ++row) {
7726 if (STS::isComplex) {
7727 out << STS::real (printData[row + col * printStride]) << " "
7728 << STS::imag (printData[row + col * printStride]) << endl;
7729 } else {
7730 out << printData[row + col * printStride] << endl;
7731 }
7732 }
7733 }
7734 }
7735 else if (myRank == p) { // Process p
7736 // Wait on my send-data send.
7737 if (debug) {
7738 std::ostringstream os;
7739 os << myRank << ": Wait on my send-data send" << endl;
7740 *dbg << os.str ();
7741 }
7742 wait<int> (comm, outArg (sendReqData));
7743 }
7744 else if (myRank == p + 1) { // Process p + 1
7745 // Post send-data send to Process 0.
7746 if (debug) {
7747 std::ostringstream os;
7748 os << myRank << ": Post send-data send: tag = " << dataTag
7749 << endl;
7750 *dbg << os.str ();
7751 }
7752 sendReqData = isend<int, scalar_type> (sendDataBuf, 0, dataTag, comm);
7753 // Wait on my send-size send.
7754 if (debug) {
7755 std::ostringstream os;
7756 os << myRank << ": Wait on my send-size send" << endl;
7757 *dbg << os.str ();
7758 }
7759 wait<int> (comm, outArg (sendReqSize));
7760 }
7761 else if (myRank == p + 2) { // Process p + 2
7762 // Post send-size send to Process 0.
7763 if (debug) {
7764 std::ostringstream os;
7765 os << myRank << ": Post send-size send: size = "
7766 << sendDataSize[0] << ", tag = " << sizeTag << endl;
7767 *dbg << os.str ();
7768 }
7769 sendReqSize = isend<int, size_t> (sendDataSize, 0, sizeTag, comm);
7770 }
7771 }
7772
7773 // Establish global agreement on the error state.
7774 reduceAll<int, int> (comm, REDUCE_MAX, lclErr, outArg (gblErr));
7775 TEUCHOS_TEST_FOR_EXCEPTION(
7776 gblErr == 1, std::runtime_error, "Tpetra::MatrixMarket::writeDense "
7777 "experienced some kind of error and was unable to complete.");
7778
7779 if (debug) {
7780 dbg->popTab ();
7781 *dbg << myRank << ": writeDenseColumn: Done" << endl;
7782 dbg->popTab ();
7783 }
7784 }
7785
7786 public:
7787
7793 static void
7794 writeDense (std::ostream& out,
7795 const Teuchos::RCP<const multivector_type>& X,
7796 const std::string& matrixName,
7797 const std::string& matrixDescription,
7798 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7799 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7800 {
7801 TEUCHOS_TEST_FOR_EXCEPTION(
7802 X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
7803 "writeDense: The input MultiVector X is null.");
7804 writeDense (out, *X, matrixName, matrixDescription, err, dbg);
7805 }
7806
7812 static void
7813 writeDense (std::ostream& out,
7814 const multivector_type& X,
7815 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7816 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7817 {
7818 writeDense (out, X, "", "", err, dbg);
7819 }
7820
7826 static void
7827 writeDense (std::ostream& out,
7828 const Teuchos::RCP<const multivector_type>& X,
7829 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7830 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7831 {
7832 TEUCHOS_TEST_FOR_EXCEPTION(
7833 X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
7834 "writeDense: The input MultiVector X is null.");
7835 writeDense (out, *X, "", "", err, dbg);
7836 }
7837
7857 static void
7858 writeMap (std::ostream& out, const map_type& map, const bool debug=false)
7859 {
7860 Teuchos::RCP<Teuchos::FancyOStream> err =
7861 Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
7862 writeMap (out, map, err, debug);
7863 }
7864
7873 static void
7874 writeMap (std::ostream& out,
7875 const map_type& map,
7876 const Teuchos::RCP<Teuchos::FancyOStream>& err,
7877 const bool debug=false)
7878 {
7879 using Teuchos::Array;
7880 using Teuchos::ArrayRCP;
7881 using Teuchos::ArrayView;
7882 using Teuchos::Comm;
7883 using Teuchos::CommRequest;
7884 using Teuchos::ireceive;
7885 using Teuchos::isend;
7886 using Teuchos::RCP;
7887 using Teuchos::TypeNameTraits;
7888 using Teuchos::wait;
7889 using std::endl;
7890 typedef global_ordinal_type GO;
7891 typedef int pid_type;
7892
7893 // Treat the Map as a 1-column "multivector." This differs
7894 // from the previous two-column format, in which column 0 held
7895 // the GIDs, and column 1 held the corresponding PIDs. It
7896 // differs because printing that format requires knowing the
7897 // entire first column -- that is, all the GIDs -- in advance.
7898 // Sending messages from each process one at a time saves
7899 // memory, but it means that Process 0 doesn't ever have all
7900 // the GIDs at once.
7901 //
7902 // We pack the entries as ptrdiff_t, since this should be the
7903 // biggest signed built-in integer type that can hold any GO
7904 // or pid_type (= int) quantity without overflow. Test this
7905 // assumption at run time.
7906 typedef ptrdiff_t int_type;
7907 TEUCHOS_TEST_FOR_EXCEPTION(
7908 sizeof (GO) > sizeof (int_type), std::logic_error,
7909 "The global ordinal type GO=" << TypeNameTraits<GO>::name ()
7910 << " is too big for ptrdiff_t. sizeof(GO) = " << sizeof (GO)
7911 << " > sizeof(ptrdiff_t) = " << sizeof (ptrdiff_t) << ".");
7912 TEUCHOS_TEST_FOR_EXCEPTION(
7913 sizeof (pid_type) > sizeof (int_type), std::logic_error,
7914 "The (MPI) process rank type pid_type=" <<
7915 TypeNameTraits<pid_type>::name () << " is too big for ptrdiff_t. "
7916 "sizeof(pid_type) = " << sizeof (pid_type) << " > sizeof(ptrdiff_t)"
7917 " = " << sizeof (ptrdiff_t) << ".");
7918
7919 const Comm<int>& comm = * (map.getComm ());
7920 const int myRank = comm.getRank ();
7921 const int numProcs = comm.getSize ();
7922
7923 if (! err.is_null ()) {
7924 err->pushTab ();
7925 }
7926 if (debug) {
7927 std::ostringstream os;
7928 os << myRank << ": writeMap" << endl;
7929 *err << os.str ();
7930 }
7931 if (! err.is_null ()) {
7932 err->pushTab ();
7933 }
7934
7935 const size_t myNumRows = map.getLocalNumElements ();
7936 // Use a different tag for the "size" messages than for the
7937 // "data" messages, in order to help us debug any mix-ups.
7938 const int sizeTag = 1337;
7939 const int dataTag = 1338;
7940
7941 // Process 0 pipelines nonblocking receives with file output.
7942 //
7943 // Constraints:
7944 // - Process 0 can't post a receive for another process'
7945 // actual data, until it posts and waits on the receive
7946 // from that process with the amount of data to receive.
7947 // (We could just post receives with a max data size, but
7948 // I feel uncomfortable about that.)
7949 // - The C++ standard library doesn't allow nonblocking
7950 // output to an std::ostream.
7951 //
7952 // Process 0: Post receive-size receives from Processes 1 and 2.
7953 // Process 1: Post send-size send to Process 0.
7954 // Process 2: Post send-size send to Process 0.
7955 //
7956 // All processes: Pack my GIDs and PIDs.
7957 //
7958 // Process 1:
7959 // - Post send-data send to Process 0.
7960 // - Wait on my send-size send to Process 0.
7961 //
7962 // Process 0:
7963 // - Print MatrixMarket header.
7964 // - Print my GIDs and PIDs.
7965 // - Wait on receive-size receive from Process 1.
7966 // - Post receive-data receive from Process 1.
7967 //
7968 // For each process p = 1, 2, ... numProcs-1:
7969 // If I am Process 0:
7970 // - Post receive-size receive from Process p + 2
7971 // - Wait on receive-size receive from Process p + 1
7972 // - Post receive-data receive from Process p + 1
7973 // - Wait on receive-data receive from Process p
7974 // - Write data from Process p.
7975 // Else if I am Process p:
7976 // - Wait on my send-data send.
7977 // Else if I am Process p+1:
7978 // - Post send-data send to Process 0.
7979 // - Wait on my send-size send.
7980 // Else if I am Process p+2:
7981 // - Post send-size send to Process 0.
7982 //
7983 // Pipelining has three goals here:
7984 // 1. Overlap communication (the receives) with file I/O
7985 // 2. Give Process 0 a chance to prepost some receives,
7986 // before sends show up, by packing local data before
7987 // posting sends
7988 // 3. Don't post _all_ receives or _all_ sends, because that
7989 // wouldn't be memory scalable. (Just because we can't
7990 // see how much memory MPI consumes, doesn't mean that it
7991 // doesn't consume any!)
7992
7993 // These are used on every process. sendReqSize[0] holds the
7994 // number of rows on this process, and sendReqBuf holds this
7995 // process' data. Process 0 packs into sendReqBuf, but
7996 // doesn't send; it only uses that for printing. All other
7997 // processes send both of these to Process 0.
7998 RCP<CommRequest<int> > sendReqSize, sendReqData;
7999
8000 // These are used only on Process 0, for received data. Keep
8001 // 3 of each, and treat the arrays as circular buffers. When
8002 // receiving from Process p, the corresponding array index
8003 // here is p % 3.
8004 Array<ArrayRCP<int_type> > recvSizeBufs (3);
8005 Array<ArrayRCP<int_type> > recvDataBufs (3);
8006 Array<RCP<CommRequest<int> > > recvSizeReqs (3);
8007 Array<RCP<CommRequest<int> > > recvDataReqs (3);
8008
8009 // Buffer for nonblocking send of the "send size."
8010 ArrayRCP<int_type> sendDataSize (1);
8011 sendDataSize[0] = myNumRows;
8012
8013 if (myRank == 0) {
8014 if (debug) {
8015 std::ostringstream os;
8016 os << myRank << ": Post receive-size receives from "
8017 "Procs 1 and 2: tag = " << sizeTag << endl;
8018 *err << os.str ();
8019 }
8020 // Process 0: Post receive-size receives from Processes 1 and 2.
8021 recvSizeBufs[0].resize (1);
8022 (recvSizeBufs[0])[0] = -1; // error flag
8023 recvSizeBufs[1].resize (1);
8024 (recvSizeBufs[1])[0] = -1; // error flag
8025 recvSizeBufs[2].resize (1);
8026 (recvSizeBufs[2])[0] = -1; // error flag
8027 if (numProcs > 1) {
8028 recvSizeReqs[1] =
8029 ireceive<int, int_type> (recvSizeBufs[1], 1, sizeTag, comm);
8030 }
8031 if (numProcs > 2) {
8032 recvSizeReqs[2] =
8033 ireceive<int, int_type> (recvSizeBufs[2], 2, sizeTag, comm);
8034 }
8035 }
8036 else if (myRank == 1 || myRank == 2) {
8037 if (debug) {
8038 std::ostringstream os;
8039 os << myRank << ": Post send-size send: size = "
8040 << sendDataSize[0] << ", tag = " << sizeTag << endl;
8041 *err << os.str ();
8042 }
8043 // Prime the pipeline by having Processes 1 and 2 start
8044 // their send-size sends. We don't want _all_ the processes
8045 // to start their send-size sends, because that wouldn't be
8046 // memory scalable.
8047 sendReqSize = isend<int, int_type> (sendDataSize, 0, sizeTag, comm);
8048 }
8049 else {
8050 if (debug) {
8051 std::ostringstream os;
8052 os << myRank << ": Not posting my send-size send yet" << endl;
8053 *err << os.str ();
8054 }
8055 }
8056
8057 //
8058 // Pack my GIDs and PIDs. Each (GID,PID) pair gets packed
8059 // consecutively, for better locality.
8060 //
8061
8062 if (debug) {
8063 std::ostringstream os;
8064 os << myRank << ": Pack my GIDs and PIDs" << endl;
8065 *err << os.str ();
8066 }
8067
8068 ArrayRCP<int_type> sendDataBuf (myNumRows * 2);
8069
8070 if (map.isContiguous ()) {
8071 const int_type myMinGblIdx =
8072 static_cast<int_type> (map.getMinGlobalIndex ());
8073 for (size_t k = 0; k < myNumRows; ++k) {
8074 const int_type gid = myMinGblIdx + static_cast<int_type> (k);
8075 const int_type pid = static_cast<int_type> (myRank);
8076 sendDataBuf[2*k] = gid;
8077 sendDataBuf[2*k+1] = pid;
8078 }
8079 }
8080 else {
8081 ArrayView<const GO> myGblInds = map.getLocalElementList ();
8082 for (size_t k = 0; k < myNumRows; ++k) {
8083 const int_type gid = static_cast<int_type> (myGblInds[k]);
8084 const int_type pid = static_cast<int_type> (myRank);
8085 sendDataBuf[2*k] = gid;
8086 sendDataBuf[2*k+1] = pid;
8087 }
8088 }
8089
8090 if (debug) {
8091 std::ostringstream os;
8092 os << myRank << ": Done packing my GIDs and PIDs" << endl;
8093 *err << os.str ();
8094 }
8095
8096 if (myRank == 1) {
8097 // Process 1: post send-data send to Process 0.
8098 if (debug) {
8099 *err << myRank << ": Post send-data send: tag = " << dataTag
8100 << endl;
8101 }
8102 sendReqData = isend<int, int_type> (sendDataBuf, 0, dataTag, comm);
8103 }
8104
8105 if (myRank == 0) {
8106 if (debug) {
8107 *err << myRank << ": Write MatrixMarket header" << endl;
8108 }
8109
8110 // Process 0: Write the MatrixMarket header.
8111 // Description section explains each column.
8112 std::ostringstream hdr;
8113
8114 // Print the Matrix Market header. MultiVector stores data
8115 // nonsymmetrically, hence "general" in the banner line.
8116 hdr << "%%MatrixMarket matrix array integer general" << endl
8117 << "% Format: Version 2.0" << endl
8118 << "%" << endl
8119 << "% This file encodes a Tpetra::Map." << endl
8120 << "% It is stored as a dense vector, with twice as many " << endl
8121 << "% entries as the global number of GIDs (global indices)." << endl
8122 << "% (GID, PID) pairs are stored contiguously, where the PID " << endl
8123 << "% is the rank of the process owning that GID." << endl
8124 << (2 * map.getGlobalNumElements ()) << " " << 1 << endl;
8125 out << hdr.str ();
8126
8127 if (debug) {
8128 std::ostringstream os;
8129 os << myRank << ": Write my GIDs and PIDs" << endl;
8130 *err << os.str ();
8131 }
8132
8133 // Write Process 0's data to the output stream.
8134 // Matrix Market prints dense matrices in column-major order.
8135 const int_type printNumRows = myNumRows;
8136 ArrayView<const int_type> printData = sendDataBuf ();
8137 for (int_type k = 0; k < printNumRows; ++k) {
8138 const int_type gid = printData[2*k];
8139 const int_type pid = printData[2*k+1];
8140 out << gid << endl << pid << endl;
8141 }
8142 }
8143
8144 if (myRank == 0) {
8145 // Wait on receive-size receive from Process 1.
8146 const int recvRank = 1;
8147 const int circBufInd = recvRank % 3;
8148 if (debug) {
8149 std::ostringstream os;
8150 os << myRank << ": Wait on receive-size receive from Process "
8151 << recvRank << endl;
8152 *err << os.str ();
8153 }
8154 if (numProcs > 1) {
8155 wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
8156
8157 // We received the number of rows of data. (The data
8158 // come in two columns.)
8159 const int_type recvNumRows = (recvSizeBufs[circBufInd])[0];
8160 if (debug && recvNumRows == -1) {
8161 std::ostringstream os;
8162 os << myRank << ": Result of receive-size receive from Process "
8163 << recvRank << " is -1. This should never happen, and "
8164 "suggests that the receive never got posted. Please report "
8165 "this bug to the Tpetra developers." << endl;
8166 *err << os.str ();
8167 }
8168
8169 // Post receive-data receive from Process 1.
8170 recvDataBufs[circBufInd].resize (recvNumRows * 2);
8171 if (debug) {
8172 std::ostringstream os;
8173 os << myRank << ": Post receive-data receive from Process "
8174 << recvRank << ": tag = " << dataTag << ", buffer size = "
8175 << recvDataBufs[circBufInd].size () << endl;
8176 *err << os.str ();
8177 }
8178 if (! recvSizeReqs[circBufInd].is_null ()) {
8179 std::ostringstream os;
8180 os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
8181 "null, before posting the receive-data receive from Process "
8182 << recvRank << ". This should never happen. Please report "
8183 "this bug to the Tpetra developers." << endl;
8184 *err << os.str ();
8185 }
8186 recvDataReqs[circBufInd] =
8187 ireceive<int, int_type> (recvDataBufs[circBufInd],
8188 recvRank, dataTag, comm);
8189 } // numProcs > 1
8190 }
8191 else if (myRank == 1) {
8192 // Wait on my send-size send.
8193 if (debug) {
8194 std::ostringstream os;
8195 os << myRank << ": Wait on my send-size send" << endl;
8196 *err << os.str ();
8197 }
8198 wait<int> (comm, outArg (sendReqSize));
8199 }
8200
8201 //
8202 // Pipeline loop
8203 //
8204 for (int p = 1; p < numProcs; ++p) {
8205 if (myRank == 0) {
8206 if (p + 2 < numProcs) {
8207 // Post receive-size receive from Process p + 2.
8208 const int recvRank = p + 2;
8209 const int circBufInd = recvRank % 3;
8210 if (debug) {
8211 std::ostringstream os;
8212 os << myRank << ": Post receive-size receive from Process "
8213 << recvRank << ": tag = " << sizeTag << endl;
8214 *err << os.str ();
8215 }
8216 if (! recvSizeReqs[circBufInd].is_null ()) {
8217 std::ostringstream os;
8218 os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
8219 << "null, for the receive-size receive from Process "
8220 << recvRank << "! This may mean that this process never "
8221 << "finished waiting for the receive from Process "
8222 << (recvRank - 3) << "." << endl;
8223 *err << os.str ();
8224 }
8225 recvSizeReqs[circBufInd] =
8226 ireceive<int, int_type> (recvSizeBufs[circBufInd],
8227 recvRank, sizeTag, comm);
8228 }
8229
8230 if (p + 1 < numProcs) {
8231 const int recvRank = p + 1;
8232 const int circBufInd = recvRank % 3;
8233
8234 // Wait on receive-size receive from Process p + 1.
8235 if (debug) {
8236 std::ostringstream os;
8237 os << myRank << ": Wait on receive-size receive from Process "
8238 << recvRank << endl;
8239 *err << os.str ();
8240 }
8241 wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
8242
8243 // We received the number of rows of data. (The data
8244 // come in two columns.)
8245 const int_type recvNumRows = (recvSizeBufs[circBufInd])[0];
8246 if (debug && recvNumRows == -1) {
8247 std::ostringstream os;
8248 os << myRank << ": Result of receive-size receive from Process "
8249 << recvRank << " is -1. This should never happen, and "
8250 "suggests that the receive never got posted. Please report "
8251 "this bug to the Tpetra developers." << endl;
8252 *err << os.str ();
8253 }
8254
8255 // Post receive-data receive from Process p + 1.
8256 recvDataBufs[circBufInd].resize (recvNumRows * 2);
8257 if (debug) {
8258 std::ostringstream os;
8259 os << myRank << ": Post receive-data receive from Process "
8260 << recvRank << ": tag = " << dataTag << ", buffer size = "
8261 << recvDataBufs[circBufInd].size () << endl;
8262 *err << os.str ();
8263 }
8264 if (! recvDataReqs[circBufInd].is_null ()) {
8265 std::ostringstream os;
8266 os << myRank << ": recvDataReqs[" << circBufInd << "] is not "
8267 << "null, for the receive-data receive from Process "
8268 << recvRank << "! This may mean that this process never "
8269 << "finished waiting for the receive from Process "
8270 << (recvRank - 3) << "." << endl;
8271 *err << os.str ();
8272 }
8273 recvDataReqs[circBufInd] =
8274 ireceive<int, int_type> (recvDataBufs[circBufInd],
8275 recvRank, dataTag, comm);
8276 }
8277
8278 // Wait on receive-data receive from Process p.
8279 const int recvRank = p;
8280 const int circBufInd = recvRank % 3;
8281 if (debug) {
8282 std::ostringstream os;
8283 os << myRank << ": Wait on receive-data receive from Process "
8284 << recvRank << endl;
8285 *err << os.str ();
8286 }
8287 wait<int> (comm, outArg (recvDataReqs[circBufInd]));
8288
8289 // Write Process p's data. Number of rows lives in
8290 // recvSizeBufs[circBufInd], and the actual data live in
8291 // recvDataBufs[circBufInd]. Do this after posting receives,
8292 // in order to expose overlap of comm. with file I/O.
8293 if (debug) {
8294 std::ostringstream os;
8295 os << myRank << ": Write GIDs and PIDs from Process "
8296 << recvRank << endl;
8297 *err << os.str () << endl;
8298 }
8299 const int_type printNumRows = (recvSizeBufs[circBufInd])[0];
8300 if (debug && printNumRows == -1) {
8301 std::ostringstream os;
8302 os << myRank << ": Result of receive-size receive from Process "
8303 << recvRank << " was -1. This should never happen, and "
8304 "suggests that its receive-size receive was never posted. "
8305 "Please report this bug to the Tpetra developers." << endl;
8306 *err << os.str ();
8307 }
8308 if (debug && printNumRows > 0 && recvDataBufs[circBufInd].is_null ()) {
8309 std::ostringstream os;
8310 os << myRank << ": Result of receive-size receive from Proc "
8311 << recvRank << " was " << printNumRows << " > 0, but "
8312 "recvDataBufs[" << circBufInd << "] is null. This should "
8313 "never happen. Please report this bug to the Tpetra "
8314 "developers." << endl;
8315 *err << os.str ();
8316 }
8317 ArrayView<const int_type> printData = (recvDataBufs[circBufInd]) ();
8318 for (int_type k = 0; k < printNumRows; ++k) {
8319 const int_type gid = printData[2*k];
8320 const int_type pid = printData[2*k+1];
8321 out << gid << endl << pid << endl;
8322 }
8323 }
8324 else if (myRank == p) { // Process p
8325 // Wait on my send-data send.
8326 if (debug) {
8327 std::ostringstream os;
8328 os << myRank << ": Wait on my send-data send" << endl;
8329 *err << os.str ();
8330 }
8331 wait<int> (comm, outArg (sendReqData));
8332 }
8333 else if (myRank == p + 1) { // Process p + 1
8334 // Post send-data send to Process 0.
8335 if (debug) {
8336 std::ostringstream os;
8337 os << myRank << ": Post send-data send: tag = " << dataTag
8338 << endl;
8339 *err << os.str ();
8340 }
8341 sendReqData = isend<int, int_type> (sendDataBuf, 0, dataTag, comm);
8342 // Wait on my send-size send.
8343 if (debug) {
8344 std::ostringstream os;
8345 os << myRank << ": Wait on my send-size send" << endl;
8346 *err << os.str ();
8347 }
8348 wait<int> (comm, outArg (sendReqSize));
8349 }
8350 else if (myRank == p + 2) { // Process p + 2
8351 // Post send-size send to Process 0.
8352 if (debug) {
8353 std::ostringstream os;
8354 os << myRank << ": Post send-size send: size = "
8355 << sendDataSize[0] << ", tag = " << sizeTag << endl;
8356 *err << os.str ();
8357 }
8358 sendReqSize = isend<int, int_type> (sendDataSize, 0, sizeTag, comm);
8359 }
8360 }
8361
8362 if (! err.is_null ()) {
8363 err->popTab ();
8364 }
8365 if (debug) {
8366 *err << myRank << ": writeMap: Done" << endl;
8367 }
8368 if (! err.is_null ()) {
8369 err->popTab ();
8370 }
8371 }
8372
8374 static void
8375 writeMapFile (const std::string& filename,
8376 const map_type& map)
8377 {
8378 const int myRank = map.getComm ()->getRank ();
8379 std::ofstream out;
8380 if (myRank == 0) { // Only open the file on Proc 0.
8381 out.open (filename.c_str());
8382 }
8383 writeMap (out, map);
8384 // We can rely on the destructor of the output stream to close
8385 // the file on scope exit, even if writeDense() throws an
8386 // exception.
8387 }
8388
8389 private:
8413 static void
8414 printAsComment (std::ostream& out, const std::string& str)
8415 {
8416 using std::endl;
8417 std::istringstream inpstream (str);
8418 std::string line;
8419
8420 while (getline (inpstream, line)) {
8421 if (! line.empty()) {
8422 // Note that getline() doesn't store '\n', so we have to
8423 // append the endline ourselves.
8424 if (line[0] == '%') { // Line starts with a comment character.
8425 out << line << endl;
8426 }
8427 else { // Line doesn't start with a comment character.
8428 out << "%% " << line << endl;
8429 }
8430 }
8431 }
8432 }
8433
8434 public:
8435
8454 static void
8455 writeOperator(const std::string& fileName, operator_type const &A) {
8456 Teuchos::ParameterList pl;
8457 writeOperator(fileName, A, pl);
8458 }
8459
8480 static void
8481 writeOperator (std::ostream& out, const operator_type& A) {
8482 Teuchos::ParameterList pl;
8483 writeOperator (out, A, pl);
8484 }
8485
8522 static void
8523 writeOperator (const std::string& fileName,
8524 const operator_type& A,
8525 const Teuchos::ParameterList& params)
8526 {
8527 std::ofstream out;
8528 std::string tmpFile = "__TMP__" + fileName;
8529 const int myRank = A.getDomainMap()->getComm()->getRank();
8530 bool precisionChanged=false;
8531 int oldPrecision;
8532 // The number of nonzero entries in a Tpetra::Operator is
8533 // unknown until probing is completed. In order to write a
8534 // MatrixMarket header, we write the matrix to a temporary
8535 // file.
8536 //
8537 // FIXME (mfh 23 May 2015) IT WASN'T MY IDEA TO WRITE TO A
8538 // TEMPORARY FILE.
8539 if (myRank==0) {
8540 if (std::ifstream(tmpFile))
8541 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error,
8542 "writeOperator: temporary file " << tmpFile << " already exists");
8543 out.open(tmpFile.c_str());
8544 if (params.isParameter("precision")) {
8545 oldPrecision = out.precision(params.get<int>("precision"));
8546 precisionChanged=true;
8547 }
8548 }
8549
8550 const std::string header = writeOperatorImpl(out, A, params);
8551
8552 if (myRank==0) {
8553 if (precisionChanged)
8554 out.precision(oldPrecision);
8555 out.close();
8556 out.open(fileName.c_str(), std::ios::binary);
8557 bool printMatrixMarketHeader = true;
8558 if (params.isParameter("print MatrixMarket header"))
8559 printMatrixMarketHeader = params.get<bool>("print MatrixMarket header");
8560 if (printMatrixMarketHeader && myRank == 0) {
8561 // Write header to final file.
8562 out << header;
8563 }
8564 // Append matrix from temporary to final file.
8565 std::ifstream src(tmpFile, std::ios_base::binary);
8566 out << src.rdbuf();
8567 src.close();
8568 // Delete the temporary file.
8569 remove(tmpFile.c_str());
8570 }
8571 }
8572
8611 static void
8612 writeOperator (std::ostream& out,
8613 const operator_type& A,
8614 const Teuchos::ParameterList& params)
8615 {
8616 const int myRank = A.getDomainMap ()->getComm ()->getRank ();
8617
8618 // The number of nonzero entries in a Tpetra::Operator is
8619 // unknown until probing is completed. In order to write a
8620 // MatrixMarket header, we write the matrix to a temporary
8621 // output stream.
8622 //
8623 // NOTE (mfh 23 May 2015): Writing to a temporary output
8624 // stream may double the memory usage, depending on whether
8625 // 'out' is a file stream or an in-memory output stream (e.g.,
8626 // std::ostringstream). It might be wise to use a temporary
8627 // file instead. However, please look carefully at POSIX
8628 // functions for safe creation of temporary files. Don't just
8629 // prepend "__TMP__" to the filename and hope for the best.
8630 // Furthermore, it should be valid to call the std::ostream
8631 // overload of this method even when Process 0 does not have
8632 // access to a file system.
8633 std::ostringstream tmpOut;
8634 if (myRank == 0) {
8635 if (params.isParameter ("precision") && params.isType<int> ("precision")) {
8636 (void) tmpOut.precision (params.get<int> ("precision"));
8637 }
8638 }
8639
8640 const std::string header = writeOperatorImpl (tmpOut, A, params);
8641
8642 if (myRank == 0) {
8643 bool printMatrixMarketHeader = true;
8644 if (params.isParameter ("print MatrixMarket header") &&
8645 params.isType<bool> ("print MatrixMarket header")) {
8646 printMatrixMarketHeader = params.get<bool> ("print MatrixMarket header");
8647 }
8648 if (printMatrixMarketHeader && myRank == 0) {
8649 out << header; // write header to final output stream
8650 }
8651 // Append matrix from temporary output stream to final output stream.
8652 //
8653 // NOTE (mfh 23 May 2015) This might use a lot of memory.
8654 // However, we should not use temporary files in this
8655 // method. Since it does not access the file system (unlike
8656 // the overload that takes a file name), it should not
8657 // require the file system at all.
8658 //
8659 // If memory usage becomes a problem, one thing we could do
8660 // is write the entries of the Operator one column (or a few
8661 // columns) at a time. The Matrix Market sparse format does
8662 // not impose an order on its entries, so it would be OK to
8663 // write them in that order.
8664 out << tmpOut.str ();
8665 }
8666 }
8667
8668 private:
8669
8677 static std::string
8678 writeOperatorImpl (std::ostream& os,
8679 const operator_type& A,
8680 const Teuchos::ParameterList& params)
8681 {
8682 using Teuchos::RCP;
8683 using Teuchos::rcp;
8684 using Teuchos::ArrayRCP;
8685 using Teuchos::Array;
8686
8687 typedef local_ordinal_type LO;
8688 typedef global_ordinal_type GO;
8689 typedef scalar_type Scalar;
8690 typedef Teuchos::OrdinalTraits<LO> TLOT;
8691 typedef Teuchos::OrdinalTraits<GO> TGOT;
8694
8695 const map_type& domainMap = *(A.getDomainMap());
8696 RCP<const map_type> rangeMap = A.getRangeMap();
8697 RCP<const Teuchos::Comm<int> > comm = rangeMap->getComm();
8698 const int myRank = comm->getRank();
8699 const size_t numProcs = comm->getSize();
8700
8701 size_t numMVs = 10;
8702 if (params.isParameter("probing size"))
8703 numMVs = params.get<int>("probing size");
8704
8705 GO globalNnz = 0;
8706 GO minColGid = domainMap.getMinAllGlobalIndex();
8707 GO maxColGid = domainMap.getMaxAllGlobalIndex();
8708 // Rather than replicating the domainMap on all processors, we instead
8709 // iterate from the min GID to the max GID. If the map is gappy,
8710 // there will be invalid GIDs, i.e., GIDs no one has. This will require
8711 // unnecessary matvecs against potentially zero vectors.
8712 GO numGlobElts = maxColGid - minColGid + TGOT::one();
8713 GO numChunks = numGlobElts / numMVs;
8714 GO rem = numGlobElts % numMVs;
8715 GO indexBase = rangeMap->getIndexBase();
8716
8717 int offsetToUseInPrinting = 1 - indexBase; // default is 1-based indexing
8718 if (params.isParameter("zero-based indexing")) {
8719 if (params.get<bool>("zero-based indexing") == true)
8720 offsetToUseInPrinting = -indexBase; // If 0-based, use as-is. If 1-based, subtract 1.
8721 }
8722
8723 // Create map that replicates the range map on pid 0 and is empty for all other pids
8724 size_t numLocalRangeEntries = rangeMap->getLocalNumElements();
8725
8726 // Create contiguous source map
8727 RCP<const map_type> allGidsMap = rcp(new map_type(TGOT::invalid(), numLocalRangeEntries,
8728 indexBase, comm));
8729 // Create vector based on above map. Populate it with GIDs corresponding to this pid's GIDs in rangeMap.
8730 mv_type_go allGids(allGidsMap,1);
8731 Teuchos::ArrayRCP<GO> allGidsData = allGids.getDataNonConst(0);
8732
8733 for (size_t i=0; i<numLocalRangeEntries; i++)
8734 allGidsData[i] = rangeMap->getGlobalElement(i);
8735 allGidsData = Teuchos::null;
8736
8737 // Create target map that is nontrivial only on pid 0
8738 GO numTargetMapEntries=TGOT::zero();
8739 Teuchos::Array<GO> importGidList;
8740 if (myRank==0) {
8741 numTargetMapEntries = rangeMap->getGlobalNumElements();
8742 importGidList.reserve(numTargetMapEntries);
8743 for (GO j=0; j<numTargetMapEntries; ++j) importGidList.push_back(j + indexBase);
8744 } else {
8745 importGidList.reserve(numTargetMapEntries);
8746 }
8747 RCP<map_type> importGidMap = rcp(new map_type(TGOT::invalid(), importGidList(), indexBase, comm));
8748
8749 // Import all rangeMap GIDs to pid 0
8750 import_type gidImporter(allGidsMap, importGidMap);
8751 mv_type_go importedGids(importGidMap, 1);
8752 importedGids.doImport(allGids, gidImporter, INSERT);
8753
8754 // The following import map will be non-trivial only on pid 0.
8755 ArrayRCP<const GO> importedGidsData = importedGids.getData(0);
8756 RCP<const map_type> importMap = rcp(new map_type(TGOT::invalid(), importedGidsData(), indexBase, comm) );
8757
8758 // Importer from original range map to pid 0
8759 import_type importer(rangeMap, importMap);
8760 // Target vector on pid 0
8761 RCP<mv_type> colsOnPid0 = rcp(new mv_type(importMap,numMVs));
8762
8763 RCP<mv_type> ei = rcp(new mv_type(A.getDomainMap(),numMVs)); //probing vector
8764 RCP<mv_type> colsA = rcp(new mv_type(A.getRangeMap(),numMVs)); //columns of A revealed by probing
8765
8766 Array<GO> globalColsArray, localColsArray;
8767 globalColsArray.reserve(numMVs);
8768 localColsArray.reserve(numMVs);
8769
8770 ArrayRCP<ArrayRCP<Scalar> > eiData(numMVs);
8771 for (size_t i=0; i<numMVs; ++i)
8772 eiData[i] = ei->getDataNonConst(i);
8773
8774 // //////////////////////////////////////
8775 // Discover A by chunks
8776 // //////////////////////////////////////
8777 for (GO k=0; k<numChunks; ++k) {
8778 for (size_t j=0; j<numMVs; ++j ) {
8779 //GO curGlobalCol = maxColGid - numMVs + j + TGOT::one();
8780 GO curGlobalCol = minColGid + k*numMVs + j;
8781 globalColsArray.push_back(curGlobalCol);
8782 //TODO extract the g2l map outside of this loop loop
8783 LO curLocalCol = domainMap.getLocalElement(curGlobalCol);
8784 if (curLocalCol != TLOT::invalid()) {
8785 eiData[j][curLocalCol] = TGOT::one();
8786 localColsArray.push_back(curLocalCol);
8787 }
8788 }
8789
8790 // drop host views before apply
8791 for (size_t i=0; i<numMVs; ++i)
8792 eiData[i] = Teuchos::null;
8793 // probe
8794 A.apply(*ei,*colsA);
8795
8796 colsOnPid0->doImport(*colsA,importer,INSERT);
8797
8798 if (myRank==0)
8799 globalNnz += writeColumns(os,*colsOnPid0, numMVs, importedGidsData(),
8800 globalColsArray, offsetToUseInPrinting);
8801
8802 // reconstruct dropped eiData
8803 for (size_t i=0; i<numMVs; ++i)
8804 eiData[i] = ei->getDataNonConst(i);
8805 for (size_t j=0; j<numMVs; ++j ) {
8806 GO curGlobalCol = minColGid + k*numMVs + j;
8807 //TODO extract the g2l map outside of this loop loop
8808 LO curLocalCol = domainMap.getLocalElement(curGlobalCol);
8809 if (curLocalCol != TLOT::invalid()) {
8810 eiData[j][curLocalCol] = TGOT::one();
8811 }
8812 }
8813
8814 //zero out the ei's
8815 for (size_t j=0; j<numMVs; ++j ) {
8816 for (int i=0; i<localColsArray.size(); ++i)
8817 eiData[j][localColsArray[i]] = TGOT::zero();
8818 }
8819 globalColsArray.clear();
8820 localColsArray.clear();
8821
8822 }
8823
8824 // //////////////////////////////////////
8825 // Handle leftover part of A
8826 // //////////////////////////////////////
8827 if (rem > 0) {
8828 for (int j=0; j<rem; ++j ) {
8829 GO curGlobalCol = maxColGid - rem + j + TGOT::one();
8830 globalColsArray.push_back(curGlobalCol);
8831 //TODO extract the g2l map outside of this loop loop
8832 LO curLocalCol = domainMap.getLocalElement(curGlobalCol);
8833 if (curLocalCol != TLOT::invalid()) {
8834 eiData[j][curLocalCol] = TGOT::one();
8835 localColsArray.push_back(curLocalCol);
8836 }
8837 }
8838
8839 // drop host views before apply
8840 for (size_t i=0; i<numMVs; ++i)
8841 eiData[i] = Teuchos::null;
8842 // probe
8843 A.apply(*ei,*colsA);
8844
8845 colsOnPid0->doImport(*colsA,importer,INSERT);
8846 if (myRank==0)
8847 globalNnz += writeColumns(os,*colsOnPid0, rem, importedGidsData(),
8848 globalColsArray, offsetToUseInPrinting);
8849
8850 // reconstruct dropped eiData
8851 for (size_t i=0; i<numMVs; ++i)
8852 eiData[i] = ei->getDataNonConst(i);
8853 for (int j=0; j<rem; ++j ) {
8854 GO curGlobalCol = maxColGid - rem + j + TGOT::one();
8855 //TODO extract the g2l map outside of this loop loop
8856 LO curLocalCol = domainMap.getLocalElement(curGlobalCol);
8857 if (curLocalCol != TLOT::invalid()) {
8858 eiData[j][curLocalCol] = TGOT::one();
8859 }
8860 }
8861
8862 //zero out the ei's
8863 for (int j=0; j<rem; ++j ) {
8864 for (int i=0; i<localColsArray.size(); ++i)
8865 eiData[j][localColsArray[i]] = TGOT::zero();
8866 }
8867 globalColsArray.clear();
8868 localColsArray.clear();
8869
8870 }
8871
8872 // Return the Matrix Market header. It includes the header
8873 // line (that starts with "%%"), some comments, and the triple
8874 // of matrix dimensions and number of nonzero entries. We
8875 // don't actually print this here, because we don't know the
8876 // number of nonzero entries until after probing.
8877 std::ostringstream oss;
8878 if (myRank == 0) {
8879 oss << "%%MatrixMarket matrix coordinate ";
8880 if (Teuchos::ScalarTraits<typename operator_type::scalar_type>::isComplex) {
8881 oss << "complex";
8882 } else {
8883 oss << "real";
8884 }
8885 oss << " general" << std::endl;
8886 oss << "% Tpetra::Operator" << std::endl;
8887 std::time_t now = std::time(NULL);
8888 oss << "% time stamp: " << ctime(&now);
8889 oss << "% written from " << numProcs << " processes" << std::endl;
8890 size_t numRows = rangeMap->getGlobalNumElements();
8891 size_t numCols = domainMap.getGlobalNumElements();
8892 oss << numRows << " " << numCols << " " << globalNnz << std::endl;
8893 }
8894
8895 return oss.str ();
8896 }
8897
8898 static global_ordinal_type
8899 writeColumns(std::ostream& os, mv_type const &colsA, size_t const &numCols,
8900 Teuchos::ArrayView<const global_ordinal_type> const &rowGids,
8901 Teuchos::Array<global_ordinal_type> const &colsArray,
8902 global_ordinal_type const & indexBase) {
8903
8904 typedef global_ordinal_type GO;
8905 typedef scalar_type Scalar;
8906 typedef Teuchos::ScalarTraits<Scalar> STS;
8907
8908 GO nnz=0;
8909 const Scalar zero = STS::zero();
8910 const size_t numRows = colsA.getGlobalLength();
8911 for (size_t j=0; j<numCols; ++j) {
8912 Teuchos::ArrayRCP<const Scalar> const curCol = colsA.getData(j);
8913 const GO J = colsArray[j];
8914 for (size_t i=0; i<numRows; ++i) {
8915 const Scalar val = curCol[i];
8916 if (val!=zero) {
8917 os << rowGids[i]+indexBase << " " << J+indexBase << " " << val << std::endl;
8918 ++nnz;
8919 }
8920 }
8921 }
8922
8923 return nnz;
8924
8925 }
8926
8927 public:
8928
8929
8936
8937 static
8938 void
8939 writeSparsePerRank (const std::string& filename_prefix,
8940 const std::string& filename_suffix,
8941 const sparse_matrix_type& matrix,
8942 const std::string& matrixName,
8943 const std::string& matrixDescription,
8944 const int ranksToWriteAtOnce=8,
8945 const bool debug=false) {
8946
8947 using ST = scalar_type;
8948 //using LO = local_ordinal_type;
8949 using GO = global_ordinal_type;
8950 using STS = typename Teuchos::ScalarTraits<ST>;
8951 using Teuchos::RCP;
8952
8953 // Sanity Checks
8954 Teuchos::RCP<const Teuchos::Comm<int> > comm = matrix.getComm ();
8955 TEUCHOS_TEST_FOR_EXCEPTION
8956 (comm.is_null (), std::invalid_argument,
8957 "The input matrix's communicator (Teuchos::Comm object) is null.");
8958 TEUCHOS_TEST_FOR_EXCEPTION
8959 (matrix.isGloballyIndexed() || !matrix.isFillComplete(), std::invalid_argument,
8960 "The input matrix must not be GloballyIndexed and must be fillComplete.");
8961
8962 // Setup
8963 const int myRank = comm->getRank();
8964 const int numProc = comm->getSize();
8965 std::string filename = filename_prefix + std::to_string(myRank) + filename_suffix;
8966 RCP<const map_type> rowMap = matrix.getRowMap();
8967 RCP<const map_type> colMap = matrix.getColMap();
8968 size_t local_nnz = matrix.getLocalNumEntries();
8969 size_t local_num_rows = rowMap->getLocalNumElements();
8970 size_t local_num_cols = colMap->getLocalNumElements();
8971 const GO rowIndexBase = rowMap->getIndexBase();
8972 const GO colIndexBase = colMap->getIndexBase();
8973
8974 // Bounds check the writing limits
8975 int rank_limit = std::min(std::max(ranksToWriteAtOnce,1),numProc);
8976
8977 // Start the writing
8978 for(int base_rank = 0; base_rank < numProc; base_rank += rank_limit) {
8979 int stop = std::min(base_rank+rank_limit,numProc);
8980
8981 if(base_rank <= myRank && myRank < stop) {
8982 // My turn to write
8983 std::ofstream out(filename);
8984
8985 // MatrixMarket Header
8986 out << "%%MatrixMarket matrix coordinate "
8987 << (STS::isComplex ? "complex" : "real")
8988 << " general" << std::endl;
8989
8990 // Print comments (the matrix name and / or description).
8991 if (matrixName != "") {
8992 printAsComment (out, matrixName);
8993 }
8994 if (matrixDescription != "") {
8995 printAsComment (out, matrixDescription);
8996 }
8997
8998 // Print the Matrix Market header (# local rows, # local columns, #
8999 // local enonzeros). This will *not* be read correctly by a generic matrix
9000 // market reader since we'll be writing out GIDs here and local row/col counts
9001 out << local_num_rows << " " << local_num_cols << " " << local_nnz <<std::endl;
9002
9003 {
9004 // Make the output stream write floating-point numbers in
9005 // scientific notation. It will politely put the output
9006 // stream back to its state on input, when this scope
9007 // terminates.
9008 Teuchos::SetScientific<ST> sci (out);
9009
9010 for(size_t l_row = 0; l_row < local_num_rows; l_row++) {
9011 GO g_row = rowMap->getGlobalElement(l_row);
9012
9013 typename sparse_matrix_type::local_inds_host_view_type indices;
9014 typename sparse_matrix_type::values_host_view_type values;
9015 matrix.getLocalRowView(l_row, indices, values);
9016 for (size_t ii = 0; ii < indices.extent(0); ii++) {
9017 const GO g_col = colMap->getGlobalElement(indices(ii));
9018 // Convert row and column indices to 1-based.
9019 // This works because the global index type is signed.
9020 out << (g_row + 1 - rowIndexBase) << " "
9021 << (g_col + 1 - colIndexBase) << " ";
9022 if (STS::isComplex) {
9023 out << STS::real(values(ii)) << " " << STS::imag(values(ii));
9024 } else {
9025 out << values(ii);
9026 }
9027 out << std::endl;
9028 } // For each entry in the current row
9029 } // For each row of the matrix
9030 }// end Teuchos::SetScientfic scoping
9031
9032 out.close();
9033 }// end if base_rank <= myRank < stop
9034
9035 // Barrier after each writing "batch" to make sure we're not hammering the file system
9036 // too aggressively
9037 comm->barrier();
9038
9039 }// end outer loop
9040
9041 }// end writeSparsePerRank
9042
9043 }; // class Writer
9044
9045 } // namespace MatrixMarket
9046} // namespace Tpetra
9047
9048#endif // __MatrixMarket_Tpetra_hpp
From a distributed map build a map with all GIDs on the root node.
Declaration of a function that prints strings from each process.
A distributed graph accessed by rows (adjacency lists) and stored sparsely.
Teuchos::RCP< const map_type > getColMap() const override
Returns the Map that describes the column distribution in this graph.
global_size_t getGlobalNumEntries() const override
Returns the global number of entries in the graph.
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const override
Returns the communicator.
void fillComplete(const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const Teuchos::RCP< Teuchos::ParameterList > &params=Teuchos::null)
Tell the graph that you are done changing its structure.
Teuchos::RCP< const map_type > getDomainMap() const override
Returns the Map associated with the domain of this graph.
void getGlobalRowView(const global_ordinal_type gblRow, global_inds_host_view_type &gblColInds) const override
Get a const view of the given global row's global column indices.
Teuchos::RCP< const map_type > getRangeMap() const override
Returns the Map associated with the domain of this graph.
Teuchos::RCP< const map_type > getRowMap() const override
Returns the Map that describes the row distribution in this graph.
void getLocalRowView(const LocalOrdinal lclRow, local_inds_host_view_type &lclColInds) const override
Get a const view of the given local row's local column indices.
bool isGloballyIndexed() const override
Whether the graph's column indices are stored as global indices.
Teuchos::RCP< const map_type > getRangeMap() const override
The range Map of this matrix.
void doImport(const SrcDistObject &source, const Import< LocalOrdinal, GlobalOrdinal, Node > &importer, const CombineMode CM, const bool restrictedMode=false)
Communication plan for data redistribution from a (possibly) multiply-owned to a uniquely-owned distr...
Communication plan for data redistribution from a uniquely-owned to a (possibly) multiply-owned distr...
A parallel distribution of indices over processes.
Teuchos::ArrayView< const global_ordinal_type > getLocalElementList() const
Return a NONOWNING view of the global indices owned by this process.
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
Accessors for the Teuchos::Comm and Kokkos Node objects.
global_ordinal_type getMinGlobalIndex() const
The minimum global index owned by the calling process.
global_size_t getGlobalNumElements() const
The number of elements in this Map.
bool isContiguous() const
True if this Map is distributed contiguously, else false.
size_t getLocalNumElements() const
The number of elements belonging to the calling process.
Matrix Market file reader for CrsMatrix and MultiVector.
MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > multivector_type
The MultiVector specialization associated with SparseMatrixType.
static Teuchos::RCP< sparse_matrix_type > readSparse(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream.
static Teuchos::RCP< const map_type > readMap(std::istream &in, const Teuchos::RCP< const comm_type > &comm, const Teuchos::RCP< Teuchos::FancyOStream > &err, const bool tolerant=false, const bool debug=false, const bool binary=false)
Read Map (as a MultiVector) from the given input stream, with optional debugging output stream.
SparseMatrixType::global_ordinal_type global_ordinal_type
static Teuchos::RCP< const map_type > readMap(std::istream &in, const Teuchos::RCP< const comm_type > &comm, const bool tolerant=false, const bool debug=false, const bool binary=false)
Read Map (as a MultiVector) from the given input stream.
static Teuchos::RCP< vector_type > readVector(std::istream &in, const Teuchos::RCP< const comm_type > &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Read Vector from the given Matrix Market input stream.
static Teuchos::RCP< sparse_matrix_type > readSparsePerRank(const std::string &filename_prefix, const std::string &filename_suffix, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const int ranksToReadAtOnce=8, const bool debug=false)
Read a Tpetra::CrsMatrix from a file per rank setup.
Vector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > vector_type
The Vector specialization associated with SparseMatrixType.
static Teuchos::RCP< sparse_matrix_type > readSparse(std::istream &in, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream, with provided Maps.
static Teuchos::RCP< sparse_matrix_type > readSparseFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market file.
SparseMatrixType::node_type node_type
The fourth template parameter of CrsMatrix and MultiVector.
static Teuchos::RCP< multivector_type > readDenseFile(const std::string &filename, const Teuchos::RCP< const comm_type > &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false, const bool binary=false)
Read dense matrix (as a MultiVector) from the given Matrix Market file.
static Teuchos::RCP< sparse_matrix_type > readSparse(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream.
static Teuchos::RCP< vector_type > readVectorFile(const std::string &filename, const Teuchos::RCP< const comm_type > &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Read a Vector from the given Matrix Market file.
static Teuchos::RCP< const map_type > readMapFile(const std::string &filename, const Teuchos::RCP< const comm_type > &comm, const bool tolerant=false, const bool debug=false, const bool binary=false)
Read Map (as a MultiVector) from the given Matrix Market file.
static Teuchos::RCP< sparse_graph_type > readSparseGraph(std::istream &in, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream, with provided Maps.
static Teuchos::RCP< sparse_graph_type > readSparseGraphFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &comm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market file.
static Teuchos::RCP< sparse_matrix_type > readSparseFile(const std::string &filename, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market file, with provided Maps.
SparseMatrixType::local_ordinal_type local_ordinal_type
SparseMatrixType sparse_matrix_type
This class' template parameter; a specialization of CrsMatrix.
static Teuchos::RCP< sparse_graph_type > readSparseGraphFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market file.
static Teuchos::RCP< sparse_graph_type > readSparseGraph(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market input stream.
static Teuchos::RCP< multivector_type > readDense(std::istream &in, const Teuchos::RCP< const comm_type > &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false, const bool binary=false)
Read dense matrix (as a MultiVector) from the given Matrix Market input stream.
static Teuchos::RCP< sparse_graph_type > readSparseGraph(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market input stream.
static Teuchos::RCP< sparse_matrix_type > readSparseFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market file.
SparseMatrixType::scalar_type scalar_type
static Teuchos::RCP< sparse_graph_type > readSparseGraphFile(const std::string &filename, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market file, with provided Maps.
CrsGraph< local_ordinal_type, global_ordinal_type, node_type > sparse_graph_type
The CrsGraph specialization associated with SparseMatrixType.
Matrix Market file writer for CrsMatrix and MultiVector.
static void writeMap(std::ostream &out, const map_type &map, const bool debug=false)
Print the Map to the given output stream.
static void writeDense(std::ostream &out, const Teuchos::RCP< const multivector_type > &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and or description.
static void writeSparseFile(const std::string &filename, const Teuchos::RCP< const sparse_matrix_type > &pMatrix, const std::string &matrixName, const std::string &matrixDescription, const bool debug=false)
Only for backwards compatibility; prefer the overload above.
CrsGraph< local_ordinal_type, global_ordinal_type, node_type > crs_graph_type
Specialization of Tpetra::CrsGraph that matches SparseMatrixType.
static void writeSparseFile(const std::string &filename, const Teuchos::RCP< const sparse_matrix_type > &pMatrix, const bool debug=false)
Only for backwards compatibility; prefer the overload above.
static void writeSparseGraphFile(const std::string &filename, const crs_graph_type &graph, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename), with no comments.
static void writeDense(std::ostream &out, const multivector_type &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and description.
static void writeSparsePerRank(const std::string &filename_prefix, const std::string &filename_suffix, const sparse_matrix_type &matrix, const std::string &matrixName, const std::string &matrixDescription, const int ranksToWriteAtOnce=8, const bool debug=false)
Write a Tpetra::CrsMatrix to a file per rank.
static void writeSparseGraphFile(const std::string &filename, const Teuchos::RCP< const crs_graph_type > &pGraph, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename), with no comments,...
SparseMatrixType sparse_matrix_type
Template parameter of this class; specialization of CrsMatrix.
static void writeSparse(std::ostream &out, const sparse_matrix_type &matrix, const std::string &matrixName, const std::string &matrixDescription, const bool debug=false)
Print the sparse matrix in Matrix Market format, with comments.
SparseMatrixType::scalar_type scalar_type
Type of the entries of the sparse matrix.
static void writeSparseGraphFile(const std::string &filename, const Teuchos::RCP< const crs_graph_type > &pGraph, const std::string &graphName, const std::string &graphDescription, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename), taking the graph by T...
static void writeDenseFile(const std::string &filename, const Teuchos::RCP< const multivector_type > &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and description.
static void writeDense(std::ostream &out, const Teuchos::RCP< const multivector_type > &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
SparseMatrixType::global_ordinal_type global_ordinal_type
Type of indices as read from the Matrix Market file.
SparseMatrixType::node_type node_type
The Kokkos Node type; fourth template parameter of Tpetra::CrsMatrix.
static void writeDense(std::ostream &out, const multivector_type &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
static void writeSparse(std::ostream &out, const Teuchos::RCP< const sparse_matrix_type > &pMatrix, const std::string &matrixName, const std::string &matrixDescription, const bool debug=false)
Only for backwards compatibility; prefer the overload above.
static void writeOperator(std::ostream &out, const operator_type &A)
Write a Tpetra::Operator to an output stream.
static void writeOperator(const std::string &fileName, operator_type const &A)
Write a Tpetra::Operator to a file.
static void writeOperator(std::ostream &out, const operator_type &A, const Teuchos::ParameterList &params)
Write a Tpetra::Operator to an output stream, with options.
static void writeDenseFile(const std::string &filename, const multivector_type &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and description.
static void writeDenseFile(const std::string &filename, const multivector_type &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
static void writeSparseGraph(std::ostream &out, const crs_graph_type &graph, const bool debug=false)
Print the sparse graph in Matrix Market format to the given output stream, with no comments.
static void writeOperator(const std::string &fileName, const operator_type &A, const Teuchos::ParameterList &params)
Write a Tpetra::Operator to a file, with options.
MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > multivector_type
Specialization of Tpetra::MultiVector that matches SparseMatrixType.
static void writeSparse(std::ostream &out, const Teuchos::RCP< const sparse_matrix_type > &pMatrix, const bool debug=false)
Only for backwards compatibility; prefer the overload above.
static void writeMapFile(const std::string &filename, const map_type &map)
Write the Map to the given file.
static void writeDenseFile(const std::string &filename, const Teuchos::RCP< const multivector_type > &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
Map< local_ordinal_type, global_ordinal_type, node_type > map_type
Specialization of Tpetra::Map that matches SparseMatrixType.
SparseMatrixType::local_ordinal_type local_ordinal_type
Type of the local indices of the sparse matrix.
static void writeSparseFile(const std::string &filename, const sparse_matrix_type &matrix, const std::string &matrixName, const std::string &matrixDescription, const bool debug=false)
Print the sparse matrix in Matrix Market format, with comments.
static void writeSparseGraph(std::ostream &out, const crs_graph_type &graph, const std::string &graphName, const std::string &graphDescription, const bool debug=false)
Print the sparse graph in Matrix Market format to the given output stream.
static void writeSparseGraphFile(const std::string &filename, const crs_graph_type &graph, const std::string &graphName, const std::string &graphDescription, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename).
static void writeMap(std::ostream &out, const map_type &map, const Teuchos::RCP< Teuchos::FancyOStream > &err, const bool debug=false)
Print the Map to the given output stream out.
static void writeSparseFile(const std::string &filename, const sparse_matrix_type &matrix, const bool debug=false)
Print the sparse matrix in Matrix Market format.
static void writeSparse(std::ostream &out, const sparse_matrix_type &matrix, const bool debug=false)
Print the sparse matrix in Matrix Market format.
One or more distributed dense vectors.
Teuchos::RCP< const Vector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > getVector(const size_t j) const
Return a Vector which is a const view of column j.
size_t getNumVectors() const
Number of columns in the multivector.
Abstract interface for operators (e.g., matrices and preconditioners).
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 distributed dense vector.
Matrix Market file readers and writers for sparse and dense matrices (as CrsMatrix resp....
void gathervPrint(std::ostream &out, const std::string &s, const Teuchos::Comm< int > &comm)
On Process 0 in the given communicator, print strings from each process in that communicator,...
Namespace Tpetra contains the class and methods constituting the Tpetra library.
Teuchos::RCP< MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > createMultiVector(const Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > &map, const size_t numVectors)
Nonmember MultiVector "constructor": Create a MultiVector from a given Map.
Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > createUniformContigMapWithNode(const global_size_t numElements, const Teuchos::RCP< const Teuchos::Comm< int > > &comm)
Non-member constructor for a uniformly distributed, contiguous Map with a user-specified Kokkos Node.
Teuchos::RCP< Vector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > createVector(const Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > &map)
Nonmember Vector "constructor": Create a Vector from a given Map.
size_t global_size_t
Global size_t object.
@ INSERT
Insert new values that don't currently exist.
Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > createContigMapWithNode(const global_size_t numElements, const size_t localNumElements, const Teuchos::RCP< const Teuchos::Comm< int > > &comm)
Nonmember constructor for a (potentially) nonuniformly distributed, contiguous Map for a user-specifi...