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 {
325 return createUniformContigMapWithNode<LO,GO,NT> (numCols,
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 for (global_ordinal_type r = prvRow+1; r <= curRow; ++r) {
3677 rowPtr[r] = curPos;
3678 }
3679 prvRow = curRow;
3680 }
3681 numEntriesPerRow[curRow]++;
3682 colInd[curPos] = curEntry.colIndex();
3683 values[curPos] = curEntry.value();
3684 }
3685 // rowPtr has one more entry than numEntriesPerRow. The
3686 // last entry of rowPtr is the number of entries in
3687 // colInd and values.
3688 rowPtr[numRows] = numEntries;
3689 } // Finished conversion to CSR format
3690 catch (std::exception& e) {
3691 mergeAndConvertSucceeded = 0;
3692 errMsg << "Failed to merge sparse matrix entries and convert to "
3693 "CSR format: " << e.what();
3694 }
3695
3696 if (debug && mergeAndConvertSucceeded) {
3697 // Number of rows in the matrix.
3698 const size_type numRows = dims[0];
3699 const size_type maxToDisplay = 100;
3700
3701 cerr << "----- Proc 0: numEntriesPerRow[0.."
3702 << (numEntriesPerRow.size()-1) << "] ";
3703 if (numRows > maxToDisplay) {
3704 cerr << "(only showing first and last few entries) ";
3705 }
3706 cerr << "= [";
3707 if (numRows > 0) {
3708 if (numRows > maxToDisplay) {
3709 for (size_type k = 0; k < 2; ++k) {
3710 cerr << numEntriesPerRow[k] << " ";
3711 }
3712 cerr << "... ";
3713 for (size_type k = numRows-2; k < numRows-1; ++k) {
3714 cerr << numEntriesPerRow[k] << " ";
3715 }
3716 }
3717 else {
3718 for (size_type k = 0; k < numRows-1; ++k) {
3719 cerr << numEntriesPerRow[k] << " ";
3720 }
3721 }
3722 cerr << numEntriesPerRow[numRows-1];
3723 } // numRows > 0
3724 cerr << "]" << endl;
3725
3726 cerr << "----- Proc 0: rowPtr ";
3727 if (numRows > maxToDisplay) {
3728 cerr << "(only showing first and last few entries) ";
3729 }
3730 cerr << "= [";
3731 if (numRows > maxToDisplay) {
3732 for (size_type k = 0; k < 2; ++k) {
3733 cerr << rowPtr[k] << " ";
3734 }
3735 cerr << "... ";
3736 for (size_type k = numRows-2; k < numRows; ++k) {
3737 cerr << rowPtr[k] << " ";
3738 }
3739 }
3740 else {
3741 for (size_type k = 0; k < numRows; ++k) {
3742 cerr << rowPtr[k] << " ";
3743 }
3744 }
3745 cerr << rowPtr[numRows] << "]" << endl;
3746
3747 cerr << "----- Proc 0: colInd = [";
3748 for (size_t k = 0; k < rowPtr[numRows]; ++k) {
3749 cerr << colInd[k] << " ";
3750 }
3751 cerr << "]" << endl;
3752 }
3753 } // if myRank == rootRank
3754 } // Done converting sparse matrix data to CSR format
3755
3756 // Now we're done with the Adder, so we can release the
3757 // reference ("free" it) to save space. This only actually
3758 // does anything on Rank 0, since pAdder is null on all the
3759 // other MPI processes.
3760 pAdder = null;
3761
3762 // Verify details of the Maps. Don't count the global number
3763 // of entries in the row Map, since that number doesn't
3764 // correctly count overlap.
3765 if (debug && myRank == rootRank) {
3766 cerr << "-- Verifying Maps" << endl;
3767 }
3768 TEUCHOS_TEST_FOR_EXCEPTION(
3769 as<global_size_t> (dims[0]) != rangeMap->getGlobalNumElements(),
3770 std::invalid_argument,
3771 "The range Map has " << rangeMap->getGlobalNumElements ()
3772 << " entries, but the matrix has a global number of rows " << dims[0]
3773 << ".");
3774 TEUCHOS_TEST_FOR_EXCEPTION(
3775 as<global_size_t> (dims[1]) != domainMap->getGlobalNumElements (),
3776 std::invalid_argument,
3777 "The domain Map has " << domainMap->getGlobalNumElements ()
3778 << " entries, but the matrix has a global number of columns "
3779 << dims[1] << ".");
3780
3781 // Create a row Map which is entirely owned on Proc 0.
3782 RCP<Teuchos::FancyOStream> err = debug ?
3783 Teuchos::getFancyOStream (Teuchos::rcpFromRef (cerr)) : null;
3784
3785 RCP<const map_type> gatherRowMap = Details::computeGatherMap (rowMap, err, debug);
3786 ArrayView<const global_ordinal_type> myRows =
3787 gatherRowMap->getLocalElementList ();
3788 const size_type myNumRows = myRows.size ();
3789 const global_ordinal_type indexBase = gatherRowMap->getIndexBase ();
3790
3791 ArrayRCP<size_t> gatherNumEntriesPerRow = arcp<size_t>(myNumRows);
3792 for (size_type i_ = 0; i_ < myNumRows; i_++) {
3793 gatherNumEntriesPerRow[i_] = numEntriesPerRow[myRows[i_]-indexBase];
3794 }
3795
3796 // Create a matrix using this Map, and fill in on Proc 0. We
3797 // know how many entries there are in each row, so we can use
3798 // static profile.
3799 RCP<sparse_matrix_type> A_proc0 =
3800 rcp (new sparse_matrix_type (gatherRowMap, gatherNumEntriesPerRow()));
3801 if (myRank == rootRank) {
3802 if (debug) {
3803 cerr << "-- Proc 0: Filling gather matrix" << endl;
3804 }
3805 if (debug) {
3806 cerr << "---- Rows: " << Teuchos::toString (myRows) << endl;
3807 }
3808
3809 // Add Proc 0's matrix entries to the CrsMatrix.
3810 for (size_type i_ = 0; i_ < myNumRows; ++i_) {
3811 size_type i = myRows[i_] - indexBase;
3812
3813 const size_type curPos = as<size_type> (rowPtr[i]);
3814 const local_ordinal_type curNumEntries = numEntriesPerRow[i];
3815 ArrayView<global_ordinal_type> curColInd =
3816 colInd.view (curPos, curNumEntries);
3817 ArrayView<scalar_type> curValues =
3818 values.view (curPos, curNumEntries);
3819
3820 // Modify the column indices in place to have the right index base.
3821 for (size_type k = 0; k < curNumEntries; ++k) {
3822 curColInd[k] += indexBase;
3823 }
3824 if (debug) {
3825 cerr << "------ Columns: " << Teuchos::toString (curColInd) << endl;
3826 cerr << "------ Values: " << Teuchos::toString (curValues) << endl;
3827 }
3828 // Avoid constructing empty views of ArrayRCP objects.
3829 if (curNumEntries > 0) {
3830 A_proc0->insertGlobalValues (myRows[i_], curColInd, curValues);
3831 }
3832 }
3833 // Now we can save space by deallocating numEntriesPerRow,
3834 // rowPtr, colInd, and values, since we've already put those
3835 // data in the matrix.
3836 numEntriesPerRow = null;
3837 rowPtr = null;
3838 colInd = null;
3839 values = null;
3840 } // if myRank == rootRank
3841
3842 RCP<sparse_matrix_type> A;
3844 export_type exp (gatherRowMap, rowMap);
3845
3846 // Communicate the precise number of nonzeros per row, which was already
3847 // calculated above.
3848 typedef local_ordinal_type LO;
3849 typedef global_ordinal_type GO;
3851 mv_type_go target_nnzPerRow(rowMap,1);
3852 mv_type_go source_nnzPerRow(gatherRowMap,1);
3853 Teuchos::ArrayRCP<GO> srcData = source_nnzPerRow.getDataNonConst(0);
3854 for (int i=0; i<myNumRows; i++)
3855 srcData[i] = gatherNumEntriesPerRow[i];
3856 srcData = Teuchos::null;
3857 target_nnzPerRow.doExport(source_nnzPerRow,exp,Tpetra::INSERT);
3858 Teuchos::ArrayRCP<GO> targetData = target_nnzPerRow.getDataNonConst(0);
3859 ArrayRCP<size_t> targetData_size_t = arcp<size_t>(targetData.size());
3860 for (int i=0; i<targetData.size(); i++)
3861 targetData_size_t[i] = targetData[i];
3862
3863 if (colMap.is_null ()) {
3864 A = rcp (new sparse_matrix_type (rowMap, targetData_size_t()));
3865 } else {
3866 A = rcp (new sparse_matrix_type (rowMap, colMap, targetData_size_t()));
3867 }
3868 A->doExport (*A_proc0, exp, INSERT);
3869 if (callFillComplete) {
3870 A->fillComplete (domainMap, rangeMap);
3871 }
3872
3873 // We can't get the dimensions of the matrix until after
3874 // fillComplete() is called. Thus, we can't do the sanity
3875 // check (dimensions read from the Matrix Market data,
3876 // vs. dimensions reported by the CrsMatrix) unless the user
3877 // asked us to call fillComplete().
3878 //
3879 // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
3880 // what one might think it does, so you have to ask the range
3881 // resp. domain map for the number of rows resp. columns.
3882 if (callFillComplete) {
3883 const int numProcs = pComm->getSize ();
3884
3885 if (extraDebug && debug) {
3886 const global_size_t globalNumRows = rangeMap->getGlobalNumElements ();
3887 const global_size_t globalNumCols = domainMap->getGlobalNumElements ();
3888 if (myRank == rootRank) {
3889 cerr << "-- Matrix is "
3890 << globalNumRows << " x " << globalNumCols
3891 << " with " << A->getGlobalNumEntries()
3892 << " entries, and index base "
3893 << A->getIndexBase() << "." << endl;
3894 }
3895 pComm->barrier ();
3896 for (int p = 0; p < numProcs; ++p) {
3897 if (myRank == p) {
3898 cerr << "-- Proc " << p << " owns "
3899 << A->getLocalNumCols() << " columns, and "
3900 << A->getLocalNumEntries() << " entries." << endl;
3901 }
3902 pComm->barrier ();
3903 }
3904 } // if (extraDebug && debug)
3905 } // if (callFillComplete)
3906
3907 if (debug && myRank == rootRank) {
3908 cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
3909 << endl;
3910 }
3911 return A;
3912 }
3913
3943 static Teuchos::RCP<multivector_type>
3944 readDenseFile (const std::string& filename,
3945 const Teuchos::RCP<const comm_type>& comm,
3946 Teuchos::RCP<const map_type>& map,
3947 const bool tolerant=false,
3948 const bool debug=false,
3949 const bool binary=false)
3950 {
3951 using Teuchos::broadcast;
3952 using Teuchos::outArg;
3953
3954 std::ifstream in;
3955 int opened = 0;
3956 if (comm->getRank() == 0) {
3957 try {
3958 if (!binary)
3959 in.open (filename.c_str ());
3960 else
3961 in.open (filename.c_str (), std::ios::binary);
3962 opened = in.is_open();
3963 }
3964 catch (...) {
3965 opened = 0;
3966 }
3967 }
3968 broadcast<int, int> (*comm, 0, outArg (opened));
3969 TEUCHOS_TEST_FOR_EXCEPTION(
3970 opened == 0, std::runtime_error,
3971 "readDenseFile: Failed to open file \"" << filename << "\" on "
3972 "Process 0.");
3973 return readDense (in, comm, map, tolerant, debug, binary);
3974 }
3975
3976
4006 static Teuchos::RCP<vector_type>
4007 readVectorFile (const std::string& filename,
4008 const Teuchos::RCP<const comm_type>& comm,
4009 Teuchos::RCP<const map_type>& map,
4010 const bool tolerant=false,
4011 const bool debug=false)
4012 {
4013 using Teuchos::broadcast;
4014 using Teuchos::outArg;
4015
4016 std::ifstream in;
4017 int opened = 0;
4018 if (comm->getRank() == 0) {
4019 try {
4020 in.open (filename.c_str ());
4021 opened = in.is_open();
4022 }
4023 catch (...) {
4024 opened = 0;
4025 }
4026 }
4027 broadcast<int, int> (*comm, 0, outArg (opened));
4028 TEUCHOS_TEST_FOR_EXCEPTION(
4029 opened == 0, std::runtime_error,
4030 "readVectorFile: Failed to open file \"" << filename << "\" on "
4031 "Process 0.");
4032 return readVector (in, comm, map, tolerant, debug);
4033 }
4034
4035
4103
4104 static Teuchos::RCP<multivector_type>
4105 readDense (std::istream& in,
4106 const Teuchos::RCP<const comm_type>& comm,
4107 Teuchos::RCP<const map_type>& map,
4108 const bool tolerant=false,
4109 const bool debug=false,
4110 const bool binary=false)
4111 {
4112 Teuchos::RCP<Teuchos::FancyOStream> err =
4113 Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
4114 return readDenseImpl<scalar_type> (in, comm, map, err, tolerant, debug, binary);
4115 }
4116
4117
4119 static Teuchos::RCP<vector_type>
4120 readVector (std::istream& in,
4121 const Teuchos::RCP<const comm_type>& comm,
4122 Teuchos::RCP<const map_type>& map,
4123 const bool tolerant=false,
4124 const bool debug=false)
4125 {
4126 Teuchos::RCP<Teuchos::FancyOStream> err =
4127 Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
4128 return readVectorImpl<scalar_type> (in, comm, map, err, tolerant, debug);
4129 }
4130
4131
4153 static Teuchos::RCP<const map_type>
4154 readMapFile (const std::string& filename,
4155 const Teuchos::RCP<const comm_type>& comm,
4156 const bool tolerant=false,
4157 const bool debug=false,
4158 const bool binary=false)
4159 {
4160 using Teuchos::inOutArg;
4161 using Teuchos::broadcast;
4162 std::ifstream in;
4163
4164 int success = 1;
4165 if (comm->getRank () == 0) { // Only open the file on Proc 0.
4166 if (binary)
4167 in.open (filename.c_str (), std::ios::binary);
4168 else
4169 in.open (filename.c_str ()); // Destructor closes safely
4170 if (! in) {
4171 success = 0;
4172 }
4173 }
4174 broadcast<int, int> (*comm, 0, inOutArg (success));
4175 TEUCHOS_TEST_FOR_EXCEPTION(
4176 success == 0, std::runtime_error,
4177 "Tpetra::MatrixMarket::Reader::readMapFile: "
4178 "Failed to read file \"" << filename << "\" on Process 0.");
4179 return readMap (in, comm, tolerant, debug, binary);
4180 }
4181
4182
4183 private:
4184 template<class MultiVectorScalarType>
4185 static Teuchos::RCP<Tpetra::MultiVector<MultiVectorScalarType,
4188 node_type> >
4189 readDenseImpl (std::istream& in,
4190 const Teuchos::RCP<const comm_type>& comm,
4191 Teuchos::RCP<const map_type>& map,
4192 const Teuchos::RCP<Teuchos::FancyOStream>& err,
4193 const bool tolerant=false,
4194 const bool debug=false,
4195 const bool binary=false)
4196 {
4197 using Teuchos::MatrixMarket::Banner;
4198 using Teuchos::MatrixMarket::checkCommentLine;
4199 using Teuchos::ArrayRCP;
4200 using Teuchos::as;
4201 using Teuchos::broadcast;
4202 using Teuchos::outArg;
4203 using Teuchos::RCP;
4204 using Teuchos::Tuple;
4205 using std::endl;
4206 typedef MultiVectorScalarType ST;
4207 typedef local_ordinal_type LO;
4208 typedef global_ordinal_type GO;
4209 typedef node_type NT;
4210 typedef Teuchos::ScalarTraits<ST> STS;
4211 typedef typename STS::magnitudeType MT;
4212 typedef Teuchos::ScalarTraits<MT> STM;
4214
4215 // Rank 0 is the only (MPI) process allowed to read from the
4216 // input stream.
4217 const int myRank = comm->getRank ();
4218
4219 if (! err.is_null ()) {
4220 err->pushTab ();
4221 }
4222 if (debug) {
4223 *err << myRank << ": readDenseImpl" << endl;
4224 }
4225 if (! err.is_null ()) {
4226 err->pushTab ();
4227 }
4228
4229 // mfh 17 Feb 2013: It's not strictly necessary that the Comm
4230 // instances be identical and that the Node instances be
4231 // identical. The essential condition is more complicated to
4232 // test and isn't the same for all Node types. Thus, we just
4233 // leave it up to the user.
4234
4235 // // If map is nonnull, check the precondition that its
4236 // // communicator resp. node equal comm resp. node. Checking
4237 // // now avoids doing a lot of file reading before we detect the
4238 // // violated precondition.
4239 // TEUCHOS_TEST_FOR_EXCEPTION(
4240 // ! map.is_null() && (map->getComm() != comm || map->getNode () != node,
4241 // std::invalid_argument, "If you supply a nonnull Map, the Map's "
4242 // "communicator and node must equal the supplied communicator resp. "
4243 // "node.");
4244
4245 // Process 0 will read in the matrix dimensions from the file,
4246 // and broadcast them to all ranks in the given communicator.
4247 // There are only 2 dimensions in the matrix, but we use the
4248 // third element of the Tuple to encode the banner's reported
4249 // data type: "real" == 0, "complex" == 1, and "integer" == 0
4250 // (same as "real"). We don't allow pattern matrices (i.e.,
4251 // graphs) since they only make sense for sparse data.
4252 Tuple<GO, 3> dims;
4253 dims[0] = 0;
4254 dims[1] = 0;
4255 dims[2] = 0;
4256
4257 // Current line number in the input stream. Only valid on
4258 // Proc 0. Various calls will modify this depending on the
4259 // number of lines that are read from the input stream.
4260 size_t lineNumber = 1;
4261
4262 // Capture errors and their messages on Proc 0.
4263 std::ostringstream exMsg;
4264 int localBannerReadSuccess = 1;
4265 int localDimsReadSuccess = 1;
4266
4267 // Only Proc 0 gets to read matrix data from the input stream.
4268 if (myRank == 0) {
4269 if (! binary) {
4270 if (debug) {
4271 *err << myRank << ": readDenseImpl: Reading banner line (dense)" << endl;
4272 }
4273
4274 // The "Banner" tells you whether the input stream
4275 // represents a dense matrix, the symmetry type of the
4276 // matrix, and the type of the data it contains.
4277 RCP<const Banner> pBanner;
4278 try {
4279 pBanner = readBanner (in, lineNumber, tolerant, debug);
4280 } catch (std::exception& e) {
4281 exMsg << e.what ();
4282 localBannerReadSuccess = 0;
4283 }
4284 // Make sure the input stream is the right kind of data.
4285 if (localBannerReadSuccess) {
4286 if (pBanner->matrixType () != "array") {
4287 exMsg << "The Matrix Market file does not contain dense matrix "
4288 "data. Its banner (first) line says that its matrix type is \""
4289 << pBanner->matrixType () << "\", rather that the required "
4290 "\"array\".";
4291 localBannerReadSuccess = 0;
4292 } else if (pBanner->dataType() == "pattern") {
4293 exMsg << "The Matrix Market file's banner (first) "
4294 "line claims that the matrix's data type is \"pattern\". This does "
4295 "not make sense for a dense matrix, yet the file reports the matrix "
4296 "as dense. The only valid data types for a dense matrix are "
4297 "\"real\", \"complex\", and \"integer\".";
4298 localBannerReadSuccess = 0;
4299 } else {
4300 // Encode the data type reported by the Banner as the
4301 // third element of the dimensions Tuple.
4302 dims[2] = encodeDataType (pBanner->dataType ());
4303 }
4304 } // if we successfully read the banner line
4305
4306 // At this point, we've successfully read the banner line.
4307 // Now read the dimensions line.
4308 if (localBannerReadSuccess) {
4309 if (debug) {
4310 *err << myRank << ": readDenseImpl: Reading dimensions line (dense)" << endl;
4311 }
4312 // Keep reading lines from the input stream until we find
4313 // a non-comment line, or until we run out of lines. The
4314 // latter is an error, since every "array" format Matrix
4315 // Market file must have a dimensions line after the
4316 // banner (even if the matrix has zero rows or columns, or
4317 // zero entries).
4318 std::string line;
4319 bool commentLine = true;
4320
4321 while (commentLine) {
4322 // Test whether it is even valid to read from the input
4323 // stream wrapping the line.
4324 if (in.eof () || in.fail ()) {
4325 exMsg << "Unable to get array dimensions line (at all) from line "
4326 << lineNumber << " of input stream. The input stream "
4327 << "claims that it is "
4328 << (in.eof() ? "at end-of-file." : "in a failed state.");
4329 localDimsReadSuccess = 0;
4330 } else {
4331 // Try to get the next line from the input stream.
4332 if (getline (in, line)) {
4333 ++lineNumber; // We did actually read a line.
4334 }
4335 // Is the current line a comment line? Ignore start
4336 // and size; they are only useful for reading the
4337 // actual matrix entries. (We could use them here as
4338 // an optimization, but we've chosen not to.)
4339 size_t start = 0, size = 0;
4340 commentLine = checkCommentLine (line, start, size, lineNumber, tolerant);
4341 } // whether we failed to read the line at all
4342 } // while the line we just read is a comment line
4343
4344 //
4345 // Get <numRows> <numCols> from the line we just read.
4346 //
4347 std::istringstream istr (line);
4348
4349 // Test whether it is even valid to read from the input
4350 // stream wrapping the line.
4351 if (istr.eof () || istr.fail ()) {
4352 exMsg << "Unable to read any data from line " << lineNumber
4353 << " of input; the line should contain the matrix dimensions "
4354 << "\"<numRows> <numCols>\".";
4355 localDimsReadSuccess = 0;
4356 } else { // It's valid to read from the line.
4357 GO theNumRows = 0;
4358 istr >> theNumRows; // Read in the number of rows.
4359 if (istr.fail ()) {
4360 exMsg << "Failed to get number of rows from line "
4361 << lineNumber << " of input; the line should contains the "
4362 << "matrix dimensions \"<numRows> <numCols>\".";
4363 localDimsReadSuccess = 0;
4364 } else { // We successfully read the number of rows
4365 dims[0] = theNumRows; // Save the number of rows
4366 if (istr.eof ()) { // Do we still have data to read?
4367 exMsg << "No more data after number of rows on line "
4368 << lineNumber << " of input; the line should contain the "
4369 << "matrix dimensions \"<numRows> <numCols>\".";
4370 localDimsReadSuccess = 0;
4371 } else { // Still data left to read; read in number of columns.
4372 GO theNumCols = 0;
4373 istr >> theNumCols; // Read in the number of columns
4374 if (istr.fail ()) {
4375 exMsg << "Failed to get number of columns from line "
4376 << lineNumber << " of input; the line should contain "
4377 << "the matrix dimensions \"<numRows> <numCols>\".";
4378 localDimsReadSuccess = 0;
4379 } else { // We successfully read the number of columns
4380 dims[1] = theNumCols; // Save the number of columns
4381 } // if istr.fail ()
4382 } // if istr.eof ()
4383 } // if we read the number of rows
4384 } // if the input stream wrapping the dims line was (in)valid
4385 } // if we successfully read the banner line
4386 } // not in binary format
4387 else { // in binary format
4388 global_size_t numRows, numCols;
4389 in.read(reinterpret_cast<char*>(&numRows), sizeof(numRows));
4390 in.read(reinterpret_cast<char*>(&numCols), sizeof(numCols));
4391 dims[0] = Teuchos::as<GO>(numRows);
4392 dims[1] = Teuchos::as<GO>(numCols);
4393 if ((typeid(ST) == typeid(double)) || Teuchos::ScalarTraits<ST>::isOrdinal) {
4394 dims[2] = 0;
4395 } else if (Teuchos::ScalarTraits<ST>::isComplex) {
4396 dims[2] = 1;
4397 } else {
4398 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
4399 "Unrecognized Matrix Market data type. "
4400 "We should never get here. "
4401 "Please report this bug to the Tpetra developers.");
4402 }
4403 localDimsReadSuccess = true;
4404 localDimsReadSuccess = true;
4405 } // in binary format
4406 } // if (myRank == 0)
4407
4408 // Broadcast the matrix dimensions, the encoded data type, and
4409 // whether or not Proc 0 succeeded in reading the banner and
4410 // dimensions.
4411 Tuple<GO, 5> bannerDimsReadResult;
4412 if (myRank == 0) {
4413 bannerDimsReadResult[0] = dims[0]; // numRows
4414 bannerDimsReadResult[1] = dims[1]; // numCols
4415 bannerDimsReadResult[2] = dims[2]; // encoded data type
4416 bannerDimsReadResult[3] = localBannerReadSuccess;
4417 bannerDimsReadResult[4] = localDimsReadSuccess;
4418 }
4419 // Broadcast matrix dimensions and the encoded data type from
4420 // Proc 0 to all the MPI processes.
4421 broadcast (*comm, 0, bannerDimsReadResult);
4422
4423 TEUCHOS_TEST_FOR_EXCEPTION(
4424 bannerDimsReadResult[3] == 0, std::runtime_error,
4425 "Failed to read banner line: " << exMsg.str ());
4426 TEUCHOS_TEST_FOR_EXCEPTION(
4427 bannerDimsReadResult[4] == 0, std::runtime_error,
4428 "Failed to read matrix dimensions line: " << exMsg.str ());
4429 if (myRank != 0) {
4430 dims[0] = bannerDimsReadResult[0];
4431 dims[1] = bannerDimsReadResult[1];
4432 dims[2] = bannerDimsReadResult[2];
4433 }
4434
4435 // Tpetra objects want the matrix dimensions in these types.
4436 const global_size_t numRows = static_cast<global_size_t> (dims[0]);
4437 const size_t numCols = static_cast<size_t> (dims[1]);
4438
4439 // Make a "Proc 0 owns everything" Map that we will use to
4440 // read in the multivector entries in the correct order on
4441 // Proc 0. This must be a collective
4442 RCP<const map_type> proc0Map; // "Proc 0 owns everything" Map
4443 if (map.is_null ()) {
4444 // The user didn't supply a Map. Make a contiguous
4445 // distributed Map for them, using the read-in multivector
4446 // dimensions.
4447 map = createUniformContigMapWithNode<LO, GO, NT> (numRows, comm);
4448 const size_t localNumRows = (myRank == 0) ? numRows : 0;
4449 // At this point, map exists and has a nonnull node.
4450 proc0Map = createContigMapWithNode<LO, GO, NT> (numRows, localNumRows,
4451 comm);
4452 }
4453 else { // The user supplied a Map.
4454 proc0Map = Details::computeGatherMap<map_type> (map, err, debug);
4455 }
4456
4457 // Make a multivector X owned entirely by Proc 0.
4458 RCP<MV> X = createMultiVector<ST, LO, GO, NT> (proc0Map, numCols);
4459
4460 //
4461 // On Proc 0, read the Matrix Market data from the input
4462 // stream into the multivector X.
4463 //
4464 int localReadDataSuccess = 1;
4465 if (myRank == 0) {
4466 if (! binary) {
4467 try {
4468 if (debug) {
4469 *err << myRank << ": readDenseImpl: Reading matrix data (dense)"
4470 << endl;
4471 }
4472
4473 // Make sure that we can get a 1-D view of X.
4474 TEUCHOS_TEST_FOR_EXCEPTION(
4475 ! X->isConstantStride (), std::logic_error,
4476 "Can't get a 1-D view of the entries of the MultiVector X on "
4477 "Process 0, because the stride between the columns of X is not "
4478 "constant. This shouldn't happen because we just created X and "
4479 "haven't filled it in yet. Please report this bug to the Tpetra "
4480 "developers.");
4481
4482 // Get a writeable 1-D view of the entries of X. Rank 0
4483 // owns all of them. The view will expire at the end of
4484 // scope, so (if necessary) it will be written back to X
4485 // at this time.
4486 ArrayRCP<ST> X_view = X->get1dViewNonConst ();
4487 TEUCHOS_TEST_FOR_EXCEPTION(
4488 as<global_size_t> (X_view.size ()) < numRows * numCols,
4489 std::logic_error,
4490 "The view of X has size " << X_view.size() << " which is not enough to "
4491 "accommodate the expected number of entries numRows*numCols = "
4492 << numRows << "*" << numCols << " = " << numRows*numCols << ". "
4493 "Please report this bug to the Tpetra developers.");
4494 const size_t stride = X->getStride ();
4495
4496 // The third element of the dimensions Tuple encodes the data
4497 // type reported by the Banner: "real" == 0, "complex" == 1,
4498 // "integer" == 0 (same as "real"), "pattern" == 2. We do not
4499 // allow dense matrices to be pattern matrices, so dims[2] ==
4500 // 0 or 1. We've already checked for this above.
4501 const bool isComplex = (dims[2] == 1);
4502 size_type count = 0, curRow = 0, curCol = 0;
4503
4504 std::string line;
4505 while (getline (in, line)) {
4506 ++lineNumber;
4507 // Is the current line a comment line? If it's not,
4508 // line.substr(start,size) contains the data.
4509 size_t start = 0, size = 0;
4510 const bool commentLine =
4511 checkCommentLine (line, start, size, lineNumber, tolerant);
4512 if (! commentLine) {
4513 // Make sure we have room in which to put the new matrix
4514 // entry. We check this only after checking for a
4515 // comment line, because there may be one or more
4516 // comment lines at the end of the file. In tolerant
4517 // mode, we simply ignore any extra data.
4518 if (count >= X_view.size()) {
4519 if (tolerant) {
4520 break;
4521 }
4522 else {
4523 TEUCHOS_TEST_FOR_EXCEPTION(
4524 count >= X_view.size(),
4525 std::runtime_error,
4526 "The Matrix Market input stream has more data in it than "
4527 "its metadata reported. Current line number is "
4528 << lineNumber << ".");
4529 }
4530 }
4531
4532 // mfh 19 Dec 2012: Ignore everything up to the initial
4533 // colon. writeDense() has the option to print out the
4534 // global row index in front of each entry, followed by
4535 // a colon and space.
4536 {
4537 const size_t pos = line.substr (start, size).find (':');
4538 if (pos != std::string::npos) {
4539 start = pos+1;
4540 }
4541 }
4542 std::istringstream istr (line.substr (start, size));
4543 // Does the line contain anything at all? Can we
4544 // safely read from the input stream wrapping the
4545 // line?
4546 if (istr.eof() || istr.fail()) {
4547 // In tolerant mode, simply ignore the line.
4548 if (tolerant) {
4549 break;
4550 }
4551 // We repeat the full test here so the exception
4552 // message is more informative.
4553 TEUCHOS_TEST_FOR_EXCEPTION(
4554 ! tolerant && (istr.eof() || istr.fail()),
4555 std::runtime_error,
4556 "Line " << lineNumber << " of the Matrix Market file is "
4557 "empty, or we cannot read from it for some other reason.");
4558 }
4559 // Current matrix entry to read in.
4560 ST val = STS::zero();
4561 // Real and imaginary parts of the current matrix entry.
4562 // The imaginary part is zero if the matrix is real-valued.
4563 MT real = STM::zero(), imag = STM::zero();
4564
4565 // isComplex refers to the input stream's data, not to
4566 // the scalar type S. It's OK to read real-valued
4567 // data into a matrix storing complex-valued data; in
4568 // that case, all entries' imaginary parts are zero.
4569 if (isComplex) {
4570 // STS::real() and STS::imag() return a copy of
4571 // their respective components, not a writeable
4572 // reference. Otherwise we could just assign to
4573 // them using the istream extraction operator (>>).
4574 // That's why we have separate magnitude type "real"
4575 // and "imag" variables.
4576
4577 // Attempt to read the real part of the current entry.
4578 istr >> real;
4579 if (istr.fail()) {
4580 TEUCHOS_TEST_FOR_EXCEPTION(
4581 ! tolerant && istr.eof(), std::runtime_error,
4582 "Failed to get the real part of a complex-valued matrix "
4583 "entry from line " << lineNumber << " of the Matrix Market "
4584 "file.");
4585 // In tolerant mode, just skip bad lines.
4586 if (tolerant) {
4587 break;
4588 }
4589 } else if (istr.eof()) {
4590 TEUCHOS_TEST_FOR_EXCEPTION(
4591 ! tolerant && istr.eof(), std::runtime_error,
4592 "Missing imaginary part of a complex-valued matrix entry "
4593 "on line " << lineNumber << " of the Matrix Market file.");
4594 // In tolerant mode, let any missing imaginary part be 0.
4595 } else {
4596 // Attempt to read the imaginary part of the current
4597 // matrix entry.
4598 istr >> imag;
4599 TEUCHOS_TEST_FOR_EXCEPTION(
4600 ! tolerant && istr.fail(), std::runtime_error,
4601 "Failed to get the imaginary part of a complex-valued "
4602 "matrix entry from line " << lineNumber << " of the "
4603 "Matrix Market file.");
4604 // In tolerant mode, let any missing or corrupted
4605 // imaginary part be 0.
4606 }
4607 } else { // Matrix Market file contains real-valued data.
4608 // Attempt to read the current matrix entry.
4609 istr >> real;
4610 TEUCHOS_TEST_FOR_EXCEPTION(
4611 ! tolerant && istr.fail(), std::runtime_error,
4612 "Failed to get a real-valued matrix entry from line "
4613 << lineNumber << " of the Matrix Market file.");
4614 // In tolerant mode, simply ignore the line if
4615 // we failed to read a matrix entry.
4616 if (istr.fail() && tolerant) {
4617 break;
4618 }
4619 }
4620 // In tolerant mode, we simply let pass through whatever
4621 // data we got.
4622 TEUCHOS_TEST_FOR_EXCEPTION(
4623 ! tolerant && istr.fail(), std::runtime_error,
4624 "Failed to read matrix data from line " << lineNumber
4625 << " of the Matrix Market file.");
4626
4627 // Assign val = ST(real, imag).
4628 Teuchos::MatrixMarket::details::assignScalar<ST> (val, real, imag);
4629
4630 curRow = count % numRows;
4631 curCol = count / numRows;
4632 X_view[curRow + curCol*stride] = val;
4633 ++count;
4634 } // if not a comment line
4635 } // while there are still lines in the file, get the next one
4636
4637 TEUCHOS_TEST_FOR_EXCEPTION(
4638 ! tolerant && static_cast<global_size_t> (count) < numRows * numCols,
4639 std::runtime_error,
4640 "The Matrix Market metadata reports that the dense matrix is "
4641 << numRows << " x " << numCols << ", and thus has "
4642 << numRows*numCols << " total entries, but we only found " << count
4643 << " entr" << (count == 1 ? "y" : "ies") << " in the file.");
4644 } catch (std::exception& e) {
4645 exMsg << e.what ();
4646 localReadDataSuccess = 0;
4647 }
4648 } // not binary file
4649 else {
4650 if (debug) {
4651 *err << myRank << ": readDenseImpl: Reading matrix data (dense)"
4652 << endl;
4653 }
4654
4655 // Make sure that we can get a 1-D view of X.
4656 TEUCHOS_TEST_FOR_EXCEPTION(
4657 ! X->isConstantStride (), std::logic_error,
4658 "Can't get a 1-D view of the entries of the MultiVector X on "
4659 "Process 0, because the stride between the columns of X is not "
4660 "constant. This shouldn't happen because we just created X and "
4661 "haven't filled it in yet. Please report this bug to the Tpetra "
4662 "developers.");
4663
4664 // Get a writeable 1-D view of the entries of X. Rank 0
4665 // owns all of them. The view will expire at the end of
4666 // scope, so (if necessary) it will be written back to X
4667 // at this time.
4668 auto X_view = X->getLocalViewHost (Access::OverwriteAll);
4669
4670 TEUCHOS_TEST_FOR_EXCEPTION(
4671 as<global_size_t> (X_view.extent(0)) < numRows,
4672 std::logic_error,
4673 "The view of X has " << X_view.extent(0) << " rows which is not enough to "
4674 "accommodate the expected number of entries numRows = "
4675 << numRows << ". "
4676 "Please report this bug to the Tpetra developers.");
4677 TEUCHOS_TEST_FOR_EXCEPTION(
4678 as<global_size_t> (X_view.extent(1)) < numCols,
4679 std::logic_error,
4680 "The view of X has " << X_view.extent(1) << " colums which is not enough to "
4681 "accommodate the expected number of entries numRows = "
4682 << numCols << ". "
4683 "Please report this bug to the Tpetra developers.");
4684
4685 for (size_t curRow = 0; curRow < numRows; ++curRow) {
4686 for (size_t curCol = 0; curCol < numCols; ++curCol) {
4687 if (Teuchos::ScalarTraits<ST>::isOrdinal){
4688 global_size_t val;
4689 in.read(reinterpret_cast<char*>(&val), sizeof(val));
4690 X_view(curRow, curCol) = val;
4691 } else {
4692 double val;
4693 in.read(reinterpret_cast<char*>(&val), sizeof(val));
4694 X_view(curRow, curCol) = val;
4695 }
4696 }
4697 }
4698 } // binary
4699 } // if (myRank == 0)
4700
4701 if (debug) {
4702 *err << myRank << ": readDenseImpl: done reading data" << endl;
4703 }
4704
4705 // Synchronize on whether Proc 0 successfully read the data.
4706 int globalReadDataSuccess = localReadDataSuccess;
4707 broadcast (*comm, 0, outArg (globalReadDataSuccess));
4708 TEUCHOS_TEST_FOR_EXCEPTION(
4709 globalReadDataSuccess == 0, std::runtime_error,
4710 "Failed to read the multivector's data: " << exMsg.str ());
4711
4712 // If there's only one MPI process and the user didn't supply
4713 // a Map (i.e., pMap is null), we're done. Set pMap to the
4714 // Map used to distribute X, and return X.
4715 if (comm->getSize () == 1 && map.is_null ()) {
4716 map = proc0Map;
4717 if (! err.is_null ()) {
4718 err->popTab ();
4719 }
4720 if (debug) {
4721 *err << myRank << ": readDenseImpl: done" << endl;
4722 }
4723 if (! err.is_null ()) {
4724 err->popTab ();
4725 }
4726 return X;
4727 }
4728
4729 if (debug) {
4730 *err << myRank << ": readDenseImpl: Creating target MV" << endl;
4731 }
4732
4733 // Make a multivector Y with the distributed map pMap.
4734 RCP<MV> Y = createMultiVector<ST, LO, GO, NT> (map, numCols);
4735
4736 if (debug) {
4737 *err << myRank << ": readDenseImpl: Creating Export" << endl;
4738 }
4739
4740 // Make an Export object that will export X to Y. First
4741 // argument is the source map, second argument is the target
4742 // map.
4743 Export<LO, GO, NT> exporter (proc0Map, map, err);
4744
4745 if (debug) {
4746 *err << myRank << ": readDenseImpl: Exporting" << endl;
4747 }
4748 // Export X into Y.
4749 Y->doExport (*X, exporter, INSERT);
4750
4751 if (! err.is_null ()) {
4752 err->popTab ();
4753 }
4754 if (debug) {
4755 *err << myRank << ": readDenseImpl: done" << endl;
4756 }
4757 if (! err.is_null ()) {
4758 err->popTab ();
4759 }
4760
4761 // Y is distributed over all process(es) in the communicator.
4762 return Y;
4763 }
4764
4765
4766 template<class VectorScalarType>
4767 static Teuchos::RCP<Tpetra::Vector<VectorScalarType,
4770 node_type> >
4771 readVectorImpl (std::istream& in,
4772 const Teuchos::RCP<const comm_type>& comm,
4773 Teuchos::RCP<const map_type>& map,
4774 const Teuchos::RCP<Teuchos::FancyOStream>& err,
4775 const bool tolerant=false,
4776 const bool debug=false)
4777 {
4778 using Teuchos::MatrixMarket::Banner;
4779 using Teuchos::MatrixMarket::checkCommentLine;
4780 using Teuchos::as;
4781 using Teuchos::broadcast;
4782 using Teuchos::outArg;
4783 using Teuchos::RCP;
4784 using Teuchos::Tuple;
4785 using std::endl;
4786 typedef VectorScalarType ST;
4787 typedef local_ordinal_type LO;
4788 typedef global_ordinal_type GO;
4789 typedef node_type NT;
4790 typedef Teuchos::ScalarTraits<ST> STS;
4791 typedef typename STS::magnitudeType MT;
4792 typedef Teuchos::ScalarTraits<MT> STM;
4794
4795 // Rank 0 is the only (MPI) process allowed to read from the
4796 // input stream.
4797 const int myRank = comm->getRank ();
4798
4799 if (! err.is_null ()) {
4800 err->pushTab ();
4801 }
4802 if (debug) {
4803 *err << myRank << ": readVectorImpl" << endl;
4804 }
4805 if (! err.is_null ()) {
4806 err->pushTab ();
4807 }
4808
4809 // mfh 17 Feb 2013: It's not strictly necessary that the Comm
4810 // instances be identical and that the Node instances be
4811 // identical. The essential condition is more complicated to
4812 // test and isn't the same for all Node types. Thus, we just
4813 // leave it up to the user.
4814
4815 // // If map is nonnull, check the precondition that its
4816 // // communicator resp. node equal comm resp. node. Checking
4817 // // now avoids doing a lot of file reading before we detect the
4818 // // violated precondition.
4819 // TEUCHOS_TEST_FOR_EXCEPTION(
4820 // ! map.is_null() && (map->getComm() != comm || map->getNode () != node,
4821 // std::invalid_argument, "If you supply a nonnull Map, the Map's "
4822 // "communicator and node must equal the supplied communicator resp. "
4823 // "node.");
4824
4825 // Process 0 will read in the matrix dimensions from the file,
4826 // and broadcast them to all ranks in the given communicator.
4827 // There are only 2 dimensions in the matrix, but we use the
4828 // third element of the Tuple to encode the banner's reported
4829 // data type: "real" == 0, "complex" == 1, and "integer" == 0
4830 // (same as "real"). We don't allow pattern matrices (i.e.,
4831 // graphs) since they only make sense for sparse data.
4832 Tuple<GO, 3> dims;
4833 dims[0] = 0;
4834 dims[1] = 0;
4835
4836 // Current line number in the input stream. Only valid on
4837 // Proc 0. Various calls will modify this depending on the
4838 // number of lines that are read from the input stream.
4839 size_t lineNumber = 1;
4840
4841 // Capture errors and their messages on Proc 0.
4842 std::ostringstream exMsg;
4843 int localBannerReadSuccess = 1;
4844 int localDimsReadSuccess = 1;
4845
4846 // Only Proc 0 gets to read matrix data from the input stream.
4847 if (myRank == 0) {
4848 if (debug) {
4849 *err << myRank << ": readVectorImpl: Reading banner line (dense)" << endl;
4850 }
4851
4852 // The "Banner" tells you whether the input stream
4853 // represents a dense matrix, the symmetry type of the
4854 // matrix, and the type of the data it contains.
4855 RCP<const Banner> pBanner;
4856 try {
4857 pBanner = readBanner (in, lineNumber, tolerant, debug);
4858 } catch (std::exception& e) {
4859 exMsg << e.what ();
4860 localBannerReadSuccess = 0;
4861 }
4862 // Make sure the input stream is the right kind of data.
4863 if (localBannerReadSuccess) {
4864 if (pBanner->matrixType () != "array") {
4865 exMsg << "The Matrix Market file does not contain dense matrix "
4866 "data. Its banner (first) line says that its matrix type is \""
4867 << pBanner->matrixType () << "\", rather that the required "
4868 "\"array\".";
4869 localBannerReadSuccess = 0;
4870 } else if (pBanner->dataType() == "pattern") {
4871 exMsg << "The Matrix Market file's banner (first) "
4872 "line claims that the matrix's data type is \"pattern\". This does "
4873 "not make sense for a dense matrix, yet the file reports the matrix "
4874 "as dense. The only valid data types for a dense matrix are "
4875 "\"real\", \"complex\", and \"integer\".";
4876 localBannerReadSuccess = 0;
4877 } else {
4878 // Encode the data type reported by the Banner as the
4879 // third element of the dimensions Tuple.
4880 dims[2] = encodeDataType (pBanner->dataType ());
4881 }
4882 } // if we successfully read the banner line
4883
4884 // At this point, we've successfully read the banner line.
4885 // Now read the dimensions line.
4886 if (localBannerReadSuccess) {
4887 if (debug) {
4888 *err << myRank << ": readVectorImpl: Reading dimensions line (dense)" << endl;
4889 }
4890 // Keep reading lines from the input stream until we find
4891 // a non-comment line, or until we run out of lines. The
4892 // latter is an error, since every "array" format Matrix
4893 // Market file must have a dimensions line after the
4894 // banner (even if the matrix has zero rows or columns, or
4895 // zero entries).
4896 std::string line;
4897 bool commentLine = true;
4898
4899 while (commentLine) {
4900 // Test whether it is even valid to read from the input
4901 // stream wrapping the line.
4902 if (in.eof () || in.fail ()) {
4903 exMsg << "Unable to get array dimensions line (at all) from line "
4904 << lineNumber << " of input stream. The input stream "
4905 << "claims that it is "
4906 << (in.eof() ? "at end-of-file." : "in a failed state.");
4907 localDimsReadSuccess = 0;
4908 } else {
4909 // Try to get the next line from the input stream.
4910 if (getline (in, line)) {
4911 ++lineNumber; // We did actually read a line.
4912 }
4913 // Is the current line a comment line? Ignore start
4914 // and size; they are only useful for reading the
4915 // actual matrix entries. (We could use them here as
4916 // an optimization, but we've chosen not to.)
4917 size_t start = 0, size = 0;
4918 commentLine = checkCommentLine (line, start, size, lineNumber, tolerant);
4919 } // whether we failed to read the line at all
4920 } // while the line we just read is a comment line
4921
4922 //
4923 // Get <numRows> <numCols> from the line we just read.
4924 //
4925 std::istringstream istr (line);
4926
4927 // Test whether it is even valid to read from the input
4928 // stream wrapping the line.
4929 if (istr.eof () || istr.fail ()) {
4930 exMsg << "Unable to read any data from line " << lineNumber
4931 << " of input; the line should contain the matrix dimensions "
4932 << "\"<numRows> <numCols>\".";
4933 localDimsReadSuccess = 0;
4934 } else { // It's valid to read from the line.
4935 GO theNumRows = 0;
4936 istr >> theNumRows; // Read in the number of rows.
4937 if (istr.fail ()) {
4938 exMsg << "Failed to get number of rows from line "
4939 << lineNumber << " of input; the line should contains the "
4940 << "matrix dimensions \"<numRows> <numCols>\".";
4941 localDimsReadSuccess = 0;
4942 } else { // We successfully read the number of rows
4943 dims[0] = theNumRows; // Save the number of rows
4944 if (istr.eof ()) { // Do we still have data to read?
4945 exMsg << "No more data after number of rows on line "
4946 << lineNumber << " of input; the line should contain the "
4947 << "matrix dimensions \"<numRows> <numCols>\".";
4948 localDimsReadSuccess = 0;
4949 } else { // Still data left to read; read in number of columns.
4950 GO theNumCols = 0;
4951 istr >> theNumCols; // Read in the number of columns
4952 if (istr.fail ()) {
4953 exMsg << "Failed to get number of columns from line "
4954 << lineNumber << " of input; the line should contain "
4955 << "the matrix dimensions \"<numRows> <numCols>\".";
4956 localDimsReadSuccess = 0;
4957 } else { // We successfully read the number of columns
4958 dims[1] = theNumCols; // Save the number of columns
4959 } // if istr.fail ()
4960 } // if istr.eof ()
4961 } // if we read the number of rows
4962 } // if the input stream wrapping the dims line was (in)valid
4963 } // if we successfully read the banner line
4964 } // if (myRank == 0)
4965
4966 // Check if file has a Vector
4967 if (dims[1]!=1) {
4968 exMsg << "File does not contain a 1D Vector";
4969 localDimsReadSuccess = 0;
4970 }
4971
4972 // Broadcast the matrix dimensions, the encoded data type, and
4973 // whether or not Proc 0 succeeded in reading the banner and
4974 // dimensions.
4975 Tuple<GO, 5> bannerDimsReadResult;
4976 if (myRank == 0) {
4977 bannerDimsReadResult[0] = dims[0]; // numRows
4978 bannerDimsReadResult[1] = dims[1]; // numCols
4979 bannerDimsReadResult[2] = dims[2]; // encoded data type
4980 bannerDimsReadResult[3] = localBannerReadSuccess;
4981 bannerDimsReadResult[4] = localDimsReadSuccess;
4982 }
4983
4984 // Broadcast matrix dimensions and the encoded data type from
4985 // Proc 0 to all the MPI processes.
4986 broadcast (*comm, 0, bannerDimsReadResult);
4987
4988 TEUCHOS_TEST_FOR_EXCEPTION(
4989 bannerDimsReadResult[3] == 0, std::runtime_error,
4990 "Failed to read banner line: " << exMsg.str ());
4991 TEUCHOS_TEST_FOR_EXCEPTION(
4992 bannerDimsReadResult[4] == 0, std::runtime_error,
4993 "Failed to read matrix dimensions line: " << exMsg.str ());
4994 if (myRank != 0) {
4995 dims[0] = bannerDimsReadResult[0];
4996 dims[1] = bannerDimsReadResult[1];
4997 dims[2] = bannerDimsReadResult[2];
4998 }
4999
5000 // Tpetra objects want the matrix dimensions in these types.
5001 const global_size_t numRows = static_cast<global_size_t> (dims[0]);
5002 const size_t numCols = static_cast<size_t> (dims[1]);
5003
5004 // Make a "Proc 0 owns everything" Map that we will use to
5005 // read in the multivector entries in the correct order on
5006 // Proc 0. This must be a collective
5007 RCP<const map_type> proc0Map; // "Proc 0 owns everything" Map
5008 if (map.is_null ()) {
5009 // The user didn't supply a Map. Make a contiguous
5010 // distributed Map for them, using the read-in multivector
5011 // dimensions.
5012 map = createUniformContigMapWithNode<LO, GO, NT> (numRows, comm);
5013 const size_t localNumRows = (myRank == 0) ? numRows : 0;
5014 // At this point, map exists and has a nonnull node.
5015 proc0Map = createContigMapWithNode<LO, GO, NT> (numRows, localNumRows,
5016 comm);
5017 }
5018 else { // The user supplied a Map.
5019 proc0Map = Details::computeGatherMap<map_type> (map, err, debug);
5020 }
5021
5022 // Make a multivector X owned entirely by Proc 0.
5023 RCP<MV> X = createVector<ST, LO, GO, NT> (proc0Map);
5024
5025 //
5026 // On Proc 0, read the Matrix Market data from the input
5027 // stream into the multivector X.
5028 //
5029 int localReadDataSuccess = 1;
5030 if (myRank == 0) {
5031 try {
5032 if (debug) {
5033 *err << myRank << ": readVectorImpl: Reading matrix data (dense)"
5034 << endl;
5035 }
5036
5037 // Make sure that we can get a 1-D view of X.
5038 TEUCHOS_TEST_FOR_EXCEPTION(
5039 ! X->isConstantStride (), std::logic_error,
5040 "Can't get a 1-D view of the entries of the MultiVector X on "
5041 "Process 0, because the stride between the columns of X is not "
5042 "constant. This shouldn't happen because we just created X and "
5043 "haven't filled it in yet. Please report this bug to the Tpetra "
5044 "developers.");
5045
5046 // Get a writeable 1-D view of the entries of X. Rank 0
5047 // owns all of them. The view will expire at the end of
5048 // scope, so (if necessary) it will be written back to X
5049 // at this time.
5050 Teuchos::ArrayRCP<ST> X_view = X->get1dViewNonConst ();
5051 TEUCHOS_TEST_FOR_EXCEPTION(
5052 as<global_size_t> (X_view.size ()) < numRows * numCols,
5053 std::logic_error,
5054 "The view of X has size " << X_view << " which is not enough to "
5055 "accommodate the expected number of entries numRows*numCols = "
5056 << numRows << "*" << numCols << " = " << numRows*numCols << ". "
5057 "Please report this bug to the Tpetra developers.");
5058 const size_t stride = X->getStride ();
5059
5060 // The third element of the dimensions Tuple encodes the data
5061 // type reported by the Banner: "real" == 0, "complex" == 1,
5062 // "integer" == 0 (same as "real"), "pattern" == 2. We do not
5063 // allow dense matrices to be pattern matrices, so dims[2] ==
5064 // 0 or 1. We've already checked for this above.
5065 const bool isComplex = (dims[2] == 1);
5066 size_type count = 0, curRow = 0, curCol = 0;
5067
5068 std::string line;
5069 while (getline (in, line)) {
5070 ++lineNumber;
5071 // Is the current line a comment line? If it's not,
5072 // line.substr(start,size) contains the data.
5073 size_t start = 0, size = 0;
5074 const bool commentLine =
5075 checkCommentLine (line, start, size, lineNumber, tolerant);
5076 if (! commentLine) {
5077 // Make sure we have room in which to put the new matrix
5078 // entry. We check this only after checking for a
5079 // comment line, because there may be one or more
5080 // comment lines at the end of the file. In tolerant
5081 // mode, we simply ignore any extra data.
5082 if (count >= X_view.size()) {
5083 if (tolerant) {
5084 break;
5085 }
5086 else {
5087 TEUCHOS_TEST_FOR_EXCEPTION(
5088 count >= X_view.size(),
5089 std::runtime_error,
5090 "The Matrix Market input stream has more data in it than "
5091 "its metadata reported. Current line number is "
5092 << lineNumber << ".");
5093 }
5094 }
5095
5096 // mfh 19 Dec 2012: Ignore everything up to the initial
5097 // colon. writeDense() has the option to print out the
5098 // global row index in front of each entry, followed by
5099 // a colon and space.
5100 {
5101 const size_t pos = line.substr (start, size).find (':');
5102 if (pos != std::string::npos) {
5103 start = pos+1;
5104 }
5105 }
5106 std::istringstream istr (line.substr (start, size));
5107 // Does the line contain anything at all? Can we
5108 // safely read from the input stream wrapping the
5109 // line?
5110 if (istr.eof() || istr.fail()) {
5111 // In tolerant mode, simply ignore the line.
5112 if (tolerant) {
5113 break;
5114 }
5115 // We repeat the full test here so the exception
5116 // message is more informative.
5117 TEUCHOS_TEST_FOR_EXCEPTION(
5118 ! tolerant && (istr.eof() || istr.fail()),
5119 std::runtime_error,
5120 "Line " << lineNumber << " of the Matrix Market file is "
5121 "empty, or we cannot read from it for some other reason.");
5122 }
5123 // Current matrix entry to read in.
5124 ST val = STS::zero();
5125 // Real and imaginary parts of the current matrix entry.
5126 // The imaginary part is zero if the matrix is real-valued.
5127 MT real = STM::zero(), imag = STM::zero();
5128
5129 // isComplex refers to the input stream's data, not to
5130 // the scalar type S. It's OK to read real-valued
5131 // data into a matrix storing complex-valued data; in
5132 // that case, all entries' imaginary parts are zero.
5133 if (isComplex) {
5134 // STS::real() and STS::imag() return a copy of
5135 // their respective components, not a writeable
5136 // reference. Otherwise we could just assign to
5137 // them using the istream extraction operator (>>).
5138 // That's why we have separate magnitude type "real"
5139 // and "imag" variables.
5140
5141 // Attempt to read the real part of the current entry.
5142 istr >> real;
5143 if (istr.fail()) {
5144 TEUCHOS_TEST_FOR_EXCEPTION(
5145 ! tolerant && istr.eof(), std::runtime_error,
5146 "Failed to get the real part of a complex-valued matrix "
5147 "entry from line " << lineNumber << " of the Matrix Market "
5148 "file.");
5149 // In tolerant mode, just skip bad lines.
5150 if (tolerant) {
5151 break;
5152 }
5153 } else if (istr.eof()) {
5154 TEUCHOS_TEST_FOR_EXCEPTION(
5155 ! tolerant && istr.eof(), std::runtime_error,
5156 "Missing imaginary part of a complex-valued matrix entry "
5157 "on line " << lineNumber << " of the Matrix Market file.");
5158 // In tolerant mode, let any missing imaginary part be 0.
5159 } else {
5160 // Attempt to read the imaginary part of the current
5161 // matrix entry.
5162 istr >> imag;
5163 TEUCHOS_TEST_FOR_EXCEPTION(
5164 ! tolerant && istr.fail(), std::runtime_error,
5165 "Failed to get the imaginary part of a complex-valued "
5166 "matrix entry from line " << lineNumber << " of the "
5167 "Matrix Market file.");
5168 // In tolerant mode, let any missing or corrupted
5169 // imaginary part be 0.
5170 }
5171 } else { // Matrix Market file contains real-valued data.
5172 // Attempt to read the current matrix entry.
5173 istr >> real;
5174 TEUCHOS_TEST_FOR_EXCEPTION(
5175 ! tolerant && istr.fail(), std::runtime_error,
5176 "Failed to get a real-valued matrix entry from line "
5177 << lineNumber << " of the Matrix Market file.");
5178 // In tolerant mode, simply ignore the line if
5179 // we failed to read a matrix entry.
5180 if (istr.fail() && tolerant) {
5181 break;
5182 }
5183 }
5184 // In tolerant mode, we simply let pass through whatever
5185 // data we got.
5186 TEUCHOS_TEST_FOR_EXCEPTION(
5187 ! tolerant && istr.fail(), std::runtime_error,
5188 "Failed to read matrix data from line " << lineNumber
5189 << " of the Matrix Market file.");
5190
5191 // Assign val = ST(real, imag).
5192 Teuchos::MatrixMarket::details::assignScalar<ST> (val, real, imag);
5193
5194 curRow = count % numRows;
5195 curCol = count / numRows;
5196 X_view[curRow + curCol*stride] = val;
5197 ++count;
5198 } // if not a comment line
5199 } // while there are still lines in the file, get the next one
5200
5201 TEUCHOS_TEST_FOR_EXCEPTION(
5202 ! tolerant && static_cast<global_size_t> (count) < numRows * numCols,
5203 std::runtime_error,
5204 "The Matrix Market metadata reports that the dense matrix is "
5205 << numRows << " x " << numCols << ", and thus has "
5206 << numRows*numCols << " total entries, but we only found " << count
5207 << " entr" << (count == 1 ? "y" : "ies") << " in the file.");
5208 } catch (std::exception& e) {
5209 exMsg << e.what ();
5210 localReadDataSuccess = 0;
5211 }
5212 } // if (myRank == 0)
5213
5214 if (debug) {
5215 *err << myRank << ": readVectorImpl: done reading data" << endl;
5216 }
5217
5218 // Synchronize on whether Proc 0 successfully read the data.
5219 int globalReadDataSuccess = localReadDataSuccess;
5220 broadcast (*comm, 0, outArg (globalReadDataSuccess));
5221 TEUCHOS_TEST_FOR_EXCEPTION(
5222 globalReadDataSuccess == 0, std::runtime_error,
5223 "Failed to read the multivector's data: " << exMsg.str ());
5224
5225 // If there's only one MPI process and the user didn't supply
5226 // a Map (i.e., pMap is null), we're done. Set pMap to the
5227 // Map used to distribute X, and return X.
5228 if (comm->getSize () == 1 && map.is_null ()) {
5229 map = proc0Map;
5230 if (! err.is_null ()) {
5231 err->popTab ();
5232 }
5233 if (debug) {
5234 *err << myRank << ": readVectorImpl: done" << endl;
5235 }
5236 if (! err.is_null ()) {
5237 err->popTab ();
5238 }
5239 return X;
5240 }
5241
5242 if (debug) {
5243 *err << myRank << ": readVectorImpl: Creating target MV" << endl;
5244 }
5245
5246 // Make a multivector Y with the distributed map pMap.
5247 RCP<MV> Y = createVector<ST, LO, GO, NT> (map);
5248
5249 if (debug) {
5250 *err << myRank << ": readVectorImpl: Creating Export" << endl;
5251 }
5252
5253 // Make an Export object that will export X to Y. First
5254 // argument is the source map, second argument is the target
5255 // map.
5256 Export<LO, GO, NT> exporter (proc0Map, map, err);
5257
5258 if (debug) {
5259 *err << myRank << ": readVectorImpl: Exporting" << endl;
5260 }
5261 // Export X into Y.
5262 Y->doExport (*X, exporter, INSERT);
5263
5264 if (! err.is_null ()) {
5265 err->popTab ();
5266 }
5267 if (debug) {
5268 *err << myRank << ": readVectorImpl: done" << endl;
5269 }
5270 if (! err.is_null ()) {
5271 err->popTab ();
5272 }
5273
5274 // Y is distributed over all process(es) in the communicator.
5275 return Y;
5276 }
5277
5278 public:
5299 static Teuchos::RCP<const map_type>
5300 readMap (std::istream& in,
5301 const Teuchos::RCP<const comm_type>& comm,
5302 const bool tolerant=false,
5303 const bool debug=false,
5304 const bool binary=false)
5305 {
5306 Teuchos::RCP<Teuchos::FancyOStream> err =
5307 Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
5308 return readMap (in, comm, err, tolerant, debug, binary);
5309 }
5310
5311
5338 static Teuchos::RCP<const map_type>
5339 readMap (std::istream& in,
5340 const Teuchos::RCP<const comm_type>& comm,
5341 const Teuchos::RCP<Teuchos::FancyOStream>& err,
5342 const bool tolerant=false,
5343 const bool debug=false,
5344 const bool binary=false)
5345 {
5346 using Teuchos::arcp;
5347 using Teuchos::Array;
5348 using Teuchos::ArrayRCP;
5349 using Teuchos::as;
5350 using Teuchos::broadcast;
5351 using Teuchos::Comm;
5352 using Teuchos::CommRequest;
5353 using Teuchos::inOutArg;
5354 using Teuchos::ireceive;
5355 using Teuchos::outArg;
5356 using Teuchos::RCP;
5357 using Teuchos::receive;
5358 using Teuchos::reduceAll;
5359 using Teuchos::REDUCE_MIN;
5360 using Teuchos::isend;
5361 using Teuchos::SerialComm;
5362 using Teuchos::toString;
5363 using Teuchos::wait;
5364 using std::endl;
5365 typedef Tpetra::global_size_t GST;
5366 typedef ptrdiff_t int_type; // Can hold int and GO
5367 typedef local_ordinal_type LO;
5368 typedef global_ordinal_type GO;
5369 typedef node_type NT;
5371
5372 const int numProcs = comm->getSize ();
5373 const int myRank = comm->getRank ();
5374
5375 if (err.is_null ()) {
5376 err->pushTab ();
5377 }
5378 if (debug) {
5379 std::ostringstream os;
5380 os << myRank << ": readMap: " << endl;
5381 *err << os.str ();
5382 }
5383 if (err.is_null ()) {
5384 err->pushTab ();
5385 }
5386
5387 // Tag for receive-size / send-size messages. writeMap used
5388 // tags 1337 and 1338; we count up from there.
5389 const int sizeTag = 1339;
5390 // Tag for receive-data / send-data messages.
5391 const int dataTag = 1340;
5392
5393 // These are for sends on Process 0, and for receives on all
5394 // other processes. sizeReq is for the {receive,send}-size
5395 // message, and dataReq is for the message containing the
5396 // actual GIDs to belong to the receiving process.
5397 RCP<CommRequest<int> > sizeReq;
5398 RCP<CommRequest<int> > dataReq;
5399
5400 // Each process will have to receive the number of GIDs to
5401 // expect. Thus, we can post the receives now, and cancel
5402 // them if something should go wrong in the meantime.
5403 ArrayRCP<int_type> numGidsToRecv (1);
5404 numGidsToRecv[0] = 0;
5405 if (myRank != 0) {
5406 sizeReq = ireceive<int, int_type> (numGidsToRecv, 0, sizeTag, *comm);
5407 }
5408
5409 int readSuccess = 1;
5410 std::ostringstream exMsg;
5411 RCP<MV> data; // Will only be valid on Proc 0
5412 if (myRank == 0) {
5413 // If we want to reuse readDenseImpl, we have to make a
5414 // communicator that only contains Proc 0. Otherwise,
5415 // readDenseImpl will redistribute the data to all
5416 // processes. While we eventually want that, neither we nor
5417 // readDenseImpl know the correct Map to use at the moment.
5418 // That depends on the second column of the multivector.
5419 RCP<const Comm<int> > proc0Comm (new SerialComm<int> ());
5420 try {
5421 RCP<const map_type> dataMap;
5422 // This is currently the only place where we use the
5423 // 'tolerant' argument. Later, if we want to be clever,
5424 // we could have tolerant mode allow PIDs out of order.
5425 data = readDenseImpl<GO> (in, proc0Comm, dataMap, err, tolerant, debug, binary);
5426 (void) dataMap; // Silence "unused" warnings
5427 if (data.is_null ()) {
5428 readSuccess = 0;
5429 exMsg << "readDenseImpl() returned null." << endl;
5430 }
5431 } catch (std::exception& e) {
5432 readSuccess = 0;
5433 exMsg << e.what () << endl;
5434 }
5435 }
5436
5437 // Map from PID to all the GIDs for that PID.
5438 // Only populated on Process 0.
5439 std::map<int, Array<GO> > pid2gids;
5440
5441 // The index base must be the global minimum GID.
5442 // We will compute this on Process 0 and broadcast,
5443 // so that all processes can set up the Map.
5444 int_type globalNumGIDs = 0;
5445
5446 // The index base must be the global minimum GID.
5447 // We will compute this on Process 0 and broadcast,
5448 // so that all processes can set up the Map.
5449 GO indexBase = 0;
5450
5451 // Process 0: If the above read of the MultiVector succeeded,
5452 // extract the GIDs and PIDs into pid2gids, and find the
5453 // global min GID.
5454 if (myRank == 0 && readSuccess == 1) {
5455 if (data->getNumVectors () == 2) { // Map format 1.0
5456 ArrayRCP<const GO> GIDs = data->getData (0);
5457 ArrayRCP<const GO> PIDs = data->getData (1); // convert to int
5458 globalNumGIDs = GIDs.size ();
5459
5460 // Start computing the global min GID, while collecting
5461 // the GIDs for each PID.
5462 if (globalNumGIDs > 0) {
5463 const int pid = static_cast<int> (PIDs[0]);
5464
5465 if (pid < 0 || pid >= numProcs) {
5466 readSuccess = 0;
5467 exMsg << "Tpetra::MatrixMarket::readMap: "
5468 << "Encountered invalid PID " << pid << "." << endl;
5469 }
5470 else {
5471 const GO gid = GIDs[0];
5472 pid2gids[pid].push_back (gid);
5473 indexBase = gid; // the current min GID
5474 }
5475 }
5476 if (readSuccess == 1) {
5477 // Collect the rest of the GIDs for each PID, and compute
5478 // the global min GID.
5479 for (size_type k = 1; k < globalNumGIDs; ++k) {
5480 const int pid = static_cast<int> (PIDs[k]);
5481 if (pid < 0 || pid >= numProcs) {
5482 readSuccess = 0;
5483 exMsg << "Tpetra::MatrixMarket::readMap: "
5484 << "Encountered invalid PID " << pid << "." << endl;
5485 }
5486 else {
5487 const int_type gid = GIDs[k];
5488 pid2gids[pid].push_back (gid);
5489 if (gid < indexBase) {
5490 indexBase = gid; // the current min GID
5491 }
5492 }
5493 }
5494 }
5495 }
5496 else if (data->getNumVectors () == 1) { // Map format 2.0
5497 if (data->getGlobalLength () % 2 != static_cast<GST> (0)) {
5498 readSuccess = 0;
5499 exMsg << "Tpetra::MatrixMarket::readMap: Input data has the "
5500 "wrong format (for Map format 2.0). The global number of rows "
5501 "in the MultiVector must be even (divisible by 2)." << endl;
5502 }
5503 else {
5504 ArrayRCP<const GO> theData = data->getData (0);
5505 globalNumGIDs = static_cast<GO> (data->getGlobalLength ()) /
5506 static_cast<GO> (2);
5507
5508 // Start computing the global min GID, while
5509 // collecting the GIDs for each PID.
5510 if (globalNumGIDs > 0) {
5511 const int pid = static_cast<int> (theData[1]);
5512 if (pid < 0 || pid >= numProcs) {
5513 readSuccess = 0;
5514 exMsg << "Tpetra::MatrixMarket::readMap: "
5515 << "Encountered invalid PID " << pid << "." << endl;
5516 }
5517 else {
5518 const GO gid = theData[0];
5519 pid2gids[pid].push_back (gid);
5520 indexBase = gid; // the current min GID
5521 }
5522 }
5523 // Collect the rest of the GIDs for each PID, and
5524 // compute the global min GID.
5525 for (int_type k = 1; k < globalNumGIDs; ++k) {
5526 const int pid = static_cast<int> (theData[2*k + 1]);
5527 if (pid < 0 || pid >= numProcs) {
5528 readSuccess = 0;
5529 exMsg << "Tpetra::MatrixMarket::readMap: "
5530 << "Encountered invalid PID " << pid << "." << endl;
5531 }
5532 else {
5533 const GO gid = theData[2*k];
5534 pid2gids[pid].push_back (gid);
5535 if (gid < indexBase) {
5536 indexBase = gid; // the current min GID
5537 }
5538 }
5539 } // for each GID
5540 } // if the amount of data is correct
5541 }
5542 else {
5543 readSuccess = 0;
5544 exMsg << "Tpetra::MatrixMarket::readMap: Input data must have "
5545 "either 1 column (for the new Map format 2.0) or 2 columns (for "
5546 "the old Map format 1.0).";
5547 }
5548 } // myRank is zero
5549
5550 // Broadcast the indexBase, the global number of GIDs, and the
5551 // current success status. Use int_type for all of these.
5552 {
5553 int_type readResults[3];
5554 readResults[0] = static_cast<int_type> (indexBase);
5555 readResults[1] = static_cast<int_type> (globalNumGIDs);
5556 readResults[2] = static_cast<int_type> (readSuccess);
5557 broadcast<int, int_type> (*comm, 0, 3, readResults);
5558
5559 indexBase = static_cast<GO> (readResults[0]);
5560 globalNumGIDs = static_cast<int_type> (readResults[1]);
5561 readSuccess = static_cast<int> (readResults[2]);
5562 }
5563
5564 // Unwinding the stack will invoke sizeReq's destructor, which
5565 // will cancel the receive-size request on all processes that
5566 // posted it.
5567 TEUCHOS_TEST_FOR_EXCEPTION(
5568 readSuccess != 1, std::runtime_error,
5569 "Tpetra::MatrixMarket::readMap: Reading the Map failed with the "
5570 "following exception message: " << exMsg.str ());
5571
5572 if (myRank == 0) {
5573 // Proc 0: Send each process' number of GIDs to that process.
5574 for (int p = 1; p < numProcs; ++p) {
5575 ArrayRCP<int_type> numGidsToSend (1);
5576
5577 auto it = pid2gids.find (p);
5578 if (it == pid2gids.end ()) {
5579 numGidsToSend[0] = 0;
5580 } else {
5581 numGidsToSend[0] = it->second.size ();
5582 }
5583 sizeReq = isend<int, int_type> (numGidsToSend, p, sizeTag, *comm);
5584 wait<int> (*comm, outArg (sizeReq));
5585 }
5586 }
5587 else {
5588 // Wait on the receive-size message to finish.
5589 wait<int> (*comm, outArg (sizeReq));
5590 }
5591
5592 // Allocate / get the array for my GIDs.
5593 // Only Process 0 will have its actual GIDs at this point.
5594 ArrayRCP<GO> myGids;
5595 int_type myNumGids = 0;
5596 if (myRank == 0) {
5597 GO* myGidsRaw = NULL;
5598
5599 typename std::map<int, Array<GO> >::iterator it = pid2gids.find (0);
5600 if (it != pid2gids.end ()) {
5601 myGidsRaw = it->second.getRawPtr ();
5602 myNumGids = it->second.size ();
5603 // Nonowning ArrayRCP just views the Array.
5604 myGids = arcp<GO> (myGidsRaw, 0, myNumGids, false);
5605 }
5606 }
5607 else { // myRank != 0
5608 myNumGids = numGidsToRecv[0];
5609 myGids = arcp<GO> (myNumGids);
5610 }
5611
5612 if (myRank != 0) {
5613 // Post receive for data, now that we know how much data we
5614 // will receive. Only post receive if my process actually
5615 // has nonzero GIDs.
5616 if (myNumGids > 0) {
5617 dataReq = ireceive<int, GO> (myGids, 0, dataTag, *comm);
5618 }
5619 }
5620
5621 for (int p = 1; p < numProcs; ++p) {
5622 if (myRank == 0) {
5623 ArrayRCP<GO> sendGids; // to send to Process p
5624 GO* sendGidsRaw = NULL;
5625 int_type numSendGids = 0;
5626
5627 typename std::map<int, Array<GO> >::iterator it = pid2gids.find (p);
5628 if (it != pid2gids.end ()) {
5629 numSendGids = it->second.size ();
5630 sendGidsRaw = it->second.getRawPtr ();
5631 sendGids = arcp<GO> (sendGidsRaw, 0, numSendGids, false);
5632 }
5633 // Only send if that process actually has nonzero GIDs.
5634 if (numSendGids > 0) {
5635 dataReq = isend<int, GO> (sendGids, p, dataTag, *comm);
5636 }
5637 wait<int> (*comm, outArg (dataReq));
5638 }
5639 else if (myRank == p) {
5640 // Wait on my receive of GIDs to finish.
5641 wait<int> (*comm, outArg (dataReq));
5642 }
5643 } // for each process rank p in 1, 2, ..., numProcs-1
5644
5645 if (debug) {
5646 std::ostringstream os;
5647 os << myRank << ": readMap: creating Map" << endl;
5648 *err << os.str ();
5649 }
5650 const GST INVALID = Teuchos::OrdinalTraits<GST>::invalid ();
5651 RCP<const map_type> newMap;
5652
5653 // Create the Map; test whether the constructor threw. This
5654 // avoids deadlock and makes error reporting more readable.
5655
5656 int lclSuccess = 1;
5657 int gblSuccess = 0; // output argument
5658 std::ostringstream errStrm;
5659 try {
5660 newMap = rcp (new map_type (INVALID, myGids (), indexBase, comm));
5661 }
5662 catch (std::exception& e) {
5663 lclSuccess = 0;
5664 errStrm << "Process " << comm->getRank () << " threw an exception: "
5665 << e.what () << std::endl;
5666 }
5667 catch (...) {
5668 lclSuccess = 0;
5669 errStrm << "Process " << comm->getRank () << " threw an exception "
5670 "not a subclass of std::exception" << std::endl;
5671 }
5672 Teuchos::reduceAll<int, int> (*comm, Teuchos::REDUCE_MIN,
5673 lclSuccess, Teuchos::outArg (gblSuccess));
5674 if (gblSuccess != 1) {
5675 Tpetra::Details::gathervPrint (std::cerr, errStrm.str (), *comm);
5676 }
5677 TEUCHOS_TEST_FOR_EXCEPTION(gblSuccess != 1, std::runtime_error, "Map constructor failed!");
5678
5679 if (err.is_null ()) {
5680 err->popTab ();
5681 }
5682 if (debug) {
5683 std::ostringstream os;
5684 os << myRank << ": readMap: done" << endl;
5685 *err << os.str ();
5686 }
5687 if (err.is_null ()) {
5688 err->popTab ();
5689 }
5690 return newMap;
5691 }
5692
5693
5694 private:
5695
5706 static int
5707 encodeDataType (const std::string& dataType)
5708 {
5709 if (dataType == "real" || dataType == "integer") {
5710 return 0;
5711 } else if (dataType == "complex") {
5712 return 1;
5713 } else if (dataType == "pattern") {
5714 return 2;
5715 } else {
5716 // We should never get here, since Banner validates the
5717 // reported data type and ensures it is one of the accepted
5718 // values.
5719 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
5720 "Unrecognized Matrix Market data type \"" << dataType
5721 << "\". We should never get here. "
5722 "Please report this bug to the Tpetra developers.");
5723 }
5724 }
5725
5726 public:
5727
5757 static Teuchos::RCP<sparse_matrix_type>
5758 readSparsePerRank (const std::string& filename_prefix,
5759 const std::string& filename_suffix,
5760 const Teuchos::RCP<const map_type>& rowMap,
5761 Teuchos::RCP<const map_type>& colMap,
5762 const Teuchos::RCP<const map_type>& domainMap,
5763 const Teuchos::RCP<const map_type>& rangeMap,
5764 const bool callFillComplete=true,
5765 const bool tolerant=false,
5766 const int ranksToReadAtOnce=8,
5767 const bool debug=false)
5768 {
5769 using ST = scalar_type;
5770 using LO = local_ordinal_type;
5771 using GO = global_ordinal_type;
5772 using STS = typename Teuchos::ScalarTraits<ST>;
5773 using Teuchos::RCP;
5774 using Teuchos::ArrayRCP;
5775 using Teuchos::arcp;
5776 using Teuchos::rcp;
5777
5778 // Sanity Checks
5779 // Fast checks for invalid input. We can't check other
5780 // attributes of the Maps until we've read in the matrix
5781 // dimensions.
5782 TEUCHOS_TEST_FOR_EXCEPTION(
5783 rowMap.is_null (), std::invalid_argument,
5784 "Row Map must be nonnull.");
5785 Teuchos::RCP<const Teuchos::Comm<int> > comm = rowMap->getComm();
5786 TEUCHOS_TEST_FOR_EXCEPTION
5787 (comm.is_null (), std::invalid_argument,
5788 "The input row map's communicator (Teuchos::Comm object) is null.");
5789 TEUCHOS_TEST_FOR_EXCEPTION(
5790 rangeMap.is_null (), std::invalid_argument,
5791 "Range Map must be nonnull.");
5792 TEUCHOS_TEST_FOR_EXCEPTION(
5793 domainMap.is_null (), std::invalid_argument,
5794 "Domain Map must be nonnull.");
5795 TEUCHOS_TEST_FOR_EXCEPTION(
5796 domainMap->getComm().getRawPtr() != comm.getRawPtr(),
5797 std::invalid_argument,
5798 "The specified domain Map's communicator (domainMap->getComm())"
5799 "differs from row Map's communicator");
5800 TEUCHOS_TEST_FOR_EXCEPTION(
5801 rangeMap->getComm().getRawPtr() != comm.getRawPtr(),
5802 std::invalid_argument,
5803 "The specified range Map's communicator (rangeMap->getComm())"
5804 "differs from row Map's communicator");
5805
5806 // Setup
5807 const int myRank = comm->getRank();
5808 const int numProc = comm->getSize();
5809 std::string filename = filename_prefix + std::to_string(myRank) + filename_suffix;
5810
5811 // Bounds check the writing limits
5812 int rank_limit = std::min(std::max(ranksToReadAtOnce,1),numProc);
5813
5814 // Data structures for constructor
5815 ArrayRCP<size_t> numEntriesPerRow;
5816 ArrayRCP<size_t> rowPtr;
5817 ArrayRCP<global_ordinal_type> colInd;
5818 ArrayRCP<scalar_type> values;
5819 std::ostringstream errMsg;
5820
5822 // Start the reading of the banners to get
5823 // local row / nnz counts and then read the
5824 // data. We'll pack everything into big ol'
5825 // rowptr/colind/values ArrayRCPs
5826 bool success = true;
5827 int bannerIsCorrect = 1, readSuccess = 1;
5828 LO numRows, numCols, numNonzeros;
5829 for(int base_rank = 0; base_rank < numProc; base_rank += rank_limit) {
5830 int stop = std::min(base_rank+rank_limit,numProc);
5831
5832 // Is my rank in this batch?
5833 if(base_rank <= myRank && myRank < stop) {
5834 // My turn to read
5835 std::ifstream in(filename);
5836 using Teuchos::MatrixMarket::Banner;
5837 size_t lineNumber = 1;
5838 RCP<const Banner> pBanner;
5839 try {
5840 pBanner = readBanner (in, lineNumber, tolerant, debug);
5841 }
5842 catch (std::exception& e) {
5843 errMsg << "Attempt to read the Matrix Market file's Banner line "
5844 "threw an exception: " << e.what();
5845 bannerIsCorrect = 0;
5846 }
5847 if (bannerIsCorrect) {
5848 // Validate the Banner for the case of a sparse matrix.
5849 // We validate on Proc 0, since it reads the Banner.
5850
5851 // In intolerant mode, the matrix type must be "coordinate".
5852 if (! tolerant && pBanner->matrixType() != "coordinate") {
5853 bannerIsCorrect = 0;
5854 errMsg << "The Matrix Market input file must contain a "
5855 "\"coordinate\"-format sparse matrix in order to create a "
5856 "Tpetra::CrsMatrix object from it, but the file's matrix "
5857 "type is \"" << pBanner->matrixType() << "\" instead.";
5858 }
5859 // In tolerant mode, we allow the matrix type to be
5860 // anything other than "array" (which would mean that
5861 // the file contains a dense matrix).
5862 if (tolerant && pBanner->matrixType() == "array") {
5863 bannerIsCorrect = 0;
5864 errMsg << "Matrix Market file must contain a \"coordinate\"-"
5865 "format sparse matrix in order to create a Tpetra::CrsMatrix "
5866 "object from it, but the file's matrix type is \"array\" "
5867 "instead. That probably means the file contains dense matrix "
5868 "data.";
5869 }
5870 }
5871
5872 // Unpacked coordinate matrix dimensions
5873 using Teuchos::MatrixMarket::readCoordinateDimensions;
5874 success = readCoordinateDimensions (in, numRows, numCols,
5875 numNonzeros, lineNumber,
5876 tolerant);
5877
5878 // Sanity checking of headers
5879 TEUCHOS_TEST_FOR_EXCEPTION(numRows != (LO)rowMap->getLocalNumElements(), std::invalid_argument,
5880 "# rows in file does not match rowmap.");
5881 TEUCHOS_TEST_FOR_EXCEPTION(!colMap.is_null() && numCols != (LO)colMap->getLocalNumElements(), std::invalid_argument,
5882 "# rows in file does not match colmap.");
5883
5884
5885 // Read the data
5886 typedef Teuchos::MatrixMarket::Raw::Adder<scalar_type,global_ordinal_type> raw_adder_type;
5887 bool tolerant_required = true;
5888 Teuchos::RCP<raw_adder_type> pRaw =
5889 Teuchos::rcp (new raw_adder_type (numRows,numCols,numNonzeros,tolerant_required,debug));
5890 RCP<adder_type> pAdder = Teuchos::rcp (new adder_type (pRaw, pBanner->symmType ()));
5891
5892 if (debug) {
5893 std::cerr << "-- Reading matrix data" << std::endl;
5894 }
5895
5896 try {
5897 // Reader for "coordinate" format sparse matrix data.
5898 typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
5899 global_ordinal_type, scalar_type, STS::isComplex> reader_type;
5900 reader_type reader (pAdder);
5901
5902 // Read the sparse matrix entries.
5903 std::pair<bool, std::vector<size_t> > results = reader.read (in, lineNumber, tolerant_required, debug);
5904
5905
5906 readSuccess = results.first ? 1 : 0;
5907 }
5908 catch (std::exception& e) {
5909 readSuccess = 0;
5910 errMsg << e.what();
5911 }
5912
5914 // Create the CSR Arrays
5915 typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,global_ordinal_type> element_type;
5916
5917 // Additively merge duplicate matrix entries.
5918 pAdder->getAdder()->merge ();
5919
5920 // Get a temporary const view of the merged matrix entries.
5921 const std::vector<element_type>& entries = pAdder->getAdder()->getEntries();
5922
5923 // Number of matrix entries (after merging).
5924 const size_t numEntries = (size_t)entries.size();
5925
5926 if (debug) {
5927 std::cerr << "----- Proc "<<myRank<<": Matrix has numRows=" << numRows
5928 << " rows and numEntries=" << numEntries
5929 << " entries." << std::endl;
5930 }
5931
5932
5933 // Make space for the CSR matrix data. Converting to
5934 // CSR is easier if we fill numEntriesPerRow with zeros
5935 // at first.
5936 numEntriesPerRow = arcp<size_t> (numRows);
5937 std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
5938 rowPtr = arcp<size_t> (numRows+1);
5939 std::fill (rowPtr.begin(), rowPtr.end(), 0);
5940 colInd = arcp<global_ordinal_type> (numEntries);
5941 values = arcp<scalar_type> (numEntries);
5942
5943 // Convert from array-of-structs coordinate format to CSR
5944 // (compressed sparse row) format.
5945 global_ordinal_type l_prvRow = 0;
5946 size_t curPos = 0;
5947 LO INVALID = Teuchos::OrdinalTraits<LO>::invalid();
5948 rowPtr[0] = 0;
5949 LO indexBase = rowMap->getIndexBase();
5950 for (curPos = 0; curPos < numEntries; ++curPos) {
5951 const element_type& curEntry = entries[curPos];
5952 const global_ordinal_type curRow = curEntry.rowIndex() + indexBase;
5953 LO l_curRow = rowMap->getLocalElement(curRow);
5954
5955
5956 TEUCHOS_TEST_FOR_EXCEPTION(l_curRow == INVALID,std::logic_error,
5957 "Current global row "<< curRow << " is invalid.");
5958
5959 TEUCHOS_TEST_FOR_EXCEPTION(l_curRow < l_prvRow, std::logic_error,
5960 "Row indices are out of order, even though they are supposed "
5961 "to be sorted. curRow = " << l_curRow << ", prvRow = "
5962 << l_prvRow << ", at curPos = " << curPos << ". Please report "
5963 "this bug to the Tpetra developers.");
5964 if (l_curRow > l_prvRow) {
5965 for (LO r = l_prvRow+1; r <= l_curRow; ++r) {
5966 rowPtr[r] = curPos;
5967 }
5968 l_prvRow = l_curRow;
5969 }
5970 numEntriesPerRow[l_curRow]++;
5971 colInd[curPos] = curEntry.colIndex() + indexBase;
5972 values[curPos] = curEntry.value();
5973
5974 }
5975 // rowPtr has one more entry than numEntriesPerRow. The
5976 // last entry of rowPtr is the number of entries in
5977 // colInd and values.
5978 rowPtr[numRows] = numEntries;
5979
5980 }// end base_rank <= myRank < stop
5981
5982 // Barrier between batches to keep the filesystem happy
5983 comm->barrier();
5984
5985 }//end outer rank loop
5986
5987
5988 // Call the matrix constructor and fill. This isn't particularly efficient
5989 RCP<sparse_matrix_type> A;
5990 if(colMap.is_null()) {
5991 A=rcp(new sparse_matrix_type(rowMap,numEntriesPerRow()));
5992 for(size_t i=0; i<rowMap->getLocalNumElements(); i++) {
5993 GO g_row = rowMap->getGlobalElement(i);
5994 size_t start = rowPtr[i];
5995 size_t size = rowPtr[i+1] - rowPtr[i];
5996 if(size>0) {
5997 A->insertGlobalValues(g_row,size,&values[start],&colInd[start]);
5998 }
5999 }
6000 }
6001 else {
6002 throw std::runtime_error("Reading with a column map is not yet implemented");
6003 }
6004 RCP<const map_type> myDomainMap = domainMap.is_null() ? rowMap : domainMap;
6005 RCP<const map_type> myRangeMap = rangeMap.is_null() ? rowMap : rangeMap;
6006
6007 A->fillComplete(myDomainMap,myRangeMap);
6008
6009 if(!readSuccess)
6010 success = false;
6011 TEUCHOS_TEST_FOR_EXCEPTION(success == false, std::runtime_error,
6012 "Read failed.");
6013
6014 return A;
6015 }// end readSparsePerRank
6016
6017
6018 }; // class Reader
6019
6048 template<class SparseMatrixType>
6049 class Writer {
6050 public:
6052 typedef SparseMatrixType sparse_matrix_type;
6053 typedef Teuchos::RCP<sparse_matrix_type> sparse_matrix_ptr;
6054
6056 typedef typename SparseMatrixType::scalar_type scalar_type;
6058 typedef typename SparseMatrixType::local_ordinal_type local_ordinal_type;
6064 typedef typename SparseMatrixType::global_ordinal_type global_ordinal_type;
6066 typedef typename SparseMatrixType::node_type node_type;
6067
6069 typedef MultiVector<scalar_type,
6077
6080
6112 static void
6113 writeSparseFile (const std::string& filename,
6114 const sparse_matrix_type& matrix,
6115 const std::string& matrixName,
6116 const std::string& matrixDescription,
6117 const bool debug=false)
6118 {
6119 Teuchos::RCP<const Teuchos::Comm<int> > comm = matrix.getComm ();
6120 TEUCHOS_TEST_FOR_EXCEPTION
6121 (comm.is_null (), std::invalid_argument,
6122 "The input matrix's communicator (Teuchos::Comm object) is null.");
6123 const int myRank = comm->getRank ();
6124 std::ofstream out;
6125
6126 // Only open the file on Rank 0.
6127 if (myRank == 0) {
6128 out.open (filename.c_str ());
6129 }
6130 writeSparse (out, matrix, matrixName, matrixDescription, debug);
6131 // We can rely on the destructor of the output stream to close
6132 // the file on scope exit, even if writeSparse() throws an
6133 // exception.
6134 }
6135
6137 static void
6138 writeSparseFile (const std::string& filename,
6139 const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6140 const std::string& matrixName,
6141 const std::string& matrixDescription,
6142 const bool debug=false)
6143 {
6144 TEUCHOS_TEST_FOR_EXCEPTION
6145 (pMatrix.is_null (), std::invalid_argument,
6146 "The input matrix is null.");
6147 writeSparseFile (filename, *pMatrix, matrixName,
6148 matrixDescription, debug);
6149 }
6150
6170 static void
6171 writeSparseFile (const std::string& filename,
6172 const sparse_matrix_type& matrix,
6173 const bool debug=false)
6174 {
6175 writeSparseFile (filename, matrix, "", "", debug);
6176 }
6177
6179 static void
6180 writeSparseFile (const std::string& filename,
6181 const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6182 const bool debug=false)
6183 {
6184 writeSparseFile (filename, *pMatrix, "", "", debug);
6185 }
6186
6217 static void
6218 writeSparse (std::ostream& out,
6219 const sparse_matrix_type& matrix,
6220 const std::string& matrixName,
6221 const std::string& matrixDescription,
6222 const bool debug=false)
6223 {
6224 using Teuchos::ArrayView;
6225 using Teuchos::Comm;
6226 using Teuchos::FancyOStream;
6227 using Teuchos::getFancyOStream;
6228 using Teuchos::null;
6229 using Teuchos::RCP;
6230 using Teuchos::rcpFromRef;
6231 using std::cerr;
6232 using std::endl;
6233 using ST = scalar_type;
6234 using LO = local_ordinal_type;
6235 using GO = global_ordinal_type;
6236 using STS = typename Teuchos::ScalarTraits<ST>;
6237
6238 // Make the output stream write floating-point numbers in
6239 // scientific notation. It will politely put the output
6240 // stream back to its state on input, when this scope
6241 // terminates.
6242 Teuchos::SetScientific<ST> sci (out);
6243
6244 // Get the matrix's communicator.
6245 RCP<const Comm<int> > comm = matrix.getComm ();
6246 TEUCHOS_TEST_FOR_EXCEPTION(
6247 comm.is_null (), std::invalid_argument,
6248 "The input matrix's communicator (Teuchos::Comm object) is null.");
6249 const int myRank = comm->getRank ();
6250
6251 // Optionally, make a stream for debugging output.
6252 RCP<FancyOStream> err =
6253 debug ? getFancyOStream (rcpFromRef (std::cerr)) : null;
6254 if (debug) {
6255 std::ostringstream os;
6256 os << myRank << ": writeSparse" << endl;
6257 *err << os.str ();
6258 comm->barrier ();
6259 os << "-- " << myRank << ": past barrier" << endl;
6260 *err << os.str ();
6261 }
6262
6263 // Whether to print debugging output to stderr.
6264 const bool debugPrint = debug && myRank == 0;
6265
6266 RCP<const map_type> rowMap = matrix.getRowMap ();
6267 RCP<const map_type> colMap = matrix.getColMap ();
6268 RCP<const map_type> domainMap = matrix.getDomainMap ();
6269 RCP<const map_type> rangeMap = matrix.getRangeMap ();
6270
6271 const global_size_t numRows = rangeMap->getGlobalNumElements ();
6272 const global_size_t numCols = domainMap->getGlobalNumElements ();
6273
6274 if (debug && myRank == 0) {
6275 std::ostringstream os;
6276 os << "-- Input sparse matrix is:"
6277 << "---- " << numRows << " x " << numCols << endl
6278 << "---- "
6279 << (matrix.isGloballyIndexed() ? "Globally" : "Locally")
6280 << " indexed." << endl
6281 << "---- Its row map has " << rowMap->getGlobalNumElements ()
6282 << " elements." << endl
6283 << "---- Its col map has " << colMap->getGlobalNumElements ()
6284 << " elements." << endl;
6285 *err << os.str ();
6286 }
6287 // Make the "gather" row map, where Proc 0 owns all rows and
6288 // the other procs own no rows.
6289 const size_t localNumRows = (myRank == 0) ? numRows : 0;
6290 if (debug) {
6291 std::ostringstream os;
6292 os << "-- " << myRank << ": making gatherRowMap" << endl;
6293 *err << os.str ();
6294 }
6295 RCP<const map_type> gatherRowMap =
6296 Details::computeGatherMap (rowMap, err, debug);
6297
6298 // Since the matrix may in general be non-square, we need to
6299 // make a column map as well. In this case, the column map
6300 // contains all the columns of the original matrix, because we
6301 // are gathering the whole matrix onto Proc 0. We call
6302 // computeGatherMap to preserve the original order of column
6303 // indices over all the processes.
6304 const size_t localNumCols = (myRank == 0) ? numCols : 0;
6305 RCP<const map_type> gatherColMap =
6306 Details::computeGatherMap (colMap, err, debug);
6307
6308 // Current map is the source map, gather map is the target map.
6309 typedef Import<LO, GO, node_type> import_type;
6310 import_type importer (rowMap, gatherRowMap);
6311
6312 // Create a new CrsMatrix to hold the result of the import.
6313 // The constructor needs a column map as well as a row map,
6314 // for the case that the matrix is not square.
6315 RCP<sparse_matrix_type> newMatrix =
6316 rcp (new sparse_matrix_type (gatherRowMap, gatherColMap,
6317 static_cast<size_t> (0)));
6318 // Import the sparse matrix onto Proc 0.
6319 newMatrix->doImport (matrix, importer, INSERT);
6320
6321 // fillComplete() needs the domain and range maps for the case
6322 // that the matrix is not square.
6323 {
6324 RCP<const map_type> gatherDomainMap =
6325 rcp (new map_type (numCols, localNumCols,
6326 domainMap->getIndexBase (),
6327 comm));
6328 RCP<const map_type> gatherRangeMap =
6329 rcp (new map_type (numRows, localNumRows,
6330 rangeMap->getIndexBase (),
6331 comm));
6332 newMatrix->fillComplete (gatherDomainMap, gatherRangeMap);
6333 }
6334
6335 if (debugPrint) {
6336 cerr << "-- Output sparse matrix is:"
6337 << "---- " << newMatrix->getRangeMap ()->getGlobalNumElements ()
6338 << " x "
6339 << newMatrix->getDomainMap ()->getGlobalNumElements ()
6340 << " with "
6341 << newMatrix->getGlobalNumEntries () << " entries;" << endl
6342 << "---- "
6343 << (newMatrix->isGloballyIndexed () ? "Globally" : "Locally")
6344 << " indexed." << endl
6345 << "---- Its row map has "
6346 << newMatrix->getRowMap ()->getGlobalNumElements ()
6347 << " elements, with index base "
6348 << newMatrix->getRowMap ()->getIndexBase () << "." << endl
6349 << "---- Its col map has "
6350 << newMatrix->getColMap ()->getGlobalNumElements ()
6351 << " elements, with index base "
6352 << newMatrix->getColMap ()->getIndexBase () << "." << endl
6353 << "---- Element count of output matrix's column Map may differ "
6354 << "from that of the input matrix's column Map, if some columns "
6355 << "of the matrix contain no entries." << endl;
6356 }
6357
6358 //
6359 // Print the metadata and the matrix entries on Rank 0.
6360 //
6361 if (myRank == 0) {
6362 // Print the Matrix Market banner line. CrsMatrix stores
6363 // data nonsymmetrically ("general"). This implies that
6364 // readSparse() on a symmetrically stored input file,
6365 // followed by writeSparse() on the resulting sparse matrix,
6366 // will result in an output file with a different banner
6367 // line than the original input file.
6368 out << "%%MatrixMarket matrix coordinate "
6369 << (STS::isComplex ? "complex" : "real")
6370 << " general" << endl;
6371
6372 // Print comments (the matrix name and / or description).
6373 if (matrixName != "") {
6374 printAsComment (out, matrixName);
6375 }
6376 if (matrixDescription != "") {
6377 printAsComment (out, matrixDescription);
6378 }
6379
6380 // Print the Matrix Market header (# rows, # columns, #
6381 // nonzeros). Use the range resp. domain map for the number
6382 // of rows resp. columns, since Tpetra::CrsMatrix uses the
6383 // column map for the number of columns. That only
6384 // corresponds to the "linear-algebraic" number of columns
6385 // when the column map is uniquely owned (a.k.a. one-to-one),
6386 // which only happens if the matrix is (block) diagonal.
6387 out << newMatrix->getRangeMap ()->getGlobalNumElements () << " "
6388 << newMatrix->getDomainMap ()->getGlobalNumElements () << " "
6389 << newMatrix->getGlobalNumEntries () << endl;
6390
6391 // The Matrix Market format expects one-based row and column
6392 // indices. We'll convert the indices on output from
6393 // whatever index base they use to one-based indices.
6394 const GO rowIndexBase = gatherRowMap->getIndexBase ();
6395 const GO colIndexBase = newMatrix->getColMap()->getIndexBase ();
6396 //
6397 // Print the entries of the matrix.
6398 //
6399 // newMatrix can never be globally indexed, since we called
6400 // fillComplete() on it. We include code for both cases
6401 // (globally or locally indexed) just in case that ever
6402 // changes.
6403 if (newMatrix->isGloballyIndexed()) {
6404 // We know that the "gather" row Map is contiguous, so we
6405 // don't need to get the list of GIDs.
6406 const GO minAllGlobalIndex = gatherRowMap->getMinAllGlobalIndex ();
6407 const GO maxAllGlobalIndex = gatherRowMap->getMaxAllGlobalIndex ();
6408 for (GO globalRowIndex = minAllGlobalIndex;
6409 globalRowIndex <= maxAllGlobalIndex; // inclusive range
6410 ++globalRowIndex) {
6411 typename sparse_matrix_type::global_inds_host_view_type ind;
6412 typename sparse_matrix_type::values_host_view_type val;
6413 newMatrix->getGlobalRowView (globalRowIndex, ind, val);
6414 for (size_t ii = 0; ii < ind.extent(0); ii++) {
6415 const GO globalColIndex = ind(ii);
6416 // Convert row and column indices to 1-based.
6417 // This works because the global index type is signed.
6418 out << (globalRowIndex + 1 - rowIndexBase) << " "
6419 << (globalColIndex + 1 - colIndexBase) << " ";
6420 if (STS::isComplex) {
6421 out << STS::real (val(ii)) << " " << STS::imag (val(ii));
6422 } else {
6423 out << val(ii);
6424 }
6425 out << endl;
6426 } // For each entry in the current row
6427 } // For each row of the "gather" matrix
6428 }
6429 else { // newMatrix is locally indexed
6430 using OTG = Teuchos::OrdinalTraits<GO>;
6431 for (LO localRowIndex = gatherRowMap->getMinLocalIndex();
6432 localRowIndex <= gatherRowMap->getMaxLocalIndex();
6433 ++localRowIndex) {
6434 // Convert from local to global row index.
6435 const GO globalRowIndex =
6436 gatherRowMap->getGlobalElement (localRowIndex);
6437 TEUCHOS_TEST_FOR_EXCEPTION(
6438 globalRowIndex == OTG::invalid(), std::logic_error,
6439 "Failed to convert the supposed local row index "
6440 << localRowIndex << " into a global row index. "
6441 "Please report this bug to the Tpetra developers.");
6442 typename sparse_matrix_type::local_inds_host_view_type ind;
6443 typename sparse_matrix_type::values_host_view_type val;
6444 newMatrix->getLocalRowView (localRowIndex, ind, val);
6445 for (size_t ii = 0; ii < ind.extent(0); ii++) {
6446 // Convert the column index from local to global.
6447 const GO globalColIndex =
6448 newMatrix->getColMap()->getGlobalElement (ind(ii));
6449 TEUCHOS_TEST_FOR_EXCEPTION(
6450 globalColIndex == OTG::invalid(), std::logic_error,
6451 "On local row " << localRowIndex << " of the sparse matrix: "
6452 "Failed to convert the supposed local column index "
6453 << ind(ii) << " into a global column index. Please report "
6454 "this bug to the Tpetra developers.");
6455 // Convert row and column indices to 1-based.
6456 // This works because the global index type is signed.
6457 out << (globalRowIndex + 1 - rowIndexBase) << " "
6458 << (globalColIndex + 1 - colIndexBase) << " ";
6459 if (STS::isComplex) {
6460 out << STS::real (val(ii)) << " " << STS::imag (val(ii));
6461 } else {
6462 out << val(ii);
6463 }
6464 out << endl;
6465 } // For each entry in the current row
6466 } // For each row of the "gather" matrix
6467 } // Whether the "gather" matrix is locally or globally indexed
6468 } // If my process' rank is 0
6469 }
6470
6472 static void
6473 writeSparse (std::ostream& out,
6474 const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6475 const std::string& matrixName,
6476 const std::string& matrixDescription,
6477 const bool debug=false)
6478 {
6479 TEUCHOS_TEST_FOR_EXCEPTION
6480 (pMatrix.is_null (), std::invalid_argument,
6481 "The input matrix is null.");
6482 writeSparse (out, *pMatrix, matrixName, matrixDescription, debug);
6483 }
6484
6515 static void
6516 writeSparseGraph (std::ostream& out,
6517 const crs_graph_type& graph,
6518 const std::string& graphName,
6519 const std::string& graphDescription,
6520 const bool debug=false)
6521 {
6522 using Teuchos::ArrayView;
6523 using Teuchos::Comm;
6524 using Teuchos::FancyOStream;
6525 using Teuchos::getFancyOStream;
6526 using Teuchos::null;
6527 using Teuchos::RCP;
6528 using Teuchos::rcpFromRef;
6529 using std::cerr;
6530 using std::endl;
6531 typedef local_ordinal_type LO;
6532 typedef global_ordinal_type GO;
6533
6534 // Get the graph's communicator. Processes on which the
6535 // graph's Map or communicator is null don't participate in
6536 // this operation. This function shouldn't even be called on
6537 // those processes.
6538 auto rowMap = graph.getRowMap ();
6539 if (rowMap.is_null ()) {
6540 return;
6541 }
6542 auto comm = rowMap->getComm ();
6543 if (comm.is_null ()) {
6544 return;
6545 }
6546 const int myRank = comm->getRank ();
6547
6548 // Optionally, make a stream for debugging output.
6549 RCP<FancyOStream> err =
6550 debug ? getFancyOStream (rcpFromRef (std::cerr)) : null;
6551 if (debug) {
6552 std::ostringstream os;
6553 os << myRank << ": writeSparseGraph" << endl;
6554 *err << os.str ();
6555 comm->barrier ();
6556 os << "-- " << myRank << ": past barrier" << endl;
6557 *err << os.str ();
6558 }
6559
6560 // Whether to print debugging output to stderr.
6561 const bool debugPrint = debug && myRank == 0;
6562
6563 // We've already gotten the rowMap above.
6564 auto colMap = graph.getColMap ();
6565 auto domainMap = graph.getDomainMap ();
6566 auto rangeMap = graph.getRangeMap ();
6567
6568 const global_size_t numRows = rangeMap->getGlobalNumElements ();
6569 const global_size_t numCols = domainMap->getGlobalNumElements ();
6570
6571 if (debug && myRank == 0) {
6572 std::ostringstream os;
6573 os << "-- Input sparse graph is:"
6574 << "---- " << numRows << " x " << numCols << " with "
6575 << graph.getGlobalNumEntries () << " entries;" << endl
6576 << "---- "
6577 << (graph.isGloballyIndexed () ? "Globally" : "Locally")
6578 << " indexed." << endl
6579 << "---- Its row Map has " << rowMap->getGlobalNumElements ()
6580 << " elements." << endl
6581 << "---- Its col Map has " << colMap->getGlobalNumElements ()
6582 << " elements." << endl;
6583 *err << os.str ();
6584 }
6585 // Make the "gather" row map, where Proc 0 owns all rows and
6586 // the other procs own no rows.
6587 const size_t localNumRows = (myRank == 0) ? numRows : 0;
6588 if (debug) {
6589 std::ostringstream os;
6590 os << "-- " << myRank << ": making gatherRowMap" << endl;
6591 *err << os.str ();
6592 }
6593 auto gatherRowMap = Details::computeGatherMap (rowMap, err, debug);
6594
6595 // Since the graph may in general be non-square, we need to
6596 // make a column map as well. In this case, the column map
6597 // contains all the columns of the original graph, because we
6598 // are gathering the whole graph onto Proc 0. We call
6599 // computeGatherMap to preserve the original order of column
6600 // indices over all the processes.
6601 const size_t localNumCols = (myRank == 0) ? numCols : 0;
6602 auto gatherColMap = Details::computeGatherMap (colMap, err, debug);
6603
6604 // Current map is the source map, gather map is the target map.
6605 Import<LO, GO, node_type> importer (rowMap, gatherRowMap);
6606
6607 // Create a new CrsGraph to hold the result of the import.
6608 // The constructor needs a column map as well as a row map,
6609 // for the case that the graph is not square.
6610 crs_graph_type newGraph (gatherRowMap, gatherColMap,
6611 static_cast<size_t> (0));
6612 // Import the sparse graph onto Proc 0.
6613 newGraph.doImport (graph, importer, INSERT);
6614
6615 // fillComplete() needs the domain and range maps for the case
6616 // that the graph is not square.
6617 {
6618 RCP<const map_type> gatherDomainMap =
6619 rcp (new map_type (numCols, localNumCols,
6620 domainMap->getIndexBase (),
6621 comm));
6622 RCP<const map_type> gatherRangeMap =
6623 rcp (new map_type (numRows, localNumRows,
6624 rangeMap->getIndexBase (),
6625 comm));
6626 newGraph.fillComplete (gatherDomainMap, gatherRangeMap);
6627 }
6628
6629 if (debugPrint) {
6630 cerr << "-- Output sparse graph is:"
6631 << "---- " << newGraph.getRangeMap ()->getGlobalNumElements ()
6632 << " x "
6633 << newGraph.getDomainMap ()->getGlobalNumElements ()
6634 << " with "
6635 << newGraph.getGlobalNumEntries () << " entries;" << endl
6636 << "---- "
6637 << (newGraph.isGloballyIndexed () ? "Globally" : "Locally")
6638 << " indexed." << endl
6639 << "---- Its row map has "
6640 << newGraph.getRowMap ()->getGlobalNumElements ()
6641 << " elements, with index base "
6642 << newGraph.getRowMap ()->getIndexBase () << "." << endl
6643 << "---- Its col map has "
6644 << newGraph.getColMap ()->getGlobalNumElements ()
6645 << " elements, with index base "
6646 << newGraph.getColMap ()->getIndexBase () << "." << endl
6647 << "---- Element count of output graph's column Map may differ "
6648 << "from that of the input matrix's column Map, if some columns "
6649 << "of the matrix contain no entries." << endl;
6650 }
6651
6652 //
6653 // Print the metadata and the graph entries on Process 0 of
6654 // the graph's communicator.
6655 //
6656 if (myRank == 0) {
6657 // Print the Matrix Market banner line. CrsGraph stores
6658 // data nonsymmetrically ("general"). This implies that
6659 // readSparseGraph() on a symmetrically stored input file,
6660 // followed by writeSparseGraph() on the resulting sparse
6661 // graph, will result in an output file with a different
6662 // banner line than the original input file.
6663 out << "%%MatrixMarket matrix coordinate pattern general" << endl;
6664
6665 // Print comments (the graph name and / or description).
6666 if (graphName != "") {
6667 printAsComment (out, graphName);
6668 }
6669 if (graphDescription != "") {
6670 printAsComment (out, graphDescription);
6671 }
6672
6673 // Print the Matrix Market header (# rows, # columns, #
6674 // stored entries). Use the range resp. domain map for the
6675 // number of rows resp. columns, since Tpetra::CrsGraph uses
6676 // the column map for the number of columns. That only
6677 // corresponds to the "linear-algebraic" number of columns
6678 // when the column map is uniquely owned
6679 // (a.k.a. one-to-one), which only happens if the graph is
6680 // block diagonal (one block per process).
6681 out << newGraph.getRangeMap ()->getGlobalNumElements () << " "
6682 << newGraph.getDomainMap ()->getGlobalNumElements () << " "
6683 << newGraph.getGlobalNumEntries () << endl;
6684
6685 // The Matrix Market format expects one-based row and column
6686 // indices. We'll convert the indices on output from
6687 // whatever index base they use to one-based indices.
6688 const GO rowIndexBase = gatherRowMap->getIndexBase ();
6689 const GO colIndexBase = newGraph.getColMap()->getIndexBase ();
6690 //
6691 // Print the entries of the graph.
6692 //
6693 // newGraph can never be globally indexed, since we called
6694 // fillComplete() on it. We include code for both cases
6695 // (globally or locally indexed) just in case that ever
6696 // changes.
6697 if (newGraph.isGloballyIndexed ()) {
6698 // We know that the "gather" row Map is contiguous, so we
6699 // don't need to get the list of GIDs.
6700 const GO minAllGlobalIndex = gatherRowMap->getMinAllGlobalIndex ();
6701 const GO maxAllGlobalIndex = gatherRowMap->getMaxAllGlobalIndex ();
6702 for (GO globalRowIndex = minAllGlobalIndex;
6703 globalRowIndex <= maxAllGlobalIndex; // inclusive range
6704 ++globalRowIndex) {
6705 typename crs_graph_type::global_inds_host_view_type ind;
6706 newGraph.getGlobalRowView (globalRowIndex, ind);
6707 for (size_t ii = 0; ii < ind.extent(0); ii++) {
6708 const GO globalColIndex = ind(ii);
6709 // Convert row and column indices to 1-based.
6710 // This works because the global index type is signed.
6711 out << (globalRowIndex + 1 - rowIndexBase) << " "
6712 << (globalColIndex + 1 - colIndexBase) << " ";
6713 out << endl;
6714 } // For each entry in the current row
6715 } // For each row of the "gather" graph
6716 }
6717 else { // newGraph is locally indexed
6718 typedef Teuchos::OrdinalTraits<GO> OTG;
6719 for (LO localRowIndex = gatherRowMap->getMinLocalIndex ();
6720 localRowIndex <= gatherRowMap->getMaxLocalIndex ();
6721 ++localRowIndex) {
6722 // Convert from local to global row index.
6723 const GO globalRowIndex =
6724 gatherRowMap->getGlobalElement (localRowIndex);
6725 TEUCHOS_TEST_FOR_EXCEPTION
6726 (globalRowIndex == OTG::invalid (), std::logic_error, "Failed "
6727 "to convert the supposed local row index " << localRowIndex <<
6728 " into a global row index. Please report this bug to the "
6729 "Tpetra developers.");
6730 typename crs_graph_type::local_inds_host_view_type ind;
6731 newGraph.getLocalRowView (localRowIndex, ind);
6732 for (size_t ii = 0; ii < ind.extent(0); ii++) {
6733 // Convert the column index from local to global.
6734 const GO globalColIndex =
6735 newGraph.getColMap ()->getGlobalElement (ind(ii));
6736 TEUCHOS_TEST_FOR_EXCEPTION(
6737 globalColIndex == OTG::invalid(), std::logic_error,
6738 "On local row " << localRowIndex << " of the sparse graph: "
6739 "Failed to convert the supposed local column index "
6740 << ind(ii) << " into a global column index. Please report "
6741 "this bug to the Tpetra developers.");
6742 // Convert row and column indices to 1-based.
6743 // This works because the global index type is signed.
6744 out << (globalRowIndex + 1 - rowIndexBase) << " "
6745 << (globalColIndex + 1 - colIndexBase) << " ";
6746 out << endl;
6747 } // For each entry in the current row
6748 } // For each row of the "gather" graph
6749 } // Whether the "gather" graph is locally or globally indexed
6750 } // If my process' rank is 0
6751 }
6752
6758 static void
6759 writeSparseGraph (std::ostream& out,
6760 const crs_graph_type& graph,
6761 const bool debug=false)
6762 {
6763 writeSparseGraph (out, graph, "", "", debug);
6764 }
6765
6800 static void
6801 writeSparseGraphFile (const std::string& filename,
6802 const crs_graph_type& graph,
6803 const std::string& graphName,
6804 const std::string& graphDescription,
6805 const bool debug=false)
6806 {
6807 auto comm = graph.getComm ();
6808 if (comm.is_null ()) {
6809 // Processes on which the communicator is null shouldn't
6810 // even call this function. The convention is that
6811 // processes on which the object's communicator is null do
6812 // not participate in collective operations involving the
6813 // object.
6814 return;
6815 }
6816 const int myRank = comm->getRank ();
6817 std::ofstream out;
6818
6819 // Only open the file on Process 0.
6820 if (myRank == 0) {
6821 out.open (filename.c_str ());
6822 }
6823 writeSparseGraph (out, graph, graphName, graphDescription, debug);
6824 // We can rely on the destructor of the output stream to close
6825 // the file on scope exit, even if writeSparseGraph() throws
6826 // an exception.
6827 }
6828
6833 static void
6834 writeSparseGraphFile (const std::string& filename,
6835 const crs_graph_type& graph,
6836 const bool debug=false)
6837 {
6838 writeSparseGraphFile (filename, graph, "", "", debug);
6839 }
6840
6849 static void
6850 writeSparseGraphFile (const std::string& filename,
6851 const Teuchos::RCP<const crs_graph_type>& pGraph,
6852 const std::string& graphName,
6853 const std::string& graphDescription,
6854 const bool debug=false)
6855 {
6856 writeSparseGraphFile (filename, *pGraph, graphName, graphDescription, debug);
6857 }
6858
6868 static void
6869 writeSparseGraphFile (const std::string& filename,
6870 const Teuchos::RCP<const crs_graph_type>& pGraph,
6871 const bool debug=false)
6872 {
6873 writeSparseGraphFile (filename, *pGraph, "", "", debug);
6874 }
6875
6898 static void
6899 writeSparse (std::ostream& out,
6900 const sparse_matrix_type& matrix,
6901 const bool debug=false)
6902 {
6903 writeSparse (out, matrix, "", "", debug);
6904 }
6905
6907 static void
6908 writeSparse (std::ostream& out,
6909 const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6910 const bool debug=false)
6911 {
6912 writeSparse (out, *pMatrix, "", "", debug);
6913 }
6914
6943 static void
6944 writeDenseFile (const std::string& filename,
6945 const multivector_type& X,
6946 const std::string& matrixName,
6947 const std::string& matrixDescription,
6948 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6949 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6950 {
6951 const int myRank = X.getMap ().is_null () ? 0 :
6952 (X.getMap ()->getComm ().is_null () ? 0 :
6953 X.getMap ()->getComm ()->getRank ());
6954 std::ofstream out;
6955
6956 if (myRank == 0) { // Only open the file on Process 0.
6957 out.open (filename.c_str());
6958 }
6959
6960 writeDense (out, X, matrixName, matrixDescription, err, dbg);
6961 // We can rely on the destructor of the output stream to close
6962 // the file on scope exit, even if writeDense() throws an
6963 // exception.
6964 }
6965
6971 static void
6972 writeDenseFile (const std::string& filename,
6973 const Teuchos::RCP<const multivector_type>& X,
6974 const std::string& matrixName,
6975 const std::string& matrixDescription,
6976 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6977 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6978 {
6979 TEUCHOS_TEST_FOR_EXCEPTION(
6980 X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
6981 "writeDenseFile: The input MultiVector X is null.");
6982 writeDenseFile (filename, *X, matrixName, matrixDescription, err, dbg);
6983 }
6984
6990 static void
6991 writeDenseFile (const std::string& filename,
6992 const multivector_type& X,
6993 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6994 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6995 {
6996 writeDenseFile (filename, X, "", "", err, dbg);
6997 }
6998
7004 static void
7005 writeDenseFile (const std::string& filename,
7006 const Teuchos::RCP<const multivector_type>& X,
7007 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7008 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7009 {
7010 TEUCHOS_TEST_FOR_EXCEPTION(
7011 X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
7012 "writeDenseFile: The input MultiVector X is null.");
7013 writeDenseFile (filename, *X, err, dbg);
7014 }
7015
7016
7047 static void
7048 writeDense (std::ostream& out,
7049 const multivector_type& X,
7050 const std::string& matrixName,
7051 const std::string& matrixDescription,
7052 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7053 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7054 {
7055 using Teuchos::Comm;
7056 using Teuchos::outArg;
7057 using Teuchos::REDUCE_MAX;
7058 using Teuchos::reduceAll;
7059 using Teuchos::RCP;
7060 using std::endl;
7061
7062 RCP<const Comm<int> > comm = X.getMap ().is_null () ?
7063 Teuchos::null : X.getMap ()->getComm ();
7064 const int myRank = comm.is_null () ? 0 : comm->getRank ();
7065
7066 // If the caller provides a nonnull debug output stream, we
7067 // print debugging output to it. This is a local thing; we
7068 // don't have to check across processes.
7069 const bool debug = ! dbg.is_null ();
7070 if (debug) {
7071 dbg->pushTab ();
7072 std::ostringstream os;
7073 os << myRank << ": writeDense" << endl;
7074 *dbg << os.str ();
7075 dbg->pushTab ();
7076 }
7077 // Print the Matrix Market header.
7078 writeDenseHeader (out, X, matrixName, matrixDescription, err, dbg);
7079
7080 // Print each column one at a time. This is a (perhaps)
7081 // temporary fix for Bug 6288.
7082 const size_t numVecs = X.getNumVectors ();
7083 for (size_t j = 0; j < numVecs; ++j) {
7084 writeDenseColumn (out, * (X.getVector (j)), err, dbg);
7085 }
7086
7087 if (debug) {
7088 dbg->popTab ();
7089 std::ostringstream os;
7090 os << myRank << ": writeDense: Done" << endl;
7091 *dbg << os.str ();
7092 dbg->popTab ();
7093 }
7094 }
7095
7096 private:
7097
7123 static void
7124 writeDenseHeader (std::ostream& out,
7125 const multivector_type& X,
7126 const std::string& matrixName,
7127 const std::string& matrixDescription,
7128 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7129 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7130 {
7131 using Teuchos::Comm;
7132 using Teuchos::outArg;
7133 using Teuchos::RCP;
7134 using Teuchos::REDUCE_MAX;
7135 using Teuchos::reduceAll;
7136 using std::endl;
7137 typedef Teuchos::ScalarTraits<scalar_type> STS;
7138 const char prefix[] = "Tpetra::MatrixMarket::writeDenseHeader: ";
7139
7140 RCP<const Comm<int> > comm = X.getMap ().is_null () ?
7141 Teuchos::null : X.getMap ()->getComm ();
7142 const int myRank = comm.is_null () ? 0 : comm->getRank ();
7143 int lclErr = 0; // whether this MPI process has seen an error
7144 int gblErr = 0; // whether we know if some MPI process has seen an error
7145
7146 // If the caller provides a nonnull debug output stream, we
7147 // print debugging output to it. This is a local thing; we
7148 // don't have to check across processes.
7149 const bool debug = ! dbg.is_null ();
7150
7151 if (debug) {
7152 dbg->pushTab ();
7153 std::ostringstream os;
7154 os << myRank << ": writeDenseHeader" << endl;
7155 *dbg << os.str ();
7156 dbg->pushTab ();
7157 }
7158
7159 //
7160 // Process 0: Write the MatrixMarket header.
7161 //
7162 if (myRank == 0) {
7163 try {
7164 // Print the Matrix Market header. MultiVector stores data
7165 // nonsymmetrically, hence "general" in the banner line.
7166 // Print first to a temporary string output stream, and then
7167 // write it to the main output stream, so that at least the
7168 // header output has transactional semantics. We can't
7169 // guarantee transactional semantics for the whole output,
7170 // since that would not be memory scalable. (This could be
7171 // done in the file system by using a temporary file; we
7172 // don't do this, but users could.)
7173 std::ostringstream hdr;
7174 {
7175 std::string dataType;
7176 if (STS::isComplex) {
7177 dataType = "complex";
7178 } else if (STS::isOrdinal) {
7179 dataType = "integer";
7180 } else {
7181 dataType = "real";
7182 }
7183 hdr << "%%MatrixMarket matrix array " << dataType << " general"
7184 << endl;
7185 }
7186
7187 // Print comments (the matrix name and / or description).
7188 if (matrixName != "") {
7189 printAsComment (hdr, matrixName);
7190 }
7191 if (matrixDescription != "") {
7192 printAsComment (hdr, matrixDescription);
7193 }
7194 // Print the Matrix Market dimensions header for dense matrices.
7195 hdr << X.getGlobalLength () << " " << X.getNumVectors () << endl;
7196
7197 // Write the MatrixMarket header to the output stream.
7198 out << hdr.str ();
7199 } catch (std::exception& e) {
7200 if (! err.is_null ()) {
7201 *err << prefix << "While writing the Matrix Market header, "
7202 "Process 0 threw an exception: " << e.what () << endl;
7203 }
7204 lclErr = 1;
7205 }
7206 } // if I am Process 0
7207
7208 // Establish global agreement on the error state. It wouldn't
7209 // be good for other processes to keep going, if Process 0
7210 // finds out that it can't write to the given output stream.
7211 reduceAll<int, int> (*comm, REDUCE_MAX, lclErr, outArg (gblErr));
7212 TEUCHOS_TEST_FOR_EXCEPTION(
7213 gblErr == 1, std::runtime_error, prefix << "Some error occurred "
7214 "which prevented this method from completing.");
7215
7216 if (debug) {
7217 dbg->popTab ();
7218 *dbg << myRank << ": writeDenseHeader: Done" << endl;
7219 dbg->popTab ();
7220 }
7221 }
7222
7240 static void
7241 writeDenseColumn (std::ostream& out,
7242 const multivector_type& X,
7243 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7244 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7245 {
7246 using Teuchos::arcp;
7247 using Teuchos::Array;
7248 using Teuchos::ArrayRCP;
7249 using Teuchos::ArrayView;
7250 using Teuchos::Comm;
7251 using Teuchos::CommRequest;
7252 using Teuchos::ireceive;
7253 using Teuchos::isend;
7254 using Teuchos::outArg;
7255 using Teuchos::REDUCE_MAX;
7256 using Teuchos::reduceAll;
7257 using Teuchos::RCP;
7258 using Teuchos::TypeNameTraits;
7259 using Teuchos::wait;
7260 using std::endl;
7261 typedef Teuchos::ScalarTraits<scalar_type> STS;
7262
7263 const Comm<int>& comm = * (X.getMap ()->getComm ());
7264 const int myRank = comm.getRank ();
7265 const int numProcs = comm.getSize ();
7266 int lclErr = 0; // whether this MPI process has seen an error
7267 int gblErr = 0; // whether we know if some MPI process has seen an error
7268
7269 // If the caller provides a nonnull debug output stream, we
7270 // print debugging output to it. This is a local thing; we
7271 // don't have to check across processes.
7272 const bool debug = ! dbg.is_null ();
7273
7274 if (debug) {
7275 dbg->pushTab ();
7276 std::ostringstream os;
7277 os << myRank << ": writeDenseColumn" << endl;
7278 *dbg << os.str ();
7279 dbg->pushTab ();
7280 }
7281
7282 // Make the output stream write floating-point numbers in
7283 // scientific notation. It will politely put the output
7284 // stream back to its state on input, when this scope
7285 // terminates.
7286 Teuchos::SetScientific<scalar_type> sci (out);
7287
7288 const size_t myNumRows = X.getLocalLength ();
7289 const size_t numCols = X.getNumVectors ();
7290 // Use a different tag for the "size" messages than for the
7291 // "data" messages, in order to help us debug any mix-ups.
7292 const int sizeTag = 1337;
7293 const int dataTag = 1338;
7294
7295 // Process 0 pipelines nonblocking receives with file output.
7296 //
7297 // Constraints:
7298 // - Process 0 can't post a receive for another process'
7299 // actual data, until it posts and waits on the receive
7300 // from that process with the amount of data to receive.
7301 // (We could just post receives with a max data size, but
7302 // I feel uncomfortable about that.)
7303 // - The C++ standard library doesn't allow nonblocking
7304 // output to an std::ostream. (Thus, we have to start a
7305 // receive or send before starting the write, and hope
7306 // that MPI completes it in the background.)
7307 //
7308 // Process 0: Post receive-size receives from Processes 1 and 2.
7309 // Process 1: Post send-size send to Process 0.
7310 // Process 2: Post send-size send to Process 0.
7311 //
7312 // All processes: Pack my entries.
7313 //
7314 // Process 1:
7315 // - Post send-data send to Process 0.
7316 // - Wait on my send-size send to Process 0.
7317 //
7318 // Process 0:
7319 // - Print MatrixMarket header.
7320 // - Print my entries.
7321 // - Wait on receive-size receive from Process 1.
7322 // - Post receive-data receive from Process 1.
7323 //
7324 // For each process p = 1, 2, ... numProcs-1:
7325 // If I am Process 0:
7326 // - Post receive-size receive from Process p + 2
7327 // - Wait on receive-size receive from Process p + 1
7328 // - Post receive-data receive from Process p + 1
7329 // - Wait on receive-data receive from Process p
7330 // - Write data from Process p.
7331 // Else if I am Process p:
7332 // - Wait on my send-data send.
7333 // Else if I am Process p+1:
7334 // - Post send-data send to Process 0.
7335 // - Wait on my send-size send.
7336 // Else if I am Process p+2:
7337 // - Post send-size send to Process 0.
7338 //
7339 // Pipelining has three goals here:
7340 // 1. Overlap communication (the receives) with file I/O
7341 // 2. Give Process 0 a chance to prepost some receives,
7342 // before sends show up, by packing local data before
7343 // posting sends
7344 // 3. Don't post _all_ receives or _all_ sends, because that
7345 // wouldn't be memory scalable. (Just because we can't
7346 // see how much memory MPI consumes, doesn't mean that it
7347 // doesn't consume any!)
7348
7349 // These are used on every process. sendReqSize[0] holds the
7350 // number of rows on this process, and sendReqBuf holds this
7351 // process' data. Process 0 packs into sendReqBuf, but
7352 // doesn't send; it only uses that for printing. All other
7353 // processes send both of these to Process 0.
7354 RCP<CommRequest<int> > sendReqSize, sendReqData;
7355
7356 // These are used only on Process 0, for received data. Keep
7357 // 3 of each, and treat the arrays as circular buffers. When
7358 // receiving from Process p, the corresponding array index
7359 // here is p % 3.
7360 Array<ArrayRCP<size_t> > recvSizeBufs (3);
7361 Array<ArrayRCP<scalar_type> > recvDataBufs (3);
7362 Array<RCP<CommRequest<int> > > recvSizeReqs (3);
7363 Array<RCP<CommRequest<int> > > recvDataReqs (3);
7364
7365 // Buffer for nonblocking send of the "send size."
7366 ArrayRCP<size_t> sendDataSize (1);
7367 sendDataSize[0] = myNumRows;
7368
7369 if (myRank == 0) {
7370 if (debug) {
7371 std::ostringstream os;
7372 os << myRank << ": Post receive-size receives from "
7373 "Procs 1 and 2: tag = " << sizeTag << endl;
7374 *dbg << os.str ();
7375 }
7376 // Process 0: Post receive-size receives from Processes 1 and 2.
7377 recvSizeBufs[0].resize (1);
7378 // Set these three to an invalid value as a flag. If we
7379 // don't get these messages, then the invalid value will
7380 // remain, so we can test for it.
7381 (recvSizeBufs[0])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
7382 recvSizeBufs[1].resize (1);
7383 (recvSizeBufs[1])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
7384 recvSizeBufs[2].resize (1);
7385 (recvSizeBufs[2])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
7386 if (numProcs > 1) {
7387 recvSizeReqs[1] =
7388 ireceive<int, size_t> (recvSizeBufs[1], 1, sizeTag, comm);
7389 }
7390 if (numProcs > 2) {
7391 recvSizeReqs[2] =
7392 ireceive<int, size_t> (recvSizeBufs[2], 2, sizeTag, comm);
7393 }
7394 }
7395 else if (myRank == 1 || myRank == 2) {
7396 if (debug) {
7397 std::ostringstream os;
7398 os << myRank << ": Post send-size send: size = "
7399 << sendDataSize[0] << ", tag = " << sizeTag << endl;
7400 *dbg << os.str ();
7401 }
7402 // Prime the pipeline by having Processes 1 and 2 start
7403 // their send-size sends. We don't want _all_ the processes
7404 // to start their send-size sends, because that wouldn't be
7405 // memory scalable.
7406 sendReqSize = isend<int, size_t> (sendDataSize, 0, sizeTag, comm);
7407 }
7408 else {
7409 if (debug) {
7410 std::ostringstream os;
7411 os << myRank << ": Not posting my send-size send yet" << endl;
7412 *dbg << os.str ();
7413 }
7414 }
7415
7416 //
7417 // Pack my entries, in column-major order.
7418 //
7419 if (debug) {
7420 std::ostringstream os;
7421 os << myRank << ": Pack my entries" << endl;
7422 *dbg << os.str ();
7423 }
7424 ArrayRCP<scalar_type> sendDataBuf;
7425 try {
7426 sendDataBuf = arcp<scalar_type> (myNumRows * numCols);
7427 X.get1dCopy (sendDataBuf (), myNumRows);
7428 }
7429 catch (std::exception& e) {
7430 lclErr = 1;
7431 if (! err.is_null ()) {
7432 std::ostringstream os;
7433 os << "Process " << myRank << ": Attempt to pack my MultiVector "
7434 "entries threw an exception: " << e.what () << endl;
7435 *err << os.str ();
7436 }
7437 }
7438 if (debug) {
7439 std::ostringstream os;
7440 os << myRank << ": Done packing my entries" << endl;
7441 *dbg << os.str ();
7442 }
7443
7444 //
7445 // Process 1: post send-data send to Process 0.
7446 //
7447 if (myRank == 1) {
7448 if (debug) {
7449 *dbg << myRank << ": Post send-data send: tag = " << dataTag
7450 << endl;
7451 }
7452 sendReqData = isend<int, scalar_type> (sendDataBuf, 0, dataTag, comm);
7453 }
7454
7455 //
7456 // Process 0: Write my entries.
7457 //
7458 if (myRank == 0) {
7459 if (debug) {
7460 std::ostringstream os;
7461 os << myRank << ": Write my entries" << endl;
7462 *dbg << os.str ();
7463 }
7464
7465 // Write Process 0's data to the output stream.
7466 // Matrix Market prints dense matrices in column-major order.
7467 const size_t printNumRows = myNumRows;
7468 ArrayView<const scalar_type> printData = sendDataBuf ();
7469 const size_t printStride = printNumRows;
7470 if (static_cast<size_t> (printData.size ()) < printStride * numCols) {
7471 lclErr = 1;
7472 if (! err.is_null ()) {
7473 std::ostringstream os;
7474 os << "Process " << myRank << ": My MultiVector data's size "
7475 << printData.size () << " does not match my local dimensions "
7476 << printStride << " x " << numCols << "." << endl;
7477 *err << os.str ();
7478 }
7479 }
7480 else {
7481 // Matrix Market dense format wants one number per line.
7482 // It wants each complex number as two real numbers (real
7483 // resp. imaginary parts) with a space between.
7484 for (size_t col = 0; col < numCols; ++col) {
7485 for (size_t row = 0; row < printNumRows; ++row) {
7486 if (STS::isComplex) {
7487 out << STS::real (printData[row + col * printStride]) << " "
7488 << STS::imag (printData[row + col * printStride]) << endl;
7489 } else {
7490 out << printData[row + col * printStride] << endl;
7491 }
7492 }
7493 }
7494 }
7495 }
7496
7497 if (myRank == 0) {
7498 // Wait on receive-size receive from Process 1.
7499 const int recvRank = 1;
7500 const int circBufInd = recvRank % 3;
7501 if (debug) {
7502 std::ostringstream os;
7503 os << myRank << ": Wait on receive-size receive from Process "
7504 << recvRank << endl;
7505 *dbg << os.str ();
7506 }
7507 if (numProcs > 1) {
7508 wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7509
7510 // We received the number of rows of data. (The data
7511 // come in two columns.)
7512 size_t recvNumRows = (recvSizeBufs[circBufInd])[0];
7513 if (recvNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7514 lclErr = 1;
7515 if (! err.is_null ()) {
7516 std::ostringstream os;
7517 os << myRank << ": Result of receive-size receive from Process "
7518 << recvRank << " is Teuchos::OrdinalTraits<size_t>::invalid() "
7519 << "= " << Teuchos::OrdinalTraits<size_t>::invalid () << ". "
7520 "This should never happen, and suggests that the receive never "
7521 "got posted. Please report this bug to the Tpetra developers."
7522 << endl;
7523 *err << os.str ();
7524 }
7525
7526 // If we're going to continue after error, set the
7527 // number of rows to receive to a reasonable size. This
7528 // may cause MPI_ERR_TRUNCATE if the sending process is
7529 // sending more than 0 rows, but that's better than MPI
7530 // overflowing due to the huge positive value that is
7531 // Teuchos::OrdinalTraits<size_t>::invalid().
7532 recvNumRows = 0;
7533 }
7534
7535 // Post receive-data receive from Process 1.
7536 recvDataBufs[circBufInd].resize (recvNumRows * numCols);
7537 if (debug) {
7538 std::ostringstream os;
7539 os << myRank << ": Post receive-data receive from Process "
7540 << recvRank << ": tag = " << dataTag << ", buffer size = "
7541 << recvDataBufs[circBufInd].size () << endl;
7542 *dbg << os.str ();
7543 }
7544 if (! recvSizeReqs[circBufInd].is_null ()) {
7545 lclErr = 1;
7546 if (! err.is_null ()) {
7547 std::ostringstream os;
7548 os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7549 "null, before posting the receive-data receive from Process "
7550 << recvRank << ". This should never happen. Please report "
7551 "this bug to the Tpetra developers." << endl;
7552 *err << os.str ();
7553 }
7554 }
7555 recvDataReqs[circBufInd] =
7556 ireceive<int, scalar_type> (recvDataBufs[circBufInd],
7557 recvRank, dataTag, comm);
7558 } // numProcs > 1
7559 }
7560 else if (myRank == 1) {
7561 // Wait on my send-size send.
7562 if (debug) {
7563 std::ostringstream os;
7564 os << myRank << ": Wait on my send-size send" << endl;
7565 *dbg << os.str ();
7566 }
7567 wait<int> (comm, outArg (sendReqSize));
7568 }
7569
7570 //
7571 // Pipeline loop
7572 //
7573 for (int p = 1; p < numProcs; ++p) {
7574 if (myRank == 0) {
7575 if (p + 2 < numProcs) {
7576 // Post receive-size receive from Process p + 2.
7577 const int recvRank = p + 2;
7578 const int circBufInd = recvRank % 3;
7579 if (debug) {
7580 std::ostringstream os;
7581 os << myRank << ": Post receive-size receive from Process "
7582 << recvRank << ": tag = " << sizeTag << endl;
7583 *dbg << os.str ();
7584 }
7585 if (! recvSizeReqs[circBufInd].is_null ()) {
7586 lclErr = 1;
7587 if (! err.is_null ()) {
7588 std::ostringstream os;
7589 os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7590 << "null, for the receive-size receive from Process "
7591 << recvRank << "! This may mean that this process never "
7592 << "finished waiting for the receive from Process "
7593 << (recvRank - 3) << "." << endl;
7594 *err << os.str ();
7595 }
7596 }
7597 recvSizeReqs[circBufInd] =
7598 ireceive<int, size_t> (recvSizeBufs[circBufInd],
7599 recvRank, sizeTag, comm);
7600 }
7601
7602 if (p + 1 < numProcs) {
7603 const int recvRank = p + 1;
7604 const int circBufInd = recvRank % 3;
7605
7606 // Wait on receive-size receive from Process p + 1.
7607 if (debug) {
7608 std::ostringstream os;
7609 os << myRank << ": Wait on receive-size receive from Process "
7610 << recvRank << endl;
7611 *dbg << os.str ();
7612 }
7613 wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7614
7615 // We received the number of rows of data. (The data
7616 // come in two columns.)
7617 size_t recvNumRows = (recvSizeBufs[circBufInd])[0];
7618 if (recvNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7619 lclErr = 1;
7620 if (! err.is_null ()) {
7621 std::ostringstream os;
7622 os << myRank << ": Result of receive-size receive from Process "
7623 << recvRank << " is Teuchos::OrdinalTraits<size_t>::invalid() "
7624 << "= " << Teuchos::OrdinalTraits<size_t>::invalid () << ". "
7625 "This should never happen, and suggests that the receive never "
7626 "got posted. Please report this bug to the Tpetra developers."
7627 << endl;
7628 *err << os.str ();
7629 }
7630 // If we're going to continue after error, set the
7631 // number of rows to receive to a reasonable size.
7632 // This may cause MPI_ERR_TRUNCATE if the sending
7633 // process sends more than 0 rows, but that's better
7634 // than MPI overflowing due to the huge positive value
7635 // Teuchos::OrdinalTraits<size_t>::invalid().
7636 recvNumRows = 0;
7637 }
7638
7639 // Post receive-data receive from Process p + 1.
7640 recvDataBufs[circBufInd].resize (recvNumRows * numCols);
7641 if (debug) {
7642 std::ostringstream os;
7643 os << myRank << ": Post receive-data receive from Process "
7644 << recvRank << ": tag = " << dataTag << ", buffer size = "
7645 << recvDataBufs[circBufInd].size () << endl;
7646 *dbg << os.str ();
7647 }
7648 if (! recvDataReqs[circBufInd].is_null ()) {
7649 lclErr = 1;
7650 if (! err.is_null ()) {
7651 std::ostringstream os;
7652 os << myRank << ": recvDataReqs[" << circBufInd << "] is not "
7653 << "null, for the receive-data receive from Process "
7654 << recvRank << "! This may mean that this process never "
7655 << "finished waiting for the receive from Process "
7656 << (recvRank - 3) << "." << endl;
7657 *err << os.str ();
7658 }
7659 }
7660 recvDataReqs[circBufInd] =
7661 ireceive<int, scalar_type> (recvDataBufs[circBufInd],
7662 recvRank, dataTag, comm);
7663 }
7664
7665 // Wait on receive-data receive from Process p.
7666 const int recvRank = p;
7667 const int circBufInd = recvRank % 3;
7668 if (debug) {
7669 std::ostringstream os;
7670 os << myRank << ": Wait on receive-data receive from Process "
7671 << recvRank << endl;
7672 *dbg << os.str ();
7673 }
7674 wait<int> (comm, outArg (recvDataReqs[circBufInd]));
7675
7676 // Write Process p's data. Number of rows lives in
7677 // recvSizeBufs[circBufInd], and the actual data live in
7678 // recvDataBufs[circBufInd]. Do this after posting receives,
7679 // in order to expose overlap of comm. with file I/O.
7680 if (debug) {
7681 std::ostringstream os;
7682 os << myRank << ": Write entries from Process " << recvRank
7683 << endl;
7684 *dbg << os.str () << endl;
7685 }
7686 size_t printNumRows = (recvSizeBufs[circBufInd])[0];
7687 if (printNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7688 lclErr = 1;
7689 if (! err.is_null ()) {
7690 std::ostringstream os;
7691 os << myRank << ": Result of receive-size receive from Process "
7692 << recvRank << " was Teuchos::OrdinalTraits<size_t>::"
7693 "invalid() = " << Teuchos::OrdinalTraits<size_t>::invalid ()
7694 << ". This should never happen, and suggests that its "
7695 "receive-size receive was never posted. "
7696 "Please report this bug to the Tpetra developers." << endl;
7697 *err << os.str ();
7698 }
7699 // If we're going to continue after error, set the
7700 // number of rows to print to a reasonable size.
7701 printNumRows = 0;
7702 }
7703 if (printNumRows > 0 && recvDataBufs[circBufInd].is_null ()) {
7704 lclErr = 1;
7705 if (! err.is_null ()) {
7706 std::ostringstream os;
7707 os << myRank << ": Result of receive-size receive from Proc "
7708 << recvRank << " was " << printNumRows << " > 0, but "
7709 "recvDataBufs[" << circBufInd << "] is null. This should "
7710 "never happen. Please report this bug to the Tpetra "
7711 "developers." << endl;
7712 *err << os.str ();
7713 }
7714 // If we're going to continue after error, set the
7715 // number of rows to print to a reasonable size.
7716 printNumRows = 0;
7717 }
7718
7719 // Write the received data to the output stream.
7720 // Matrix Market prints dense matrices in column-major order.
7721 ArrayView<const scalar_type> printData = (recvDataBufs[circBufInd]) ();
7722 const size_t printStride = printNumRows;
7723 // Matrix Market dense format wants one number per line.
7724 // It wants each complex number as two real numbers (real
7725 // resp. imaginary parts) with a space between.
7726 for (size_t col = 0; col < numCols; ++col) {
7727 for (size_t row = 0; row < printNumRows; ++row) {
7728 if (STS::isComplex) {
7729 out << STS::real (printData[row + col * printStride]) << " "
7730 << STS::imag (printData[row + col * printStride]) << endl;
7731 } else {
7732 out << printData[row + col * printStride] << endl;
7733 }
7734 }
7735 }
7736 }
7737 else if (myRank == p) { // Process p
7738 // Wait on my send-data send.
7739 if (debug) {
7740 std::ostringstream os;
7741 os << myRank << ": Wait on my send-data send" << endl;
7742 *dbg << os.str ();
7743 }
7744 wait<int> (comm, outArg (sendReqData));
7745 }
7746 else if (myRank == p + 1) { // Process p + 1
7747 // Post send-data send to Process 0.
7748 if (debug) {
7749 std::ostringstream os;
7750 os << myRank << ": Post send-data send: tag = " << dataTag
7751 << endl;
7752 *dbg << os.str ();
7753 }
7754 sendReqData = isend<int, scalar_type> (sendDataBuf, 0, dataTag, comm);
7755 // Wait on my send-size send.
7756 if (debug) {
7757 std::ostringstream os;
7758 os << myRank << ": Wait on my send-size send" << endl;
7759 *dbg << os.str ();
7760 }
7761 wait<int> (comm, outArg (sendReqSize));
7762 }
7763 else if (myRank == p + 2) { // Process p + 2
7764 // Post send-size send to Process 0.
7765 if (debug) {
7766 std::ostringstream os;
7767 os << myRank << ": Post send-size send: size = "
7768 << sendDataSize[0] << ", tag = " << sizeTag << endl;
7769 *dbg << os.str ();
7770 }
7771 sendReqSize = isend<int, size_t> (sendDataSize, 0, sizeTag, comm);
7772 }
7773 }
7774
7775 // Establish global agreement on the error state.
7776 reduceAll<int, int> (comm, REDUCE_MAX, lclErr, outArg (gblErr));
7777 TEUCHOS_TEST_FOR_EXCEPTION(
7778 gblErr == 1, std::runtime_error, "Tpetra::MatrixMarket::writeDense "
7779 "experienced some kind of error and was unable to complete.");
7780
7781 if (debug) {
7782 dbg->popTab ();
7783 *dbg << myRank << ": writeDenseColumn: Done" << endl;
7784 dbg->popTab ();
7785 }
7786 }
7787
7788 public:
7789
7795 static void
7796 writeDense (std::ostream& out,
7797 const Teuchos::RCP<const multivector_type>& X,
7798 const std::string& matrixName,
7799 const std::string& matrixDescription,
7800 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7801 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7802 {
7803 TEUCHOS_TEST_FOR_EXCEPTION(
7804 X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
7805 "writeDense: The input MultiVector X is null.");
7806 writeDense (out, *X, matrixName, matrixDescription, err, dbg);
7807 }
7808
7814 static void
7815 writeDense (std::ostream& out,
7816 const multivector_type& X,
7817 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7818 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7819 {
7820 writeDense (out, X, "", "", err, dbg);
7821 }
7822
7828 static void
7829 writeDense (std::ostream& out,
7830 const Teuchos::RCP<const multivector_type>& X,
7831 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7832 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7833 {
7834 TEUCHOS_TEST_FOR_EXCEPTION(
7835 X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
7836 "writeDense: The input MultiVector X is null.");
7837 writeDense (out, *X, "", "", err, dbg);
7838 }
7839
7859 static void
7860 writeMap (std::ostream& out, const map_type& map, const bool debug=false)
7861 {
7862 Teuchos::RCP<Teuchos::FancyOStream> err =
7863 Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
7864 writeMap (out, map, err, debug);
7865 }
7866
7875 static void
7876 writeMap (std::ostream& out,
7877 const map_type& map,
7878 const Teuchos::RCP<Teuchos::FancyOStream>& err,
7879 const bool debug=false)
7880 {
7881 using Teuchos::Array;
7882 using Teuchos::ArrayRCP;
7883 using Teuchos::ArrayView;
7884 using Teuchos::Comm;
7885 using Teuchos::CommRequest;
7886 using Teuchos::ireceive;
7887 using Teuchos::isend;
7888 using Teuchos::RCP;
7889 using Teuchos::TypeNameTraits;
7890 using Teuchos::wait;
7891 using std::endl;
7892 typedef global_ordinal_type GO;
7893 typedef int pid_type;
7894
7895 // Treat the Map as a 1-column "multivector." This differs
7896 // from the previous two-column format, in which column 0 held
7897 // the GIDs, and column 1 held the corresponding PIDs. It
7898 // differs because printing that format requires knowing the
7899 // entire first column -- that is, all the GIDs -- in advance.
7900 // Sending messages from each process one at a time saves
7901 // memory, but it means that Process 0 doesn't ever have all
7902 // the GIDs at once.
7903 //
7904 // We pack the entries as ptrdiff_t, since this should be the
7905 // biggest signed built-in integer type that can hold any GO
7906 // or pid_type (= int) quantity without overflow. Test this
7907 // assumption at run time.
7908 typedef ptrdiff_t int_type;
7909 TEUCHOS_TEST_FOR_EXCEPTION(
7910 sizeof (GO) > sizeof (int_type), std::logic_error,
7911 "The global ordinal type GO=" << TypeNameTraits<GO>::name ()
7912 << " is too big for ptrdiff_t. sizeof(GO) = " << sizeof (GO)
7913 << " > sizeof(ptrdiff_t) = " << sizeof (ptrdiff_t) << ".");
7914 TEUCHOS_TEST_FOR_EXCEPTION(
7915 sizeof (pid_type) > sizeof (int_type), std::logic_error,
7916 "The (MPI) process rank type pid_type=" <<
7917 TypeNameTraits<pid_type>::name () << " is too big for ptrdiff_t. "
7918 "sizeof(pid_type) = " << sizeof (pid_type) << " > sizeof(ptrdiff_t)"
7919 " = " << sizeof (ptrdiff_t) << ".");
7920
7921 const Comm<int>& comm = * (map.getComm ());
7922 const int myRank = comm.getRank ();
7923 const int numProcs = comm.getSize ();
7924
7925 if (! err.is_null ()) {
7926 err->pushTab ();
7927 }
7928 if (debug) {
7929 std::ostringstream os;
7930 os << myRank << ": writeMap" << endl;
7931 *err << os.str ();
7932 }
7933 if (! err.is_null ()) {
7934 err->pushTab ();
7935 }
7936
7937 const size_t myNumRows = map.getLocalNumElements ();
7938 // Use a different tag for the "size" messages than for the
7939 // "data" messages, in order to help us debug any mix-ups.
7940 const int sizeTag = 1337;
7941 const int dataTag = 1338;
7942
7943 // Process 0 pipelines nonblocking receives with file output.
7944 //
7945 // Constraints:
7946 // - Process 0 can't post a receive for another process'
7947 // actual data, until it posts and waits on the receive
7948 // from that process with the amount of data to receive.
7949 // (We could just post receives with a max data size, but
7950 // I feel uncomfortable about that.)
7951 // - The C++ standard library doesn't allow nonblocking
7952 // output to an std::ostream.
7953 //
7954 // Process 0: Post receive-size receives from Processes 1 and 2.
7955 // Process 1: Post send-size send to Process 0.
7956 // Process 2: Post send-size send to Process 0.
7957 //
7958 // All processes: Pack my GIDs and PIDs.
7959 //
7960 // Process 1:
7961 // - Post send-data send to Process 0.
7962 // - Wait on my send-size send to Process 0.
7963 //
7964 // Process 0:
7965 // - Print MatrixMarket header.
7966 // - Print my GIDs and PIDs.
7967 // - Wait on receive-size receive from Process 1.
7968 // - Post receive-data receive from Process 1.
7969 //
7970 // For each process p = 1, 2, ... numProcs-1:
7971 // If I am Process 0:
7972 // - Post receive-size receive from Process p + 2
7973 // - Wait on receive-size receive from Process p + 1
7974 // - Post receive-data receive from Process p + 1
7975 // - Wait on receive-data receive from Process p
7976 // - Write data from Process p.
7977 // Else if I am Process p:
7978 // - Wait on my send-data send.
7979 // Else if I am Process p+1:
7980 // - Post send-data send to Process 0.
7981 // - Wait on my send-size send.
7982 // Else if I am Process p+2:
7983 // - Post send-size send to Process 0.
7984 //
7985 // Pipelining has three goals here:
7986 // 1. Overlap communication (the receives) with file I/O
7987 // 2. Give Process 0 a chance to prepost some receives,
7988 // before sends show up, by packing local data before
7989 // posting sends
7990 // 3. Don't post _all_ receives or _all_ sends, because that
7991 // wouldn't be memory scalable. (Just because we can't
7992 // see how much memory MPI consumes, doesn't mean that it
7993 // doesn't consume any!)
7994
7995 // These are used on every process. sendReqSize[0] holds the
7996 // number of rows on this process, and sendReqBuf holds this
7997 // process' data. Process 0 packs into sendReqBuf, but
7998 // doesn't send; it only uses that for printing. All other
7999 // processes send both of these to Process 0.
8000 RCP<CommRequest<int> > sendReqSize, sendReqData;
8001
8002 // These are used only on Process 0, for received data. Keep
8003 // 3 of each, and treat the arrays as circular buffers. When
8004 // receiving from Process p, the corresponding array index
8005 // here is p % 3.
8006 Array<ArrayRCP<int_type> > recvSizeBufs (3);
8007 Array<ArrayRCP<int_type> > recvDataBufs (3);
8008 Array<RCP<CommRequest<int> > > recvSizeReqs (3);
8009 Array<RCP<CommRequest<int> > > recvDataReqs (3);
8010
8011 // Buffer for nonblocking send of the "send size."
8012 ArrayRCP<int_type> sendDataSize (1);
8013 sendDataSize[0] = myNumRows;
8014
8015 if (myRank == 0) {
8016 if (debug) {
8017 std::ostringstream os;
8018 os << myRank << ": Post receive-size receives from "
8019 "Procs 1 and 2: tag = " << sizeTag << endl;
8020 *err << os.str ();
8021 }
8022 // Process 0: Post receive-size receives from Processes 1 and 2.
8023 recvSizeBufs[0].resize (1);
8024 (recvSizeBufs[0])[0] = -1; // error flag
8025 recvSizeBufs[1].resize (1);
8026 (recvSizeBufs[1])[0] = -1; // error flag
8027 recvSizeBufs[2].resize (1);
8028 (recvSizeBufs[2])[0] = -1; // error flag
8029 if (numProcs > 1) {
8030 recvSizeReqs[1] =
8031 ireceive<int, int_type> (recvSizeBufs[1], 1, sizeTag, comm);
8032 }
8033 if (numProcs > 2) {
8034 recvSizeReqs[2] =
8035 ireceive<int, int_type> (recvSizeBufs[2], 2, sizeTag, comm);
8036 }
8037 }
8038 else if (myRank == 1 || myRank == 2) {
8039 if (debug) {
8040 std::ostringstream os;
8041 os << myRank << ": Post send-size send: size = "
8042 << sendDataSize[0] << ", tag = " << sizeTag << endl;
8043 *err << os.str ();
8044 }
8045 // Prime the pipeline by having Processes 1 and 2 start
8046 // their send-size sends. We don't want _all_ the processes
8047 // to start their send-size sends, because that wouldn't be
8048 // memory scalable.
8049 sendReqSize = isend<int, int_type> (sendDataSize, 0, sizeTag, comm);
8050 }
8051 else {
8052 if (debug) {
8053 std::ostringstream os;
8054 os << myRank << ": Not posting my send-size send yet" << endl;
8055 *err << os.str ();
8056 }
8057 }
8058
8059 //
8060 // Pack my GIDs and PIDs. Each (GID,PID) pair gets packed
8061 // consecutively, for better locality.
8062 //
8063
8064 if (debug) {
8065 std::ostringstream os;
8066 os << myRank << ": Pack my GIDs and PIDs" << endl;
8067 *err << os.str ();
8068 }
8069
8070 ArrayRCP<int_type> sendDataBuf (myNumRows * 2);
8071
8072 if (map.isContiguous ()) {
8073 const int_type myMinGblIdx =
8074 static_cast<int_type> (map.getMinGlobalIndex ());
8075 for (size_t k = 0; k < myNumRows; ++k) {
8076 const int_type gid = myMinGblIdx + static_cast<int_type> (k);
8077 const int_type pid = static_cast<int_type> (myRank);
8078 sendDataBuf[2*k] = gid;
8079 sendDataBuf[2*k+1] = pid;
8080 }
8081 }
8082 else {
8083 ArrayView<const GO> myGblInds = map.getLocalElementList ();
8084 for (size_t k = 0; k < myNumRows; ++k) {
8085 const int_type gid = static_cast<int_type> (myGblInds[k]);
8086 const int_type pid = static_cast<int_type> (myRank);
8087 sendDataBuf[2*k] = gid;
8088 sendDataBuf[2*k+1] = pid;
8089 }
8090 }
8091
8092 if (debug) {
8093 std::ostringstream os;
8094 os << myRank << ": Done packing my GIDs and PIDs" << endl;
8095 *err << os.str ();
8096 }
8097
8098 if (myRank == 1) {
8099 // Process 1: post send-data send to Process 0.
8100 if (debug) {
8101 *err << myRank << ": Post send-data send: tag = " << dataTag
8102 << endl;
8103 }
8104 sendReqData = isend<int, int_type> (sendDataBuf, 0, dataTag, comm);
8105 }
8106
8107 if (myRank == 0) {
8108 if (debug) {
8109 *err << myRank << ": Write MatrixMarket header" << endl;
8110 }
8111
8112 // Process 0: Write the MatrixMarket header.
8113 // Description section explains each column.
8114 std::ostringstream hdr;
8115
8116 // Print the Matrix Market header. MultiVector stores data
8117 // nonsymmetrically, hence "general" in the banner line.
8118 hdr << "%%MatrixMarket matrix array integer general" << endl
8119 << "% Format: Version 2.0" << endl
8120 << "%" << endl
8121 << "% This file encodes a Tpetra::Map." << endl
8122 << "% It is stored as a dense vector, with twice as many " << endl
8123 << "% entries as the global number of GIDs (global indices)." << endl
8124 << "% (GID, PID) pairs are stored contiguously, where the PID " << endl
8125 << "% is the rank of the process owning that GID." << endl
8126 << (2 * map.getGlobalNumElements ()) << " " << 1 << endl;
8127 out << hdr.str ();
8128
8129 if (debug) {
8130 std::ostringstream os;
8131 os << myRank << ": Write my GIDs and PIDs" << endl;
8132 *err << os.str ();
8133 }
8134
8135 // Write Process 0's data to the output stream.
8136 // Matrix Market prints dense matrices in column-major order.
8137 const int_type printNumRows = myNumRows;
8138 ArrayView<const int_type> printData = sendDataBuf ();
8139 for (int_type k = 0; k < printNumRows; ++k) {
8140 const int_type gid = printData[2*k];
8141 const int_type pid = printData[2*k+1];
8142 out << gid << endl << pid << endl;
8143 }
8144 }
8145
8146 if (myRank == 0) {
8147 // Wait on receive-size receive from Process 1.
8148 const int recvRank = 1;
8149 const int circBufInd = recvRank % 3;
8150 if (debug) {
8151 std::ostringstream os;
8152 os << myRank << ": Wait on receive-size receive from Process "
8153 << recvRank << endl;
8154 *err << os.str ();
8155 }
8156 if (numProcs > 1) {
8157 wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
8158
8159 // We received the number of rows of data. (The data
8160 // come in two columns.)
8161 const int_type recvNumRows = (recvSizeBufs[circBufInd])[0];
8162 if (debug && recvNumRows == -1) {
8163 std::ostringstream os;
8164 os << myRank << ": Result of receive-size receive from Process "
8165 << recvRank << " is -1. This should never happen, and "
8166 "suggests that the receive never got posted. Please report "
8167 "this bug to the Tpetra developers." << endl;
8168 *err << os.str ();
8169 }
8170
8171 // Post receive-data receive from Process 1.
8172 recvDataBufs[circBufInd].resize (recvNumRows * 2);
8173 if (debug) {
8174 std::ostringstream os;
8175 os << myRank << ": Post receive-data receive from Process "
8176 << recvRank << ": tag = " << dataTag << ", buffer size = "
8177 << recvDataBufs[circBufInd].size () << endl;
8178 *err << os.str ();
8179 }
8180 if (! recvSizeReqs[circBufInd].is_null ()) {
8181 std::ostringstream os;
8182 os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
8183 "null, before posting the receive-data receive from Process "
8184 << recvRank << ". This should never happen. Please report "
8185 "this bug to the Tpetra developers." << endl;
8186 *err << os.str ();
8187 }
8188 recvDataReqs[circBufInd] =
8189 ireceive<int, int_type> (recvDataBufs[circBufInd],
8190 recvRank, dataTag, comm);
8191 } // numProcs > 1
8192 }
8193 else if (myRank == 1) {
8194 // Wait on my send-size send.
8195 if (debug) {
8196 std::ostringstream os;
8197 os << myRank << ": Wait on my send-size send" << endl;
8198 *err << os.str ();
8199 }
8200 wait<int> (comm, outArg (sendReqSize));
8201 }
8202
8203 //
8204 // Pipeline loop
8205 //
8206 for (int p = 1; p < numProcs; ++p) {
8207 if (myRank == 0) {
8208 if (p + 2 < numProcs) {
8209 // Post receive-size receive from Process p + 2.
8210 const int recvRank = p + 2;
8211 const int circBufInd = recvRank % 3;
8212 if (debug) {
8213 std::ostringstream os;
8214 os << myRank << ": Post receive-size receive from Process "
8215 << recvRank << ": tag = " << sizeTag << endl;
8216 *err << os.str ();
8217 }
8218 if (! recvSizeReqs[circBufInd].is_null ()) {
8219 std::ostringstream os;
8220 os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
8221 << "null, for the receive-size receive from Process "
8222 << recvRank << "! This may mean that this process never "
8223 << "finished waiting for the receive from Process "
8224 << (recvRank - 3) << "." << endl;
8225 *err << os.str ();
8226 }
8227 recvSizeReqs[circBufInd] =
8228 ireceive<int, int_type> (recvSizeBufs[circBufInd],
8229 recvRank, sizeTag, comm);
8230 }
8231
8232 if (p + 1 < numProcs) {
8233 const int recvRank = p + 1;
8234 const int circBufInd = recvRank % 3;
8235
8236 // Wait on receive-size receive from Process p + 1.
8237 if (debug) {
8238 std::ostringstream os;
8239 os << myRank << ": Wait on receive-size receive from Process "
8240 << recvRank << endl;
8241 *err << os.str ();
8242 }
8243 wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
8244
8245 // We received the number of rows of data. (The data
8246 // come in two columns.)
8247 const int_type recvNumRows = (recvSizeBufs[circBufInd])[0];
8248 if (debug && recvNumRows == -1) {
8249 std::ostringstream os;
8250 os << myRank << ": Result of receive-size receive from Process "
8251 << recvRank << " is -1. This should never happen, and "
8252 "suggests that the receive never got posted. Please report "
8253 "this bug to the Tpetra developers." << endl;
8254 *err << os.str ();
8255 }
8256
8257 // Post receive-data receive from Process p + 1.
8258 recvDataBufs[circBufInd].resize (recvNumRows * 2);
8259 if (debug) {
8260 std::ostringstream os;
8261 os << myRank << ": Post receive-data receive from Process "
8262 << recvRank << ": tag = " << dataTag << ", buffer size = "
8263 << recvDataBufs[circBufInd].size () << endl;
8264 *err << os.str ();
8265 }
8266 if (! recvDataReqs[circBufInd].is_null ()) {
8267 std::ostringstream os;
8268 os << myRank << ": recvDataReqs[" << circBufInd << "] is not "
8269 << "null, for the receive-data receive from Process "
8270 << recvRank << "! This may mean that this process never "
8271 << "finished waiting for the receive from Process "
8272 << (recvRank - 3) << "." << endl;
8273 *err << os.str ();
8274 }
8275 recvDataReqs[circBufInd] =
8276 ireceive<int, int_type> (recvDataBufs[circBufInd],
8277 recvRank, dataTag, comm);
8278 }
8279
8280 // Wait on receive-data receive from Process p.
8281 const int recvRank = p;
8282 const int circBufInd = recvRank % 3;
8283 if (debug) {
8284 std::ostringstream os;
8285 os << myRank << ": Wait on receive-data receive from Process "
8286 << recvRank << endl;
8287 *err << os.str ();
8288 }
8289 wait<int> (comm, outArg (recvDataReqs[circBufInd]));
8290
8291 // Write Process p's data. Number of rows lives in
8292 // recvSizeBufs[circBufInd], and the actual data live in
8293 // recvDataBufs[circBufInd]. Do this after posting receives,
8294 // in order to expose overlap of comm. with file I/O.
8295 if (debug) {
8296 std::ostringstream os;
8297 os << myRank << ": Write GIDs and PIDs from Process "
8298 << recvRank << endl;
8299 *err << os.str () << endl;
8300 }
8301 const int_type printNumRows = (recvSizeBufs[circBufInd])[0];
8302 if (debug && printNumRows == -1) {
8303 std::ostringstream os;
8304 os << myRank << ": Result of receive-size receive from Process "
8305 << recvRank << " was -1. This should never happen, and "
8306 "suggests that its receive-size receive was never posted. "
8307 "Please report this bug to the Tpetra developers." << endl;
8308 *err << os.str ();
8309 }
8310 if (debug && printNumRows > 0 && recvDataBufs[circBufInd].is_null ()) {
8311 std::ostringstream os;
8312 os << myRank << ": Result of receive-size receive from Proc "
8313 << recvRank << " was " << printNumRows << " > 0, but "
8314 "recvDataBufs[" << circBufInd << "] is null. This should "
8315 "never happen. Please report this bug to the Tpetra "
8316 "developers." << endl;
8317 *err << os.str ();
8318 }
8319 ArrayView<const int_type> printData = (recvDataBufs[circBufInd]) ();
8320 for (int_type k = 0; k < printNumRows; ++k) {
8321 const int_type gid = printData[2*k];
8322 const int_type pid = printData[2*k+1];
8323 out << gid << endl << pid << endl;
8324 }
8325 }
8326 else if (myRank == p) { // Process p
8327 // Wait on my send-data send.
8328 if (debug) {
8329 std::ostringstream os;
8330 os << myRank << ": Wait on my send-data send" << endl;
8331 *err << os.str ();
8332 }
8333 wait<int> (comm, outArg (sendReqData));
8334 }
8335 else if (myRank == p + 1) { // Process p + 1
8336 // Post send-data send to Process 0.
8337 if (debug) {
8338 std::ostringstream os;
8339 os << myRank << ": Post send-data send: tag = " << dataTag
8340 << endl;
8341 *err << os.str ();
8342 }
8343 sendReqData = isend<int, int_type> (sendDataBuf, 0, dataTag, comm);
8344 // Wait on my send-size send.
8345 if (debug) {
8346 std::ostringstream os;
8347 os << myRank << ": Wait on my send-size send" << endl;
8348 *err << os.str ();
8349 }
8350 wait<int> (comm, outArg (sendReqSize));
8351 }
8352 else if (myRank == p + 2) { // Process p + 2
8353 // Post send-size send to Process 0.
8354 if (debug) {
8355 std::ostringstream os;
8356 os << myRank << ": Post send-size send: size = "
8357 << sendDataSize[0] << ", tag = " << sizeTag << endl;
8358 *err << os.str ();
8359 }
8360 sendReqSize = isend<int, int_type> (sendDataSize, 0, sizeTag, comm);
8361 }
8362 }
8363
8364 if (! err.is_null ()) {
8365 err->popTab ();
8366 }
8367 if (debug) {
8368 *err << myRank << ": writeMap: Done" << endl;
8369 }
8370 if (! err.is_null ()) {
8371 err->popTab ();
8372 }
8373 }
8374
8376 static void
8377 writeMapFile (const std::string& filename,
8378 const map_type& map)
8379 {
8380 const int myRank = map.getComm ()->getRank ();
8381 std::ofstream out;
8382 if (myRank == 0) { // Only open the file on Proc 0.
8383 out.open (filename.c_str());
8384 }
8385 writeMap (out, map);
8386 // We can rely on the destructor of the output stream to close
8387 // the file on scope exit, even if writeDense() throws an
8388 // exception.
8389 }
8390
8391 private:
8415 static void
8416 printAsComment (std::ostream& out, const std::string& str)
8417 {
8418 using std::endl;
8419 std::istringstream inpstream (str);
8420 std::string line;
8421
8422 while (getline (inpstream, line)) {
8423 if (! line.empty()) {
8424 // Note that getline() doesn't store '\n', so we have to
8425 // append the endline ourselves.
8426 if (line[0] == '%') { // Line starts with a comment character.
8427 out << line << endl;
8428 }
8429 else { // Line doesn't start with a comment character.
8430 out << "%% " << line << endl;
8431 }
8432 }
8433 }
8434 }
8435
8436 public:
8437
8456 static void
8457 writeOperator(const std::string& fileName, operator_type const &A) {
8458 Teuchos::ParameterList pl;
8459 writeOperator(fileName, A, pl);
8460 }
8461
8482 static void
8483 writeOperator (std::ostream& out, const operator_type& A) {
8484 Teuchos::ParameterList pl;
8485 writeOperator (out, A, pl);
8486 }
8487
8524 static void
8525 writeOperator (const std::string& fileName,
8526 const operator_type& A,
8527 const Teuchos::ParameterList& params)
8528 {
8529 std::ofstream out;
8530 std::string tmpFile = "__TMP__" + fileName;
8531 const int myRank = A.getDomainMap()->getComm()->getRank();
8532 bool precisionChanged=false;
8533 int oldPrecision;
8534 // The number of nonzero entries in a Tpetra::Operator is
8535 // unknown until probing is completed. In order to write a
8536 // MatrixMarket header, we write the matrix to a temporary
8537 // file.
8538 //
8539 // FIXME (mfh 23 May 2015) IT WASN'T MY IDEA TO WRITE TO A
8540 // TEMPORARY FILE.
8541 if (myRank==0) {
8542 if (std::ifstream(tmpFile))
8543 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error,
8544 "writeOperator: temporary file " << tmpFile << " already exists");
8545 out.open(tmpFile.c_str());
8546 if (params.isParameter("precision")) {
8547 oldPrecision = out.precision(params.get<int>("precision"));
8548 precisionChanged=true;
8549 }
8550 }
8551
8552 const std::string header = writeOperatorImpl(out, A, params);
8553
8554 if (myRank==0) {
8555 if (precisionChanged)
8556 out.precision(oldPrecision);
8557 out.close();
8558 out.open(fileName.c_str(), std::ios::binary);
8559 bool printMatrixMarketHeader = true;
8560 if (params.isParameter("print MatrixMarket header"))
8561 printMatrixMarketHeader = params.get<bool>("print MatrixMarket header");
8562 if (printMatrixMarketHeader && myRank == 0) {
8563 // Write header to final file.
8564 out << header;
8565 }
8566 // Append matrix from temporary to final file.
8567 std::ifstream src(tmpFile, std::ios_base::binary);
8568 out << src.rdbuf();
8569 src.close();
8570 // Delete the temporary file.
8571 remove(tmpFile.c_str());
8572 }
8573 }
8574
8613 static void
8614 writeOperator (std::ostream& out,
8615 const operator_type& A,
8616 const Teuchos::ParameterList& params)
8617 {
8618 const int myRank = A.getDomainMap ()->getComm ()->getRank ();
8619
8620 // The number of nonzero entries in a Tpetra::Operator is
8621 // unknown until probing is completed. In order to write a
8622 // MatrixMarket header, we write the matrix to a temporary
8623 // output stream.
8624 //
8625 // NOTE (mfh 23 May 2015): Writing to a temporary output
8626 // stream may double the memory usage, depending on whether
8627 // 'out' is a file stream or an in-memory output stream (e.g.,
8628 // std::ostringstream). It might be wise to use a temporary
8629 // file instead. However, please look carefully at POSIX
8630 // functions for safe creation of temporary files. Don't just
8631 // prepend "__TMP__" to the filename and hope for the best.
8632 // Furthermore, it should be valid to call the std::ostream
8633 // overload of this method even when Process 0 does not have
8634 // access to a file system.
8635 std::ostringstream tmpOut;
8636 if (myRank == 0) {
8637 if (params.isParameter ("precision") && params.isType<int> ("precision")) {
8638 (void) tmpOut.precision (params.get<int> ("precision"));
8639 }
8640 }
8641
8642 const std::string header = writeOperatorImpl (tmpOut, A, params);
8643
8644 if (myRank == 0) {
8645 bool printMatrixMarketHeader = true;
8646 if (params.isParameter ("print MatrixMarket header") &&
8647 params.isType<bool> ("print MatrixMarket header")) {
8648 printMatrixMarketHeader = params.get<bool> ("print MatrixMarket header");
8649 }
8650 if (printMatrixMarketHeader && myRank == 0) {
8651 out << header; // write header to final output stream
8652 }
8653 // Append matrix from temporary output stream to final output stream.
8654 //
8655 // NOTE (mfh 23 May 2015) This might use a lot of memory.
8656 // However, we should not use temporary files in this
8657 // method. Since it does not access the file system (unlike
8658 // the overload that takes a file name), it should not
8659 // require the file system at all.
8660 //
8661 // If memory usage becomes a problem, one thing we could do
8662 // is write the entries of the Operator one column (or a few
8663 // columns) at a time. The Matrix Market sparse format does
8664 // not impose an order on its entries, so it would be OK to
8665 // write them in that order.
8666 out << tmpOut.str ();
8667 }
8668 }
8669
8670 private:
8671
8679 static std::string
8680 writeOperatorImpl (std::ostream& os,
8681 const operator_type& A,
8682 const Teuchos::ParameterList& params)
8683 {
8684 using Teuchos::RCP;
8685 using Teuchos::rcp;
8686 using Teuchos::ArrayRCP;
8687 using Teuchos::Array;
8688
8689 typedef local_ordinal_type LO;
8690 typedef global_ordinal_type GO;
8691 typedef scalar_type Scalar;
8692 typedef Teuchos::OrdinalTraits<LO> TLOT;
8693 typedef Teuchos::OrdinalTraits<GO> TGOT;
8694 typedef Tpetra::Import<LO, GO, node_type> import_type;
8696
8697 const map_type& domainMap = *(A.getDomainMap());
8698 RCP<const map_type> rangeMap = A.getRangeMap();
8699 RCP<const Teuchos::Comm<int> > comm = rangeMap->getComm();
8700 const int myRank = comm->getRank();
8701 const size_t numProcs = comm->getSize();
8702
8703 size_t numMVs = 10;
8704 if (params.isParameter("probing size"))
8705 numMVs = params.get<int>("probing size");
8706
8707 GO globalNnz = 0;
8708 GO minColGid = domainMap.getMinAllGlobalIndex();
8709 GO maxColGid = domainMap.getMaxAllGlobalIndex();
8710 // Rather than replicating the domainMap on all processors, we instead
8711 // iterate from the min GID to the max GID. If the map is gappy,
8712 // there will be invalid GIDs, i.e., GIDs no one has. This will require
8713 // unnecessary matvecs against potentially zero vectors.
8714 GO numGlobElts = maxColGid - minColGid + TGOT::one();
8715 GO numChunks = numGlobElts / numMVs;
8716 GO rem = numGlobElts % numMVs;
8717 GO indexBase = rangeMap->getIndexBase();
8718
8719 int offsetToUseInPrinting = 1 - indexBase; // default is 1-based indexing
8720 if (params.isParameter("zero-based indexing")) {
8721 if (params.get<bool>("zero-based indexing") == true)
8722 offsetToUseInPrinting = -indexBase; // If 0-based, use as-is. If 1-based, subtract 1.
8723 }
8724
8725 // Create map that replicates the range map on pid 0 and is empty for all other pids
8726 size_t numLocalRangeEntries = rangeMap->getLocalNumElements();
8727
8728 // Create contiguous source map
8729 RCP<const map_type> allGidsMap = rcp(new map_type(TGOT::invalid(), numLocalRangeEntries,
8730 indexBase, comm));
8731 // Create vector based on above map. Populate it with GIDs corresponding to this pid's GIDs in rangeMap.
8732 mv_type_go allGids(allGidsMap,1);
8733 Teuchos::ArrayRCP<GO> allGidsData = allGids.getDataNonConst(0);
8734
8735 for (size_t i=0; i<numLocalRangeEntries; i++)
8736 allGidsData[i] = rangeMap->getGlobalElement(i);
8737 allGidsData = Teuchos::null;
8738
8739 // Create target map that is nontrivial only on pid 0
8740 GO numTargetMapEntries=TGOT::zero();
8741 Teuchos::Array<GO> importGidList;
8742 if (myRank==0) {
8743 numTargetMapEntries = rangeMap->getGlobalNumElements();
8744 importGidList.reserve(numTargetMapEntries);
8745 for (GO j=0; j<numTargetMapEntries; ++j) importGidList.push_back(j + indexBase);
8746 } else {
8747 importGidList.reserve(numTargetMapEntries);
8748 }
8749 RCP<map_type> importGidMap = rcp(new map_type(TGOT::invalid(), importGidList(), indexBase, comm));
8750
8751 // Import all rangeMap GIDs to pid 0
8752 import_type gidImporter(allGidsMap, importGidMap);
8753 mv_type_go importedGids(importGidMap, 1);
8754 importedGids.doImport(allGids, gidImporter, INSERT);
8755
8756 // The following import map will be non-trivial only on pid 0.
8757 ArrayRCP<const GO> importedGidsData = importedGids.getData(0);
8758 RCP<const map_type> importMap = rcp(new map_type(TGOT::invalid(), importedGidsData(), indexBase, comm) );
8759
8760 // Importer from original range map to pid 0
8761 import_type importer(rangeMap, importMap);
8762 // Target vector on pid 0
8763 RCP<mv_type> colsOnPid0 = rcp(new mv_type(importMap,numMVs));
8764
8765 RCP<mv_type> ei = rcp(new mv_type(A.getDomainMap(),numMVs)); //probing vector
8766 RCP<mv_type> colsA = rcp(new mv_type(A.getRangeMap(),numMVs)); //columns of A revealed by probing
8767
8768 Array<GO> globalColsArray, localColsArray;
8769 globalColsArray.reserve(numMVs);
8770 localColsArray.reserve(numMVs);
8771
8772 ArrayRCP<ArrayRCP<Scalar> > eiData(numMVs);
8773 for (size_t i=0; i<numMVs; ++i)
8774 eiData[i] = ei->getDataNonConst(i);
8775
8776 // //////////////////////////////////////
8777 // Discover A by chunks
8778 // //////////////////////////////////////
8779 for (GO k=0; k<numChunks; ++k) {
8780 for (size_t j=0; j<numMVs; ++j ) {
8781 //GO curGlobalCol = maxColGid - numMVs + j + TGOT::one();
8782 GO curGlobalCol = minColGid + k*numMVs + j;
8783 globalColsArray.push_back(curGlobalCol);
8784 //TODO extract the g2l map outside of this loop loop
8785 LO curLocalCol = domainMap.getLocalElement(curGlobalCol);
8786 if (curLocalCol != TLOT::invalid()) {
8787 eiData[j][curLocalCol] = TGOT::one();
8788 localColsArray.push_back(curLocalCol);
8789 }
8790 }
8791 //TODO Do the views eiData need to be released prior to the matvec?
8792
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 //zero out the ei's
8803 for (size_t j=0; j<numMVs; ++j ) {
8804 for (int i=0; i<localColsArray.size(); ++i)
8805 eiData[j][localColsArray[i]] = TGOT::zero();
8806 }
8807 globalColsArray.clear();
8808 localColsArray.clear();
8809
8810 }
8811
8812 // //////////////////////////////////////
8813 // Handle leftover part of A
8814 // //////////////////////////////////////
8815 if (rem > 0) {
8816 for (int j=0; j<rem; ++j ) {
8817 GO curGlobalCol = maxColGid - rem + j + TGOT::one();
8818 globalColsArray.push_back(curGlobalCol);
8819 //TODO extract the g2l map outside of this loop loop
8820 LO curLocalCol = domainMap.getLocalElement(curGlobalCol);
8821 if (curLocalCol != TLOT::invalid()) {
8822 eiData[j][curLocalCol] = TGOT::one();
8823 localColsArray.push_back(curLocalCol);
8824 }
8825 }
8826 //TODO Do the views eiData need to be released prior to the matvec?
8827
8828 // probe
8829 A.apply(*ei,*colsA);
8830
8831 colsOnPid0->doImport(*colsA,importer,INSERT);
8832 if (myRank==0)
8833 globalNnz += writeColumns(os,*colsOnPid0, rem, importedGidsData(),
8834 globalColsArray, offsetToUseInPrinting);
8835
8836 //zero out the ei's
8837 for (int j=0; j<rem; ++j ) {
8838 for (int i=0; i<localColsArray.size(); ++i)
8839 eiData[j][localColsArray[i]] = TGOT::zero();
8840 }
8841 globalColsArray.clear();
8842 localColsArray.clear();
8843
8844 }
8845
8846 // Return the Matrix Market header. It includes the header
8847 // line (that starts with "%%"), some comments, and the triple
8848 // of matrix dimensions and number of nonzero entries. We
8849 // don't actually print this here, because we don't know the
8850 // number of nonzero entries until after probing.
8851 std::ostringstream oss;
8852 if (myRank == 0) {
8853 oss << "%%MatrixMarket matrix coordinate ";
8854 if (Teuchos::ScalarTraits<typename operator_type::scalar_type>::isComplex) {
8855 oss << "complex";
8856 } else {
8857 oss << "real";
8858 }
8859 oss << " general" << std::endl;
8860 oss << "% Tpetra::Operator" << std::endl;
8861 std::time_t now = std::time(NULL);
8862 oss << "% time stamp: " << ctime(&now);
8863 oss << "% written from " << numProcs << " processes" << std::endl;
8864 size_t numRows = rangeMap->getGlobalNumElements();
8865 size_t numCols = domainMap.getGlobalNumElements();
8866 oss << numRows << " " << numCols << " " << globalNnz << std::endl;
8867 }
8868
8869 return oss.str ();
8870 }
8871
8872 static global_ordinal_type
8873 writeColumns(std::ostream& os, mv_type const &colsA, size_t const &numCols,
8874 Teuchos::ArrayView<const global_ordinal_type> const &rowGids,
8875 Teuchos::Array<global_ordinal_type> const &colsArray,
8876 global_ordinal_type const & indexBase) {
8877
8878 typedef global_ordinal_type GO;
8879 typedef scalar_type Scalar;
8880 typedef Teuchos::ScalarTraits<Scalar> STS;
8881
8882 GO nnz=0;
8883 const Scalar zero = STS::zero();
8884 const size_t numRows = colsA.getGlobalLength();
8885 for (size_t j=0; j<numCols; ++j) {
8886 Teuchos::ArrayRCP<const Scalar> const curCol = colsA.getData(j);
8887 const GO J = colsArray[j];
8888 for (size_t i=0; i<numRows; ++i) {
8889 const Scalar val = curCol[i];
8890 if (val!=zero) {
8891 os << rowGids[i]+indexBase << " " << J+indexBase << " " << val << std::endl;
8892 ++nnz;
8893 }
8894 }
8895 }
8896
8897 return nnz;
8898
8899 }
8900
8901 public:
8902
8903
8910
8911 static
8912 void
8913 writeSparsePerRank (const std::string& filename_prefix,
8914 const std::string& filename_suffix,
8915 const sparse_matrix_type& matrix,
8916 const std::string& matrixName,
8917 const std::string& matrixDescription,
8918 const int ranksToWriteAtOnce=8,
8919 const bool debug=false) {
8920
8921 using ST = scalar_type;
8922 //using LO = local_ordinal_type;
8923 using GO = global_ordinal_type;
8924 using STS = typename Teuchos::ScalarTraits<ST>;
8925 using Teuchos::RCP;
8926
8927 // Sanity Checks
8928 Teuchos::RCP<const Teuchos::Comm<int> > comm = matrix.getComm ();
8929 TEUCHOS_TEST_FOR_EXCEPTION
8930 (comm.is_null (), std::invalid_argument,
8931 "The input matrix's communicator (Teuchos::Comm object) is null.");
8932 TEUCHOS_TEST_FOR_EXCEPTION
8933 (matrix.isGloballyIndexed() || !matrix.isFillComplete(), std::invalid_argument,
8934 "The input matrix must not be GloballyIndexed and must be fillComplete.");
8935
8936 // Setup
8937 const int myRank = comm->getRank();
8938 const int numProc = comm->getSize();
8939 std::string filename = filename_prefix + std::to_string(myRank) + filename_suffix;
8940 RCP<const map_type> rowMap = matrix.getRowMap();
8941 RCP<const map_type> colMap = matrix.getColMap();
8942 size_t local_nnz = matrix.getLocalNumEntries();
8943 size_t local_num_rows = rowMap->getLocalNumElements();
8944 size_t local_num_cols = colMap->getLocalNumElements();
8945 const GO rowIndexBase = rowMap->getIndexBase();
8946 const GO colIndexBase = colMap->getIndexBase();
8947
8948 // Bounds check the writing limits
8949 int rank_limit = std::min(std::max(ranksToWriteAtOnce,1),numProc);
8950
8951 // Start the writing
8952 for(int base_rank = 0; base_rank < numProc; base_rank += rank_limit) {
8953 int stop = std::min(base_rank+rank_limit,numProc);
8954
8955 if(base_rank <= myRank && myRank < stop) {
8956 // My turn to write
8957 std::ofstream out(filename);
8958
8959 // MatrixMarket Header
8960 out << "%%MatrixMarket matrix coordinate "
8961 << (STS::isComplex ? "complex" : "real")
8962 << " general" << std::endl;
8963
8964 // Print comments (the matrix name and / or description).
8965 if (matrixName != "") {
8966 printAsComment (out, matrixName);
8967 }
8968 if (matrixDescription != "") {
8969 printAsComment (out, matrixDescription);
8970 }
8971
8972 // Print the Matrix Market header (# local rows, # local columns, #
8973 // local enonzeros). This will *not* be read correctly by a generic matrix
8974 // market reader since we'll be writing out GIDs here and local row/col counts
8975 out << local_num_rows << " " << local_num_cols << " " << local_nnz <<std::endl;
8976
8977 {
8978 // Make the output stream write floating-point numbers in
8979 // scientific notation. It will politely put the output
8980 // stream back to its state on input, when this scope
8981 // terminates.
8982 Teuchos::SetScientific<ST> sci (out);
8983
8984 for(size_t l_row = 0; l_row < local_num_rows; l_row++) {
8985 GO g_row = rowMap->getGlobalElement(l_row);
8986
8987 typename sparse_matrix_type::local_inds_host_view_type indices;
8988 typename sparse_matrix_type::values_host_view_type values;
8989 matrix.getLocalRowView(l_row, indices, values);
8990 for (size_t ii = 0; ii < indices.extent(0); ii++) {
8991 const GO g_col = colMap->getGlobalElement(indices(ii));
8992 // Convert row and column indices to 1-based.
8993 // This works because the global index type is signed.
8994 out << (g_row + 1 - rowIndexBase) << " "
8995 << (g_col + 1 - colIndexBase) << " ";
8996 if (STS::isComplex) {
8997 out << STS::real(values(ii)) << " " << STS::imag(values(ii));
8998 } else {
8999 out << values(ii);
9000 }
9001 out << std::endl;
9002 } // For each entry in the current row
9003 } // For each row of the matrix
9004 }// end Teuchos::SetScientfic scoping
9005
9006 out.close();
9007 }// end if base_rank <= myRank < stop
9008
9009 // Barrier after each writing "batch" to make sure we're not hammering the file system
9010 // too aggressively
9011 comm->barrier();
9012
9013 }// end outer loop
9014
9015 }// end writeSparsePerRank
9016
9017 }; // class Writer
9018
9019 } // namespace MatrixMarket
9020} // namespace Tpetra
9021
9022#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.
void doImport(const SrcDistObject &source, const Import< LocalOrdinal, GlobalOrdinal, Node > &importer, const CombineMode CM, const bool restrictedMode=false)
Import data into this object using an Import object ("forward mode").
virtual Teuchos::RCP< const map_type > getMap() const
The Map describing the parallel distribution of this object.
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.
size_t global_size_t
Global size_t object.
@ INSERT
Insert new values that don't currently exist.