Tpetra parallel linear algebra Version of the Day
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->getNodeElementList();
439 const size_type myNumRows = myRows.size();
440 TEUCHOS_TEST_FOR_EXCEPTION(static_cast<size_t>(myNumRows) !=
441 pRowMap->getNodeNumElements(),
442 std::logic_error,
443 "pRowMap->getNodeElementList().size() = "
444 << myNumRows
445 << " != pRowMap->getNodeNumElements() = "
446 << pRowMap->getNodeNumElements() << ". "
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->getNodeElementList().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 StaticProfile));
808
809 // List of the global indices of my rows.
810 // They may or may not be contiguous.
811 ArrayView<const GO> myRows = pRowMap->getNodeElementList ();
812 const size_type myNumRows = myRows.size ();
813
814 // Add this processor's matrix entries to the CrsMatrix.
815 const GO indexBase = pRowMap->getIndexBase ();
816 for (size_type i = 0; i < myNumRows; ++i) {
817 const size_type myCurPos = myRowPtr[i];
818 const local_ordinal_type curNumEntries = myNumEntriesPerRow[i];
819 ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
820 ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
821
822 // Modify the column indices in place to have the right index base.
823 for (size_type k = 0; k < curNumEntries; ++k) {
824 curColInd[k] += indexBase;
825 }
826 // Avoid constructing empty views of ArrayRCP objects.
827 if (curNumEntries > 0) {
828 A->insertGlobalValues (myRows[i], curColInd, curValues);
829 }
830 }
831 // We've entered in all our matrix entries, so we can delete
832 // the original data. This will save memory when we call
833 // fillComplete(), so that we never keep more than two copies
834 // of the matrix's data in memory at once.
835 myNumEntriesPerRow = null;
836 myRowPtr = null;
837 myColInd = null;
838 myValues = null;
839
840 if (callFillComplete) {
841 A->fillComplete (pDomainMap, pRangeMap);
842 }
843 return A;
844 }
845
851 static Teuchos::RCP<sparse_matrix_type>
852 makeMatrix (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
853 Teuchos::ArrayRCP<size_t>& myRowPtr,
854 Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
855 Teuchos::ArrayRCP<scalar_type>& myValues,
856 const Teuchos::RCP<const map_type>& pRowMap,
857 const Teuchos::RCP<const map_type>& pRangeMap,
858 const Teuchos::RCP<const map_type>& pDomainMap,
859 const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
860 const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams)
861 {
862 using Teuchos::ArrayView;
863 using Teuchos::null;
864 using Teuchos::RCP;
865 using Teuchos::rcp;
866 using std::cerr;
867 using std::endl;
868 // Typedef to make certain type declarations shorter.
869 typedef global_ordinal_type GO;
870
871 // The row pointer array always has at least one entry, even
872 // if the matrix has zero rows. myNumEntriesPerRow, myColInd,
873 // and myValues would all be empty arrays in that degenerate
874 // case, but the row and domain maps would still be nonnull
875 // (though they would be trivial maps).
876 TEUCHOS_TEST_FOR_EXCEPTION(
877 myRowPtr.is_null(), std::logic_error,
878 "makeMatrix: myRowPtr array is null. "
879 "Please report this bug to the Tpetra developers.");
880 TEUCHOS_TEST_FOR_EXCEPTION(
881 pDomainMap.is_null(), std::logic_error,
882 "makeMatrix: domain map is null. "
883 "Please report this bug to the Tpetra developers.");
884 TEUCHOS_TEST_FOR_EXCEPTION(
885 pRangeMap.is_null(), std::logic_error,
886 "makeMatrix: range map is null. "
887 "Please report this bug to the Tpetra developers.");
888 TEUCHOS_TEST_FOR_EXCEPTION(
889 pRowMap.is_null(), std::logic_error,
890 "makeMatrix: row map is null. "
891 "Please report this bug to the Tpetra developers.");
892
893 // Construct the CrsMatrix, using the row map, with the
894 // constructor specifying the number of nonzeros for each row.
895 RCP<sparse_matrix_type> A =
896 rcp (new sparse_matrix_type (pRowMap, myNumEntriesPerRow(),
897 StaticProfile, constructorParams));
898
899 // List of the global indices of my rows.
900 // They may or may not be contiguous.
901 ArrayView<const GO> myRows = pRowMap->getNodeElementList();
902 const size_type myNumRows = myRows.size();
903
904 // Add this processor's matrix entries to the CrsMatrix.
905 const GO indexBase = pRowMap->getIndexBase ();
906 for (size_type i = 0; i < myNumRows; ++i) {
907 const size_type myCurPos = myRowPtr[i];
908 const local_ordinal_type curNumEntries = myNumEntriesPerRow[i];
909 ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
910 ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
911
912 // Modify the column indices in place to have the right index base.
913 for (size_type k = 0; k < curNumEntries; ++k) {
914 curColInd[k] += indexBase;
915 }
916 if (curNumEntries > 0) {
917 A->insertGlobalValues (myRows[i], curColInd, curValues);
918 }
919 }
920 // We've entered in all our matrix entries, so we can delete
921 // the original data. This will save memory when we call
922 // fillComplete(), so that we never keep more than two copies
923 // of the matrix's data in memory at once.
924 myNumEntriesPerRow = null;
925 myRowPtr = null;
926 myColInd = null;
927 myValues = null;
928
929 A->fillComplete (pDomainMap, pRangeMap, fillCompleteParams);
930 return A;
931 }
932
937 static Teuchos::RCP<sparse_matrix_type>
938 makeMatrix (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
939 Teuchos::ArrayRCP<size_t>& myRowPtr,
940 Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
941 Teuchos::ArrayRCP<scalar_type>& myValues,
942 const Teuchos::RCP<const map_type>& rowMap,
943 Teuchos::RCP<const map_type>& colMap,
944 const Teuchos::RCP<const map_type>& domainMap,
945 const Teuchos::RCP<const map_type>& rangeMap,
946 const bool callFillComplete = true)
947 {
948 using Teuchos::ArrayView;
949 using Teuchos::as;
950 using Teuchos::null;
951 using Teuchos::RCP;
952 using Teuchos::rcp;
953 typedef global_ordinal_type GO;
954
955 // Construct the CrsMatrix.
956
957 RCP<sparse_matrix_type> A; // the matrix to return.
958 if (colMap.is_null ()) { // the user didn't provide a column Map
959 A = rcp (new sparse_matrix_type (rowMap, myNumEntriesPerRow, StaticProfile));
960 } else { // the user provided a column Map
961 A = rcp (new sparse_matrix_type (rowMap, colMap, myNumEntriesPerRow, StaticProfile));
962 }
963
964 // List of the global indices of my rows.
965 // They may or may not be contiguous.
966 ArrayView<const GO> myRows = rowMap->getNodeElementList ();
967 const size_type myNumRows = myRows.size ();
968
969 // Add this process' matrix entries to the CrsMatrix.
970 const GO indexBase = rowMap->getIndexBase ();
971 for (size_type i = 0; i < myNumRows; ++i) {
972 const size_type myCurPos = myRowPtr[i];
973 const size_type curNumEntries = as<size_type> (myNumEntriesPerRow[i]);
974 ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
975 ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
976
977 // Modify the column indices in place to have the right index base.
978 for (size_type k = 0; k < curNumEntries; ++k) {
979 curColInd[k] += indexBase;
980 }
981 if (curNumEntries > 0) {
982 A->insertGlobalValues (myRows[i], curColInd, curValues);
983 }
984 }
985 // We've entered in all our matrix entries, so we can delete
986 // the original data. This will save memory when we call
987 // fillComplete(), so that we never keep more than two copies
988 // of the matrix's data in memory at once.
989 myNumEntriesPerRow = null;
990 myRowPtr = null;
991 myColInd = null;
992 myValues = null;
993
994 if (callFillComplete) {
995 A->fillComplete (domainMap, rangeMap);
996 if (colMap.is_null ()) {
997 colMap = A->getColMap ();
998 }
999 }
1000 return A;
1001 }
1002
1003 private:
1004
1021 static Teuchos::RCP<const Teuchos::MatrixMarket::Banner>
1022 readBanner (std::istream& in,
1023 size_t& lineNumber,
1024 const bool tolerant=false,
1025 const bool /* debug */=false,
1026 const bool isGraph=false)
1027 {
1028 using Teuchos::MatrixMarket::Banner;
1029 using Teuchos::RCP;
1030 using Teuchos::rcp;
1031 using std::cerr;
1032 using std::endl;
1033 typedef Teuchos::ScalarTraits<scalar_type> STS;
1034
1035 RCP<Banner> pBanner; // On output, if successful: the read-in Banner.
1036 std::string line; // If read from stream successful: the Banner line
1037
1038 // Try to read a line from the input stream.
1039 const bool readFailed = ! getline(in, line);
1040 TEUCHOS_TEST_FOR_EXCEPTION(readFailed, std::invalid_argument,
1041 "Failed to get Matrix Market banner line from input.");
1042
1043 // We read a line from the input stream.
1044 lineNumber++;
1045
1046 // Assume that the line we found is the Banner line.
1047 try {
1048 pBanner = rcp (new Banner (line, tolerant));
1049 } catch (std::exception& e) {
1050 TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
1051 "Matrix Market banner line contains syntax error(s): "
1052 << e.what());
1053 }
1054 TEUCHOS_TEST_FOR_EXCEPTION(pBanner->objectType() != "matrix",
1055 std::invalid_argument, "The Matrix Market file does not contain "
1056 "matrix data. Its Banner (first) line says that its object type is \""
1057 << pBanner->matrixType() << "\", rather than the required \"matrix\".");
1058
1059 // Validate the data type of the matrix, with respect to the
1060 // Scalar type of the CrsMatrix entries.
1061 TEUCHOS_TEST_FOR_EXCEPTION(
1062 ! STS::isComplex && pBanner->dataType() == "complex",
1063 std::invalid_argument,
1064 "The Matrix Market file contains complex-valued data, but you are "
1065 "trying to read it into a matrix containing entries of the real-"
1066 "valued Scalar type \""
1067 << Teuchos::TypeNameTraits<scalar_type>::name() << "\".");
1068 TEUCHOS_TEST_FOR_EXCEPTION(
1069 !isGraph &&
1070 pBanner->dataType() != "real" &&
1071 pBanner->dataType() != "complex" &&
1072 pBanner->dataType() != "integer",
1073 std::invalid_argument,
1074 "When reading Matrix Market data into a Tpetra::CrsMatrix, the "
1075 "Matrix Market file may not contain a \"pattern\" matrix. A "
1076 "pattern matrix is really just a graph with no weights. It "
1077 "should be stored in a CrsGraph, not a CrsMatrix.");
1078
1079 TEUCHOS_TEST_FOR_EXCEPTION(
1080 isGraph &&
1081 pBanner->dataType() != "pattern",
1082 std::invalid_argument,
1083 "When reading Matrix Market data into a Tpetra::CrsGraph, the "
1084 "Matrix Market file must contain a \"pattern\" matrix.");
1085
1086 return pBanner;
1087 }
1088
1111 static Teuchos::Tuple<global_ordinal_type, 3>
1112 readCoordDims (std::istream& in,
1113 size_t& lineNumber,
1114 const Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1115 const Teuchos::RCP<const comm_type>& pComm,
1116 const bool tolerant = false,
1117 const bool /* debug */ = false)
1118 {
1119 using Teuchos::MatrixMarket::readCoordinateDimensions;
1120 using Teuchos::Tuple;
1121
1122 // Packed coordinate matrix dimensions (numRows, numCols,
1123 // numNonzeros); computed on Rank 0 and broadcasted to all MPI
1124 // ranks.
1125 Tuple<global_ordinal_type, 3> dims;
1126
1127 // Read in the coordinate matrix dimensions from the input
1128 // stream. "success" tells us whether reading in the
1129 // coordinate matrix dimensions succeeded ("Guilty unless
1130 // proven innocent").
1131 bool success = false;
1132 if (pComm->getRank() == 0) {
1133 TEUCHOS_TEST_FOR_EXCEPTION(pBanner->matrixType() != "coordinate",
1134 std::invalid_argument, "The Tpetra::CrsMatrix Matrix Market reader "
1135 "only accepts \"coordinate\" (sparse) matrix data.");
1136 // Unpacked coordinate matrix dimensions
1137 global_ordinal_type numRows, numCols, numNonzeros;
1138 // Only MPI Rank 0 reads from the input stream
1139 success = readCoordinateDimensions (in, numRows, numCols,
1140 numNonzeros, lineNumber,
1141 tolerant);
1142 // Pack up the data into a Tuple so we can send them with
1143 // one broadcast instead of three.
1144 dims[0] = numRows;
1145 dims[1] = numCols;
1146 dims[2] = numNonzeros;
1147 }
1148 // Only Rank 0 did the reading, so it decides success.
1149 //
1150 // FIXME (mfh 02 Feb 2011) Teuchos::broadcast doesn't know how
1151 // to send bools. For now, we convert to/from int instead,
1152 // using the usual "true is 1, false is 0" encoding.
1153 {
1154 int the_success = success ? 1 : 0; // only matters on MPI Rank 0
1155 Teuchos::broadcast (*pComm, 0, &the_success);
1156 success = (the_success == 1);
1157 }
1158 if (success) {
1159 // Broadcast (numRows, numCols, numNonzeros) from Rank 0
1160 // to all the other MPI ranks.
1161 Teuchos::broadcast (*pComm, 0, dims);
1162 }
1163 else {
1164 // Perhaps in tolerant mode, we could set all the
1165 // dimensions to zero for now, and deduce correct
1166 // dimensions by reading all of the file's entries and
1167 // computing the max(row index) and max(column index).
1168 // However, for now we just error out in that case.
1169 TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
1170 "Error reading Matrix Market sparse matrix: failed to read "
1171 "coordinate matrix dimensions.");
1172 }
1173 return dims;
1174 }
1175
1186 typedef Teuchos::MatrixMarket::SymmetrizingAdder<Teuchos::MatrixMarket::Raw::Adder<scalar_type, global_ordinal_type> > adder_type;
1187
1188 typedef Teuchos::MatrixMarket::SymmetrizingGraphAdder<Teuchos::MatrixMarket::Raw::GraphAdder<global_ordinal_type> > graph_adder_type;
1189
1215 static Teuchos::RCP<adder_type>
1216 makeAdder (const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1217 Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1218 const Teuchos::Tuple<global_ordinal_type, 3>& dims,
1219 const bool tolerant=false,
1220 const bool debug=false)
1221 {
1222 if (pComm->getRank () == 0) {
1223 typedef Teuchos::MatrixMarket::Raw::Adder<scalar_type,
1225 raw_adder_type;
1226 Teuchos::RCP<raw_adder_type> pRaw =
1227 Teuchos::rcp (new raw_adder_type (dims[0], dims[1], dims[2],
1228 tolerant, debug));
1229 return Teuchos::rcp (new adder_type (pRaw, pBanner->symmType ()));
1230 }
1231 else {
1232 return Teuchos::null;
1233 }
1234 }
1235
1261 static Teuchos::RCP<graph_adder_type>
1262 makeGraphAdder (const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1263 Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1264 const Teuchos::Tuple<global_ordinal_type, 3>& dims,
1265 const bool tolerant=false,
1266 const bool debug=false)
1267 {
1268 if (pComm->getRank () == 0) {
1269 typedef Teuchos::MatrixMarket::Raw::GraphAdder<global_ordinal_type> raw_adder_type;
1270 Teuchos::RCP<raw_adder_type> pRaw =
1271 Teuchos::rcp (new raw_adder_type (dims[0], dims[1], dims[2],
1272 tolerant, debug));
1273 return Teuchos::rcp (new graph_adder_type (pRaw, pBanner->symmType ()));
1274 }
1275 else {
1276 return Teuchos::null;
1277 }
1278 }
1279
1281 static Teuchos::RCP<sparse_graph_type>
1282 readSparseGraphHelper (std::istream& in,
1283 const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1284 const Teuchos::RCP<const map_type>& rowMap,
1285 Teuchos::RCP<const map_type>& colMap,
1286 const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1287 const bool tolerant,
1288 const bool debug)
1289 {
1290 using Teuchos::MatrixMarket::Banner;
1291 using Teuchos::RCP;
1292 using Teuchos::ptr;
1293 using Teuchos::Tuple;
1294 using std::cerr;
1295 using std::endl;
1296
1297 const int myRank = pComm->getRank ();
1298 const int rootRank = 0;
1299
1300 // Current line number in the input stream. Various calls
1301 // will modify this depending on the number of lines that are
1302 // read from the input stream. Only Rank 0 modifies this.
1303 size_t lineNumber = 1;
1304
1305 if (debug && myRank == rootRank) {
1306 cerr << "Matrix Market reader: readGraph:" << endl
1307 << "-- Reading banner line" << endl;
1308 }
1309
1310 // The "Banner" tells you whether the input stream represents
1311 // a sparse matrix, the symmetry type of the matrix, and the
1312 // type of the data it contains.
1313 //
1314 // pBanner will only be nonnull on MPI Rank 0. It will be
1315 // null on all other MPI processes.
1316 RCP<const Banner> pBanner;
1317 {
1318 // We read and validate the Banner on Proc 0, but broadcast
1319 // the validation result to all processes.
1320 // Teuchos::broadcast doesn't currently work with bool, so
1321 // we use int (true -> 1, false -> 0).
1322 int bannerIsCorrect = 1;
1323 std::ostringstream errMsg;
1324
1325 if (myRank == rootRank) {
1326 // Read the Banner line from the input stream.
1327 try {
1328 pBanner = readBanner (in, lineNumber, tolerant, debug, true);
1329 }
1330 catch (std::exception& e) {
1331 errMsg << "Attempt to read the Matrix Market file's Banner line "
1332 "threw an exception: " << e.what();
1333 bannerIsCorrect = 0;
1334 }
1335
1336 if (bannerIsCorrect) {
1337 // Validate the Banner for the case of a sparse graph.
1338 // We validate on Proc 0, since it reads the Banner.
1339
1340 // In intolerant mode, the matrix type must be "coordinate".
1341 if (! tolerant && pBanner->matrixType() != "coordinate") {
1342 bannerIsCorrect = 0;
1343 errMsg << "The Matrix Market input file must contain a "
1344 "\"coordinate\"-format sparse graph in order to create a "
1345 "Tpetra::CrsGraph object from it, but the file's matrix "
1346 "type is \"" << pBanner->matrixType() << "\" instead.";
1347 }
1348 // In tolerant mode, we allow the matrix type to be
1349 // anything other than "array" (which would mean that
1350 // the file contains a dense matrix).
1351 if (tolerant && pBanner->matrixType() == "array") {
1352 bannerIsCorrect = 0;
1353 errMsg << "Matrix Market file must contain a \"coordinate\"-"
1354 "format sparse graph in order to create a Tpetra::CrsGraph "
1355 "object from it, but the file's matrix type is \"array\" "
1356 "instead. That probably means the file contains dense matrix "
1357 "data.";
1358 }
1359 }
1360 } // Proc 0: Done reading the Banner, hopefully successfully.
1361
1362 // Broadcast from Proc 0 whether the Banner was read correctly.
1363 broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
1364
1365 // If the Banner is invalid, all processes throw an
1366 // exception. Only Proc 0 gets the exception message, but
1367 // that's OK, since the main point is to "stop the world"
1368 // (rather than throw an exception on one process and leave
1369 // the others hanging).
1370 TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
1371 std::invalid_argument, errMsg.str ());
1372 } // Done reading the Banner line and broadcasting success.
1373 if (debug && myRank == rootRank) {
1374 cerr << "-- Reading dimensions line" << endl;
1375 }
1376
1377 // Read the graph dimensions from the Matrix Market metadata.
1378 // dims = (numRows, numCols, numEntries). Proc 0 does the
1379 // reading, but it broadcasts the results to all MPI
1380 // processes. Thus, readCoordDims() is a collective
1381 // operation. It does a collective check for correctness too.
1382 Tuple<global_ordinal_type, 3> dims =
1383 readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
1384
1385 if (debug && myRank == rootRank) {
1386 cerr << "-- Making Adder for collecting graph data" << endl;
1387 }
1388
1389 // "Adder" object for collecting all the sparse graph entries
1390 // from the input stream. This is only nonnull on Proc 0.
1391 // The Adder internally converts the one-based indices (native
1392 // Matrix Market format) into zero-based indices.
1393 RCP<graph_adder_type> pAdder =
1394 makeGraphAdder (pComm, pBanner, dims, tolerant, debug);
1395
1396 if (debug && myRank == rootRank) {
1397 cerr << "-- Reading graph data" << endl;
1398 }
1399 //
1400 // Read the graph entries from the input stream on Proc 0.
1401 //
1402 {
1403 // We use readSuccess to broadcast the results of the read
1404 // (succeeded or not) to all MPI processes. Since
1405 // Teuchos::broadcast doesn't currently know how to send
1406 // bools, we convert to int (true -> 1, false -> 0).
1407 int readSuccess = 1;
1408 std::ostringstream errMsg; // Exception message (only valid on Proc 0)
1409 if (myRank == rootRank) {
1410 try {
1411 // Reader for "coordinate" format sparse graph data.
1412 typedef Teuchos::MatrixMarket::CoordPatternReader<graph_adder_type,
1413 global_ordinal_type> reader_type;
1414 reader_type reader (pAdder);
1415
1416 // Read the sparse graph entries.
1417 std::pair<bool, std::vector<size_t> > results =
1418 reader.read (in, lineNumber, tolerant, debug);
1419 readSuccess = results.first ? 1 : 0;
1420 }
1421 catch (std::exception& e) {
1422 readSuccess = 0;
1423 errMsg << e.what();
1424 }
1425 }
1426 broadcast (*pComm, rootRank, ptr (&readSuccess));
1427
1428 // It would be nice to add a "verbose" flag, so that in
1429 // tolerant mode, we could log any bad line number(s) on
1430 // Proc 0. For now, we just throw if the read fails to
1431 // succeed.
1432 //
1433 // Question: If we're in tolerant mode, and if the read did
1434 // not succeed, should we attempt to call fillComplete()?
1435 TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
1436 "Failed to read the Matrix Market sparse graph file: "
1437 << errMsg.str());
1438 } // Done reading the graph entries (stored on Proc 0 for now)
1439
1440 if (debug && myRank == rootRank) {
1441 cerr << "-- Successfully read the Matrix Market data" << endl;
1442 }
1443
1444 // In tolerant mode, we need to rebroadcast the graph
1445 // dimensions, since they may be different after reading the
1446 // actual graph data. We only need to broadcast the number
1447 // of rows and columns. Only Rank 0 needs to know the actual
1448 // global number of entries, since (a) we need to merge
1449 // duplicates on Rank 0 first anyway, and (b) when we
1450 // distribute the entries, each rank other than Rank 0 will
1451 // only need to know how many entries it owns, not the total
1452 // number of entries.
1453 if (tolerant) {
1454 if (debug && myRank == rootRank) {
1455 cerr << "-- Tolerant mode: rebroadcasting graph dimensions"
1456 << endl
1457 << "----- Dimensions before: "
1458 << dims[0] << " x " << dims[1]
1459 << endl;
1460 }
1461 // Packed coordinate graph dimensions (numRows, numCols).
1462 Tuple<global_ordinal_type, 2> updatedDims;
1463 if (myRank == rootRank) {
1464 // If one or more bottom rows of the graph contain no
1465 // entries, then the Adder will report that the number
1466 // of rows is less than that specified in the
1467 // metadata. We allow this case, and favor the
1468 // metadata so that the zero row(s) will be included.
1469 updatedDims[0] =
1470 std::max (dims[0], pAdder->getAdder()->numRows());
1471 updatedDims[1] = pAdder->getAdder()->numCols();
1472 }
1473 broadcast (*pComm, rootRank, updatedDims);
1474 dims[0] = updatedDims[0];
1475 dims[1] = updatedDims[1];
1476 if (debug && myRank == rootRank) {
1477 cerr << "----- Dimensions after: " << dims[0] << " x "
1478 << dims[1] << endl;
1479 }
1480 }
1481 else {
1482 // In strict mode, we require that the graph's metadata and
1483 // its actual data agree, at least somewhat. In particular,
1484 // the number of rows must agree, since otherwise we cannot
1485 // distribute the graph correctly.
1486
1487 // Teuchos::broadcast() doesn't know how to broadcast bools,
1488 // so we use an int with the standard 1 == true, 0 == false
1489 // encoding.
1490 int dimsMatch = 1;
1491 if (myRank == rootRank) {
1492 // If one or more bottom rows of the graph contain no
1493 // entries, then the Adder will report that the number of
1494 // rows is less than that specified in the metadata. We
1495 // allow this case, and favor the metadata, but do not
1496 // allow the Adder to think there are more rows in the
1497 // graph than the metadata says.
1498 if (dims[0] < pAdder->getAdder ()->numRows ()) {
1499 dimsMatch = 0;
1500 }
1501 }
1502 broadcast (*pComm, 0, ptr (&dimsMatch));
1503 if (dimsMatch == 0) {
1504 // We're in an error state anyway, so we might as well
1505 // work a little harder to print an informative error
1506 // message.
1507 //
1508 // Broadcast the Adder's idea of the graph dimensions
1509 // from Proc 0 to all processes.
1510 Tuple<global_ordinal_type, 2> addersDims;
1511 if (myRank == rootRank) {
1512 addersDims[0] = pAdder->getAdder()->numRows();
1513 addersDims[1] = pAdder->getAdder()->numCols();
1514 }
1515 broadcast (*pComm, 0, addersDims);
1516 TEUCHOS_TEST_FOR_EXCEPTION(
1517 dimsMatch == 0, std::runtime_error,
1518 "The graph metadata says that the graph is " << dims[0] << " x "
1519 << dims[1] << ", but the actual data says that the graph is "
1520 << addersDims[0] << " x " << addersDims[1] << ". That means the "
1521 "data includes more rows than reported in the metadata. This "
1522 "is not allowed when parsing in strict mode. Parse the graph in "
1523 "tolerant mode to ignore the metadata when it disagrees with the "
1524 "data.");
1525 }
1526 } // Matrix dimensions (# rows, # cols, # entries) agree.
1527
1528 // Create a map describing a distribution where the root owns EVERYTHING
1529 RCP<map_type> proc0Map;
1530 global_ordinal_type indexBase;
1531 if(Teuchos::is_null(rowMap)) {
1532 indexBase = 0;
1533 }
1534 else {
1535 indexBase = rowMap->getIndexBase();
1536 }
1537 if(myRank == rootRank) {
1538 proc0Map = rcp(new map_type(dims[0],dims[0],indexBase,pComm));
1539 }
1540 else {
1541 proc0Map = rcp(new map_type(dims[0],0,indexBase,pComm));
1542 }
1543
1544 // Create the graph where the root owns EVERYTHING
1545 std::map<global_ordinal_type, size_t> numEntriesPerRow_map;
1546 if (myRank == rootRank) {
1547 const auto& entries = pAdder()->getAdder()->getEntries();
1548 // This will count duplicates, but it's better than dense.
1549 // An even better approach would use a classic algorithm,
1550 // likely in Saad's old textbook, for converting COO (entries)
1551 // to CSR (the local part of the sparse matrix data structure).
1552 for (const auto& entry : entries) {
1553 const global_ordinal_type gblRow = entry.rowIndex () + indexBase;
1554 ++numEntriesPerRow_map[gblRow];
1555 }
1556 }
1557
1558 Teuchos::Array<size_t> numEntriesPerRow (proc0Map->getNodeNumElements ());
1559 for (const auto& ent : numEntriesPerRow_map) {
1560 const local_ordinal_type lclRow = proc0Map->getLocalElement (ent.first);
1561 numEntriesPerRow[lclRow] = ent.second;
1562 }
1563 // Free anything we don't need before allocating the graph.
1564 // Swapping with an empty data structure is the standard idiom
1565 // for freeing memory used by Standard Library containers.
1566 // (Just resizing to 0 doesn't promise to free memory.)
1567 {
1568 std::map<global_ordinal_type, size_t> empty_map;
1569 std::swap (numEntriesPerRow_map, empty_map);
1570 }
1571
1572 RCP<sparse_graph_type> proc0Graph =
1573 rcp(new sparse_graph_type(proc0Map,numEntriesPerRow (),
1574 StaticProfile,constructorParams));
1575 if(myRank == rootRank) {
1576 typedef Teuchos::MatrixMarket::Raw::GraphElement<global_ordinal_type> element_type;
1577
1578 // Get the entries
1579 const std::vector<element_type>& entries =
1580 pAdder->getAdder()->getEntries();
1581
1582 // Insert them one at a time
1583 for(size_t curPos=0; curPos<entries.size(); curPos++) {
1584 const element_type& curEntry = entries[curPos];
1585 const global_ordinal_type curRow = curEntry.rowIndex()+indexBase;
1586 const global_ordinal_type curCol = curEntry.colIndex()+indexBase;
1587 Teuchos::ArrayView<const global_ordinal_type> colView(&curCol,1);
1588 proc0Graph->insertGlobalIndices(curRow,colView);
1589 }
1590 }
1591 proc0Graph->fillComplete();
1592
1593 RCP<sparse_graph_type> distGraph;
1594 if(Teuchos::is_null(rowMap))
1595 {
1596 // Create a map describing the distribution we actually want
1597 RCP<map_type> distMap =
1598 rcp(new map_type(dims[0],0,pComm,GloballyDistributed));
1599
1600 // Create the graph with that distribution too
1601 distGraph = rcp(new sparse_graph_type(distMap,colMap,0,StaticProfile,constructorParams));
1602
1603 // Create an importer/exporter/vandelay to redistribute the graph
1604 typedef Import<local_ordinal_type, global_ordinal_type, node_type> import_type;
1605 import_type importer (proc0Map, distMap);
1606
1607 // Import the data
1608 distGraph->doImport(*proc0Graph,importer,INSERT);
1609 }
1610 else {
1611 distGraph = rcp(new sparse_graph_type(rowMap,colMap,0,StaticProfile,constructorParams));
1612
1613 // Create an importer/exporter/vandelay to redistribute the graph
1614 typedef Import<local_ordinal_type, global_ordinal_type, node_type> import_type;
1615 import_type importer (proc0Map, rowMap);
1616
1617 // Import the data
1618 distGraph->doImport(*proc0Graph,importer,INSERT);
1619 }
1620
1621 return distGraph;
1622 }
1623
1624 public:
1648 static Teuchos::RCP<sparse_graph_type>
1649 readSparseGraphFile (const std::string& filename,
1650 const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
1651 const bool callFillComplete=true,
1652 const bool tolerant=false,
1653 const bool debug=false)
1654 {
1655 using Teuchos::broadcast;
1656 using Teuchos::outArg;
1657
1658 // Only open the file on Process 0. Test carefully to make
1659 // sure that the file opened successfully (and broadcast that
1660 // result to all processes to prevent a hang on exception
1661 // throw), since it's a common mistake to misspell a filename.
1662 std::ifstream in;
1663 int opened = 0;
1664 if (comm->getRank () == 0) {
1665 try {
1666 in.open (filename.c_str ());
1667 opened = in.is_open();
1668 }
1669 catch (...) {
1670 opened = 0;
1671 }
1672 }
1673 broadcast<int, int> (*comm, 0, outArg (opened));
1674 TEUCHOS_TEST_FOR_EXCEPTION
1675 (opened == 0, std::runtime_error, "readSparseGraphFile: "
1676 "Failed to open file \"" << filename << "\" on Process 0.");
1677 return readSparseGraph (in, comm,
1678 callFillComplete,
1679 tolerant, debug);
1680 // We can rely on the destructor of the input stream to close
1681 // the file on scope exit, even if readSparseGraph() throws an
1682 // exception.
1683 }
1684
1685
1714 static Teuchos::RCP<sparse_graph_type>
1715 readSparseGraphFile (const std::string& filename,
1716 const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1717 const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1718 const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
1719 const bool tolerant=false,
1720 const bool debug=false)
1721 {
1722 using Teuchos::broadcast;
1723 using Teuchos::outArg;
1724
1725 // Only open the file on Process 0. Test carefully to make
1726 // sure that the file opened successfully (and broadcast that
1727 // result to all processes to prevent a hang on exception
1728 // throw), since it's a common mistake to misspell a filename.
1729 std::ifstream in;
1730 int opened = 0;
1731 if (pComm->getRank () == 0) {
1732 try {
1733 in.open (filename.c_str ());
1734 opened = in.is_open();
1735 }
1736 catch (...) {
1737 opened = 0;
1738 }
1739 }
1740 broadcast<int, int> (*pComm, 0, outArg (opened));
1741 TEUCHOS_TEST_FOR_EXCEPTION
1742 (opened == 0, std::runtime_error, "readSparseGraphFile: "
1743 "Failed to open file \"" << filename << "\" on Process 0.");
1744 if (pComm->getRank () == 0) { // only open the input file on Process 0
1745 in.open (filename.c_str ());
1746 }
1747 return readSparseGraph (in, pComm,
1748 constructorParams,
1749 fillCompleteParams, tolerant, debug);
1750 // We can rely on the destructor of the input stream to close
1751 // the file on scope exit, even if readSparseGraph() throws an
1752 // exception.
1753 }
1754
1755
1793 static Teuchos::RCP<sparse_graph_type>
1794 readSparseGraphFile (const std::string& filename,
1795 const Teuchos::RCP<const map_type>& rowMap,
1796 Teuchos::RCP<const map_type>& colMap,
1797 const Teuchos::RCP<const map_type>& domainMap,
1798 const Teuchos::RCP<const map_type>& rangeMap,
1799 const bool callFillComplete=true,
1800 const bool tolerant=false,
1801 const bool debug=false)
1802 {
1803 using Teuchos::broadcast;
1804 using Teuchos::Comm;
1805 using Teuchos::outArg;
1806 using Teuchos::RCP;
1807
1808 TEUCHOS_TEST_FOR_EXCEPTION
1809 (rowMap.is_null (), std::invalid_argument,
1810 "Input rowMap must be nonnull.");
1811 RCP<const Comm<int> > comm = rowMap->getComm ();
1812 if (comm.is_null ()) {
1813 // If the input communicator is null on some process, then
1814 // that process does not participate in the collective.
1815 return Teuchos::null;
1816 }
1817
1818 // Only open the file on Process 0. Test carefully to make
1819 // sure that the file opened successfully (and broadcast that
1820 // result to all processes to prevent a hang on exception
1821 // throw), since it's a common mistake to misspell a filename.
1822 std::ifstream in;
1823 int opened = 0;
1824 if (comm->getRank () == 0) {
1825 try {
1826 in.open (filename.c_str ());
1827 opened = in.is_open();
1828 }
1829 catch (...) {
1830 opened = 0;
1831 }
1832 }
1833 broadcast<int, int> (*comm, 0, outArg (opened));
1834 TEUCHOS_TEST_FOR_EXCEPTION
1835 (opened == 0, std::runtime_error, "readSparseGraphFile: "
1836 "Failed to open file \"" << filename << "\" on Process 0.");
1837 return readSparseGraph (in, rowMap, colMap, domainMap, rangeMap,
1838 callFillComplete, tolerant, debug);
1839 }
1840
1866 static Teuchos::RCP<sparse_graph_type>
1867 readSparseGraph (std::istream& in,
1868 const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1869 const bool callFillComplete=true,
1870 const bool tolerant=false,
1871 const bool debug=false)
1872 {
1873 Teuchos::RCP<const map_type> fakeRowMap;
1874 Teuchos::RCP<const map_type> fakeColMap;
1875 Teuchos::RCP<Teuchos::ParameterList> fakeCtorParams;
1876
1877 Teuchos::RCP<sparse_graph_type> graph =
1878 readSparseGraphHelper (in, pComm,
1879 fakeRowMap, fakeColMap,
1880 fakeCtorParams, tolerant, debug);
1881 if (callFillComplete) {
1882 graph->fillComplete ();
1883 }
1884 return graph;
1885 }
1886
1887
1917 static Teuchos::RCP<sparse_graph_type>
1918 readSparseGraph (std::istream& in,
1919 const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1920 const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1921 const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
1922 const bool tolerant=false,
1923 const bool debug=false)
1924 {
1925 Teuchos::RCP<const map_type> fakeRowMap;
1926 Teuchos::RCP<const map_type> fakeColMap;
1927 Teuchos::RCP<sparse_graph_type> graph =
1928 readSparseGraphHelper (in, pComm,
1929 fakeRowMap, fakeColMap,
1930 constructorParams, tolerant, debug);
1931 graph->fillComplete (fillCompleteParams);
1932 return graph;
1933 }
1934
1935
1976 static Teuchos::RCP<sparse_graph_type>
1977 readSparseGraph (std::istream& in,
1978 const Teuchos::RCP<const map_type>& rowMap,
1979 Teuchos::RCP<const map_type>& colMap,
1980 const Teuchos::RCP<const map_type>& domainMap,
1981 const Teuchos::RCP<const map_type>& rangeMap,
1982 const bool callFillComplete=true,
1983 const bool tolerant=false,
1984 const bool debug=false)
1985 {
1986 Teuchos::RCP<sparse_graph_type> graph =
1987 readSparseGraphHelper (in, rowMap->getComm (),
1988 rowMap, colMap, Teuchos::null, tolerant,
1989 debug);
1990 if (callFillComplete) {
1991 graph->fillComplete (domainMap, rangeMap);
1992 }
1993 return graph;
1994 }
1995
1996#include "MatrixMarket_TpetraNew.hpp"
1997
2021 static Teuchos::RCP<sparse_matrix_type>
2022 readSparseFile (const std::string& filename,
2023 const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2024 const bool callFillComplete=true,
2025 const bool tolerant=false,
2026 const bool debug=false)
2027 {
2028 const int myRank = pComm->getRank ();
2029 std::ifstream in;
2030
2031 // Only open the file on Rank 0.
2032 if (myRank == 0) {
2033 in.open (filename.c_str ());
2034 }
2035 // FIXME (mfh 16 Jun 2015) Do a broadcast to make sure that
2036 // opening the file succeeded, before continuing. That will
2037 // avoid hangs if the read doesn't work. On the other hand,
2038 // readSparse could do that too, by checking the status of the
2039 // std::ostream.
2040
2041 return readSparse (in, pComm, callFillComplete, tolerant, debug);
2042 // We can rely on the destructor of the input stream to close
2043 // the file on scope exit, even if readSparse() throws an
2044 // exception.
2045 }
2046
2047
2076 static Teuchos::RCP<sparse_matrix_type>
2077 readSparseFile (const std::string& filename,
2078 const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2079 const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
2080 const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
2081 const bool tolerant=false,
2082 const bool debug=false)
2083 {
2084 std::ifstream in;
2085 if (pComm->getRank () == 0) { // only open on Process 0
2086 in.open (filename.c_str ());
2087 }
2088 return readSparse (in, pComm, constructorParams,
2089 fillCompleteParams, tolerant, debug);
2090 }
2091
2092
2130 static Teuchos::RCP<sparse_matrix_type>
2131 readSparseFile (const std::string& filename,
2132 const Teuchos::RCP<const map_type>& rowMap,
2133 Teuchos::RCP<const map_type>& colMap,
2134 const Teuchos::RCP<const map_type>& domainMap,
2135 const Teuchos::RCP<const map_type>& rangeMap,
2136 const bool callFillComplete=true,
2137 const bool tolerant=false,
2138 const bool debug=false)
2139 {
2140 using Teuchos::broadcast;
2141 using Teuchos::Comm;
2142 using Teuchos::outArg;
2143 using Teuchos::RCP;
2144
2145 TEUCHOS_TEST_FOR_EXCEPTION(
2146 rowMap.is_null (), std::invalid_argument,
2147 "Row Map must be nonnull.");
2148
2149 RCP<const Comm<int> > comm = rowMap->getComm ();
2150 const int myRank = comm->getRank ();
2151
2152 // Only open the file on Process 0. Test carefully to make
2153 // sure that the file opened successfully (and broadcast that
2154 // result to all processes to prevent a hang on exception
2155 // throw), since it's a common mistake to misspell a filename.
2156 std::ifstream in;
2157 int opened = 0;
2158 if (myRank == 0) {
2159 try {
2160 in.open (filename.c_str ());
2161 opened = in.is_open();
2162 }
2163 catch (...) {
2164 opened = 0;
2165 }
2166 }
2167 broadcast<int, int> (*comm, 0, outArg (opened));
2168 TEUCHOS_TEST_FOR_EXCEPTION(
2169 opened == 0, std::runtime_error,
2170 "readSparseFile: Failed to open file \"" << filename << "\" on "
2171 "Process 0.");
2172 return readSparse (in, rowMap, colMap, domainMap, rangeMap,
2173 callFillComplete, tolerant, debug);
2174 }
2175
2201 static Teuchos::RCP<sparse_matrix_type>
2202 readSparse (std::istream& in,
2203 const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2204 const bool callFillComplete=true,
2205 const bool tolerant=false,
2206 const bool debug=false)
2207 {
2208 using Teuchos::MatrixMarket::Banner;
2209 using Teuchos::arcp;
2210 using Teuchos::ArrayRCP;
2211 using Teuchos::broadcast;
2212 using Teuchos::null;
2213 using Teuchos::ptr;
2214 using Teuchos::RCP;
2215 using Teuchos::REDUCE_MAX;
2216 using Teuchos::reduceAll;
2217 using Teuchos::Tuple;
2218 using std::cerr;
2219 using std::endl;
2220 typedef Teuchos::ScalarTraits<scalar_type> STS;
2221
2222 const bool extraDebug = false;
2223 const int myRank = pComm->getRank ();
2224 const int rootRank = 0;
2225
2226 // Current line number in the input stream. Various calls
2227 // will modify this depending on the number of lines that are
2228 // read from the input stream. Only Rank 0 modifies this.
2229 size_t lineNumber = 1;
2230
2231 if (debug && myRank == rootRank) {
2232 cerr << "Matrix Market reader: readSparse:" << endl
2233 << "-- Reading banner line" << endl;
2234 }
2235
2236 // The "Banner" tells you whether the input stream represents
2237 // a sparse matrix, the symmetry type of the matrix, and the
2238 // type of the data it contains.
2239 //
2240 // pBanner will only be nonnull on MPI Rank 0. It will be
2241 // null on all other MPI processes.
2242 RCP<const Banner> pBanner;
2243 {
2244 // We read and validate the Banner on Proc 0, but broadcast
2245 // the validation result to all processes.
2246 // Teuchos::broadcast doesn't currently work with bool, so
2247 // we use int (true -> 1, false -> 0).
2248 int bannerIsCorrect = 1;
2249 std::ostringstream errMsg;
2250
2251 if (myRank == rootRank) {
2252 // Read the Banner line from the input stream.
2253 try {
2254 pBanner = readBanner (in, lineNumber, tolerant, debug);
2255 }
2256 catch (std::exception& e) {
2257 errMsg << "Attempt to read the Matrix Market file's Banner line "
2258 "threw an exception: " << e.what();
2259 bannerIsCorrect = 0;
2260 }
2261
2262 if (bannerIsCorrect) {
2263 // Validate the Banner for the case of a sparse matrix.
2264 // We validate on Proc 0, since it reads the Banner.
2265
2266 // In intolerant mode, the matrix type must be "coordinate".
2267 if (! tolerant && pBanner->matrixType() != "coordinate") {
2268 bannerIsCorrect = 0;
2269 errMsg << "The Matrix Market input file must contain a "
2270 "\"coordinate\"-format sparse matrix in order to create a "
2271 "Tpetra::CrsMatrix object from it, but the file's matrix "
2272 "type is \"" << pBanner->matrixType() << "\" instead.";
2273 }
2274 // In tolerant mode, we allow the matrix type to be
2275 // anything other than "array" (which would mean that
2276 // the file contains a dense matrix).
2277 if (tolerant && pBanner->matrixType() == "array") {
2278 bannerIsCorrect = 0;
2279 errMsg << "Matrix Market file must contain a \"coordinate\"-"
2280 "format sparse matrix in order to create a Tpetra::CrsMatrix "
2281 "object from it, but the file's matrix type is \"array\" "
2282 "instead. That probably means the file contains dense matrix "
2283 "data.";
2284 }
2285 }
2286 } // Proc 0: Done reading the Banner, hopefully successfully.
2287
2288 // Broadcast from Proc 0 whether the Banner was read correctly.
2289 broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
2290
2291 // If the Banner is invalid, all processes throw an
2292 // exception. Only Proc 0 gets the exception message, but
2293 // that's OK, since the main point is to "stop the world"
2294 // (rather than throw an exception on one process and leave
2295 // the others hanging).
2296 TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
2297 std::invalid_argument, errMsg.str ());
2298 } // Done reading the Banner line and broadcasting success.
2299 if (debug && myRank == rootRank) {
2300 cerr << "-- Reading dimensions line" << endl;
2301 }
2302
2303 // Read the matrix dimensions from the Matrix Market metadata.
2304 // dims = (numRows, numCols, numEntries). Proc 0 does the
2305 // reading, but it broadcasts the results to all MPI
2306 // processes. Thus, readCoordDims() is a collective
2307 // operation. It does a collective check for correctness too.
2308 Tuple<global_ordinal_type, 3> dims =
2309 readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
2310
2311 if (debug && myRank == rootRank) {
2312 cerr << "-- Making Adder for collecting matrix data" << endl;
2313 }
2314
2315 // "Adder" object for collecting all the sparse matrix entries
2316 // from the input stream. This is only nonnull on Proc 0.
2317 RCP<adder_type> pAdder =
2318 makeAdder (pComm, pBanner, dims, tolerant, debug);
2319
2320 if (debug && myRank == rootRank) {
2321 cerr << "-- Reading matrix data" << endl;
2322 }
2323 //
2324 // Read the matrix entries from the input stream on Proc 0.
2325 //
2326 {
2327 // We use readSuccess to broadcast the results of the read
2328 // (succeeded or not) to all MPI processes. Since
2329 // Teuchos::broadcast doesn't currently know how to send
2330 // bools, we convert to int (true -> 1, false -> 0).
2331 int readSuccess = 1;
2332 std::ostringstream errMsg; // Exception message (only valid on Proc 0)
2333 if (myRank == rootRank) {
2334 try {
2335 // Reader for "coordinate" format sparse matrix data.
2336 typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
2337 global_ordinal_type, scalar_type, STS::isComplex> reader_type;
2338 reader_type reader (pAdder);
2339
2340 // Read the sparse matrix entries.
2341 std::pair<bool, std::vector<size_t> > results =
2342 reader.read (in, lineNumber, tolerant, debug);
2343 readSuccess = results.first ? 1 : 0;
2344 }
2345 catch (std::exception& e) {
2346 readSuccess = 0;
2347 errMsg << e.what();
2348 }
2349 }
2350 broadcast (*pComm, rootRank, ptr (&readSuccess));
2351
2352 // It would be nice to add a "verbose" flag, so that in
2353 // tolerant mode, we could log any bad line number(s) on
2354 // Proc 0. For now, we just throw if the read fails to
2355 // succeed.
2356 //
2357 // Question: If we're in tolerant mode, and if the read did
2358 // not succeed, should we attempt to call fillComplete()?
2359 TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
2360 "Failed to read the Matrix Market sparse matrix file: "
2361 << errMsg.str());
2362 } // Done reading the matrix entries (stored on Proc 0 for now)
2363
2364 if (debug && myRank == rootRank) {
2365 cerr << "-- Successfully read the Matrix Market data" << endl;
2366 }
2367
2368 // In tolerant mode, we need to rebroadcast the matrix
2369 // dimensions, since they may be different after reading the
2370 // actual matrix data. We only need to broadcast the number
2371 // of rows and columns. Only Rank 0 needs to know the actual
2372 // global number of entries, since (a) we need to merge
2373 // duplicates on Rank 0 first anyway, and (b) when we
2374 // distribute the entries, each rank other than Rank 0 will
2375 // only need to know how many entries it owns, not the total
2376 // number of entries.
2377 if (tolerant) {
2378 if (debug && myRank == rootRank) {
2379 cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
2380 << endl
2381 << "----- Dimensions before: "
2382 << dims[0] << " x " << dims[1]
2383 << endl;
2384 }
2385 // Packed coordinate matrix dimensions (numRows, numCols).
2386 Tuple<global_ordinal_type, 2> updatedDims;
2387 if (myRank == rootRank) {
2388 // If one or more bottom rows of the matrix contain no
2389 // entries, then the Adder will report that the number
2390 // of rows is less than that specified in the
2391 // metadata. We allow this case, and favor the
2392 // metadata so that the zero row(s) will be included.
2393 updatedDims[0] =
2394 std::max (dims[0], pAdder->getAdder()->numRows());
2395 updatedDims[1] = pAdder->getAdder()->numCols();
2396 }
2397 broadcast (*pComm, rootRank, updatedDims);
2398 dims[0] = updatedDims[0];
2399 dims[1] = updatedDims[1];
2400 if (debug && myRank == rootRank) {
2401 cerr << "----- Dimensions after: " << dims[0] << " x "
2402 << dims[1] << endl;
2403 }
2404 }
2405 else {
2406 // In strict mode, we require that the matrix's metadata and
2407 // its actual data agree, at least somewhat. In particular,
2408 // the number of rows must agree, since otherwise we cannot
2409 // distribute the matrix correctly.
2410
2411 // Teuchos::broadcast() doesn't know how to broadcast bools,
2412 // so we use an int with the standard 1 == true, 0 == false
2413 // encoding.
2414 int dimsMatch = 1;
2415 if (myRank == rootRank) {
2416 // If one or more bottom rows of the matrix contain no
2417 // entries, then the Adder will report that the number of
2418 // rows is less than that specified in the metadata. We
2419 // allow this case, and favor the metadata, but do not
2420 // allow the Adder to think there are more rows in the
2421 // matrix than the metadata says.
2422 if (dims[0] < pAdder->getAdder ()->numRows ()) {
2423 dimsMatch = 0;
2424 }
2425 }
2426 broadcast (*pComm, 0, ptr (&dimsMatch));
2427 if (dimsMatch == 0) {
2428 // We're in an error state anyway, so we might as well
2429 // work a little harder to print an informative error
2430 // message.
2431 //
2432 // Broadcast the Adder's idea of the matrix dimensions
2433 // from Proc 0 to all processes.
2434 Tuple<global_ordinal_type, 2> addersDims;
2435 if (myRank == rootRank) {
2436 addersDims[0] = pAdder->getAdder()->numRows();
2437 addersDims[1] = pAdder->getAdder()->numCols();
2438 }
2439 broadcast (*pComm, 0, addersDims);
2440 TEUCHOS_TEST_FOR_EXCEPTION(
2441 dimsMatch == 0, std::runtime_error,
2442 "The matrix metadata says that the matrix is " << dims[0] << " x "
2443 << dims[1] << ", but the actual data says that the matrix is "
2444 << addersDims[0] << " x " << addersDims[1] << ". That means the "
2445 "data includes more rows than reported in the metadata. This "
2446 "is not allowed when parsing in strict mode. Parse the matrix in "
2447 "tolerant mode to ignore the metadata when it disagrees with the "
2448 "data.");
2449 }
2450 } // Matrix dimensions (# rows, # cols, # entries) agree.
2451
2452 if (debug && myRank == rootRank) {
2453 cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
2454 }
2455
2456 // Now that we've read in all the matrix entries from the
2457 // input stream into the adder on Proc 0, post-process them
2458 // into CSR format (still on Proc 0). This will facilitate
2459 // distributing them to all the processors.
2460 //
2461 // These arrays represent the global matrix data as a CSR
2462 // matrix (with numEntriesPerRow as redundant but convenient
2463 // metadata, since it's computable from rowPtr and vice
2464 // versa). They are valid only on Proc 0.
2465 ArrayRCP<size_t> numEntriesPerRow;
2466 ArrayRCP<size_t> rowPtr;
2467 ArrayRCP<global_ordinal_type> colInd;
2468 ArrayRCP<scalar_type> values;
2469
2470 // Proc 0 first merges duplicate entries, and then converts
2471 // the coordinate-format matrix data to CSR.
2472 {
2473 int mergeAndConvertSucceeded = 1;
2474 std::ostringstream errMsg;
2475
2476 if (myRank == rootRank) {
2477 try {
2478 typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,
2479 global_ordinal_type> element_type;
2480
2481 // Number of rows in the matrix. If we are in tolerant
2482 // mode, we've already synchronized dims with the actual
2483 // matrix data. If in strict mode, we should use dims
2484 // (as read from the file's metadata) rather than the
2485 // matrix data to determine the dimensions. (The matrix
2486 // data will claim fewer rows than the metadata, if one
2487 // or more rows have no entries stored in the file.)
2488 const size_type numRows = dims[0];
2489
2490 // Additively merge duplicate matrix entries.
2491 pAdder->getAdder()->merge ();
2492
2493 // Get a temporary const view of the merged matrix entries.
2494 const std::vector<element_type>& entries =
2495 pAdder->getAdder()->getEntries();
2496
2497 // Number of matrix entries (after merging).
2498 const size_t numEntries = (size_t)entries.size();
2499
2500 if (debug) {
2501 cerr << "----- Proc 0: Matrix has numRows=" << numRows
2502 << " rows and numEntries=" << numEntries
2503 << " entries." << endl;
2504 }
2505
2506 // Make space for the CSR matrix data. Converting to
2507 // CSR is easier if we fill numEntriesPerRow with zeros
2508 // at first.
2509 numEntriesPerRow = arcp<size_t> (numRows);
2510 std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
2511 rowPtr = arcp<size_t> (numRows+1);
2512 std::fill (rowPtr.begin(), rowPtr.end(), 0);
2513 colInd = arcp<global_ordinal_type> (numEntries);
2514 values = arcp<scalar_type> (numEntries);
2515
2516 // Convert from array-of-structs coordinate format to CSR
2517 // (compressed sparse row) format.
2518 global_ordinal_type prvRow = 0;
2519 size_t curPos = 0;
2520 rowPtr[0] = 0;
2521 for (curPos = 0; curPos < numEntries; ++curPos) {
2522 const element_type& curEntry = entries[curPos];
2523 const global_ordinal_type curRow = curEntry.rowIndex();
2524 TEUCHOS_TEST_FOR_EXCEPTION(
2525 curRow < prvRow, std::logic_error,
2526 "Row indices are out of order, even though they are supposed "
2527 "to be sorted. curRow = " << curRow << ", prvRow = "
2528 << prvRow << ", at curPos = " << curPos << ". Please report "
2529 "this bug to the Tpetra developers.");
2530 if (curRow > prvRow) {
2531 for (global_ordinal_type r = prvRow+1; r <= curRow; ++r) {
2532 rowPtr[r] = curPos;
2533 }
2534 prvRow = curRow;
2535 }
2536 numEntriesPerRow[curRow]++;
2537 colInd[curPos] = curEntry.colIndex();
2538 values[curPos] = curEntry.value();
2539 }
2540 // rowPtr has one more entry than numEntriesPerRow. The
2541 // last entry of rowPtr is the number of entries in
2542 // colInd and values.
2543 rowPtr[numRows] = numEntries;
2544 } // Finished conversion to CSR format
2545 catch (std::exception& e) {
2546 mergeAndConvertSucceeded = 0;
2547 errMsg << "Failed to merge sparse matrix entries and convert to "
2548 "CSR format: " << e.what();
2549 }
2550
2551 if (debug && mergeAndConvertSucceeded) {
2552 // Number of rows in the matrix.
2553 const size_type numRows = dims[0];
2554 const size_type maxToDisplay = 100;
2555
2556 cerr << "----- Proc 0: numEntriesPerRow[0.."
2557 << (numEntriesPerRow.size()-1) << "] ";
2558 if (numRows > maxToDisplay) {
2559 cerr << "(only showing first and last few entries) ";
2560 }
2561 cerr << "= [";
2562 if (numRows > 0) {
2563 if (numRows > maxToDisplay) {
2564 for (size_type k = 0; k < 2; ++k) {
2565 cerr << numEntriesPerRow[k] << " ";
2566 }
2567 cerr << "... ";
2568 for (size_type k = numRows-2; k < numRows-1; ++k) {
2569 cerr << numEntriesPerRow[k] << " ";
2570 }
2571 }
2572 else {
2573 for (size_type k = 0; k < numRows-1; ++k) {
2574 cerr << numEntriesPerRow[k] << " ";
2575 }
2576 }
2577 cerr << numEntriesPerRow[numRows-1];
2578 } // numRows > 0
2579 cerr << "]" << endl;
2580
2581 cerr << "----- Proc 0: rowPtr ";
2582 if (numRows > maxToDisplay) {
2583 cerr << "(only showing first and last few entries) ";
2584 }
2585 cerr << "= [";
2586 if (numRows > maxToDisplay) {
2587 for (size_type k = 0; k < 2; ++k) {
2588 cerr << rowPtr[k] << " ";
2589 }
2590 cerr << "... ";
2591 for (size_type k = numRows-2; k < numRows; ++k) {
2592 cerr << rowPtr[k] << " ";
2593 }
2594 }
2595 else {
2596 for (size_type k = 0; k < numRows; ++k) {
2597 cerr << rowPtr[k] << " ";
2598 }
2599 }
2600 cerr << rowPtr[numRows] << "]" << endl;
2601 }
2602 } // if myRank == rootRank
2603 } // Done converting sparse matrix data to CSR format
2604
2605 // Now we're done with the Adder, so we can release the
2606 // reference ("free" it) to save space. This only actually
2607 // does anything on Rank 0, since pAdder is null on all the
2608 // other MPI processes.
2609 pAdder = null;
2610
2611 if (debug && myRank == rootRank) {
2612 cerr << "-- Making range, domain, and row maps" << endl;
2613 }
2614
2615 // Make the maps that describe the matrix's range and domain,
2616 // and the distribution of its rows. Creating a Map is a
2617 // collective operation, so we don't have to do a broadcast of
2618 // a success Boolean.
2619 RCP<const map_type> pRangeMap = makeRangeMap (pComm, dims[0]);
2620 RCP<const map_type> pDomainMap =
2621 makeDomainMap (pRangeMap, dims[0], dims[1]);
2622 RCP<const map_type> pRowMap = makeRowMap (null, pComm, dims[0]);
2623
2624 if (debug && myRank == rootRank) {
2625 cerr << "-- Distributing the matrix data" << endl;
2626 }
2627
2628 // Distribute the matrix data. Each processor has to add the
2629 // rows that it owns. If you try to make Proc 0 call
2630 // insertGlobalValues() for _all_ the rows, not just those it
2631 // owns, then fillComplete() will compute the number of
2632 // columns incorrectly. That's why Proc 0 has to distribute
2633 // the matrix data and why we make all the processors (not
2634 // just Proc 0) call insertGlobalValues() on their own data.
2635 //
2636 // These arrays represent each processor's part of the matrix
2637 // data, in "CSR" format (sort of, since the row indices might
2638 // not be contiguous).
2639 ArrayRCP<size_t> myNumEntriesPerRow;
2640 ArrayRCP<size_t> myRowPtr;
2641 ArrayRCP<global_ordinal_type> myColInd;
2642 ArrayRCP<scalar_type> myValues;
2643 // Distribute the matrix data. This is a collective operation.
2644 distribute (myNumEntriesPerRow, myRowPtr, myColInd, myValues, pRowMap,
2645 numEntriesPerRow, rowPtr, colInd, values, debug);
2646
2647 if (debug && myRank == rootRank) {
2648 cerr << "-- Inserting matrix entries on each processor";
2649 if (callFillComplete) {
2650 cerr << " and calling fillComplete()";
2651 }
2652 cerr << endl;
2653 }
2654 // Each processor inserts its part of the matrix data, and
2655 // then they all call fillComplete(). This method invalidates
2656 // the my* distributed matrix data before calling
2657 // fillComplete(), in order to save space. In general, we
2658 // never store more than two copies of the matrix's entries in
2659 // memory at once, which is no worse than what Tpetra
2660 // promises.
2661 RCP<sparse_matrix_type> pMatrix =
2662 makeMatrix (myNumEntriesPerRow, myRowPtr, myColInd, myValues,
2663 pRowMap, pRangeMap, pDomainMap, callFillComplete);
2664 // Only use a reduce-all in debug mode to check if pMatrix is
2665 // null. Otherwise, just throw an exception. We never expect
2666 // a null pointer here, so we can save a communication.
2667 if (debug) {
2668 int localIsNull = pMatrix.is_null () ? 1 : 0;
2669 int globalIsNull = 0;
2670 reduceAll (*pComm, REDUCE_MAX, localIsNull, ptr (&globalIsNull));
2671 TEUCHOS_TEST_FOR_EXCEPTION(globalIsNull != 0, std::logic_error,
2672 "Reader::makeMatrix() returned a null pointer on at least one "
2673 "process. Please report this bug to the Tpetra developers.");
2674 }
2675 else {
2676 TEUCHOS_TEST_FOR_EXCEPTION(pMatrix.is_null(), std::logic_error,
2677 "Reader::makeMatrix() returned a null pointer. "
2678 "Please report this bug to the Tpetra developers.");
2679 }
2680
2681 // We can't get the dimensions of the matrix until after
2682 // fillComplete() is called. Thus, we can't do the sanity
2683 // check (dimensions read from the Matrix Market data,
2684 // vs. dimensions reported by the CrsMatrix) unless the user
2685 // asked makeMatrix() to call fillComplete().
2686 //
2687 // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
2688 // what one might think it does, so you have to ask the range
2689 // resp. domain map for the number of rows resp. columns.
2690 if (callFillComplete) {
2691 const int numProcs = pComm->getSize ();
2692
2693 if (extraDebug && debug) {
2694 const global_size_t globalNumRows =
2695 pRangeMap->getGlobalNumElements ();
2696 const global_size_t globalNumCols =
2697 pDomainMap->getGlobalNumElements ();
2698 if (myRank == rootRank) {
2699 cerr << "-- Matrix is "
2700 << globalNumRows << " x " << globalNumCols
2701 << " with " << pMatrix->getGlobalNumEntries()
2702 << " entries, and index base "
2703 << pMatrix->getIndexBase() << "." << endl;
2704 }
2705 pComm->barrier ();
2706 for (int p = 0; p < numProcs; ++p) {
2707 if (myRank == p) {
2708 cerr << "-- Proc " << p << " owns "
2709 << pMatrix->getNodeNumCols() << " columns, and "
2710 << pMatrix->getNodeNumEntries() << " entries." << endl;
2711 }
2712 pComm->barrier ();
2713 }
2714 } // if (extraDebug && debug)
2715 } // if (callFillComplete)
2716
2717 if (debug && myRank == rootRank) {
2718 cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
2719 << endl;
2720 }
2721 return pMatrix;
2722 }
2723
2724
2753 static Teuchos::RCP<sparse_matrix_type>
2754 readSparse (std::istream& in,
2755 const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2756 const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
2757 const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
2758 const bool tolerant=false,
2759 const bool debug=false)
2760 {
2761 using Teuchos::MatrixMarket::Banner;
2762 using Teuchos::arcp;
2763 using Teuchos::ArrayRCP;
2764 using Teuchos::broadcast;
2765 using Teuchos::null;
2766 using Teuchos::ptr;
2767 using Teuchos::RCP;
2768 using Teuchos::reduceAll;
2769 using Teuchos::Tuple;
2770 using std::cerr;
2771 using std::endl;
2772 typedef Teuchos::ScalarTraits<scalar_type> STS;
2773
2774 const bool extraDebug = false;
2775 const int myRank = pComm->getRank ();
2776 const int rootRank = 0;
2777
2778 // Current line number in the input stream. Various calls
2779 // will modify this depending on the number of lines that are
2780 // read from the input stream. Only Rank 0 modifies this.
2781 size_t lineNumber = 1;
2782
2783 if (debug && myRank == rootRank) {
2784 cerr << "Matrix Market reader: readSparse:" << endl
2785 << "-- Reading banner line" << endl;
2786 }
2787
2788 // The "Banner" tells you whether the input stream represents
2789 // a sparse matrix, the symmetry type of the matrix, and the
2790 // type of the data it contains.
2791 //
2792 // pBanner will only be nonnull on MPI Rank 0. It will be
2793 // null on all other MPI processes.
2794 RCP<const Banner> pBanner;
2795 {
2796 // We read and validate the Banner on Proc 0, but broadcast
2797 // the validation result to all processes.
2798 // Teuchos::broadcast doesn't currently work with bool, so
2799 // we use int (true -> 1, false -> 0).
2800 int bannerIsCorrect = 1;
2801 std::ostringstream errMsg;
2802
2803 if (myRank == rootRank) {
2804 // Read the Banner line from the input stream.
2805 try {
2806 pBanner = readBanner (in, lineNumber, tolerant, debug);
2807 }
2808 catch (std::exception& e) {
2809 errMsg << "Attempt to read the Matrix Market file's Banner line "
2810 "threw an exception: " << e.what();
2811 bannerIsCorrect = 0;
2812 }
2813
2814 if (bannerIsCorrect) {
2815 // Validate the Banner for the case of a sparse matrix.
2816 // We validate on Proc 0, since it reads the Banner.
2817
2818 // In intolerant mode, the matrix type must be "coordinate".
2819 if (! tolerant && pBanner->matrixType() != "coordinate") {
2820 bannerIsCorrect = 0;
2821 errMsg << "The Matrix Market input file must contain a "
2822 "\"coordinate\"-format sparse matrix in order to create a "
2823 "Tpetra::CrsMatrix object from it, but the file's matrix "
2824 "type is \"" << pBanner->matrixType() << "\" instead.";
2825 }
2826 // In tolerant mode, we allow the matrix type to be
2827 // anything other than "array" (which would mean that
2828 // the file contains a dense matrix).
2829 if (tolerant && pBanner->matrixType() == "array") {
2830 bannerIsCorrect = 0;
2831 errMsg << "Matrix Market file must contain a \"coordinate\"-"
2832 "format sparse matrix in order to create a Tpetra::CrsMatrix "
2833 "object from it, but the file's matrix type is \"array\" "
2834 "instead. That probably means the file contains dense matrix "
2835 "data.";
2836 }
2837 }
2838 } // Proc 0: Done reading the Banner, hopefully successfully.
2839
2840 // Broadcast from Proc 0 whether the Banner was read correctly.
2841 broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
2842
2843 // If the Banner is invalid, all processes throw an
2844 // exception. Only Proc 0 gets the exception message, but
2845 // that's OK, since the main point is to "stop the world"
2846 // (rather than throw an exception on one process and leave
2847 // the others hanging).
2848 TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
2849 std::invalid_argument, errMsg.str ());
2850 } // Done reading the Banner line and broadcasting success.
2851 if (debug && myRank == rootRank) {
2852 cerr << "-- Reading dimensions line" << endl;
2853 }
2854
2855 // Read the matrix dimensions from the Matrix Market metadata.
2856 // dims = (numRows, numCols, numEntries). Proc 0 does the
2857 // reading, but it broadcasts the results to all MPI
2858 // processes. Thus, readCoordDims() is a collective
2859 // operation. It does a collective check for correctness too.
2860 Tuple<global_ordinal_type, 3> dims =
2861 readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
2862
2863 if (debug && myRank == rootRank) {
2864 cerr << "-- Making Adder for collecting matrix data" << endl;
2865 }
2866
2867 // "Adder" object for collecting all the sparse matrix entries
2868 // from the input stream. This is only nonnull on Proc 0.
2869 RCP<adder_type> pAdder =
2870 makeAdder (pComm, pBanner, dims, tolerant, debug);
2871
2872 if (debug && myRank == rootRank) {
2873 cerr << "-- Reading matrix data" << endl;
2874 }
2875 //
2876 // Read the matrix entries from the input stream on Proc 0.
2877 //
2878 {
2879 // We use readSuccess to broadcast the results of the read
2880 // (succeeded or not) to all MPI processes. Since
2881 // Teuchos::broadcast doesn't currently know how to send
2882 // bools, we convert to int (true -> 1, false -> 0).
2883 int readSuccess = 1;
2884 std::ostringstream errMsg; // Exception message (only valid on Proc 0)
2885 if (myRank == rootRank) {
2886 try {
2887 // Reader for "coordinate" format sparse matrix data.
2888 typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
2889 global_ordinal_type, scalar_type, STS::isComplex> reader_type;
2890 reader_type reader (pAdder);
2891
2892 // Read the sparse matrix entries.
2893 std::pair<bool, std::vector<size_t> > results =
2894 reader.read (in, lineNumber, tolerant, debug);
2895 readSuccess = results.first ? 1 : 0;
2896 }
2897 catch (std::exception& e) {
2898 readSuccess = 0;
2899 errMsg << e.what();
2900 }
2901 }
2902 broadcast (*pComm, rootRank, ptr (&readSuccess));
2903
2904 // It would be nice to add a "verbose" flag, so that in
2905 // tolerant mode, we could log any bad line number(s) on
2906 // Proc 0. For now, we just throw if the read fails to
2907 // succeed.
2908 //
2909 // Question: If we're in tolerant mode, and if the read did
2910 // not succeed, should we attempt to call fillComplete()?
2911 TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
2912 "Failed to read the Matrix Market sparse matrix file: "
2913 << errMsg.str());
2914 } // Done reading the matrix entries (stored on Proc 0 for now)
2915
2916 if (debug && myRank == rootRank) {
2917 cerr << "-- Successfully read the Matrix Market data" << endl;
2918 }
2919
2920 // In tolerant mode, we need to rebroadcast the matrix
2921 // dimensions, since they may be different after reading the
2922 // actual matrix data. We only need to broadcast the number
2923 // of rows and columns. Only Rank 0 needs to know the actual
2924 // global number of entries, since (a) we need to merge
2925 // duplicates on Rank 0 first anyway, and (b) when we
2926 // distribute the entries, each rank other than Rank 0 will
2927 // only need to know how many entries it owns, not the total
2928 // number of entries.
2929 if (tolerant) {
2930 if (debug && myRank == rootRank) {
2931 cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
2932 << endl
2933 << "----- Dimensions before: "
2934 << dims[0] << " x " << dims[1]
2935 << endl;
2936 }
2937 // Packed coordinate matrix dimensions (numRows, numCols).
2938 Tuple<global_ordinal_type, 2> updatedDims;
2939 if (myRank == rootRank) {
2940 // If one or more bottom rows of the matrix contain no
2941 // entries, then the Adder will report that the number
2942 // of rows is less than that specified in the
2943 // metadata. We allow this case, and favor the
2944 // metadata so that the zero row(s) will be included.
2945 updatedDims[0] =
2946 std::max (dims[0], pAdder->getAdder()->numRows());
2947 updatedDims[1] = pAdder->getAdder()->numCols();
2948 }
2949 broadcast (*pComm, rootRank, updatedDims);
2950 dims[0] = updatedDims[0];
2951 dims[1] = updatedDims[1];
2952 if (debug && myRank == rootRank) {
2953 cerr << "----- Dimensions after: " << dims[0] << " x "
2954 << dims[1] << endl;
2955 }
2956 }
2957 else {
2958 // In strict mode, we require that the matrix's metadata and
2959 // its actual data agree, at least somewhat. In particular,
2960 // the number of rows must agree, since otherwise we cannot
2961 // distribute the matrix correctly.
2962
2963 // Teuchos::broadcast() doesn't know how to broadcast bools,
2964 // so we use an int with the standard 1 == true, 0 == false
2965 // encoding.
2966 int dimsMatch = 1;
2967 if (myRank == rootRank) {
2968 // If one or more bottom rows of the matrix contain no
2969 // entries, then the Adder will report that the number of
2970 // rows is less than that specified in the metadata. We
2971 // allow this case, and favor the metadata, but do not
2972 // allow the Adder to think there are more rows in the
2973 // matrix than the metadata says.
2974 if (dims[0] < pAdder->getAdder ()->numRows ()) {
2975 dimsMatch = 0;
2976 }
2977 }
2978 broadcast (*pComm, 0, ptr (&dimsMatch));
2979 if (dimsMatch == 0) {
2980 // We're in an error state anyway, so we might as well
2981 // work a little harder to print an informative error
2982 // message.
2983 //
2984 // Broadcast the Adder's idea of the matrix dimensions
2985 // from Proc 0 to all processes.
2986 Tuple<global_ordinal_type, 2> addersDims;
2987 if (myRank == rootRank) {
2988 addersDims[0] = pAdder->getAdder()->numRows();
2989 addersDims[1] = pAdder->getAdder()->numCols();
2990 }
2991 broadcast (*pComm, 0, addersDims);
2992 TEUCHOS_TEST_FOR_EXCEPTION(
2993 dimsMatch == 0, std::runtime_error,
2994 "The matrix metadata says that the matrix is " << dims[0] << " x "
2995 << dims[1] << ", but the actual data says that the matrix is "
2996 << addersDims[0] << " x " << addersDims[1] << ". That means the "
2997 "data includes more rows than reported in the metadata. This "
2998 "is not allowed when parsing in strict mode. Parse the matrix in "
2999 "tolerant mode to ignore the metadata when it disagrees with the "
3000 "data.");
3001 }
3002 } // Matrix dimensions (# rows, # cols, # entries) agree.
3003
3004 if (debug && myRank == rootRank) {
3005 cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
3006 }
3007
3008 // Now that we've read in all the matrix entries from the
3009 // input stream into the adder on Proc 0, post-process them
3010 // into CSR format (still on Proc 0). This will facilitate
3011 // distributing them to all the processors.
3012 //
3013 // These arrays represent the global matrix data as a CSR
3014 // matrix (with numEntriesPerRow as redundant but convenient
3015 // metadata, since it's computable from rowPtr and vice
3016 // versa). They are valid only on Proc 0.
3017 ArrayRCP<size_t> numEntriesPerRow;
3018 ArrayRCP<size_t> rowPtr;
3019 ArrayRCP<global_ordinal_type> colInd;
3020 ArrayRCP<scalar_type> values;
3021
3022 // Proc 0 first merges duplicate entries, and then converts
3023 // the coordinate-format matrix data to CSR.
3024 {
3025 int mergeAndConvertSucceeded = 1;
3026 std::ostringstream errMsg;
3027
3028 if (myRank == rootRank) {
3029 try {
3030 typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,
3031 global_ordinal_type> element_type;
3032
3033 // Number of rows in the matrix. If we are in tolerant
3034 // mode, we've already synchronized dims with the actual
3035 // matrix data. If in strict mode, we should use dims
3036 // (as read from the file's metadata) rather than the
3037 // matrix data to determine the dimensions. (The matrix
3038 // data will claim fewer rows than the metadata, if one
3039 // or more rows have no entries stored in the file.)
3040 const size_type numRows = dims[0];
3041
3042 // Additively merge duplicate matrix entries.
3043 pAdder->getAdder()->merge ();
3044
3045 // Get a temporary const view of the merged matrix entries.
3046 const std::vector<element_type>& entries =
3047 pAdder->getAdder()->getEntries();
3048
3049 // Number of matrix entries (after merging).
3050 const size_t numEntries = (size_t)entries.size();
3051
3052 if (debug) {
3053 cerr << "----- Proc 0: Matrix has numRows=" << numRows
3054 << " rows and numEntries=" << numEntries
3055 << " entries." << endl;
3056 }
3057
3058 // Make space for the CSR matrix data. Converting to
3059 // CSR is easier if we fill numEntriesPerRow with zeros
3060 // at first.
3061 numEntriesPerRow = arcp<size_t> (numRows);
3062 std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
3063 rowPtr = arcp<size_t> (numRows+1);
3064 std::fill (rowPtr.begin(), rowPtr.end(), 0);
3065 colInd = arcp<global_ordinal_type> (numEntries);
3066 values = arcp<scalar_type> (numEntries);
3067
3068 // Convert from array-of-structs coordinate format to CSR
3069 // (compressed sparse row) format.
3070 global_ordinal_type prvRow = 0;
3071 size_t curPos = 0;
3072 rowPtr[0] = 0;
3073 for (curPos = 0; curPos < numEntries; ++curPos) {
3074 const element_type& curEntry = entries[curPos];
3075 const global_ordinal_type curRow = curEntry.rowIndex();
3076 TEUCHOS_TEST_FOR_EXCEPTION(
3077 curRow < prvRow, std::logic_error,
3078 "Row indices are out of order, even though they are supposed "
3079 "to be sorted. curRow = " << curRow << ", prvRow = "
3080 << prvRow << ", at curPos = " << curPos << ". Please report "
3081 "this bug to the Tpetra developers.");
3082 if (curRow > prvRow) {
3083 for (global_ordinal_type r = prvRow+1; r <= curRow; ++r) {
3084 rowPtr[r] = curPos;
3085 }
3086 prvRow = curRow;
3087 }
3088 numEntriesPerRow[curRow]++;
3089 colInd[curPos] = curEntry.colIndex();
3090 values[curPos] = curEntry.value();
3091 }
3092 // rowPtr has one more entry than numEntriesPerRow. The
3093 // last entry of rowPtr is the number of entries in
3094 // colInd and values.
3095 rowPtr[numRows] = numEntries;
3096 } // Finished conversion to CSR format
3097 catch (std::exception& e) {
3098 mergeAndConvertSucceeded = 0;
3099 errMsg << "Failed to merge sparse matrix entries and convert to "
3100 "CSR format: " << e.what();
3101 }
3102
3103 if (debug && mergeAndConvertSucceeded) {
3104 // Number of rows in the matrix.
3105 const size_type numRows = dims[0];
3106 const size_type maxToDisplay = 100;
3107
3108 cerr << "----- Proc 0: numEntriesPerRow[0.."
3109 << (numEntriesPerRow.size()-1) << "] ";
3110 if (numRows > maxToDisplay) {
3111 cerr << "(only showing first and last few entries) ";
3112 }
3113 cerr << "= [";
3114 if (numRows > 0) {
3115 if (numRows > maxToDisplay) {
3116 for (size_type k = 0; k < 2; ++k) {
3117 cerr << numEntriesPerRow[k] << " ";
3118 }
3119 cerr << "... ";
3120 for (size_type k = numRows-2; k < numRows-1; ++k) {
3121 cerr << numEntriesPerRow[k] << " ";
3122 }
3123 }
3124 else {
3125 for (size_type k = 0; k < numRows-1; ++k) {
3126 cerr << numEntriesPerRow[k] << " ";
3127 }
3128 }
3129 cerr << numEntriesPerRow[numRows-1];
3130 } // numRows > 0
3131 cerr << "]" << endl;
3132
3133 cerr << "----- Proc 0: rowPtr ";
3134 if (numRows > maxToDisplay) {
3135 cerr << "(only showing first and last few entries) ";
3136 }
3137 cerr << "= [";
3138 if (numRows > maxToDisplay) {
3139 for (size_type k = 0; k < 2; ++k) {
3140 cerr << rowPtr[k] << " ";
3141 }
3142 cerr << "... ";
3143 for (size_type k = numRows-2; k < numRows; ++k) {
3144 cerr << rowPtr[k] << " ";
3145 }
3146 }
3147 else {
3148 for (size_type k = 0; k < numRows; ++k) {
3149 cerr << rowPtr[k] << " ";
3150 }
3151 }
3152 cerr << rowPtr[numRows] << "]" << endl;
3153 }
3154 } // if myRank == rootRank
3155 } // Done converting sparse matrix data to CSR format
3156
3157 // Now we're done with the Adder, so we can release the
3158 // reference ("free" it) to save space. This only actually
3159 // does anything on Rank 0, since pAdder is null on all the
3160 // other MPI processes.
3161 pAdder = null;
3162
3163 if (debug && myRank == rootRank) {
3164 cerr << "-- Making range, domain, and row maps" << endl;
3165 }
3166
3167 // Make the maps that describe the matrix's range and domain,
3168 // and the distribution of its rows. Creating a Map is a
3169 // collective operation, so we don't have to do a broadcast of
3170 // a success Boolean.
3171 RCP<const map_type> pRangeMap = makeRangeMap (pComm, dims[0]);
3172 RCP<const map_type> pDomainMap =
3173 makeDomainMap (pRangeMap, dims[0], dims[1]);
3174 RCP<const map_type> pRowMap = makeRowMap (null, pComm, dims[0]);
3175
3176 if (debug && myRank == rootRank) {
3177 cerr << "-- Distributing the matrix data" << endl;
3178 }
3179
3180 // Distribute the matrix data. Each processor has to add the
3181 // rows that it owns. If you try to make Proc 0 call
3182 // insertGlobalValues() for _all_ the rows, not just those it
3183 // owns, then fillComplete() will compute the number of
3184 // columns incorrectly. That's why Proc 0 has to distribute
3185 // the matrix data and why we make all the processors (not
3186 // just Proc 0) call insertGlobalValues() on their own data.
3187 //
3188 // These arrays represent each processor's part of the matrix
3189 // data, in "CSR" format (sort of, since the row indices might
3190 // not be contiguous).
3191 ArrayRCP<size_t> myNumEntriesPerRow;
3192 ArrayRCP<size_t> myRowPtr;
3193 ArrayRCP<global_ordinal_type> myColInd;
3194 ArrayRCP<scalar_type> myValues;
3195 // Distribute the matrix data. This is a collective operation.
3196 distribute (myNumEntriesPerRow, myRowPtr, myColInd, myValues, pRowMap,
3197 numEntriesPerRow, rowPtr, colInd, values, debug);
3198
3199 if (debug && myRank == rootRank) {
3200 cerr << "-- Inserting matrix entries on each process "
3201 "and calling fillComplete()" << endl;
3202 }
3203 // Each processor inserts its part of the matrix data, and
3204 // then they all call fillComplete(). This method invalidates
3205 // the my* distributed matrix data before calling
3206 // fillComplete(), in order to save space. In general, we
3207 // never store more than two copies of the matrix's entries in
3208 // memory at once, which is no worse than what Tpetra
3209 // promises.
3210 Teuchos::RCP<sparse_matrix_type> pMatrix =
3211 makeMatrix (myNumEntriesPerRow, myRowPtr, myColInd, myValues,
3212 pRowMap, pRangeMap, pDomainMap, constructorParams,
3213 fillCompleteParams);
3214 // Only use a reduce-all in debug mode to check if pMatrix is
3215 // null. Otherwise, just throw an exception. We never expect
3216 // a null pointer here, so we can save a communication.
3217 if (debug) {
3218 int localIsNull = pMatrix.is_null () ? 1 : 0;
3219 int globalIsNull = 0;
3220 reduceAll (*pComm, Teuchos::REDUCE_MAX, localIsNull, ptr (&globalIsNull));
3221 TEUCHOS_TEST_FOR_EXCEPTION(globalIsNull != 0, std::logic_error,
3222 "Reader::makeMatrix() returned a null pointer on at least one "
3223 "process. Please report this bug to the Tpetra developers.");
3224 }
3225 else {
3226 TEUCHOS_TEST_FOR_EXCEPTION(pMatrix.is_null(), std::logic_error,
3227 "Reader::makeMatrix() returned a null pointer. "
3228 "Please report this bug to the Tpetra developers.");
3229 }
3230
3231 // Sanity check for dimensions (read from the Matrix Market
3232 // data, vs. dimensions reported by the CrsMatrix).
3233 //
3234 // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
3235 // what one might think it does, so you have to ask the range
3236 // resp. domain map for the number of rows resp. columns.
3237 if (extraDebug && debug) {
3238 const int numProcs = pComm->getSize ();
3239 const global_size_t globalNumRows =
3240 pRangeMap->getGlobalNumElements();
3241 const global_size_t globalNumCols =
3242 pDomainMap->getGlobalNumElements();
3243 if (myRank == rootRank) {
3244 cerr << "-- Matrix is "
3245 << globalNumRows << " x " << globalNumCols
3246 << " with " << pMatrix->getGlobalNumEntries()
3247 << " entries, and index base "
3248 << pMatrix->getIndexBase() << "." << endl;
3249 }
3250 pComm->barrier ();
3251 for (int p = 0; p < numProcs; ++p) {
3252 if (myRank == p) {
3253 cerr << "-- Proc " << p << " owns "
3254 << pMatrix->getNodeNumCols() << " columns, and "
3255 << pMatrix->getNodeNumEntries() << " entries." << endl;
3256 }
3257 pComm->barrier ();
3258 }
3259 } // if (extraDebug && debug)
3260
3261 if (debug && myRank == rootRank) {
3262 cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
3263 << endl;
3264 }
3265 return pMatrix;
3266 }
3267
3268
3309 static Teuchos::RCP<sparse_matrix_type>
3310 readSparse (std::istream& in,
3311 const Teuchos::RCP<const map_type>& rowMap,
3312 Teuchos::RCP<const map_type>& colMap,
3313 const Teuchos::RCP<const map_type>& domainMap,
3314 const Teuchos::RCP<const map_type>& rangeMap,
3315 const bool callFillComplete=true,
3316 const bool tolerant=false,
3317 const bool debug=false)
3318 {
3319 using Teuchos::MatrixMarket::Banner;
3320 using Teuchos::arcp;
3321 using Teuchos::ArrayRCP;
3322 using Teuchos::ArrayView;
3323 using Teuchos::as;
3324 using Teuchos::broadcast;
3325 using Teuchos::Comm;
3326 using Teuchos::null;
3327 using Teuchos::ptr;
3328 using Teuchos::RCP;
3329 using Teuchos::reduceAll;
3330 using Teuchos::Tuple;
3331 using std::cerr;
3332 using std::endl;
3333 typedef Teuchos::ScalarTraits<scalar_type> STS;
3334
3335 RCP<const Comm<int> > pComm = rowMap->getComm ();
3336 const int myRank = pComm->getRank ();
3337 const int rootRank = 0;
3338 const bool extraDebug = false;
3339
3340 // Fast checks for invalid input. We can't check other
3341 // attributes of the Maps until we've read in the matrix
3342 // dimensions.
3343 TEUCHOS_TEST_FOR_EXCEPTION(
3344 rowMap.is_null (), std::invalid_argument,
3345 "Row Map must be nonnull.");
3346 TEUCHOS_TEST_FOR_EXCEPTION(
3347 rangeMap.is_null (), std::invalid_argument,
3348 "Range Map must be nonnull.");
3349 TEUCHOS_TEST_FOR_EXCEPTION(
3350 domainMap.is_null (), std::invalid_argument,
3351 "Domain Map must be nonnull.");
3352 TEUCHOS_TEST_FOR_EXCEPTION(
3353 rowMap->getComm().getRawPtr() != pComm.getRawPtr(),
3354 std::invalid_argument,
3355 "The specified row Map's communicator (rowMap->getComm())"
3356 "differs from the given separately supplied communicator pComm.");
3357 TEUCHOS_TEST_FOR_EXCEPTION(
3358 domainMap->getComm().getRawPtr() != pComm.getRawPtr(),
3359 std::invalid_argument,
3360 "The specified domain Map's communicator (domainMap->getComm())"
3361 "differs from the given separately supplied communicator pComm.");
3362 TEUCHOS_TEST_FOR_EXCEPTION(
3363 rangeMap->getComm().getRawPtr() != pComm.getRawPtr(),
3364 std::invalid_argument,
3365 "The specified range Map's communicator (rangeMap->getComm())"
3366 "differs from the given separately supplied communicator pComm.");
3367
3368 // Current line number in the input stream. Various calls
3369 // will modify this depending on the number of lines that are
3370 // read from the input stream. Only Rank 0 modifies this.
3371 size_t lineNumber = 1;
3372
3373 if (debug && myRank == rootRank) {
3374 cerr << "Matrix Market reader: readSparse:" << endl
3375 << "-- Reading banner line" << endl;
3376 }
3377
3378 // The "Banner" tells you whether the input stream represents
3379 // a sparse matrix, the symmetry type of the matrix, and the
3380 // type of the data it contains.
3381 //
3382 // pBanner will only be nonnull on MPI Rank 0. It will be
3383 // null on all other MPI processes.
3384 RCP<const Banner> pBanner;
3385 {
3386 // We read and validate the Banner on Proc 0, but broadcast
3387 // the validation result to all processes.
3388 // Teuchos::broadcast doesn't currently work with bool, so
3389 // we use int (true -> 1, false -> 0).
3390 int bannerIsCorrect = 1;
3391 std::ostringstream errMsg;
3392
3393 if (myRank == rootRank) {
3394 // Read the Banner line from the input stream.
3395 try {
3396 pBanner = readBanner (in, lineNumber, tolerant, debug);
3397 }
3398 catch (std::exception& e) {
3399 errMsg << "Attempt to read the Matrix Market file's Banner line "
3400 "threw an exception: " << e.what();
3401 bannerIsCorrect = 0;
3402 }
3403
3404 if (bannerIsCorrect) {
3405 // Validate the Banner for the case of a sparse matrix.
3406 // We validate on Proc 0, since it reads the Banner.
3407
3408 // In intolerant mode, the matrix type must be "coordinate".
3409 if (! tolerant && pBanner->matrixType() != "coordinate") {
3410 bannerIsCorrect = 0;
3411 errMsg << "The Matrix Market input file must contain a "
3412 "\"coordinate\"-format sparse matrix in order to create a "
3413 "Tpetra::CrsMatrix object from it, but the file's matrix "
3414 "type is \"" << pBanner->matrixType() << "\" instead.";
3415 }
3416 // In tolerant mode, we allow the matrix type to be
3417 // anything other than "array" (which would mean that
3418 // the file contains a dense matrix).
3419 if (tolerant && pBanner->matrixType() == "array") {
3420 bannerIsCorrect = 0;
3421 errMsg << "Matrix Market file must contain a \"coordinate\"-"
3422 "format sparse matrix in order to create a Tpetra::CrsMatrix "
3423 "object from it, but the file's matrix type is \"array\" "
3424 "instead. That probably means the file contains dense matrix "
3425 "data.";
3426 }
3427 }
3428 } // Proc 0: Done reading the Banner, hopefully successfully.
3429
3430 // Broadcast from Proc 0 whether the Banner was read correctly.
3431 broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
3432
3433 // If the Banner is invalid, all processes throw an
3434 // exception. Only Proc 0 gets the exception message, but
3435 // that's OK, since the main point is to "stop the world"
3436 // (rather than throw an exception on one process and leave
3437 // the others hanging).
3438 TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
3439 std::invalid_argument, errMsg.str ());
3440 } // Done reading the Banner line and broadcasting success.
3441 if (debug && myRank == rootRank) {
3442 cerr << "-- Reading dimensions line" << endl;
3443 }
3444
3445 // Read the matrix dimensions from the Matrix Market metadata.
3446 // dims = (numRows, numCols, numEntries). Proc 0 does the
3447 // reading, but it broadcasts the results to all MPI
3448 // processes. Thus, readCoordDims() is a collective
3449 // operation. It does a collective check for correctness too.
3450 Tuple<global_ordinal_type, 3> dims =
3451 readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
3452
3453 if (debug && myRank == rootRank) {
3454 cerr << "-- Making Adder for collecting matrix data" << endl;
3455 }
3456
3457 // "Adder" object for collecting all the sparse matrix entries
3458 // from the input stream. This is only nonnull on Proc 0.
3459 // The Adder internally converts the one-based indices (native
3460 // Matrix Market format) into zero-based indices.
3461 RCP<adder_type> pAdder =
3462 makeAdder (pComm, pBanner, dims, tolerant, debug);
3463
3464 if (debug && myRank == rootRank) {
3465 cerr << "-- Reading matrix data" << endl;
3466 }
3467 //
3468 // Read the matrix entries from the input stream on Proc 0.
3469 //
3470 {
3471 // We use readSuccess to broadcast the results of the read
3472 // (succeeded or not) to all MPI processes. Since
3473 // Teuchos::broadcast doesn't currently know how to send
3474 // bools, we convert to int (true -> 1, false -> 0).
3475 int readSuccess = 1;
3476 std::ostringstream errMsg; // Exception message (only valid on Proc 0)
3477 if (myRank == rootRank) {
3478 try {
3479 // Reader for "coordinate" format sparse matrix data.
3480 typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
3481 global_ordinal_type, scalar_type, STS::isComplex> reader_type;
3482 reader_type reader (pAdder);
3483
3484 // Read the sparse matrix entries.
3485 std::pair<bool, std::vector<size_t> > results =
3486 reader.read (in, lineNumber, tolerant, debug);
3487 readSuccess = results.first ? 1 : 0;
3488 }
3489 catch (std::exception& e) {
3490 readSuccess = 0;
3491 errMsg << e.what();
3492 }
3493 }
3494 broadcast (*pComm, rootRank, ptr (&readSuccess));
3495
3496 // It would be nice to add a "verbose" flag, so that in
3497 // tolerant mode, we could log any bad line number(s) on
3498 // Proc 0. For now, we just throw if the read fails to
3499 // succeed.
3500 //
3501 // Question: If we're in tolerant mode, and if the read did
3502 // not succeed, should we attempt to call fillComplete()?
3503 TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
3504 "Failed to read the Matrix Market sparse matrix file: "
3505 << errMsg.str());
3506 } // Done reading the matrix entries (stored on Proc 0 for now)
3507
3508 if (debug && myRank == rootRank) {
3509 cerr << "-- Successfully read the Matrix Market data" << endl;
3510 }
3511
3512 // In tolerant mode, we need to rebroadcast the matrix
3513 // dimensions, since they may be different after reading the
3514 // actual matrix data. We only need to broadcast the number
3515 // of rows and columns. Only Rank 0 needs to know the actual
3516 // global number of entries, since (a) we need to merge
3517 // duplicates on Rank 0 first anyway, and (b) when we
3518 // distribute the entries, each rank other than Rank 0 will
3519 // only need to know how many entries it owns, not the total
3520 // number of entries.
3521 if (tolerant) {
3522 if (debug && myRank == rootRank) {
3523 cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
3524 << endl
3525 << "----- Dimensions before: "
3526 << dims[0] << " x " << dims[1]
3527 << endl;
3528 }
3529 // Packed coordinate matrix dimensions (numRows, numCols).
3530 Tuple<global_ordinal_type, 2> updatedDims;
3531 if (myRank == rootRank) {
3532 // If one or more bottom rows of the matrix contain no
3533 // entries, then the Adder will report that the number
3534 // of rows is less than that specified in the
3535 // metadata. We allow this case, and favor the
3536 // metadata so that the zero row(s) will be included.
3537 updatedDims[0] =
3538 std::max (dims[0], pAdder->getAdder()->numRows());
3539 updatedDims[1] = pAdder->getAdder()->numCols();
3540 }
3541 broadcast (*pComm, rootRank, updatedDims);
3542 dims[0] = updatedDims[0];
3543 dims[1] = updatedDims[1];
3544 if (debug && myRank == rootRank) {
3545 cerr << "----- Dimensions after: " << dims[0] << " x "
3546 << dims[1] << endl;
3547 }
3548 }
3549 else {
3550 // In strict mode, we require that the matrix's metadata and
3551 // its actual data agree, at least somewhat. In particular,
3552 // the number of rows must agree, since otherwise we cannot
3553 // distribute the matrix correctly.
3554
3555 // Teuchos::broadcast() doesn't know how to broadcast bools,
3556 // so we use an int with the standard 1 == true, 0 == false
3557 // encoding.
3558 int dimsMatch = 1;
3559 if (myRank == rootRank) {
3560 // If one or more bottom rows of the matrix contain no
3561 // entries, then the Adder will report that the number of
3562 // rows is less than that specified in the metadata. We
3563 // allow this case, and favor the metadata, but do not
3564 // allow the Adder to think there are more rows in the
3565 // matrix than the metadata says.
3566 if (dims[0] < pAdder->getAdder ()->numRows ()) {
3567 dimsMatch = 0;
3568 }
3569 }
3570 broadcast (*pComm, 0, ptr (&dimsMatch));
3571 if (dimsMatch == 0) {
3572 // We're in an error state anyway, so we might as well
3573 // work a little harder to print an informative error
3574 // message.
3575 //
3576 // Broadcast the Adder's idea of the matrix dimensions
3577 // from Proc 0 to all processes.
3578 Tuple<global_ordinal_type, 2> addersDims;
3579 if (myRank == rootRank) {
3580 addersDims[0] = pAdder->getAdder()->numRows();
3581 addersDims[1] = pAdder->getAdder()->numCols();
3582 }
3583 broadcast (*pComm, 0, addersDims);
3584 TEUCHOS_TEST_FOR_EXCEPTION(
3585 dimsMatch == 0, std::runtime_error,
3586 "The matrix metadata says that the matrix is " << dims[0] << " x "
3587 << dims[1] << ", but the actual data says that the matrix is "
3588 << addersDims[0] << " x " << addersDims[1] << ". That means the "
3589 "data includes more rows than reported in the metadata. This "
3590 "is not allowed when parsing in strict mode. Parse the matrix in "
3591 "tolerant mode to ignore the metadata when it disagrees with the "
3592 "data.");
3593 }
3594 } // Matrix dimensions (# rows, # cols, # entries) agree.
3595
3596 if (debug && myRank == rootRank) {
3597 cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
3598 }
3599
3600 // Now that we've read in all the matrix entries from the
3601 // input stream into the adder on Proc 0, post-process them
3602 // into CSR format (still on Proc 0). This will facilitate
3603 // distributing them to all the processors.
3604 //
3605 // These arrays represent the global matrix data as a CSR
3606 // matrix (with numEntriesPerRow as redundant but convenient
3607 // metadata, since it's computable from rowPtr and vice
3608 // versa). They are valid only on Proc 0.
3609 ArrayRCP<size_t> numEntriesPerRow;
3610 ArrayRCP<size_t> rowPtr;
3611 ArrayRCP<global_ordinal_type> colInd;
3612 ArrayRCP<scalar_type> values;
3613 size_t maxNumEntriesPerRow = 0;
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->getNodeElementList ();
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 if (gatherNumEntriesPerRow[i_] > maxNumEntriesPerRow)
3795 maxNumEntriesPerRow = gatherNumEntriesPerRow[i_];
3796 }
3797
3798 // Create a matrix using this Map, and fill in on Proc 0. We
3799 // know how many entries there are in each row, so we can use
3800 // static profile.
3801 RCP<sparse_matrix_type> A_proc0 =
3802 rcp (new sparse_matrix_type (gatherRowMap, gatherNumEntriesPerRow (),
3803 Tpetra::StaticProfile));
3804 if (myRank == rootRank) {
3805 if (debug) {
3806 cerr << "-- Proc 0: Filling gather matrix" << endl;
3807 }
3808 if (debug) {
3809 cerr << "---- Rows: " << Teuchos::toString (myRows) << endl;
3810 }
3811
3812 // Add Proc 0's matrix entries to the CrsMatrix.
3813 for (size_type i_ = 0; i_ < myNumRows; ++i_) {
3814 size_type i = myRows[i_] - indexBase;
3815
3816 const size_type curPos = as<size_type> (rowPtr[i]);
3817 const local_ordinal_type curNumEntries = numEntriesPerRow[i];
3818 ArrayView<global_ordinal_type> curColInd =
3819 colInd.view (curPos, curNumEntries);
3820 ArrayView<scalar_type> curValues =
3821 values.view (curPos, curNumEntries);
3822
3823 // Modify the column indices in place to have the right index base.
3824 for (size_type k = 0; k < curNumEntries; ++k) {
3825 curColInd[k] += indexBase;
3826 }
3827 if (debug) {
3828 cerr << "------ Columns: " << Teuchos::toString (curColInd) << endl;
3829 cerr << "------ Values: " << Teuchos::toString (curValues) << endl;
3830 }
3831 // Avoid constructing empty views of ArrayRCP objects.
3832 if (curNumEntries > 0) {
3833 A_proc0->insertGlobalValues (myRows[i_], curColInd, curValues);
3834 }
3835 }
3836 // Now we can save space by deallocating numEntriesPerRow,
3837 // rowPtr, colInd, and values, since we've already put those
3838 // data in the matrix.
3839 numEntriesPerRow = null;
3840 rowPtr = null;
3841 colInd = null;
3842 values = null;
3843 } // if myRank == rootRank
3844
3845 broadcast<int,size_t> (*pComm, 0, &maxNumEntriesPerRow);
3846
3847 RCP<sparse_matrix_type> A;
3848 if (colMap.is_null ()) {
3849 A = rcp (new sparse_matrix_type (rowMap, maxNumEntriesPerRow));
3850 } else {
3851 A = rcp (new sparse_matrix_type (rowMap, colMap, maxNumEntriesPerRow));
3852 }
3854 export_type exp (gatherRowMap, rowMap);
3855 A->doExport (*A_proc0, exp, INSERT);
3856
3857 if (callFillComplete) {
3858 A->fillComplete (domainMap, rangeMap);
3859 }
3860
3861 // We can't get the dimensions of the matrix until after
3862 // fillComplete() is called. Thus, we can't do the sanity
3863 // check (dimensions read from the Matrix Market data,
3864 // vs. dimensions reported by the CrsMatrix) unless the user
3865 // asked us to call fillComplete().
3866 //
3867 // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
3868 // what one might think it does, so you have to ask the range
3869 // resp. domain map for the number of rows resp. columns.
3870 if (callFillComplete) {
3871 const int numProcs = pComm->getSize ();
3872
3873 if (extraDebug && debug) {
3874 const global_size_t globalNumRows = rangeMap->getGlobalNumElements ();
3875 const global_size_t globalNumCols = domainMap->getGlobalNumElements ();
3876 if (myRank == rootRank) {
3877 cerr << "-- Matrix is "
3878 << globalNumRows << " x " << globalNumCols
3879 << " with " << A->getGlobalNumEntries()
3880 << " entries, and index base "
3881 << A->getIndexBase() << "." << endl;
3882 }
3883 pComm->barrier ();
3884 for (int p = 0; p < numProcs; ++p) {
3885 if (myRank == p) {
3886 cerr << "-- Proc " << p << " owns "
3887 << A->getNodeNumCols() << " columns, and "
3888 << A->getNodeNumEntries() << " entries." << endl;
3889 }
3890 pComm->barrier ();
3891 }
3892 } // if (extraDebug && debug)
3893 } // if (callFillComplete)
3894
3895 if (debug && myRank == rootRank) {
3896 cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
3897 << endl;
3898 }
3899 return A;
3900 }
3901
3930 static Teuchos::RCP<multivector_type>
3931 readDenseFile (const std::string& filename,
3932 const Teuchos::RCP<const comm_type>& comm,
3933 Teuchos::RCP<const map_type>& map,
3934 const bool tolerant=false,
3935 const bool debug=false)
3936 {
3937 using Teuchos::broadcast;
3938 using Teuchos::outArg;
3939
3940 std::ifstream in;
3941 int opened = 0;
3942 if (comm->getRank() == 0) {
3943 try {
3944 in.open (filename.c_str ());
3945 opened = in.is_open();
3946 }
3947 catch (...) {
3948 opened = 0;
3949 }
3950 }
3951 broadcast<int, int> (*comm, 0, outArg (opened));
3952 TEUCHOS_TEST_FOR_EXCEPTION(
3953 opened == 0, std::runtime_error,
3954 "readDenseFile: Failed to open file \"" << filename << "\" on "
3955 "Process 0.");
3956 return readDense (in, comm, map, tolerant, debug);
3957 }
3958
3959
3989 static Teuchos::RCP<vector_type>
3990 readVectorFile (const std::string& filename,
3991 const Teuchos::RCP<const comm_type>& comm,
3992 Teuchos::RCP<const map_type>& map,
3993 const bool tolerant=false,
3994 const bool debug=false)
3995 {
3996 using Teuchos::broadcast;
3997 using Teuchos::outArg;
3998
3999 std::ifstream in;
4000 int opened = 0;
4001 if (comm->getRank() == 0) {
4002 try {
4003 in.open (filename.c_str ());
4004 opened = in.is_open();
4005 }
4006 catch (...) {
4007 opened = 0;
4008 }
4009 }
4010 broadcast<int, int> (*comm, 0, outArg (opened));
4011 TEUCHOS_TEST_FOR_EXCEPTION(
4012 opened == 0, std::runtime_error,
4013 "readVectorFile: Failed to open file \"" << filename << "\" on "
4014 "Process 0.");
4015 return readVector (in, comm, map, tolerant, debug);
4016 }
4017
4018
4085 static Teuchos::RCP<multivector_type>
4086 readDense (std::istream& in,
4087 const Teuchos::RCP<const comm_type>& comm,
4088 Teuchos::RCP<const map_type>& map,
4089 const bool tolerant=false,
4090 const bool debug=false)
4091 {
4092 Teuchos::RCP<Teuchos::FancyOStream> err =
4093 Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
4094 return readDenseImpl<scalar_type> (in, comm, map, err, tolerant, debug);
4095 }
4096
4097
4099 static Teuchos::RCP<vector_type>
4100 readVector (std::istream& in,
4101 const Teuchos::RCP<const comm_type>& comm,
4102 Teuchos::RCP<const map_type>& map,
4103 const bool tolerant=false,
4104 const bool debug=false)
4105 {
4106 Teuchos::RCP<Teuchos::FancyOStream> err =
4107 Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
4108 return readVectorImpl<scalar_type> (in, comm, map, err, tolerant, debug);
4109 }
4110
4111
4132 static Teuchos::RCP<const map_type>
4133 readMapFile (const std::string& filename,
4134 const Teuchos::RCP<const comm_type>& comm,
4135 const bool tolerant=false,
4136 const bool debug=false)
4137 {
4138 using Teuchos::inOutArg;
4139 using Teuchos::broadcast;
4140 std::ifstream in;
4141
4142 int success = 1;
4143 if (comm->getRank () == 0) { // Only open the file on Proc 0.
4144 in.open (filename.c_str ()); // Destructor closes safely
4145 if (! in) {
4146 success = 0;
4147 }
4148 }
4149 broadcast<int, int> (*comm, 0, inOutArg (success));
4150 TEUCHOS_TEST_FOR_EXCEPTION(
4151 success == 0, std::runtime_error,
4152 "Tpetra::MatrixMarket::Reader::readMapFile: "
4153 "Failed to read file \"" << filename << "\" on Process 0.");
4154 return readMap (in, comm, tolerant, debug);
4155 }
4156
4157
4158 private:
4159 template<class MultiVectorScalarType>
4160 static Teuchos::RCP<Tpetra::MultiVector<MultiVectorScalarType,
4163 node_type> >
4164 readDenseImpl (std::istream& in,
4165 const Teuchos::RCP<const comm_type>& comm,
4166 Teuchos::RCP<const map_type>& map,
4167 const Teuchos::RCP<Teuchos::FancyOStream>& err,
4168 const bool tolerant=false,
4169 const bool debug=false)
4170 {
4171 using Teuchos::MatrixMarket::Banner;
4172 using Teuchos::MatrixMarket::checkCommentLine;
4173 using Teuchos::ArrayRCP;
4174 using Teuchos::as;
4175 using Teuchos::broadcast;
4176 using Teuchos::outArg;
4177 using Teuchos::RCP;
4178 using Teuchos::Tuple;
4179 using std::endl;
4180 typedef MultiVectorScalarType ST;
4181 typedef local_ordinal_type LO;
4182 typedef global_ordinal_type GO;
4183 typedef node_type NT;
4184 typedef Teuchos::ScalarTraits<ST> STS;
4185 typedef typename STS::magnitudeType MT;
4186 typedef Teuchos::ScalarTraits<MT> STM;
4188
4189 // Rank 0 is the only (MPI) process allowed to read from the
4190 // input stream.
4191 const int myRank = comm->getRank ();
4192
4193 if (! err.is_null ()) {
4194 err->pushTab ();
4195 }
4196 if (debug) {
4197 *err << myRank << ": readDenseImpl" << endl;
4198 }
4199 if (! err.is_null ()) {
4200 err->pushTab ();
4201 }
4202
4203 // mfh 17 Feb 2013: It's not strictly necessary that the Comm
4204 // instances be identical and that the Node instances be
4205 // identical. The essential condition is more complicated to
4206 // test and isn't the same for all Node types. Thus, we just
4207 // leave it up to the user.
4208
4209 // // If map is nonnull, check the precondition that its
4210 // // communicator resp. node equal comm resp. node. Checking
4211 // // now avoids doing a lot of file reading before we detect the
4212 // // violated precondition.
4213 // TEUCHOS_TEST_FOR_EXCEPTION(
4214 // ! map.is_null() && (map->getComm() != comm || map->getNode () != node,
4215 // std::invalid_argument, "If you supply a nonnull Map, the Map's "
4216 // "communicator and node must equal the supplied communicator resp. "
4217 // "node.");
4218
4219 // Process 0 will read in the matrix dimensions from the file,
4220 // and broadcast them to all ranks in the given communicator.
4221 // There are only 2 dimensions in the matrix, but we use the
4222 // third element of the Tuple to encode the banner's reported
4223 // data type: "real" == 0, "complex" == 1, and "integer" == 0
4224 // (same as "real"). We don't allow pattern matrices (i.e.,
4225 // graphs) since they only make sense for sparse data.
4226 Tuple<GO, 3> dims;
4227 dims[0] = 0;
4228 dims[1] = 0;
4229
4230 // Current line number in the input stream. Only valid on
4231 // Proc 0. Various calls will modify this depending on the
4232 // number of lines that are read from the input stream.
4233 size_t lineNumber = 1;
4234
4235 // Capture errors and their messages on Proc 0.
4236 std::ostringstream exMsg;
4237 int localBannerReadSuccess = 1;
4238 int localDimsReadSuccess = 1;
4239
4240 // Only Proc 0 gets to read matrix data from the input stream.
4241 if (myRank == 0) {
4242 if (debug) {
4243 *err << myRank << ": readDenseImpl: Reading banner line (dense)" << endl;
4244 }
4245
4246 // The "Banner" tells you whether the input stream
4247 // represents a dense matrix, the symmetry type of the
4248 // matrix, and the type of the data it contains.
4249 RCP<const Banner> pBanner;
4250 try {
4251 pBanner = readBanner (in, lineNumber, tolerant, debug);
4252 } catch (std::exception& e) {
4253 exMsg << e.what ();
4254 localBannerReadSuccess = 0;
4255 }
4256 // Make sure the input stream is the right kind of data.
4257 if (localBannerReadSuccess) {
4258 if (pBanner->matrixType () != "array") {
4259 exMsg << "The Matrix Market file does not contain dense matrix "
4260 "data. Its banner (first) line says that its matrix type is \""
4261 << pBanner->matrixType () << "\", rather that the required "
4262 "\"array\".";
4263 localBannerReadSuccess = 0;
4264 } else if (pBanner->dataType() == "pattern") {
4265 exMsg << "The Matrix Market file's banner (first) "
4266 "line claims that the matrix's data type is \"pattern\". This does "
4267 "not make sense for a dense matrix, yet the file reports the matrix "
4268 "as dense. The only valid data types for a dense matrix are "
4269 "\"real\", \"complex\", and \"integer\".";
4270 localBannerReadSuccess = 0;
4271 } else {
4272 // Encode the data type reported by the Banner as the
4273 // third element of the dimensions Tuple.
4274 dims[2] = encodeDataType (pBanner->dataType ());
4275 }
4276 } // if we successfully read the banner line
4277
4278 // At this point, we've successfully read the banner line.
4279 // Now read the dimensions line.
4280 if (localBannerReadSuccess) {
4281 if (debug) {
4282 *err << myRank << ": readDenseImpl: Reading dimensions line (dense)" << endl;
4283 }
4284 // Keep reading lines from the input stream until we find
4285 // a non-comment line, or until we run out of lines. The
4286 // latter is an error, since every "array" format Matrix
4287 // Market file must have a dimensions line after the
4288 // banner (even if the matrix has zero rows or columns, or
4289 // zero entries).
4290 std::string line;
4291 bool commentLine = true;
4292
4293 while (commentLine) {
4294 // Test whether it is even valid to read from the input
4295 // stream wrapping the line.
4296 if (in.eof () || in.fail ()) {
4297 exMsg << "Unable to get array dimensions line (at all) from line "
4298 << lineNumber << " of input stream. The input stream "
4299 << "claims that it is "
4300 << (in.eof() ? "at end-of-file." : "in a failed state.");
4301 localDimsReadSuccess = 0;
4302 } else {
4303 // Try to get the next line from the input stream.
4304 if (getline (in, line)) {
4305 ++lineNumber; // We did actually read a line.
4306 }
4307 // Is the current line a comment line? Ignore start
4308 // and size; they are only useful for reading the
4309 // actual matrix entries. (We could use them here as
4310 // an optimization, but we've chosen not to.)
4311 size_t start = 0, size = 0;
4312 commentLine = checkCommentLine (line, start, size, lineNumber, tolerant);
4313 } // whether we failed to read the line at all
4314 } // while the line we just read is a comment line
4315
4316 //
4317 // Get <numRows> <numCols> from the line we just read.
4318 //
4319 std::istringstream istr (line);
4320
4321 // Test whether it is even valid to read from the input
4322 // stream wrapping the line.
4323 if (istr.eof () || istr.fail ()) {
4324 exMsg << "Unable to read any data from line " << lineNumber
4325 << " of input; the line should contain the matrix dimensions "
4326 << "\"<numRows> <numCols>\".";
4327 localDimsReadSuccess = 0;
4328 } else { // It's valid to read from the line.
4329 GO theNumRows = 0;
4330 istr >> theNumRows; // Read in the number of rows.
4331 if (istr.fail ()) {
4332 exMsg << "Failed to get number of rows from line "
4333 << lineNumber << " of input; the line should contains the "
4334 << "matrix dimensions \"<numRows> <numCols>\".";
4335 localDimsReadSuccess = 0;
4336 } else { // We successfully read the number of rows
4337 dims[0] = theNumRows; // Save the number of rows
4338 if (istr.eof ()) { // Do we still have data to read?
4339 exMsg << "No more data after number of rows on line "
4340 << lineNumber << " of input; the line should contain the "
4341 << "matrix dimensions \"<numRows> <numCols>\".";
4342 localDimsReadSuccess = 0;
4343 } else { // Still data left to read; read in number of columns.
4344 GO theNumCols = 0;
4345 istr >> theNumCols; // Read in the number of columns
4346 if (istr.fail ()) {
4347 exMsg << "Failed to get number of columns from line "
4348 << lineNumber << " of input; the line should contain "
4349 << "the matrix dimensions \"<numRows> <numCols>\".";
4350 localDimsReadSuccess = 0;
4351 } else { // We successfully read the number of columns
4352 dims[1] = theNumCols; // Save the number of columns
4353 } // if istr.fail ()
4354 } // if istr.eof ()
4355 } // if we read the number of rows
4356 } // if the input stream wrapping the dims line was (in)valid
4357 } // if we successfully read the banner line
4358 } // if (myRank == 0)
4359
4360 // Broadcast the matrix dimensions, the encoded data type, and
4361 // whether or not Proc 0 succeeded in reading the banner and
4362 // dimensions.
4363 Tuple<GO, 5> bannerDimsReadResult;
4364 if (myRank == 0) {
4365 bannerDimsReadResult[0] = dims[0]; // numRows
4366 bannerDimsReadResult[1] = dims[1]; // numCols
4367 bannerDimsReadResult[2] = dims[2]; // encoded data type
4368 bannerDimsReadResult[3] = localBannerReadSuccess;
4369 bannerDimsReadResult[4] = localDimsReadSuccess;
4370 }
4371 // Broadcast matrix dimensions and the encoded data type from
4372 // Proc 0 to all the MPI processes.
4373 broadcast (*comm, 0, bannerDimsReadResult);
4374
4375 TEUCHOS_TEST_FOR_EXCEPTION(
4376 bannerDimsReadResult[3] == 0, std::runtime_error,
4377 "Failed to read banner line: " << exMsg.str ());
4378 TEUCHOS_TEST_FOR_EXCEPTION(
4379 bannerDimsReadResult[4] == 0, std::runtime_error,
4380 "Failed to read matrix dimensions line: " << exMsg.str ());
4381 if (myRank != 0) {
4382 dims[0] = bannerDimsReadResult[0];
4383 dims[1] = bannerDimsReadResult[1];
4384 dims[2] = bannerDimsReadResult[2];
4385 }
4386
4387 // Tpetra objects want the matrix dimensions in these types.
4388 const global_size_t numRows = static_cast<global_size_t> (dims[0]);
4389 const size_t numCols = static_cast<size_t> (dims[1]);
4390
4391 // Make a "Proc 0 owns everything" Map that we will use to
4392 // read in the multivector entries in the correct order on
4393 // Proc 0. This must be a collective
4394 RCP<const map_type> proc0Map; // "Proc 0 owns everything" Map
4395 if (map.is_null ()) {
4396 // The user didn't supply a Map. Make a contiguous
4397 // distributed Map for them, using the read-in multivector
4398 // dimensions.
4399 map = createUniformContigMapWithNode<LO, GO, NT> (numRows, comm);
4400 const size_t localNumRows = (myRank == 0) ? numRows : 0;
4401 // At this point, map exists and has a nonnull node.
4402 proc0Map = createContigMapWithNode<LO, GO, NT> (numRows, localNumRows,
4403 comm);
4404 }
4405 else { // The user supplied a Map.
4406 proc0Map = Details::computeGatherMap<map_type> (map, err, debug);
4407 }
4408
4409 // Make a multivector X owned entirely by Proc 0.
4410 RCP<MV> X = createMultiVector<ST, LO, GO, NT> (proc0Map, numCols);
4411
4412 //
4413 // On Proc 0, read the Matrix Market data from the input
4414 // stream into the multivector X.
4415 //
4416 int localReadDataSuccess = 1;
4417 if (myRank == 0) {
4418 try {
4419 if (debug) {
4420 *err << myRank << ": readDenseImpl: Reading matrix data (dense)"
4421 << endl;
4422 }
4423
4424 // Make sure that we can get a 1-D view of X.
4425 TEUCHOS_TEST_FOR_EXCEPTION(
4426 ! X->isConstantStride (), std::logic_error,
4427 "Can't get a 1-D view of the entries of the MultiVector X on "
4428 "Process 0, because the stride between the columns of X is not "
4429 "constant. This shouldn't happen because we just created X and "
4430 "haven't filled it in yet. Please report this bug to the Tpetra "
4431 "developers.");
4432
4433 // Get a writeable 1-D view of the entries of X. Rank 0
4434 // owns all of them. The view will expire at the end of
4435 // scope, so (if necessary) it will be written back to X
4436 // at this time.
4437 ArrayRCP<ST> X_view = X->get1dViewNonConst ();
4438 TEUCHOS_TEST_FOR_EXCEPTION(
4439 as<global_size_t> (X_view.size ()) < numRows * numCols,
4440 std::logic_error,
4441 "The view of X has size " << X_view << " which is not enough to "
4442 "accommodate the expected number of entries numRows*numCols = "
4443 << numRows << "*" << numCols << " = " << numRows*numCols << ". "
4444 "Please report this bug to the Tpetra developers.");
4445 const size_t stride = X->getStride ();
4446
4447 // The third element of the dimensions Tuple encodes the data
4448 // type reported by the Banner: "real" == 0, "complex" == 1,
4449 // "integer" == 0 (same as "real"), "pattern" == 2. We do not
4450 // allow dense matrices to be pattern matrices, so dims[2] ==
4451 // 0 or 1. We've already checked for this above.
4452 const bool isComplex = (dims[2] == 1);
4453 size_type count = 0, curRow = 0, curCol = 0;
4454
4455 std::string line;
4456 while (getline (in, line)) {
4457 ++lineNumber;
4458 // Is the current line a comment line? If it's not,
4459 // line.substr(start,size) contains the data.
4460 size_t start = 0, size = 0;
4461 const bool commentLine =
4462 checkCommentLine (line, start, size, lineNumber, tolerant);
4463 if (! commentLine) {
4464 // Make sure we have room in which to put the new matrix
4465 // entry. We check this only after checking for a
4466 // comment line, because there may be one or more
4467 // comment lines at the end of the file. In tolerant
4468 // mode, we simply ignore any extra data.
4469 if (count >= X_view.size()) {
4470 if (tolerant) {
4471 break;
4472 }
4473 else {
4474 TEUCHOS_TEST_FOR_EXCEPTION(
4475 count >= X_view.size(),
4476 std::runtime_error,
4477 "The Matrix Market input stream has more data in it than "
4478 "its metadata reported. Current line number is "
4479 << lineNumber << ".");
4480 }
4481 }
4482
4483 // mfh 19 Dec 2012: Ignore everything up to the initial
4484 // colon. writeDense() has the option to print out the
4485 // global row index in front of each entry, followed by
4486 // a colon and space.
4487 {
4488 const size_t pos = line.substr (start, size).find (':');
4489 if (pos != std::string::npos) {
4490 start = pos+1;
4491 }
4492 }
4493 std::istringstream istr (line.substr (start, size));
4494 // Does the line contain anything at all? Can we
4495 // safely read from the input stream wrapping the
4496 // line?
4497 if (istr.eof() || istr.fail()) {
4498 // In tolerant mode, simply ignore the line.
4499 if (tolerant) {
4500 break;
4501 }
4502 // We repeat the full test here so the exception
4503 // message is more informative.
4504 TEUCHOS_TEST_FOR_EXCEPTION(
4505 ! tolerant && (istr.eof() || istr.fail()),
4506 std::runtime_error,
4507 "Line " << lineNumber << " of the Matrix Market file is "
4508 "empty, or we cannot read from it for some other reason.");
4509 }
4510 // Current matrix entry to read in.
4511 ST val = STS::zero();
4512 // Real and imaginary parts of the current matrix entry.
4513 // The imaginary part is zero if the matrix is real-valued.
4514 MT real = STM::zero(), imag = STM::zero();
4515
4516 // isComplex refers to the input stream's data, not to
4517 // the scalar type S. It's OK to read real-valued
4518 // data into a matrix storing complex-valued data; in
4519 // that case, all entries' imaginary parts are zero.
4520 if (isComplex) {
4521 // STS::real() and STS::imag() return a copy of
4522 // their respective components, not a writeable
4523 // reference. Otherwise we could just assign to
4524 // them using the istream extraction operator (>>).
4525 // That's why we have separate magnitude type "real"
4526 // and "imag" variables.
4527
4528 // Attempt to read the real part of the current entry.
4529 istr >> real;
4530 if (istr.fail()) {
4531 TEUCHOS_TEST_FOR_EXCEPTION(
4532 ! tolerant && istr.eof(), std::runtime_error,
4533 "Failed to get the real part of a complex-valued matrix "
4534 "entry from line " << lineNumber << " of the Matrix Market "
4535 "file.");
4536 // In tolerant mode, just skip bad lines.
4537 if (tolerant) {
4538 break;
4539 }
4540 } else if (istr.eof()) {
4541 TEUCHOS_TEST_FOR_EXCEPTION(
4542 ! tolerant && istr.eof(), std::runtime_error,
4543 "Missing imaginary part of a complex-valued matrix entry "
4544 "on line " << lineNumber << " of the Matrix Market file.");
4545 // In tolerant mode, let any missing imaginary part be 0.
4546 } else {
4547 // Attempt to read the imaginary part of the current
4548 // matrix entry.
4549 istr >> imag;
4550 TEUCHOS_TEST_FOR_EXCEPTION(
4551 ! tolerant && istr.fail(), std::runtime_error,
4552 "Failed to get the imaginary part of a complex-valued "
4553 "matrix entry from line " << lineNumber << " of the "
4554 "Matrix Market file.");
4555 // In tolerant mode, let any missing or corrupted
4556 // imaginary part be 0.
4557 }
4558 } else { // Matrix Market file contains real-valued data.
4559 // Attempt to read the current matrix entry.
4560 istr >> real;
4561 TEUCHOS_TEST_FOR_EXCEPTION(
4562 ! tolerant && istr.fail(), std::runtime_error,
4563 "Failed to get a real-valued matrix entry from line "
4564 << lineNumber << " of the Matrix Market file.");
4565 // In tolerant mode, simply ignore the line if
4566 // we failed to read a matrix entry.
4567 if (istr.fail() && tolerant) {
4568 break;
4569 }
4570 }
4571 // In tolerant mode, we simply let pass through whatever
4572 // data we got.
4573 TEUCHOS_TEST_FOR_EXCEPTION(
4574 ! tolerant && istr.fail(), std::runtime_error,
4575 "Failed to read matrix data from line " << lineNumber
4576 << " of the Matrix Market file.");
4577
4578 // Assign val = ST(real, imag).
4579 Teuchos::MatrixMarket::details::assignScalar<ST> (val, real, imag);
4580
4581 curRow = count % numRows;
4582 curCol = count / numRows;
4583 X_view[curRow + curCol*stride] = val;
4584 ++count;
4585 } // if not a comment line
4586 } // while there are still lines in the file, get the next one
4587
4588 TEUCHOS_TEST_FOR_EXCEPTION(
4589 ! tolerant && static_cast<global_size_t> (count) < numRows * numCols,
4590 std::runtime_error,
4591 "The Matrix Market metadata reports that the dense matrix is "
4592 << numRows << " x " << numCols << ", and thus has "
4593 << numRows*numCols << " total entries, but we only found " << count
4594 << " entr" << (count == 1 ? "y" : "ies") << " in the file.");
4595 } catch (std::exception& e) {
4596 exMsg << e.what ();
4597 localReadDataSuccess = 0;
4598 }
4599 } // if (myRank == 0)
4600
4601 if (debug) {
4602 *err << myRank << ": readDenseImpl: done reading data" << endl;
4603 }
4604
4605 // Synchronize on whether Proc 0 successfully read the data.
4606 int globalReadDataSuccess = localReadDataSuccess;
4607 broadcast (*comm, 0, outArg (globalReadDataSuccess));
4608 TEUCHOS_TEST_FOR_EXCEPTION(
4609 globalReadDataSuccess == 0, std::runtime_error,
4610 "Failed to read the multivector's data: " << exMsg.str ());
4611
4612 // If there's only one MPI process and the user didn't supply
4613 // a Map (i.e., pMap is null), we're done. Set pMap to the
4614 // Map used to distribute X, and return X.
4615 if (comm->getSize () == 1 && map.is_null ()) {
4616 map = proc0Map;
4617 if (! err.is_null ()) {
4618 err->popTab ();
4619 }
4620 if (debug) {
4621 *err << myRank << ": readDenseImpl: done" << endl;
4622 }
4623 if (! err.is_null ()) {
4624 err->popTab ();
4625 }
4626 return X;
4627 }
4628
4629 if (debug) {
4630 *err << myRank << ": readDenseImpl: Creating target MV" << endl;
4631 }
4632
4633 // Make a multivector Y with the distributed map pMap.
4634 RCP<MV> Y = createMultiVector<ST, LO, GO, NT> (map, numCols);
4635
4636 if (debug) {
4637 *err << myRank << ": readDenseImpl: Creating Export" << endl;
4638 }
4639
4640 // Make an Export object that will export X to Y. First
4641 // argument is the source map, second argument is the target
4642 // map.
4643 Export<LO, GO, NT> exporter (proc0Map, map, err);
4644
4645 if (debug) {
4646 *err << myRank << ": readDenseImpl: Exporting" << endl;
4647 }
4648 // Export X into Y.
4649 Y->doExport (*X, exporter, INSERT);
4650
4651 if (! err.is_null ()) {
4652 err->popTab ();
4653 }
4654 if (debug) {
4655 *err << myRank << ": readDenseImpl: done" << endl;
4656 }
4657 if (! err.is_null ()) {
4658 err->popTab ();
4659 }
4660
4661 // Y is distributed over all process(es) in the communicator.
4662 return Y;
4663 }
4664
4665
4666 template<class VectorScalarType>
4667 static Teuchos::RCP<Tpetra::Vector<VectorScalarType,
4670 node_type> >
4671 readVectorImpl (std::istream& in,
4672 const Teuchos::RCP<const comm_type>& comm,
4673 Teuchos::RCP<const map_type>& map,
4674 const Teuchos::RCP<Teuchos::FancyOStream>& err,
4675 const bool tolerant=false,
4676 const bool debug=false)
4677 {
4678 using Teuchos::MatrixMarket::Banner;
4679 using Teuchos::MatrixMarket::checkCommentLine;
4680 using Teuchos::as;
4681 using Teuchos::broadcast;
4682 using Teuchos::outArg;
4683 using Teuchos::RCP;
4684 using Teuchos::Tuple;
4685 using std::endl;
4686 typedef VectorScalarType ST;
4687 typedef local_ordinal_type LO;
4688 typedef global_ordinal_type GO;
4689 typedef node_type NT;
4690 typedef Teuchos::ScalarTraits<ST> STS;
4691 typedef typename STS::magnitudeType MT;
4692 typedef Teuchos::ScalarTraits<MT> STM;
4694
4695 // Rank 0 is the only (MPI) process allowed to read from the
4696 // input stream.
4697 const int myRank = comm->getRank ();
4698
4699 if (! err.is_null ()) {
4700 err->pushTab ();
4701 }
4702 if (debug) {
4703 *err << myRank << ": readVectorImpl" << endl;
4704 }
4705 if (! err.is_null ()) {
4706 err->pushTab ();
4707 }
4708
4709 // mfh 17 Feb 2013: It's not strictly necessary that the Comm
4710 // instances be identical and that the Node instances be
4711 // identical. The essential condition is more complicated to
4712 // test and isn't the same for all Node types. Thus, we just
4713 // leave it up to the user.
4714
4715 // // If map is nonnull, check the precondition that its
4716 // // communicator resp. node equal comm resp. node. Checking
4717 // // now avoids doing a lot of file reading before we detect the
4718 // // violated precondition.
4719 // TEUCHOS_TEST_FOR_EXCEPTION(
4720 // ! map.is_null() && (map->getComm() != comm || map->getNode () != node,
4721 // std::invalid_argument, "If you supply a nonnull Map, the Map's "
4722 // "communicator and node must equal the supplied communicator resp. "
4723 // "node.");
4724
4725 // Process 0 will read in the matrix dimensions from the file,
4726 // and broadcast them to all ranks in the given communicator.
4727 // There are only 2 dimensions in the matrix, but we use the
4728 // third element of the Tuple to encode the banner's reported
4729 // data type: "real" == 0, "complex" == 1, and "integer" == 0
4730 // (same as "real"). We don't allow pattern matrices (i.e.,
4731 // graphs) since they only make sense for sparse data.
4732 Tuple<GO, 3> dims;
4733 dims[0] = 0;
4734 dims[1] = 0;
4735
4736 // Current line number in the input stream. Only valid on
4737 // Proc 0. Various calls will modify this depending on the
4738 // number of lines that are read from the input stream.
4739 size_t lineNumber = 1;
4740
4741 // Capture errors and their messages on Proc 0.
4742 std::ostringstream exMsg;
4743 int localBannerReadSuccess = 1;
4744 int localDimsReadSuccess = 1;
4745
4746 // Only Proc 0 gets to read matrix data from the input stream.
4747 if (myRank == 0) {
4748 if (debug) {
4749 *err << myRank << ": readVectorImpl: Reading banner line (dense)" << endl;
4750 }
4751
4752 // The "Banner" tells you whether the input stream
4753 // represents a dense matrix, the symmetry type of the
4754 // matrix, and the type of the data it contains.
4755 RCP<const Banner> pBanner;
4756 try {
4757 pBanner = readBanner (in, lineNumber, tolerant, debug);
4758 } catch (std::exception& e) {
4759 exMsg << e.what ();
4760 localBannerReadSuccess = 0;
4761 }
4762 // Make sure the input stream is the right kind of data.
4763 if (localBannerReadSuccess) {
4764 if (pBanner->matrixType () != "array") {
4765 exMsg << "The Matrix Market file does not contain dense matrix "
4766 "data. Its banner (first) line says that its matrix type is \""
4767 << pBanner->matrixType () << "\", rather that the required "
4768 "\"array\".";
4769 localBannerReadSuccess = 0;
4770 } else if (pBanner->dataType() == "pattern") {
4771 exMsg << "The Matrix Market file's banner (first) "
4772 "line claims that the matrix's data type is \"pattern\". This does "
4773 "not make sense for a dense matrix, yet the file reports the matrix "
4774 "as dense. The only valid data types for a dense matrix are "
4775 "\"real\", \"complex\", and \"integer\".";
4776 localBannerReadSuccess = 0;
4777 } else {
4778 // Encode the data type reported by the Banner as the
4779 // third element of the dimensions Tuple.
4780 dims[2] = encodeDataType (pBanner->dataType ());
4781 }
4782 } // if we successfully read the banner line
4783
4784 // At this point, we've successfully read the banner line.
4785 // Now read the dimensions line.
4786 if (localBannerReadSuccess) {
4787 if (debug) {
4788 *err << myRank << ": readVectorImpl: Reading dimensions line (dense)" << endl;
4789 }
4790 // Keep reading lines from the input stream until we find
4791 // a non-comment line, or until we run out of lines. The
4792 // latter is an error, since every "array" format Matrix
4793 // Market file must have a dimensions line after the
4794 // banner (even if the matrix has zero rows or columns, or
4795 // zero entries).
4796 std::string line;
4797 bool commentLine = true;
4798
4799 while (commentLine) {
4800 // Test whether it is even valid to read from the input
4801 // stream wrapping the line.
4802 if (in.eof () || in.fail ()) {
4803 exMsg << "Unable to get array dimensions line (at all) from line "
4804 << lineNumber << " of input stream. The input stream "
4805 << "claims that it is "
4806 << (in.eof() ? "at end-of-file." : "in a failed state.");
4807 localDimsReadSuccess = 0;
4808 } else {
4809 // Try to get the next line from the input stream.
4810 if (getline (in, line)) {
4811 ++lineNumber; // We did actually read a line.
4812 }
4813 // Is the current line a comment line? Ignore start
4814 // and size; they are only useful for reading the
4815 // actual matrix entries. (We could use them here as
4816 // an optimization, but we've chosen not to.)
4817 size_t start = 0, size = 0;
4818 commentLine = checkCommentLine (line, start, size, lineNumber, tolerant);
4819 } // whether we failed to read the line at all
4820 } // while the line we just read is a comment line
4821
4822 //
4823 // Get <numRows> <numCols> from the line we just read.
4824 //
4825 std::istringstream istr (line);
4826
4827 // Test whether it is even valid to read from the input
4828 // stream wrapping the line.
4829 if (istr.eof () || istr.fail ()) {
4830 exMsg << "Unable to read any data from line " << lineNumber
4831 << " of input; the line should contain the matrix dimensions "
4832 << "\"<numRows> <numCols>\".";
4833 localDimsReadSuccess = 0;
4834 } else { // It's valid to read from the line.
4835 GO theNumRows = 0;
4836 istr >> theNumRows; // Read in the number of rows.
4837 if (istr.fail ()) {
4838 exMsg << "Failed to get number of rows from line "
4839 << lineNumber << " of input; the line should contains the "
4840 << "matrix dimensions \"<numRows> <numCols>\".";
4841 localDimsReadSuccess = 0;
4842 } else { // We successfully read the number of rows
4843 dims[0] = theNumRows; // Save the number of rows
4844 if (istr.eof ()) { // Do we still have data to read?
4845 exMsg << "No more data after number of rows on line "
4846 << lineNumber << " of input; the line should contain the "
4847 << "matrix dimensions \"<numRows> <numCols>\".";
4848 localDimsReadSuccess = 0;
4849 } else { // Still data left to read; read in number of columns.
4850 GO theNumCols = 0;
4851 istr >> theNumCols; // Read in the number of columns
4852 if (istr.fail ()) {
4853 exMsg << "Failed to get number of columns from line "
4854 << lineNumber << " of input; the line should contain "
4855 << "the matrix dimensions \"<numRows> <numCols>\".";
4856 localDimsReadSuccess = 0;
4857 } else { // We successfully read the number of columns
4858 dims[1] = theNumCols; // Save the number of columns
4859 } // if istr.fail ()
4860 } // if istr.eof ()
4861 } // if we read the number of rows
4862 } // if the input stream wrapping the dims line was (in)valid
4863 } // if we successfully read the banner line
4864 } // if (myRank == 0)
4865
4866 // Check if file has a Vector
4867 if (dims[1]!=1) {
4868 exMsg << "File does not contain a 1D Vector";
4869 localDimsReadSuccess = 0;
4870 }
4871
4872 // Broadcast the matrix dimensions, the encoded data type, and
4873 // whether or not Proc 0 succeeded in reading the banner and
4874 // dimensions.
4875 Tuple<GO, 5> bannerDimsReadResult;
4876 if (myRank == 0) {
4877 bannerDimsReadResult[0] = dims[0]; // numRows
4878 bannerDimsReadResult[1] = dims[1]; // numCols
4879 bannerDimsReadResult[2] = dims[2]; // encoded data type
4880 bannerDimsReadResult[3] = localBannerReadSuccess;
4881 bannerDimsReadResult[4] = localDimsReadSuccess;
4882 }
4883
4884 // Broadcast matrix dimensions and the encoded data type from
4885 // Proc 0 to all the MPI processes.
4886 broadcast (*comm, 0, bannerDimsReadResult);
4887
4888 TEUCHOS_TEST_FOR_EXCEPTION(
4889 bannerDimsReadResult[3] == 0, std::runtime_error,
4890 "Failed to read banner line: " << exMsg.str ());
4891 TEUCHOS_TEST_FOR_EXCEPTION(
4892 bannerDimsReadResult[4] == 0, std::runtime_error,
4893 "Failed to read matrix dimensions line: " << exMsg.str ());
4894 if (myRank != 0) {
4895 dims[0] = bannerDimsReadResult[0];
4896 dims[1] = bannerDimsReadResult[1];
4897 dims[2] = bannerDimsReadResult[2];
4898 }
4899
4900 // Tpetra objects want the matrix dimensions in these types.
4901 const global_size_t numRows = static_cast<global_size_t> (dims[0]);
4902 const size_t numCols = static_cast<size_t> (dims[1]);
4903
4904 // Make a "Proc 0 owns everything" Map that we will use to
4905 // read in the multivector entries in the correct order on
4906 // Proc 0. This must be a collective
4907 RCP<const map_type> proc0Map; // "Proc 0 owns everything" Map
4908 if (map.is_null ()) {
4909 // The user didn't supply a Map. Make a contiguous
4910 // distributed Map for them, using the read-in multivector
4911 // dimensions.
4912 map = createUniformContigMapWithNode<LO, GO, NT> (numRows, comm);
4913 const size_t localNumRows = (myRank == 0) ? numRows : 0;
4914 // At this point, map exists and has a nonnull node.
4915 proc0Map = createContigMapWithNode<LO, GO, NT> (numRows, localNumRows,
4916 comm);
4917 }
4918 else { // The user supplied a Map.
4919 proc0Map = Details::computeGatherMap<map_type> (map, err, debug);
4920 }
4921
4922 // Make a multivector X owned entirely by Proc 0.
4923 RCP<MV> X = createVector<ST, LO, GO, NT> (proc0Map);
4924
4925 //
4926 // On Proc 0, read the Matrix Market data from the input
4927 // stream into the multivector X.
4928 //
4929 int localReadDataSuccess = 1;
4930 if (myRank == 0) {
4931 try {
4932 if (debug) {
4933 *err << myRank << ": readVectorImpl: Reading matrix data (dense)"
4934 << endl;
4935 }
4936
4937 // Make sure that we can get a 1-D view of X.
4938 TEUCHOS_TEST_FOR_EXCEPTION(
4939 ! X->isConstantStride (), std::logic_error,
4940 "Can't get a 1-D view of the entries of the MultiVector X on "
4941 "Process 0, because the stride between the columns of X is not "
4942 "constant. This shouldn't happen because we just created X and "
4943 "haven't filled it in yet. Please report this bug to the Tpetra "
4944 "developers.");
4945
4946 // Get a writeable 1-D view of the entries of X. Rank 0
4947 // owns all of them. The view will expire at the end of
4948 // scope, so (if necessary) it will be written back to X
4949 // at this time.
4950 Teuchos::ArrayRCP<ST> X_view = X->get1dViewNonConst ();
4951 TEUCHOS_TEST_FOR_EXCEPTION(
4952 as<global_size_t> (X_view.size ()) < numRows * numCols,
4953 std::logic_error,
4954 "The view of X has size " << X_view << " which is not enough to "
4955 "accommodate the expected number of entries numRows*numCols = "
4956 << numRows << "*" << numCols << " = " << numRows*numCols << ". "
4957 "Please report this bug to the Tpetra developers.");
4958 const size_t stride = X->getStride ();
4959
4960 // The third element of the dimensions Tuple encodes the data
4961 // type reported by the Banner: "real" == 0, "complex" == 1,
4962 // "integer" == 0 (same as "real"), "pattern" == 2. We do not
4963 // allow dense matrices to be pattern matrices, so dims[2] ==
4964 // 0 or 1. We've already checked for this above.
4965 const bool isComplex = (dims[2] == 1);
4966 size_type count = 0, curRow = 0, curCol = 0;
4967
4968 std::string line;
4969 while (getline (in, line)) {
4970 ++lineNumber;
4971 // Is the current line a comment line? If it's not,
4972 // line.substr(start,size) contains the data.
4973 size_t start = 0, size = 0;
4974 const bool commentLine =
4975 checkCommentLine (line, start, size, lineNumber, tolerant);
4976 if (! commentLine) {
4977 // Make sure we have room in which to put the new matrix
4978 // entry. We check this only after checking for a
4979 // comment line, because there may be one or more
4980 // comment lines at the end of the file. In tolerant
4981 // mode, we simply ignore any extra data.
4982 if (count >= X_view.size()) {
4983 if (tolerant) {
4984 break;
4985 }
4986 else {
4987 TEUCHOS_TEST_FOR_EXCEPTION(
4988 count >= X_view.size(),
4989 std::runtime_error,
4990 "The Matrix Market input stream has more data in it than "
4991 "its metadata reported. Current line number is "
4992 << lineNumber << ".");
4993 }
4994 }
4995
4996 // mfh 19 Dec 2012: Ignore everything up to the initial
4997 // colon. writeDense() has the option to print out the
4998 // global row index in front of each entry, followed by
4999 // a colon and space.
5000 {
5001 const size_t pos = line.substr (start, size).find (':');
5002 if (pos != std::string::npos) {
5003 start = pos+1;
5004 }
5005 }
5006 std::istringstream istr (line.substr (start, size));
5007 // Does the line contain anything at all? Can we
5008 // safely read from the input stream wrapping the
5009 // line?
5010 if (istr.eof() || istr.fail()) {
5011 // In tolerant mode, simply ignore the line.
5012 if (tolerant) {
5013 break;
5014 }
5015 // We repeat the full test here so the exception
5016 // message is more informative.
5017 TEUCHOS_TEST_FOR_EXCEPTION(
5018 ! tolerant && (istr.eof() || istr.fail()),
5019 std::runtime_error,
5020 "Line " << lineNumber << " of the Matrix Market file is "
5021 "empty, or we cannot read from it for some other reason.");
5022 }
5023 // Current matrix entry to read in.
5024 ST val = STS::zero();
5025 // Real and imaginary parts of the current matrix entry.
5026 // The imaginary part is zero if the matrix is real-valued.
5027 MT real = STM::zero(), imag = STM::zero();
5028
5029 // isComplex refers to the input stream's data, not to
5030 // the scalar type S. It's OK to read real-valued
5031 // data into a matrix storing complex-valued data; in
5032 // that case, all entries' imaginary parts are zero.
5033 if (isComplex) {
5034 // STS::real() and STS::imag() return a copy of
5035 // their respective components, not a writeable
5036 // reference. Otherwise we could just assign to
5037 // them using the istream extraction operator (>>).
5038 // That's why we have separate magnitude type "real"
5039 // and "imag" variables.
5040
5041 // Attempt to read the real part of the current entry.
5042 istr >> real;
5043 if (istr.fail()) {
5044 TEUCHOS_TEST_FOR_EXCEPTION(
5045 ! tolerant && istr.eof(), std::runtime_error,
5046 "Failed to get the real part of a complex-valued matrix "
5047 "entry from line " << lineNumber << " of the Matrix Market "
5048 "file.");
5049 // In tolerant mode, just skip bad lines.
5050 if (tolerant) {
5051 break;
5052 }
5053 } else if (istr.eof()) {
5054 TEUCHOS_TEST_FOR_EXCEPTION(
5055 ! tolerant && istr.eof(), std::runtime_error,
5056 "Missing imaginary part of a complex-valued matrix entry "
5057 "on line " << lineNumber << " of the Matrix Market file.");
5058 // In tolerant mode, let any missing imaginary part be 0.
5059 } else {
5060 // Attempt to read the imaginary part of the current
5061 // matrix entry.
5062 istr >> imag;
5063 TEUCHOS_TEST_FOR_EXCEPTION(
5064 ! tolerant && istr.fail(), std::runtime_error,
5065 "Failed to get the imaginary part of a complex-valued "
5066 "matrix entry from line " << lineNumber << " of the "
5067 "Matrix Market file.");
5068 // In tolerant mode, let any missing or corrupted
5069 // imaginary part be 0.
5070 }
5071 } else { // Matrix Market file contains real-valued data.
5072 // Attempt to read the current matrix entry.
5073 istr >> real;
5074 TEUCHOS_TEST_FOR_EXCEPTION(
5075 ! tolerant && istr.fail(), std::runtime_error,
5076 "Failed to get a real-valued matrix entry from line "
5077 << lineNumber << " of the Matrix Market file.");
5078 // In tolerant mode, simply ignore the line if
5079 // we failed to read a matrix entry.
5080 if (istr.fail() && tolerant) {
5081 break;
5082 }
5083 }
5084 // In tolerant mode, we simply let pass through whatever
5085 // data we got.
5086 TEUCHOS_TEST_FOR_EXCEPTION(
5087 ! tolerant && istr.fail(), std::runtime_error,
5088 "Failed to read matrix data from line " << lineNumber
5089 << " of the Matrix Market file.");
5090
5091 // Assign val = ST(real, imag).
5092 Teuchos::MatrixMarket::details::assignScalar<ST> (val, real, imag);
5093
5094 curRow = count % numRows;
5095 curCol = count / numRows;
5096 X_view[curRow + curCol*stride] = val;
5097 ++count;
5098 } // if not a comment line
5099 } // while there are still lines in the file, get the next one
5100
5101 TEUCHOS_TEST_FOR_EXCEPTION(
5102 ! tolerant && static_cast<global_size_t> (count) < numRows * numCols,
5103 std::runtime_error,
5104 "The Matrix Market metadata reports that the dense matrix is "
5105 << numRows << " x " << numCols << ", and thus has "
5106 << numRows*numCols << " total entries, but we only found " << count
5107 << " entr" << (count == 1 ? "y" : "ies") << " in the file.");
5108 } catch (std::exception& e) {
5109 exMsg << e.what ();
5110 localReadDataSuccess = 0;
5111 }
5112 } // if (myRank == 0)
5113
5114 if (debug) {
5115 *err << myRank << ": readVectorImpl: done reading data" << endl;
5116 }
5117
5118 // Synchronize on whether Proc 0 successfully read the data.
5119 int globalReadDataSuccess = localReadDataSuccess;
5120 broadcast (*comm, 0, outArg (globalReadDataSuccess));
5121 TEUCHOS_TEST_FOR_EXCEPTION(
5122 globalReadDataSuccess == 0, std::runtime_error,
5123 "Failed to read the multivector's data: " << exMsg.str ());
5124
5125 // If there's only one MPI process and the user didn't supply
5126 // a Map (i.e., pMap is null), we're done. Set pMap to the
5127 // Map used to distribute X, and return X.
5128 if (comm->getSize () == 1 && map.is_null ()) {
5129 map = proc0Map;
5130 if (! err.is_null ()) {
5131 err->popTab ();
5132 }
5133 if (debug) {
5134 *err << myRank << ": readVectorImpl: done" << endl;
5135 }
5136 if (! err.is_null ()) {
5137 err->popTab ();
5138 }
5139 return X;
5140 }
5141
5142 if (debug) {
5143 *err << myRank << ": readVectorImpl: Creating target MV" << endl;
5144 }
5145
5146 // Make a multivector Y with the distributed map pMap.
5147 RCP<MV> Y = createVector<ST, LO, GO, NT> (map);
5148
5149 if (debug) {
5150 *err << myRank << ": readVectorImpl: Creating Export" << endl;
5151 }
5152
5153 // Make an Export object that will export X to Y. First
5154 // argument is the source map, second argument is the target
5155 // map.
5156 Export<LO, GO, NT> exporter (proc0Map, map, err);
5157
5158 if (debug) {
5159 *err << myRank << ": readVectorImpl: Exporting" << endl;
5160 }
5161 // Export X into Y.
5162 Y->doExport (*X, exporter, INSERT);
5163
5164 if (! err.is_null ()) {
5165 err->popTab ();
5166 }
5167 if (debug) {
5168 *err << myRank << ": readVectorImpl: done" << endl;
5169 }
5170 if (! err.is_null ()) {
5171 err->popTab ();
5172 }
5173
5174 // Y is distributed over all process(es) in the communicator.
5175 return Y;
5176 }
5177
5178 public:
5198 static Teuchos::RCP<const map_type>
5199 readMap (std::istream& in,
5200 const Teuchos::RCP<const comm_type>& comm,
5201 const bool tolerant=false,
5202 const bool debug=false)
5203 {
5204 Teuchos::RCP<Teuchos::FancyOStream> err =
5205 Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
5206 return readMap (in, comm, err, tolerant, debug);
5207 }
5208
5209
5235 static Teuchos::RCP<const map_type>
5236 readMap (std::istream& in,
5237 const Teuchos::RCP<const comm_type>& comm,
5238 const Teuchos::RCP<Teuchos::FancyOStream>& err,
5239 const bool tolerant=false,
5240 const bool debug=false)
5241 {
5242 using Teuchos::arcp;
5243 using Teuchos::Array;
5244 using Teuchos::ArrayRCP;
5245 using Teuchos::as;
5246 using Teuchos::broadcast;
5247 using Teuchos::Comm;
5248 using Teuchos::CommRequest;
5249 using Teuchos::inOutArg;
5250 using Teuchos::ireceive;
5251 using Teuchos::outArg;
5252 using Teuchos::RCP;
5253 using Teuchos::receive;
5254 using Teuchos::reduceAll;
5255 using Teuchos::REDUCE_MIN;
5256 using Teuchos::isend;
5257 using Teuchos::SerialComm;
5258 using Teuchos::toString;
5259 using Teuchos::wait;
5260 using std::endl;
5261 typedef Tpetra::global_size_t GST;
5262 typedef ptrdiff_t int_type; // Can hold int and GO
5263 typedef local_ordinal_type LO;
5264 typedef global_ordinal_type GO;
5265 typedef node_type NT;
5267
5268 const int numProcs = comm->getSize ();
5269 const int myRank = comm->getRank ();
5270
5271 if (err.is_null ()) {
5272 err->pushTab ();
5273 }
5274 if (debug) {
5275 std::ostringstream os;
5276 os << myRank << ": readMap: " << endl;
5277 *err << os.str ();
5278 }
5279 if (err.is_null ()) {
5280 err->pushTab ();
5281 }
5282
5283 // Tag for receive-size / send-size messages. writeMap used
5284 // tags 1337 and 1338; we count up from there.
5285 const int sizeTag = 1339;
5286 // Tag for receive-data / send-data messages.
5287 const int dataTag = 1340;
5288
5289 // These are for sends on Process 0, and for receives on all
5290 // other processes. sizeReq is for the {receive,send}-size
5291 // message, and dataReq is for the message containing the
5292 // actual GIDs to belong to the receiving process.
5293 RCP<CommRequest<int> > sizeReq;
5294 RCP<CommRequest<int> > dataReq;
5295
5296 // Each process will have to receive the number of GIDs to
5297 // expect. Thus, we can post the receives now, and cancel
5298 // them if something should go wrong in the meantime.
5299 ArrayRCP<int_type> numGidsToRecv (1);
5300 numGidsToRecv[0] = 0;
5301 if (myRank != 0) {
5302 sizeReq = ireceive<int, int_type> (numGidsToRecv, 0, sizeTag, *comm);
5303 }
5304
5305 int readSuccess = 1;
5306 std::ostringstream exMsg;
5307 RCP<MV> data; // Will only be valid on Proc 0
5308 if (myRank == 0) {
5309 // If we want to reuse readDenseImpl, we have to make a
5310 // communicator that only contains Proc 0. Otherwise,
5311 // readDenseImpl will redistribute the data to all
5312 // processes. While we eventually want that, neither we nor
5313 // readDenseImpl know the correct Map to use at the moment.
5314 // That depends on the second column of the multivector.
5315 RCP<const Comm<int> > proc0Comm (new SerialComm<int> ());
5316 try {
5317 RCP<const map_type> dataMap;
5318 // This is currently the only place where we use the
5319 // 'tolerant' argument. Later, if we want to be clever,
5320 // we could have tolerant mode allow PIDs out of order.
5321 data = readDenseImpl<GO> (in, proc0Comm, dataMap, err, tolerant, debug);
5322 (void) dataMap; // Silence "unused" warnings
5323 if (data.is_null ()) {
5324 readSuccess = 0;
5325 exMsg << "readDenseImpl() returned null." << endl;
5326 }
5327 } catch (std::exception& e) {
5328 readSuccess = 0;
5329 exMsg << e.what () << endl;
5330 }
5331 }
5332
5333 // Map from PID to all the GIDs for that PID.
5334 // Only populated on Process 0.
5335 std::map<int, Array<GO> > pid2gids;
5336
5337 // The index base must be the global minimum GID.
5338 // We will compute this on Process 0 and broadcast,
5339 // so that all processes can set up the Map.
5340 int_type globalNumGIDs = 0;
5341
5342 // The index base must be the global minimum GID.
5343 // We will compute this on Process 0 and broadcast,
5344 // so that all processes can set up the Map.
5345 GO indexBase = 0;
5346
5347 // Process 0: If the above read of the MultiVector succeeded,
5348 // extract the GIDs and PIDs into pid2gids, and find the
5349 // global min GID.
5350 if (myRank == 0 && readSuccess == 1) {
5351 if (data->getNumVectors () == 2) { // Map format 1.0
5352 ArrayRCP<const GO> GIDs = data->getData (0);
5353 ArrayRCP<const GO> PIDs = data->getData (1); // convert to int
5354 globalNumGIDs = GIDs.size ();
5355
5356 // Start computing the global min GID, while collecting
5357 // the GIDs for each PID.
5358 if (globalNumGIDs > 0) {
5359 const int pid = static_cast<int> (PIDs[0]);
5360
5361 if (pid < 0 || pid >= numProcs) {
5362 readSuccess = 0;
5363 exMsg << "Tpetra::MatrixMarket::readMap: "
5364 << "Encountered invalid PID " << pid << "." << endl;
5365 }
5366 else {
5367 const GO gid = GIDs[0];
5368 pid2gids[pid].push_back (gid);
5369 indexBase = gid; // the current min GID
5370 }
5371 }
5372 if (readSuccess == 1) {
5373 // Collect the rest of the GIDs for each PID, and compute
5374 // the global min GID.
5375 for (size_type k = 1; k < globalNumGIDs; ++k) {
5376 const int pid = static_cast<int> (PIDs[k]);
5377 if (pid < 0 || pid >= numProcs) {
5378 readSuccess = 0;
5379 exMsg << "Tpetra::MatrixMarket::readMap: "
5380 << "Encountered invalid PID " << pid << "." << endl;
5381 }
5382 else {
5383 const int_type gid = GIDs[k];
5384 pid2gids[pid].push_back (gid);
5385 if (gid < indexBase) {
5386 indexBase = gid; // the current min GID
5387 }
5388 }
5389 }
5390 }
5391 }
5392 else if (data->getNumVectors () == 1) { // Map format 2.0
5393 if (data->getGlobalLength () % 2 != static_cast<GST> (0)) {
5394 readSuccess = 0;
5395 exMsg << "Tpetra::MatrixMarket::readMap: Input data has the "
5396 "wrong format (for Map format 2.0). The global number of rows "
5397 "in the MultiVector must be even (divisible by 2)." << endl;
5398 }
5399 else {
5400 ArrayRCP<const GO> theData = data->getData (0);
5401 globalNumGIDs = static_cast<GO> (data->getGlobalLength ()) /
5402 static_cast<GO> (2);
5403
5404 // Start computing the global min GID, while
5405 // collecting the GIDs for each PID.
5406 if (globalNumGIDs > 0) {
5407 const int pid = static_cast<int> (theData[1]);
5408 if (pid < 0 || pid >= numProcs) {
5409 readSuccess = 0;
5410 exMsg << "Tpetra::MatrixMarket::readMap: "
5411 << "Encountered invalid PID " << pid << "." << endl;
5412 }
5413 else {
5414 const GO gid = theData[0];
5415 pid2gids[pid].push_back (gid);
5416 indexBase = gid; // the current min GID
5417 }
5418 }
5419 // Collect the rest of the GIDs for each PID, and
5420 // compute the global min GID.
5421 for (int_type k = 1; k < globalNumGIDs; ++k) {
5422 const int pid = static_cast<int> (theData[2*k + 1]);
5423 if (pid < 0 || pid >= numProcs) {
5424 readSuccess = 0;
5425 exMsg << "Tpetra::MatrixMarket::readMap: "
5426 << "Encountered invalid PID " << pid << "." << endl;
5427 }
5428 else {
5429 const GO gid = theData[2*k];
5430 pid2gids[pid].push_back (gid);
5431 if (gid < indexBase) {
5432 indexBase = gid; // the current min GID
5433 }
5434 }
5435 } // for each GID
5436 } // if the amount of data is correct
5437 }
5438 else {
5439 readSuccess = 0;
5440 exMsg << "Tpetra::MatrixMarket::readMap: Input data must have "
5441 "either 1 column (for the new Map format 2.0) or 2 columns (for "
5442 "the old Map format 1.0).";
5443 }
5444 } // myRank is zero
5445
5446 // Broadcast the indexBase, the global number of GIDs, and the
5447 // current success status. Use int_type for all of these.
5448 {
5449 int_type readResults[3];
5450 readResults[0] = static_cast<int_type> (indexBase);
5451 readResults[1] = static_cast<int_type> (globalNumGIDs);
5452 readResults[2] = static_cast<int_type> (readSuccess);
5453 broadcast<int, int_type> (*comm, 0, 3, readResults);
5454
5455 indexBase = static_cast<GO> (readResults[0]);
5456 globalNumGIDs = static_cast<int_type> (readResults[1]);
5457 readSuccess = static_cast<int> (readResults[2]);
5458 }
5459
5460 // Unwinding the stack will invoke sizeReq's destructor, which
5461 // will cancel the receive-size request on all processes that
5462 // posted it.
5463 TEUCHOS_TEST_FOR_EXCEPTION(
5464 readSuccess != 1, std::runtime_error,
5465 "Tpetra::MatrixMarket::readMap: Reading the Map failed with the "
5466 "following exception message: " << exMsg.str ());
5467
5468 if (myRank == 0) {
5469 // Proc 0: Send each process' number of GIDs to that process.
5470 for (int p = 1; p < numProcs; ++p) {
5471 ArrayRCP<int_type> numGidsToSend (1);
5472
5473 auto it = pid2gids.find (p);
5474 if (it == pid2gids.end ()) {
5475 numGidsToSend[0] = 0;
5476 } else {
5477 numGidsToSend[0] = it->second.size ();
5478 }
5479 sizeReq = isend<int, int_type> (numGidsToSend, p, sizeTag, *comm);
5480 wait<int> (*comm, outArg (sizeReq));
5481 }
5482 }
5483 else {
5484 // Wait on the receive-size message to finish.
5485 wait<int> (*comm, outArg (sizeReq));
5486 }
5487
5488 // Allocate / get the array for my GIDs.
5489 // Only Process 0 will have its actual GIDs at this point.
5490 ArrayRCP<GO> myGids;
5491 int_type myNumGids = 0;
5492 if (myRank == 0) {
5493 GO* myGidsRaw = NULL;
5494
5495 typename std::map<int, Array<GO> >::iterator it = pid2gids.find (0);
5496 if (it != pid2gids.end ()) {
5497 myGidsRaw = it->second.getRawPtr ();
5498 myNumGids = it->second.size ();
5499 // Nonowning ArrayRCP just views the Array.
5500 myGids = arcp<GO> (myGidsRaw, 0, myNumGids, false);
5501 }
5502 }
5503 else { // myRank != 0
5504 myNumGids = numGidsToRecv[0];
5505 myGids = arcp<GO> (myNumGids);
5506 }
5507
5508 if (myRank != 0) {
5509 // Post receive for data, now that we know how much data we
5510 // will receive. Only post receive if my process actually
5511 // has nonzero GIDs.
5512 if (myNumGids > 0) {
5513 dataReq = ireceive<int, GO> (myGids, 0, dataTag, *comm);
5514 }
5515 }
5516
5517 for (int p = 1; p < numProcs; ++p) {
5518 if (myRank == 0) {
5519 ArrayRCP<GO> sendGids; // to send to Process p
5520 GO* sendGidsRaw = NULL;
5521 int_type numSendGids = 0;
5522
5523 typename std::map<int, Array<GO> >::iterator it = pid2gids.find (p);
5524 if (it != pid2gids.end ()) {
5525 numSendGids = it->second.size ();
5526 sendGidsRaw = it->second.getRawPtr ();
5527 sendGids = arcp<GO> (sendGidsRaw, 0, numSendGids, false);
5528 }
5529 // Only send if that process actually has nonzero GIDs.
5530 if (numSendGids > 0) {
5531 dataReq = isend<int, GO> (sendGids, p, dataTag, *comm);
5532 }
5533 wait<int> (*comm, outArg (dataReq));
5534 }
5535 else if (myRank == p) {
5536 // Wait on my receive of GIDs to finish.
5537 wait<int> (*comm, outArg (dataReq));
5538 }
5539 } // for each process rank p in 1, 2, ..., numProcs-1
5540
5541 if (debug) {
5542 std::ostringstream os;
5543 os << myRank << ": readMap: creating Map" << endl;
5544 *err << os.str ();
5545 }
5546 const GST INVALID = Teuchos::OrdinalTraits<GST>::invalid ();
5547 RCP<const map_type> newMap;
5548
5549 // Create the Map; test whether the constructor threw. This
5550 // avoids deadlock and makes error reporting more readable.
5551
5552 int lclSuccess = 1;
5553 int gblSuccess = 0; // output argument
5554 std::ostringstream errStrm;
5555 try {
5556 newMap = rcp (new map_type (INVALID, myGids (), indexBase, comm));
5557 }
5558 catch (std::exception& e) {
5559 lclSuccess = 0;
5560 errStrm << "Process " << comm->getRank () << " threw an exception: "
5561 << e.what () << std::endl;
5562 }
5563 catch (...) {
5564 lclSuccess = 0;
5565 errStrm << "Process " << comm->getRank () << " threw an exception "
5566 "not a subclass of std::exception" << std::endl;
5567 }
5568 Teuchos::reduceAll<int, int> (*comm, Teuchos::REDUCE_MIN,
5569 lclSuccess, Teuchos::outArg (gblSuccess));
5570 if (gblSuccess != 1) {
5571 Tpetra::Details::gathervPrint (std::cerr, errStrm.str (), *comm);
5572 }
5573 TEUCHOS_TEST_FOR_EXCEPTION(gblSuccess != 1, std::runtime_error, "Map constructor failed!");
5574
5575 if (err.is_null ()) {
5576 err->popTab ();
5577 }
5578 if (debug) {
5579 std::ostringstream os;
5580 os << myRank << ": readMap: done" << endl;
5581 *err << os.str ();
5582 }
5583 if (err.is_null ()) {
5584 err->popTab ();
5585 }
5586 return newMap;
5587 }
5588
5589
5590 private:
5591
5602 static int
5603 encodeDataType (const std::string& dataType)
5604 {
5605 if (dataType == "real" || dataType == "integer") {
5606 return 0;
5607 } else if (dataType == "complex") {
5608 return 1;
5609 } else if (dataType == "pattern") {
5610 return 2;
5611 } else {
5612 // We should never get here, since Banner validates the
5613 // reported data type and ensures it is one of the accepted
5614 // values.
5615 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
5616 "Unrecognized Matrix Market data type \"" << dataType
5617 << "\". We should never get here. "
5618 "Please report this bug to the Tpetra developers.");
5619 }
5620 }
5621 }; // class Reader
5622
5651 template<class SparseMatrixType>
5652 class Writer {
5653 public:
5655 typedef SparseMatrixType sparse_matrix_type;
5656 typedef Teuchos::RCP<sparse_matrix_type> sparse_matrix_ptr;
5657
5659 typedef typename SparseMatrixType::scalar_type scalar_type;
5661 typedef typename SparseMatrixType::local_ordinal_type local_ordinal_type;
5667 typedef typename SparseMatrixType::global_ordinal_type global_ordinal_type;
5669 typedef typename SparseMatrixType::node_type node_type;
5670
5672 typedef MultiVector<scalar_type,
5680
5683
5715 static void
5716 writeSparseFile (const std::string& filename,
5717 const sparse_matrix_type& matrix,
5718 const std::string& matrixName,
5719 const std::string& matrixDescription,
5720 const bool debug=false)
5721 {
5722 Teuchos::RCP<const Teuchos::Comm<int> > comm = matrix.getComm ();
5723 TEUCHOS_TEST_FOR_EXCEPTION
5724 (comm.is_null (), std::invalid_argument,
5725 "The input matrix's communicator (Teuchos::Comm object) is null.");
5726 const int myRank = comm->getRank ();
5727 std::ofstream out;
5728
5729 // Only open the file on Rank 0.
5730 if (myRank == 0) {
5731 out.open (filename.c_str ());
5732 }
5733 writeSparse (out, matrix, matrixName, matrixDescription, debug);
5734 // We can rely on the destructor of the output stream to close
5735 // the file on scope exit, even if writeSparse() throws an
5736 // exception.
5737 }
5738
5740 static void
5741 writeSparseFile (const std::string& filename,
5742 const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
5743 const std::string& matrixName,
5744 const std::string& matrixDescription,
5745 const bool debug=false)
5746 {
5747 TEUCHOS_TEST_FOR_EXCEPTION
5748 (pMatrix.is_null (), std::invalid_argument,
5749 "The input matrix is null.");
5750 writeSparseFile (filename, *pMatrix, matrixName,
5751 matrixDescription, debug);
5752 }
5753
5773 static void
5774 writeSparseFile (const std::string& filename,
5775 const sparse_matrix_type& matrix,
5776 const bool debug=false)
5777 {
5778 writeSparseFile (filename, matrix, "", "", debug);
5779 }
5780
5782 static void
5783 writeSparseFile (const std::string& filename,
5784 const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
5785 const bool debug=false)
5786 {
5787 writeSparseFile (filename, *pMatrix, "", "", debug);
5788 }
5789
5820 static void
5821 writeSparse (std::ostream& out,
5822 const sparse_matrix_type& matrix,
5823 const std::string& matrixName,
5824 const std::string& matrixDescription,
5825 const bool debug=false)
5826 {
5827 using Teuchos::ArrayView;
5828 using Teuchos::Comm;
5829 using Teuchos::FancyOStream;
5830 using Teuchos::getFancyOStream;
5831 using Teuchos::null;
5832 using Teuchos::RCP;
5833 using Teuchos::rcpFromRef;
5834 using std::cerr;
5835 using std::endl;
5836 using ST = scalar_type;
5837 using LO = local_ordinal_type;
5838 using GO = global_ordinal_type;
5839 using STS = typename Teuchos::ScalarTraits<ST>;
5840
5841 // Make the output stream write floating-point numbers in
5842 // scientific notation. It will politely put the output
5843 // stream back to its state on input, when this scope
5844 // terminates.
5845 Teuchos::SetScientific<ST> sci (out);
5846
5847 // Get the matrix's communicator.
5848 RCP<const Comm<int> > comm = matrix.getComm ();
5849 TEUCHOS_TEST_FOR_EXCEPTION(
5850 comm.is_null (), std::invalid_argument,
5851 "The input matrix's communicator (Teuchos::Comm object) is null.");
5852 const int myRank = comm->getRank ();
5853
5854 // Optionally, make a stream for debugging output.
5855 RCP<FancyOStream> err =
5856 debug ? getFancyOStream (rcpFromRef (std::cerr)) : null;
5857 if (debug) {
5858 std::ostringstream os;
5859 os << myRank << ": writeSparse" << endl;
5860 *err << os.str ();
5861 comm->barrier ();
5862 os << "-- " << myRank << ": past barrier" << endl;
5863 *err << os.str ();
5864 }
5865
5866 // Whether to print debugging output to stderr.
5867 const bool debugPrint = debug && myRank == 0;
5868
5869 RCP<const map_type> rowMap = matrix.getRowMap ();
5870 RCP<const map_type> colMap = matrix.getColMap ();
5871 RCP<const map_type> domainMap = matrix.getDomainMap ();
5872 RCP<const map_type> rangeMap = matrix.getRangeMap ();
5873
5874 const global_size_t numRows = rangeMap->getGlobalNumElements ();
5875 const global_size_t numCols = domainMap->getGlobalNumElements ();
5876
5877 if (debug && myRank == 0) {
5878 std::ostringstream os;
5879 os << "-- Input sparse matrix is:"
5880 << "---- " << numRows << " x " << numCols << endl
5881 << "---- "
5882 << (matrix.isGloballyIndexed() ? "Globally" : "Locally")
5883 << " indexed." << endl
5884 << "---- Its row map has " << rowMap->getGlobalNumElements ()
5885 << " elements." << endl
5886 << "---- Its col map has " << colMap->getGlobalNumElements ()
5887 << " elements." << endl;
5888 *err << os.str ();
5889 }
5890 // Make the "gather" row map, where Proc 0 owns all rows and
5891 // the other procs own no rows.
5892 const size_t localNumRows = (myRank == 0) ? numRows : 0;
5893 if (debug) {
5894 std::ostringstream os;
5895 os << "-- " << myRank << ": making gatherRowMap" << endl;
5896 *err << os.str ();
5897 }
5898 RCP<const map_type> gatherRowMap =
5899 Details::computeGatherMap (rowMap, err, debug);
5900
5901 // Since the matrix may in general be non-square, we need to
5902 // make a column map as well. In this case, the column map
5903 // contains all the columns of the original matrix, because we
5904 // are gathering the whole matrix onto Proc 0. We call
5905 // computeGatherMap to preserve the original order of column
5906 // indices over all the processes.
5907 const size_t localNumCols = (myRank == 0) ? numCols : 0;
5908 RCP<const map_type> gatherColMap =
5909 Details::computeGatherMap (colMap, err, debug);
5910
5911 // Current map is the source map, gather map is the target map.
5912 typedef Import<LO, GO, node_type> import_type;
5913 import_type importer (rowMap, gatherRowMap);
5914
5915 // Create a new CrsMatrix to hold the result of the import.
5916 // The constructor needs a column map as well as a row map,
5917 // for the case that the matrix is not square.
5918 RCP<sparse_matrix_type> newMatrix =
5919 rcp (new sparse_matrix_type (gatherRowMap, gatherColMap,
5920 static_cast<size_t> (0)));
5921 // Import the sparse matrix onto Proc 0.
5922 newMatrix->doImport (matrix, importer, INSERT);
5923
5924 // fillComplete() needs the domain and range maps for the case
5925 // that the matrix is not square.
5926 {
5927 RCP<const map_type> gatherDomainMap =
5928 rcp (new map_type (numCols, localNumCols,
5929 domainMap->getIndexBase (),
5930 comm));
5931 RCP<const map_type> gatherRangeMap =
5932 rcp (new map_type (numRows, localNumRows,
5933 rangeMap->getIndexBase (),
5934 comm));
5935 newMatrix->fillComplete (gatherDomainMap, gatherRangeMap);
5936 }
5937
5938 if (debugPrint) {
5939 cerr << "-- Output sparse matrix is:"
5940 << "---- " << newMatrix->getRangeMap ()->getGlobalNumElements ()
5941 << " x "
5942 << newMatrix->getDomainMap ()->getGlobalNumElements ()
5943 << " with "
5944 << newMatrix->getGlobalNumEntries () << " entries;" << endl
5945 << "---- "
5946 << (newMatrix->isGloballyIndexed () ? "Globally" : "Locally")
5947 << " indexed." << endl
5948 << "---- Its row map has "
5949 << newMatrix->getRowMap ()->getGlobalNumElements ()
5950 << " elements, with index base "
5951 << newMatrix->getRowMap ()->getIndexBase () << "." << endl
5952 << "---- Its col map has "
5953 << newMatrix->getColMap ()->getGlobalNumElements ()
5954 << " elements, with index base "
5955 << newMatrix->getColMap ()->getIndexBase () << "." << endl
5956 << "---- Element count of output matrix's column Map may differ "
5957 << "from that of the input matrix's column Map, if some columns "
5958 << "of the matrix contain no entries." << endl;
5959 }
5960
5961 //
5962 // Print the metadata and the matrix entries on Rank 0.
5963 //
5964 if (myRank == 0) {
5965 // Print the Matrix Market banner line. CrsMatrix stores
5966 // data nonsymmetrically ("general"). This implies that
5967 // readSparse() on a symmetrically stored input file,
5968 // followed by writeSparse() on the resulting sparse matrix,
5969 // will result in an output file with a different banner
5970 // line than the original input file.
5971 out << "%%MatrixMarket matrix coordinate "
5972 << (STS::isComplex ? "complex" : "real")
5973 << " general" << endl;
5974
5975 // Print comments (the matrix name and / or description).
5976 if (matrixName != "") {
5977 printAsComment (out, matrixName);
5978 }
5979 if (matrixDescription != "") {
5980 printAsComment (out, matrixDescription);
5981 }
5982
5983 // Print the Matrix Market header (# rows, # columns, #
5984 // nonzeros). Use the range resp. domain map for the number
5985 // of rows resp. columns, since Tpetra::CrsMatrix uses the
5986 // column map for the number of columns. That only
5987 // corresponds to the "linear-algebraic" number of columns
5988 // when the column map is uniquely owned (a.k.a. one-to-one),
5989 // which only happens if the matrix is (block) diagonal.
5990 out << newMatrix->getRangeMap ()->getGlobalNumElements () << " "
5991 << newMatrix->getDomainMap ()->getGlobalNumElements () << " "
5992 << newMatrix->getGlobalNumEntries () << endl;
5993
5994 // The Matrix Market format expects one-based row and column
5995 // indices. We'll convert the indices on output from
5996 // whatever index base they use to one-based indices.
5997 const GO rowIndexBase = gatherRowMap->getIndexBase ();
5998 const GO colIndexBase = newMatrix->getColMap()->getIndexBase ();
5999 //
6000 // Print the entries of the matrix.
6001 //
6002 // newMatrix can never be globally indexed, since we called
6003 // fillComplete() on it. We include code for both cases
6004 // (globally or locally indexed) just in case that ever
6005 // changes.
6006 if (newMatrix->isGloballyIndexed()) {
6007 // We know that the "gather" row Map is contiguous, so we
6008 // don't need to get the list of GIDs.
6009 const GO minAllGlobalIndex = gatherRowMap->getMinAllGlobalIndex ();
6010 const GO maxAllGlobalIndex = gatherRowMap->getMaxAllGlobalIndex ();
6011 for (GO globalRowIndex = minAllGlobalIndex;
6012 globalRowIndex <= maxAllGlobalIndex; // inclusive range
6013 ++globalRowIndex) {
6014 typename sparse_matrix_type::global_inds_host_view_type ind;
6015 typename sparse_matrix_type::values_host_view_type val;
6016 newMatrix->getGlobalRowView (globalRowIndex, ind, val);
6017 for (size_t ii = 0; ii < ind.extent(0); ii++) {
6018 const GO globalColIndex = ind(ii);
6019 // Convert row and column indices to 1-based.
6020 // This works because the global index type is signed.
6021 out << (globalRowIndex + 1 - rowIndexBase) << " "
6022 << (globalColIndex + 1 - colIndexBase) << " ";
6023 if (STS::isComplex) {
6024 out << STS::real (val(ii)) << " " << STS::imag (val(ii));
6025 } else {
6026 out << val(ii);
6027 }
6028 out << endl;
6029 } // For each entry in the current row
6030 } // For each row of the "gather" matrix
6031 }
6032 else { // newMatrix is locally indexed
6033 using OTG = Teuchos::OrdinalTraits<GO>;
6034 for (LO localRowIndex = gatherRowMap->getMinLocalIndex();
6035 localRowIndex <= gatherRowMap->getMaxLocalIndex();
6036 ++localRowIndex) {
6037 // Convert from local to global row index.
6038 const GO globalRowIndex =
6039 gatherRowMap->getGlobalElement (localRowIndex);
6040 TEUCHOS_TEST_FOR_EXCEPTION(
6041 globalRowIndex == OTG::invalid(), std::logic_error,
6042 "Failed to convert the supposed local row index "
6043 << localRowIndex << " into a global row index. "
6044 "Please report this bug to the Tpetra developers.");
6045 typename sparse_matrix_type::local_inds_host_view_type ind;
6046 typename sparse_matrix_type::values_host_view_type val;
6047 newMatrix->getLocalRowView (localRowIndex, ind, val);
6048 for (size_t ii = 0; ii < ind.extent(0); ii++) {
6049 // Convert the column index from local to global.
6050 const GO globalColIndex =
6051 newMatrix->getColMap()->getGlobalElement (ind(ii));
6052 TEUCHOS_TEST_FOR_EXCEPTION(
6053 globalColIndex == OTG::invalid(), std::logic_error,
6054 "On local row " << localRowIndex << " of the sparse matrix: "
6055 "Failed to convert the supposed local column index "
6056 << ind(ii) << " into a global column index. Please report "
6057 "this bug to the Tpetra developers.");
6058 // Convert row and column indices to 1-based.
6059 // This works because the global index type is signed.
6060 out << (globalRowIndex + 1 - rowIndexBase) << " "
6061 << (globalColIndex + 1 - colIndexBase) << " ";
6062 if (STS::isComplex) {
6063 out << STS::real (val(ii)) << " " << STS::imag (val(ii));
6064 } else {
6065 out << val(ii);
6066 }
6067 out << endl;
6068 } // For each entry in the current row
6069 } // For each row of the "gather" matrix
6070 } // Whether the "gather" matrix is locally or globally indexed
6071 } // If my process' rank is 0
6072 }
6073
6075 static void
6076 writeSparse (std::ostream& out,
6077 const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6078 const std::string& matrixName,
6079 const std::string& matrixDescription,
6080 const bool debug=false)
6081 {
6082 TEUCHOS_TEST_FOR_EXCEPTION
6083 (pMatrix.is_null (), std::invalid_argument,
6084 "The input matrix is null.");
6085 writeSparse (out, *pMatrix, matrixName, matrixDescription, debug);
6086 }
6087
6118 static void
6119 writeSparseGraph (std::ostream& out,
6120 const crs_graph_type& graph,
6121 const std::string& graphName,
6122 const std::string& graphDescription,
6123 const bool debug=false)
6124 {
6125 using Teuchos::ArrayView;
6126 using Teuchos::Comm;
6127 using Teuchos::FancyOStream;
6128 using Teuchos::getFancyOStream;
6129 using Teuchos::null;
6130 using Teuchos::RCP;
6131 using Teuchos::rcpFromRef;
6132 using std::cerr;
6133 using std::endl;
6134 typedef local_ordinal_type LO;
6135 typedef global_ordinal_type GO;
6136
6137 // Get the graph's communicator. Processes on which the
6138 // graph's Map or communicator is null don't participate in
6139 // this operation. This function shouldn't even be called on
6140 // those processes.
6141 auto rowMap = graph.getRowMap ();
6142 if (rowMap.is_null ()) {
6143 return;
6144 }
6145 auto comm = rowMap->getComm ();
6146 if (comm.is_null ()) {
6147 return;
6148 }
6149 const int myRank = comm->getRank ();
6150
6151 // Optionally, make a stream for debugging output.
6152 RCP<FancyOStream> err =
6153 debug ? getFancyOStream (rcpFromRef (std::cerr)) : null;
6154 if (debug) {
6155 std::ostringstream os;
6156 os << myRank << ": writeSparseGraph" << endl;
6157 *err << os.str ();
6158 comm->barrier ();
6159 os << "-- " << myRank << ": past barrier" << endl;
6160 *err << os.str ();
6161 }
6162
6163 // Whether to print debugging output to stderr.
6164 const bool debugPrint = debug && myRank == 0;
6165
6166 // We've already gotten the rowMap above.
6167 auto colMap = graph.getColMap ();
6168 auto domainMap = graph.getDomainMap ();
6169 auto rangeMap = graph.getRangeMap ();
6170
6171 const global_size_t numRows = rangeMap->getGlobalNumElements ();
6172 const global_size_t numCols = domainMap->getGlobalNumElements ();
6173
6174 if (debug && myRank == 0) {
6175 std::ostringstream os;
6176 os << "-- Input sparse graph is:"
6177 << "---- " << numRows << " x " << numCols << " with "
6178 << graph.getGlobalNumEntries () << " entries;" << endl
6179 << "---- "
6180 << (graph.isGloballyIndexed () ? "Globally" : "Locally")
6181 << " indexed." << endl
6182 << "---- Its row Map has " << rowMap->getGlobalNumElements ()
6183 << " elements." << endl
6184 << "---- Its col Map has " << colMap->getGlobalNumElements ()
6185 << " elements." << endl;
6186 *err << os.str ();
6187 }
6188 // Make the "gather" row map, where Proc 0 owns all rows and
6189 // the other procs own no rows.
6190 const size_t localNumRows = (myRank == 0) ? numRows : 0;
6191 if (debug) {
6192 std::ostringstream os;
6193 os << "-- " << myRank << ": making gatherRowMap" << endl;
6194 *err << os.str ();
6195 }
6196 auto gatherRowMap = Details::computeGatherMap (rowMap, err, debug);
6197
6198 // Since the graph may in general be non-square, we need to
6199 // make a column map as well. In this case, the column map
6200 // contains all the columns of the original graph, because we
6201 // are gathering the whole graph onto Proc 0. We call
6202 // computeGatherMap to preserve the original order of column
6203 // indices over all the processes.
6204 const size_t localNumCols = (myRank == 0) ? numCols : 0;
6205 auto gatherColMap = Details::computeGatherMap (colMap, err, debug);
6206
6207 // Current map is the source map, gather map is the target map.
6208 Import<LO, GO, node_type> importer (rowMap, gatherRowMap);
6209
6210 // Create a new CrsGraph to hold the result of the import.
6211 // The constructor needs a column map as well as a row map,
6212 // for the case that the graph is not square.
6213 crs_graph_type newGraph (gatherRowMap, gatherColMap,
6214 static_cast<size_t> (0));
6215 // Import the sparse graph onto Proc 0.
6216 newGraph.doImport (graph, importer, INSERT);
6217
6218 // fillComplete() needs the domain and range maps for the case
6219 // that the graph is not square.
6220 {
6221 RCP<const map_type> gatherDomainMap =
6222 rcp (new map_type (numCols, localNumCols,
6223 domainMap->getIndexBase (),
6224 comm));
6225 RCP<const map_type> gatherRangeMap =
6226 rcp (new map_type (numRows, localNumRows,
6227 rangeMap->getIndexBase (),
6228 comm));
6229 newGraph.fillComplete (gatherDomainMap, gatherRangeMap);
6230 }
6231
6232 if (debugPrint) {
6233 cerr << "-- Output sparse graph is:"
6234 << "---- " << newGraph.getRangeMap ()->getGlobalNumElements ()
6235 << " x "
6236 << newGraph.getDomainMap ()->getGlobalNumElements ()
6237 << " with "
6238 << newGraph.getGlobalNumEntries () << " entries;" << endl
6239 << "---- "
6240 << (newGraph.isGloballyIndexed () ? "Globally" : "Locally")
6241 << " indexed." << endl
6242 << "---- Its row map has "
6243 << newGraph.getRowMap ()->getGlobalNumElements ()
6244 << " elements, with index base "
6245 << newGraph.getRowMap ()->getIndexBase () << "." << endl
6246 << "---- Its col map has "
6247 << newGraph.getColMap ()->getGlobalNumElements ()
6248 << " elements, with index base "
6249 << newGraph.getColMap ()->getIndexBase () << "." << endl
6250 << "---- Element count of output graph's column Map may differ "
6251 << "from that of the input matrix's column Map, if some columns "
6252 << "of the matrix contain no entries." << endl;
6253 }
6254
6255 //
6256 // Print the metadata and the graph entries on Process 0 of
6257 // the graph's communicator.
6258 //
6259 if (myRank == 0) {
6260 // Print the Matrix Market banner line. CrsGraph stores
6261 // data nonsymmetrically ("general"). This implies that
6262 // readSparseGraph() on a symmetrically stored input file,
6263 // followed by writeSparseGraph() on the resulting sparse
6264 // graph, will result in an output file with a different
6265 // banner line than the original input file.
6266 out << "%%MatrixMarket matrix coordinate pattern general" << endl;
6267
6268 // Print comments (the graph name and / or description).
6269 if (graphName != "") {
6270 printAsComment (out, graphName);
6271 }
6272 if (graphDescription != "") {
6273 printAsComment (out, graphDescription);
6274 }
6275
6276 // Print the Matrix Market header (# rows, # columns, #
6277 // stored entries). Use the range resp. domain map for the
6278 // number of rows resp. columns, since Tpetra::CrsGraph uses
6279 // the column map for the number of columns. That only
6280 // corresponds to the "linear-algebraic" number of columns
6281 // when the column map is uniquely owned
6282 // (a.k.a. one-to-one), which only happens if the graph is
6283 // block diagonal (one block per process).
6284 out << newGraph.getRangeMap ()->getGlobalNumElements () << " "
6285 << newGraph.getDomainMap ()->getGlobalNumElements () << " "
6286 << newGraph.getGlobalNumEntries () << endl;
6287
6288 // The Matrix Market format expects one-based row and column
6289 // indices. We'll convert the indices on output from
6290 // whatever index base they use to one-based indices.
6291 const GO rowIndexBase = gatherRowMap->getIndexBase ();
6292 const GO colIndexBase = newGraph.getColMap()->getIndexBase ();
6293 //
6294 // Print the entries of the graph.
6295 //
6296 // newGraph can never be globally indexed, since we called
6297 // fillComplete() on it. We include code for both cases
6298 // (globally or locally indexed) just in case that ever
6299 // changes.
6300 if (newGraph.isGloballyIndexed ()) {
6301 // We know that the "gather" row Map is contiguous, so we
6302 // don't need to get the list of GIDs.
6303 const GO minAllGlobalIndex = gatherRowMap->getMinAllGlobalIndex ();
6304 const GO maxAllGlobalIndex = gatherRowMap->getMaxAllGlobalIndex ();
6305 for (GO globalRowIndex = minAllGlobalIndex;
6306 globalRowIndex <= maxAllGlobalIndex; // inclusive range
6307 ++globalRowIndex) {
6308 typename crs_graph_type::global_inds_host_view_type ind;
6309 newGraph.getGlobalRowView (globalRowIndex, ind);
6310 for (size_t ii = 0; ii < ind.extent(0); ii++) {
6311 const GO globalColIndex = ind(ii);
6312 // Convert row and column indices to 1-based.
6313 // This works because the global index type is signed.
6314 out << (globalRowIndex + 1 - rowIndexBase) << " "
6315 << (globalColIndex + 1 - colIndexBase) << " ";
6316 out << endl;
6317 } // For each entry in the current row
6318 } // For each row of the "gather" graph
6319 }
6320 else { // newGraph is locally indexed
6321 typedef Teuchos::OrdinalTraits<GO> OTG;
6322 for (LO localRowIndex = gatherRowMap->getMinLocalIndex ();
6323 localRowIndex <= gatherRowMap->getMaxLocalIndex ();
6324 ++localRowIndex) {
6325 // Convert from local to global row index.
6326 const GO globalRowIndex =
6327 gatherRowMap->getGlobalElement (localRowIndex);
6328 TEUCHOS_TEST_FOR_EXCEPTION
6329 (globalRowIndex == OTG::invalid (), std::logic_error, "Failed "
6330 "to convert the supposed local row index " << localRowIndex <<
6331 " into a global row index. Please report this bug to the "
6332 "Tpetra developers.");
6333 typename crs_graph_type::local_inds_host_view_type ind;
6334 newGraph.getLocalRowView (localRowIndex, ind);
6335 for (size_t ii = 0; ii < ind.extent(0); ii++) {
6336 // Convert the column index from local to global.
6337 const GO globalColIndex =
6338 newGraph.getColMap ()->getGlobalElement (ind(ii));
6339 TEUCHOS_TEST_FOR_EXCEPTION(
6340 globalColIndex == OTG::invalid(), std::logic_error,
6341 "On local row " << localRowIndex << " of the sparse graph: "
6342 "Failed to convert the supposed local column index "
6343 << ind(ii) << " into a global column index. Please report "
6344 "this bug to the Tpetra developers.");
6345 // Convert row and column indices to 1-based.
6346 // This works because the global index type is signed.
6347 out << (globalRowIndex + 1 - rowIndexBase) << " "
6348 << (globalColIndex + 1 - colIndexBase) << " ";
6349 out << endl;
6350 } // For each entry in the current row
6351 } // For each row of the "gather" graph
6352 } // Whether the "gather" graph is locally or globally indexed
6353 } // If my process' rank is 0
6354 }
6355
6361 static void
6362 writeSparseGraph (std::ostream& out,
6363 const crs_graph_type& graph,
6364 const bool debug=false)
6365 {
6366 writeSparseGraph (out, graph, "", "", debug);
6367 }
6368
6403 static void
6404 writeSparseGraphFile (const std::string& filename,
6405 const crs_graph_type& graph,
6406 const std::string& graphName,
6407 const std::string& graphDescription,
6408 const bool debug=false)
6409 {
6410 auto comm = graph.getComm ();
6411 if (comm.is_null ()) {
6412 // Processes on which the communicator is null shouldn't
6413 // even call this function. The convention is that
6414 // processes on which the object's communicator is null do
6415 // not participate in collective operations involving the
6416 // object.
6417 return;
6418 }
6419 const int myRank = comm->getRank ();
6420 std::ofstream out;
6421
6422 // Only open the file on Process 0.
6423 if (myRank == 0) {
6424 out.open (filename.c_str ());
6425 }
6426 writeSparseGraph (out, graph, graphName, graphDescription, debug);
6427 // We can rely on the destructor of the output stream to close
6428 // the file on scope exit, even if writeSparseGraph() throws
6429 // an exception.
6430 }
6431
6436 static void
6437 writeSparseGraphFile (const std::string& filename,
6438 const crs_graph_type& graph,
6439 const bool debug=false)
6440 {
6441 writeSparseGraphFile (filename, graph, "", "", debug);
6442 }
6443
6452 static void
6453 writeSparseGraphFile (const std::string& filename,
6454 const Teuchos::RCP<const crs_graph_type>& pGraph,
6455 const std::string& graphName,
6456 const std::string& graphDescription,
6457 const bool debug=false)
6458 {
6459 writeSparseGraphFile (filename, *pGraph, graphName, graphDescription, debug);
6460 }
6461
6471 static void
6472 writeSparseGraphFile (const std::string& filename,
6473 const Teuchos::RCP<const crs_graph_type>& pGraph,
6474 const bool debug=false)
6475 {
6476 writeSparseGraphFile (filename, *pGraph, "", "", debug);
6477 }
6478
6501 static void
6502 writeSparse (std::ostream& out,
6503 const sparse_matrix_type& matrix,
6504 const bool debug=false)
6505 {
6506 writeSparse (out, matrix, "", "", debug);
6507 }
6508
6510 static void
6511 writeSparse (std::ostream& out,
6512 const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6513 const bool debug=false)
6514 {
6515 writeSparse (out, *pMatrix, "", "", debug);
6516 }
6517
6546 static void
6547 writeDenseFile (const std::string& filename,
6548 const multivector_type& X,
6549 const std::string& matrixName,
6550 const std::string& matrixDescription,
6551 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6552 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6553 {
6554 const int myRank = X.getMap ().is_null () ? 0 :
6555 (X.getMap ()->getComm ().is_null () ? 0 :
6556 X.getMap ()->getComm ()->getRank ());
6557 std::ofstream out;
6558
6559 if (myRank == 0) { // Only open the file on Process 0.
6560 out.open (filename.c_str());
6561 }
6562
6563 writeDense (out, X, matrixName, matrixDescription, err, dbg);
6564 // We can rely on the destructor of the output stream to close
6565 // the file on scope exit, even if writeDense() throws an
6566 // exception.
6567 }
6568
6574 static void
6575 writeDenseFile (const std::string& filename,
6576 const Teuchos::RCP<const multivector_type>& X,
6577 const std::string& matrixName,
6578 const std::string& matrixDescription,
6579 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6580 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6581 {
6582 TEUCHOS_TEST_FOR_EXCEPTION(
6583 X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
6584 "writeDenseFile: The input MultiVector X is null.");
6585 writeDenseFile (filename, *X, matrixName, matrixDescription, err, dbg);
6586 }
6587
6593 static void
6594 writeDenseFile (const std::string& filename,
6595 const multivector_type& X,
6596 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6597 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6598 {
6599 writeDenseFile (filename, X, "", "", err, dbg);
6600 }
6601
6607 static void
6608 writeDenseFile (const std::string& filename,
6609 const Teuchos::RCP<const multivector_type>& X,
6610 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6611 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6612 {
6613 TEUCHOS_TEST_FOR_EXCEPTION(
6614 X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
6615 "writeDenseFile: The input MultiVector X is null.");
6616 writeDenseFile (filename, *X, err, dbg);
6617 }
6618
6619
6650 static void
6651 writeDense (std::ostream& out,
6652 const multivector_type& X,
6653 const std::string& matrixName,
6654 const std::string& matrixDescription,
6655 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6656 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6657 {
6658 using Teuchos::Comm;
6659 using Teuchos::outArg;
6660 using Teuchos::REDUCE_MAX;
6661 using Teuchos::reduceAll;
6662 using Teuchos::RCP;
6663 using std::endl;
6664
6665 RCP<const Comm<int> > comm = X.getMap ().is_null () ?
6666 Teuchos::null : X.getMap ()->getComm ();
6667 const int myRank = comm.is_null () ? 0 : comm->getRank ();
6668
6669 // If the caller provides a nonnull debug output stream, we
6670 // print debugging output to it. This is a local thing; we
6671 // don't have to check across processes.
6672 const bool debug = ! dbg.is_null ();
6673 if (debug) {
6674 dbg->pushTab ();
6675 std::ostringstream os;
6676 os << myRank << ": writeDense" << endl;
6677 *dbg << os.str ();
6678 dbg->pushTab ();
6679 }
6680 // Print the Matrix Market header.
6681 writeDenseHeader (out, X, matrixName, matrixDescription, err, dbg);
6682
6683 // Print each column one at a time. This is a (perhaps)
6684 // temporary fix for Bug 6288.
6685 const size_t numVecs = X.getNumVectors ();
6686 for (size_t j = 0; j < numVecs; ++j) {
6687 writeDenseColumn (out, * (X.getVector (j)), err, dbg);
6688 }
6689
6690 if (debug) {
6691 dbg->popTab ();
6692 std::ostringstream os;
6693 os << myRank << ": writeDense: Done" << endl;
6694 *dbg << os.str ();
6695 dbg->popTab ();
6696 }
6697 }
6698
6699 private:
6700
6726 static void
6727 writeDenseHeader (std::ostream& out,
6728 const multivector_type& X,
6729 const std::string& matrixName,
6730 const std::string& matrixDescription,
6731 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6732 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6733 {
6734 using Teuchos::Comm;
6735 using Teuchos::outArg;
6736 using Teuchos::RCP;
6737 using Teuchos::REDUCE_MAX;
6738 using Teuchos::reduceAll;
6739 using std::endl;
6740 typedef Teuchos::ScalarTraits<scalar_type> STS;
6741 const char prefix[] = "Tpetra::MatrixMarket::writeDenseHeader: ";
6742
6743 RCP<const Comm<int> > comm = X.getMap ().is_null () ?
6744 Teuchos::null : X.getMap ()->getComm ();
6745 const int myRank = comm.is_null () ? 0 : comm->getRank ();
6746 int lclErr = 0; // whether this MPI process has seen an error
6747 int gblErr = 0; // whether we know if some MPI process has seen an error
6748
6749 // If the caller provides a nonnull debug output stream, we
6750 // print debugging output to it. This is a local thing; we
6751 // don't have to check across processes.
6752 const bool debug = ! dbg.is_null ();
6753
6754 if (debug) {
6755 dbg->pushTab ();
6756 std::ostringstream os;
6757 os << myRank << ": writeDenseHeader" << endl;
6758 *dbg << os.str ();
6759 dbg->pushTab ();
6760 }
6761
6762 //
6763 // Process 0: Write the MatrixMarket header.
6764 //
6765 if (myRank == 0) {
6766 try {
6767 // Print the Matrix Market header. MultiVector stores data
6768 // nonsymmetrically, hence "general" in the banner line.
6769 // Print first to a temporary string output stream, and then
6770 // write it to the main output stream, so that at least the
6771 // header output has transactional semantics. We can't
6772 // guarantee transactional semantics for the whole output,
6773 // since that would not be memory scalable. (This could be
6774 // done in the file system by using a temporary file; we
6775 // don't do this, but users could.)
6776 std::ostringstream hdr;
6777 {
6778 std::string dataType;
6779 if (STS::isComplex) {
6780 dataType = "complex";
6781 } else if (STS::isOrdinal) {
6782 dataType = "integer";
6783 } else {
6784 dataType = "real";
6785 }
6786 hdr << "%%MatrixMarket matrix array " << dataType << " general"
6787 << endl;
6788 }
6789
6790 // Print comments (the matrix name and / or description).
6791 if (matrixName != "") {
6792 printAsComment (hdr, matrixName);
6793 }
6794 if (matrixDescription != "") {
6795 printAsComment (hdr, matrixDescription);
6796 }
6797 // Print the Matrix Market dimensions header for dense matrices.
6798 hdr << X.getGlobalLength () << " " << X.getNumVectors () << endl;
6799
6800 // Write the MatrixMarket header to the output stream.
6801 out << hdr.str ();
6802 } catch (std::exception& e) {
6803 if (! err.is_null ()) {
6804 *err << prefix << "While writing the Matrix Market header, "
6805 "Process 0 threw an exception: " << e.what () << endl;
6806 }
6807 lclErr = 1;
6808 }
6809 } // if I am Process 0
6810
6811 // Establish global agreement on the error state. It wouldn't
6812 // be good for other processes to keep going, if Process 0
6813 // finds out that it can't write to the given output stream.
6814 reduceAll<int, int> (*comm, REDUCE_MAX, lclErr, outArg (gblErr));
6815 TEUCHOS_TEST_FOR_EXCEPTION(
6816 gblErr == 1, std::runtime_error, prefix << "Some error occurred "
6817 "which prevented this method from completing.");
6818
6819 if (debug) {
6820 dbg->popTab ();
6821 *dbg << myRank << ": writeDenseHeader: Done" << endl;
6822 dbg->popTab ();
6823 }
6824 }
6825
6843 static void
6844 writeDenseColumn (std::ostream& out,
6845 const multivector_type& X,
6846 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6847 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6848 {
6849 using Teuchos::arcp;
6850 using Teuchos::Array;
6851 using Teuchos::ArrayRCP;
6852 using Teuchos::ArrayView;
6853 using Teuchos::Comm;
6854 using Teuchos::CommRequest;
6855 using Teuchos::ireceive;
6856 using Teuchos::isend;
6857 using Teuchos::outArg;
6858 using Teuchos::REDUCE_MAX;
6859 using Teuchos::reduceAll;
6860 using Teuchos::RCP;
6861 using Teuchos::TypeNameTraits;
6862 using Teuchos::wait;
6863 using std::endl;
6864 typedef Teuchos::ScalarTraits<scalar_type> STS;
6865
6866 const Comm<int>& comm = * (X.getMap ()->getComm ());
6867 const int myRank = comm.getRank ();
6868 const int numProcs = comm.getSize ();
6869 int lclErr = 0; // whether this MPI process has seen an error
6870 int gblErr = 0; // whether we know if some MPI process has seen an error
6871
6872 // If the caller provides a nonnull debug output stream, we
6873 // print debugging output to it. This is a local thing; we
6874 // don't have to check across processes.
6875 const bool debug = ! dbg.is_null ();
6876
6877 if (debug) {
6878 dbg->pushTab ();
6879 std::ostringstream os;
6880 os << myRank << ": writeDenseColumn" << endl;
6881 *dbg << os.str ();
6882 dbg->pushTab ();
6883 }
6884
6885 // Make the output stream write floating-point numbers in
6886 // scientific notation. It will politely put the output
6887 // stream back to its state on input, when this scope
6888 // terminates.
6889 Teuchos::SetScientific<scalar_type> sci (out);
6890
6891 const size_t myNumRows = X.getLocalLength ();
6892 const size_t numCols = X.getNumVectors ();
6893 // Use a different tag for the "size" messages than for the
6894 // "data" messages, in order to help us debug any mix-ups.
6895 const int sizeTag = 1337;
6896 const int dataTag = 1338;
6897
6898 // Process 0 pipelines nonblocking receives with file output.
6899 //
6900 // Constraints:
6901 // - Process 0 can't post a receive for another process'
6902 // actual data, until it posts and waits on the receive
6903 // from that process with the amount of data to receive.
6904 // (We could just post receives with a max data size, but
6905 // I feel uncomfortable about that.)
6906 // - The C++ standard library doesn't allow nonblocking
6907 // output to an std::ostream. (Thus, we have to start a
6908 // receive or send before starting the write, and hope
6909 // that MPI completes it in the background.)
6910 //
6911 // Process 0: Post receive-size receives from Processes 1 and 2.
6912 // Process 1: Post send-size send to Process 0.
6913 // Process 2: Post send-size send to Process 0.
6914 //
6915 // All processes: Pack my entries.
6916 //
6917 // Process 1:
6918 // - Post send-data send to Process 0.
6919 // - Wait on my send-size send to Process 0.
6920 //
6921 // Process 0:
6922 // - Print MatrixMarket header.
6923 // - Print my entries.
6924 // - Wait on receive-size receive from Process 1.
6925 // - Post receive-data receive from Process 1.
6926 //
6927 // For each process p = 1, 2, ... numProcs-1:
6928 // If I am Process 0:
6929 // - Post receive-size receive from Process p + 2
6930 // - Wait on receive-size receive from Process p + 1
6931 // - Post receive-data receive from Process p + 1
6932 // - Wait on receive-data receive from Process p
6933 // - Write data from Process p.
6934 // Else if I am Process p:
6935 // - Wait on my send-data send.
6936 // Else if I am Process p+1:
6937 // - Post send-data send to Process 0.
6938 // - Wait on my send-size send.
6939 // Else if I am Process p+2:
6940 // - Post send-size send to Process 0.
6941 //
6942 // Pipelining has three goals here:
6943 // 1. Overlap communication (the receives) with file I/O
6944 // 2. Give Process 0 a chance to prepost some receives,
6945 // before sends show up, by packing local data before
6946 // posting sends
6947 // 3. Don't post _all_ receives or _all_ sends, because that
6948 // wouldn't be memory scalable. (Just because we can't
6949 // see how much memory MPI consumes, doesn't mean that it
6950 // doesn't consume any!)
6951
6952 // These are used on every process. sendReqSize[0] holds the
6953 // number of rows on this process, and sendReqBuf holds this
6954 // process' data. Process 0 packs into sendReqBuf, but
6955 // doesn't send; it only uses that for printing. All other
6956 // processes send both of these to Process 0.
6957 RCP<CommRequest<int> > sendReqSize, sendReqData;
6958
6959 // These are used only on Process 0, for received data. Keep
6960 // 3 of each, and treat the arrays as circular buffers. When
6961 // receiving from Process p, the corresponding array index
6962 // here is p % 3.
6963 Array<ArrayRCP<size_t> > recvSizeBufs (3);
6964 Array<ArrayRCP<scalar_type> > recvDataBufs (3);
6965 Array<RCP<CommRequest<int> > > recvSizeReqs (3);
6966 Array<RCP<CommRequest<int> > > recvDataReqs (3);
6967
6968 // Buffer for nonblocking send of the "send size."
6969 ArrayRCP<size_t> sendDataSize (1);
6970 sendDataSize[0] = myNumRows;
6971
6972 if (myRank == 0) {
6973 if (debug) {
6974 std::ostringstream os;
6975 os << myRank << ": Post receive-size receives from "
6976 "Procs 1 and 2: tag = " << sizeTag << endl;
6977 *dbg << os.str ();
6978 }
6979 // Process 0: Post receive-size receives from Processes 1 and 2.
6980 recvSizeBufs[0].resize (1);
6981 // Set these three to an invalid value as a flag. If we
6982 // don't get these messages, then the invalid value will
6983 // remain, so we can test for it.
6984 (recvSizeBufs[0])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
6985 recvSizeBufs[1].resize (1);
6986 (recvSizeBufs[1])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
6987 recvSizeBufs[2].resize (1);
6988 (recvSizeBufs[2])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
6989 if (numProcs > 1) {
6990 recvSizeReqs[1] =
6991 ireceive<int, size_t> (recvSizeBufs[1], 1, sizeTag, comm);
6992 }
6993 if (numProcs > 2) {
6994 recvSizeReqs[2] =
6995 ireceive<int, size_t> (recvSizeBufs[2], 2, sizeTag, comm);
6996 }
6997 }
6998 else if (myRank == 1 || myRank == 2) {
6999 if (debug) {
7000 std::ostringstream os;
7001 os << myRank << ": Post send-size send: size = "
7002 << sendDataSize[0] << ", tag = " << sizeTag << endl;
7003 *dbg << os.str ();
7004 }
7005 // Prime the pipeline by having Processes 1 and 2 start
7006 // their send-size sends. We don't want _all_ the processes
7007 // to start their send-size sends, because that wouldn't be
7008 // memory scalable.
7009 sendReqSize = isend<int, size_t> (sendDataSize, 0, sizeTag, comm);
7010 }
7011 else {
7012 if (debug) {
7013 std::ostringstream os;
7014 os << myRank << ": Not posting my send-size send yet" << endl;
7015 *dbg << os.str ();
7016 }
7017 }
7018
7019 //
7020 // Pack my entries, in column-major order.
7021 //
7022 if (debug) {
7023 std::ostringstream os;
7024 os << myRank << ": Pack my entries" << endl;
7025 *dbg << os.str ();
7026 }
7027 ArrayRCP<scalar_type> sendDataBuf;
7028 try {
7029 sendDataBuf = arcp<scalar_type> (myNumRows * numCols);
7030 X.get1dCopy (sendDataBuf (), myNumRows);
7031 }
7032 catch (std::exception& e) {
7033 lclErr = 1;
7034 if (! err.is_null ()) {
7035 std::ostringstream os;
7036 os << "Process " << myRank << ": Attempt to pack my MultiVector "
7037 "entries threw an exception: " << e.what () << endl;
7038 *err << os.str ();
7039 }
7040 }
7041 if (debug) {
7042 std::ostringstream os;
7043 os << myRank << ": Done packing my entries" << endl;
7044 *dbg << os.str ();
7045 }
7046
7047 //
7048 // Process 1: post send-data send to Process 0.
7049 //
7050 if (myRank == 1) {
7051 if (debug) {
7052 *dbg << myRank << ": Post send-data send: tag = " << dataTag
7053 << endl;
7054 }
7055 sendReqData = isend<int, scalar_type> (sendDataBuf, 0, dataTag, comm);
7056 }
7057
7058 //
7059 // Process 0: Write my entries.
7060 //
7061 if (myRank == 0) {
7062 if (debug) {
7063 std::ostringstream os;
7064 os << myRank << ": Write my entries" << endl;
7065 *dbg << os.str ();
7066 }
7067
7068 // Write Process 0's data to the output stream.
7069 // Matrix Market prints dense matrices in column-major order.
7070 const size_t printNumRows = myNumRows;
7071 ArrayView<const scalar_type> printData = sendDataBuf ();
7072 const size_t printStride = printNumRows;
7073 if (static_cast<size_t> (printData.size ()) < printStride * numCols) {
7074 lclErr = 1;
7075 if (! err.is_null ()) {
7076 std::ostringstream os;
7077 os << "Process " << myRank << ": My MultiVector data's size "
7078 << printData.size () << " does not match my local dimensions "
7079 << printStride << " x " << numCols << "." << endl;
7080 *err << os.str ();
7081 }
7082 }
7083 else {
7084 // Matrix Market dense format wants one number per line.
7085 // It wants each complex number as two real numbers (real
7086 // resp. imaginary parts) with a space between.
7087 for (size_t col = 0; col < numCols; ++col) {
7088 for (size_t row = 0; row < printNumRows; ++row) {
7089 if (STS::isComplex) {
7090 out << STS::real (printData[row + col * printStride]) << " "
7091 << STS::imag (printData[row + col * printStride]) << endl;
7092 } else {
7093 out << printData[row + col * printStride] << endl;
7094 }
7095 }
7096 }
7097 }
7098 }
7099
7100 if (myRank == 0) {
7101 // Wait on receive-size receive from Process 1.
7102 const int recvRank = 1;
7103 const int circBufInd = recvRank % 3;
7104 if (debug) {
7105 std::ostringstream os;
7106 os << myRank << ": Wait on receive-size receive from Process "
7107 << recvRank << endl;
7108 *dbg << os.str ();
7109 }
7110 if (numProcs > 1) {
7111 wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7112
7113 // We received the number of rows of data. (The data
7114 // come in two columns.)
7115 size_t recvNumRows = (recvSizeBufs[circBufInd])[0];
7116 if (recvNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7117 lclErr = 1;
7118 if (! err.is_null ()) {
7119 std::ostringstream os;
7120 os << myRank << ": Result of receive-size receive from Process "
7121 << recvRank << " is Teuchos::OrdinalTraits<size_t>::invalid() "
7122 << "= " << Teuchos::OrdinalTraits<size_t>::invalid () << ". "
7123 "This should never happen, and suggests that the receive never "
7124 "got posted. Please report this bug to the Tpetra developers."
7125 << endl;
7126 *err << os.str ();
7127 }
7128
7129 // If we're going to continue after error, set the
7130 // number of rows to receive to a reasonable size. This
7131 // may cause MPI_ERR_TRUNCATE if the sending process is
7132 // sending more than 0 rows, but that's better than MPI
7133 // overflowing due to the huge positive value that is
7134 // Teuchos::OrdinalTraits<size_t>::invalid().
7135 recvNumRows = 0;
7136 }
7137
7138 // Post receive-data receive from Process 1.
7139 recvDataBufs[circBufInd].resize (recvNumRows * numCols);
7140 if (debug) {
7141 std::ostringstream os;
7142 os << myRank << ": Post receive-data receive from Process "
7143 << recvRank << ": tag = " << dataTag << ", buffer size = "
7144 << recvDataBufs[circBufInd].size () << endl;
7145 *dbg << os.str ();
7146 }
7147 if (! recvSizeReqs[circBufInd].is_null ()) {
7148 lclErr = 1;
7149 if (! err.is_null ()) {
7150 std::ostringstream os;
7151 os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7152 "null, before posting the receive-data receive from Process "
7153 << recvRank << ". This should never happen. Please report "
7154 "this bug to the Tpetra developers." << endl;
7155 *err << os.str ();
7156 }
7157 }
7158 recvDataReqs[circBufInd] =
7159 ireceive<int, scalar_type> (recvDataBufs[circBufInd],
7160 recvRank, dataTag, comm);
7161 } // numProcs > 1
7162 }
7163 else if (myRank == 1) {
7164 // Wait on my send-size send.
7165 if (debug) {
7166 std::ostringstream os;
7167 os << myRank << ": Wait on my send-size send" << endl;
7168 *dbg << os.str ();
7169 }
7170 wait<int> (comm, outArg (sendReqSize));
7171 }
7172
7173 //
7174 // Pipeline loop
7175 //
7176 for (int p = 1; p < numProcs; ++p) {
7177 if (myRank == 0) {
7178 if (p + 2 < numProcs) {
7179 // Post receive-size receive from Process p + 2.
7180 const int recvRank = p + 2;
7181 const int circBufInd = recvRank % 3;
7182 if (debug) {
7183 std::ostringstream os;
7184 os << myRank << ": Post receive-size receive from Process "
7185 << recvRank << ": tag = " << sizeTag << endl;
7186 *dbg << os.str ();
7187 }
7188 if (! recvSizeReqs[circBufInd].is_null ()) {
7189 lclErr = 1;
7190 if (! err.is_null ()) {
7191 std::ostringstream os;
7192 os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7193 << "null, for the receive-size receive from Process "
7194 << recvRank << "! This may mean that this process never "
7195 << "finished waiting for the receive from Process "
7196 << (recvRank - 3) << "." << endl;
7197 *err << os.str ();
7198 }
7199 }
7200 recvSizeReqs[circBufInd] =
7201 ireceive<int, size_t> (recvSizeBufs[circBufInd],
7202 recvRank, sizeTag, comm);
7203 }
7204
7205 if (p + 1 < numProcs) {
7206 const int recvRank = p + 1;
7207 const int circBufInd = recvRank % 3;
7208
7209 // Wait on receive-size receive from Process p + 1.
7210 if (debug) {
7211 std::ostringstream os;
7212 os << myRank << ": Wait on receive-size receive from Process "
7213 << recvRank << endl;
7214 *dbg << os.str ();
7215 }
7216 wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7217
7218 // We received the number of rows of data. (The data
7219 // come in two columns.)
7220 size_t recvNumRows = (recvSizeBufs[circBufInd])[0];
7221 if (recvNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7222 lclErr = 1;
7223 if (! err.is_null ()) {
7224 std::ostringstream os;
7225 os << myRank << ": Result of receive-size receive from Process "
7226 << recvRank << " is Teuchos::OrdinalTraits<size_t>::invalid() "
7227 << "= " << Teuchos::OrdinalTraits<size_t>::invalid () << ". "
7228 "This should never happen, and suggests that the receive never "
7229 "got posted. Please report this bug to the Tpetra developers."
7230 << endl;
7231 *err << os.str ();
7232 }
7233 // If we're going to continue after error, set the
7234 // number of rows to receive to a reasonable size.
7235 // This may cause MPI_ERR_TRUNCATE if the sending
7236 // process sends more than 0 rows, but that's better
7237 // than MPI overflowing due to the huge positive value
7238 // Teuchos::OrdinalTraits<size_t>::invalid().
7239 recvNumRows = 0;
7240 }
7241
7242 // Post receive-data receive from Process p + 1.
7243 recvDataBufs[circBufInd].resize (recvNumRows * numCols);
7244 if (debug) {
7245 std::ostringstream os;
7246 os << myRank << ": Post receive-data receive from Process "
7247 << recvRank << ": tag = " << dataTag << ", buffer size = "
7248 << recvDataBufs[circBufInd].size () << endl;
7249 *dbg << os.str ();
7250 }
7251 if (! recvDataReqs[circBufInd].is_null ()) {
7252 lclErr = 1;
7253 if (! err.is_null ()) {
7254 std::ostringstream os;
7255 os << myRank << ": recvDataReqs[" << circBufInd << "] is not "
7256 << "null, for the receive-data receive from Process "
7257 << recvRank << "! This may mean that this process never "
7258 << "finished waiting for the receive from Process "
7259 << (recvRank - 3) << "." << endl;
7260 *err << os.str ();
7261 }
7262 }
7263 recvDataReqs[circBufInd] =
7264 ireceive<int, scalar_type> (recvDataBufs[circBufInd],
7265 recvRank, dataTag, comm);
7266 }
7267
7268 // Wait on receive-data receive from Process p.
7269 const int recvRank = p;
7270 const int circBufInd = recvRank % 3;
7271 if (debug) {
7272 std::ostringstream os;
7273 os << myRank << ": Wait on receive-data receive from Process "
7274 << recvRank << endl;
7275 *dbg << os.str ();
7276 }
7277 wait<int> (comm, outArg (recvDataReqs[circBufInd]));
7278
7279 // Write Process p's data. Number of rows lives in
7280 // recvSizeBufs[circBufInd], and the actual data live in
7281 // recvDataBufs[circBufInd]. Do this after posting receives,
7282 // in order to expose overlap of comm. with file I/O.
7283 if (debug) {
7284 std::ostringstream os;
7285 os << myRank << ": Write entries from Process " << recvRank
7286 << endl;
7287 *dbg << os.str () << endl;
7288 }
7289 size_t printNumRows = (recvSizeBufs[circBufInd])[0];
7290 if (printNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7291 lclErr = 1;
7292 if (! err.is_null ()) {
7293 std::ostringstream os;
7294 os << myRank << ": Result of receive-size receive from Process "
7295 << recvRank << " was Teuchos::OrdinalTraits<size_t>::"
7296 "invalid() = " << Teuchos::OrdinalTraits<size_t>::invalid ()
7297 << ". This should never happen, and suggests that its "
7298 "receive-size receive was never posted. "
7299 "Please report this bug to the Tpetra developers." << endl;
7300 *err << os.str ();
7301 }
7302 // If we're going to continue after error, set the
7303 // number of rows to print to a reasonable size.
7304 printNumRows = 0;
7305 }
7306 if (printNumRows > 0 && recvDataBufs[circBufInd].is_null ()) {
7307 lclErr = 1;
7308 if (! err.is_null ()) {
7309 std::ostringstream os;
7310 os << myRank << ": Result of receive-size receive from Proc "
7311 << recvRank << " was " << printNumRows << " > 0, but "
7312 "recvDataBufs[" << circBufInd << "] is null. This should "
7313 "never happen. Please report this bug to the Tpetra "
7314 "developers." << endl;
7315 *err << os.str ();
7316 }
7317 // If we're going to continue after error, set the
7318 // number of rows to print to a reasonable size.
7319 printNumRows = 0;
7320 }
7321
7322 // Write the received data to the output stream.
7323 // Matrix Market prints dense matrices in column-major order.
7324 ArrayView<const scalar_type> printData = (recvDataBufs[circBufInd]) ();
7325 const size_t printStride = printNumRows;
7326 // Matrix Market dense format wants one number per line.
7327 // It wants each complex number as two real numbers (real
7328 // resp. imaginary parts) with a space between.
7329 for (size_t col = 0; col < numCols; ++col) {
7330 for (size_t row = 0; row < printNumRows; ++row) {
7331 if (STS::isComplex) {
7332 out << STS::real (printData[row + col * printStride]) << " "
7333 << STS::imag (printData[row + col * printStride]) << endl;
7334 } else {
7335 out << printData[row + col * printStride] << endl;
7336 }
7337 }
7338 }
7339 }
7340 else if (myRank == p) { // Process p
7341 // Wait on my send-data send.
7342 if (debug) {
7343 std::ostringstream os;
7344 os << myRank << ": Wait on my send-data send" << endl;
7345 *dbg << os.str ();
7346 }
7347 wait<int> (comm, outArg (sendReqData));
7348 }
7349 else if (myRank == p + 1) { // Process p + 1
7350 // Post send-data send to Process 0.
7351 if (debug) {
7352 std::ostringstream os;
7353 os << myRank << ": Post send-data send: tag = " << dataTag
7354 << endl;
7355 *dbg << os.str ();
7356 }
7357 sendReqData = isend<int, scalar_type> (sendDataBuf, 0, dataTag, comm);
7358 // Wait on my send-size send.
7359 if (debug) {
7360 std::ostringstream os;
7361 os << myRank << ": Wait on my send-size send" << endl;
7362 *dbg << os.str ();
7363 }
7364 wait<int> (comm, outArg (sendReqSize));
7365 }
7366 else if (myRank == p + 2) { // Process p + 2
7367 // Post send-size send to Process 0.
7368 if (debug) {
7369 std::ostringstream os;
7370 os << myRank << ": Post send-size send: size = "
7371 << sendDataSize[0] << ", tag = " << sizeTag << endl;
7372 *dbg << os.str ();
7373 }
7374 sendReqSize = isend<int, size_t> (sendDataSize, 0, sizeTag, comm);
7375 }
7376 }
7377
7378 // Establish global agreement on the error state.
7379 reduceAll<int, int> (comm, REDUCE_MAX, lclErr, outArg (gblErr));
7380 TEUCHOS_TEST_FOR_EXCEPTION(
7381 gblErr == 1, std::runtime_error, "Tpetra::MatrixMarket::writeDense "
7382 "experienced some kind of error and was unable to complete.");
7383
7384 if (debug) {
7385 dbg->popTab ();
7386 *dbg << myRank << ": writeDenseColumn: Done" << endl;
7387 dbg->popTab ();
7388 }
7389 }
7390
7391 public:
7392
7398 static void
7399 writeDense (std::ostream& out,
7400 const Teuchos::RCP<const multivector_type>& X,
7401 const std::string& matrixName,
7402 const std::string& matrixDescription,
7403 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7404 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7405 {
7406 TEUCHOS_TEST_FOR_EXCEPTION(
7407 X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
7408 "writeDense: The input MultiVector X is null.");
7409 writeDense (out, *X, matrixName, matrixDescription, err, dbg);
7410 }
7411
7417 static void
7418 writeDense (std::ostream& out,
7419 const multivector_type& X,
7420 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7421 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7422 {
7423 writeDense (out, X, "", "", err, dbg);
7424 }
7425
7431 static void
7432 writeDense (std::ostream& out,
7433 const Teuchos::RCP<const multivector_type>& X,
7434 const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7435 const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7436 {
7437 TEUCHOS_TEST_FOR_EXCEPTION(
7438 X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
7439 "writeDense: The input MultiVector X is null.");
7440 writeDense (out, *X, "", "", err, dbg);
7441 }
7442
7462 static void
7463 writeMap (std::ostream& out, const map_type& map, const bool debug=false)
7464 {
7465 Teuchos::RCP<Teuchos::FancyOStream> err =
7466 Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
7467 writeMap (out, map, err, debug);
7468 }
7469
7478 static void
7479 writeMap (std::ostream& out,
7480 const map_type& map,
7481 const Teuchos::RCP<Teuchos::FancyOStream>& err,
7482 const bool debug=false)
7483 {
7484 using Teuchos::Array;
7485 using Teuchos::ArrayRCP;
7486 using Teuchos::ArrayView;
7487 using Teuchos::Comm;
7488 using Teuchos::CommRequest;
7489 using Teuchos::ireceive;
7490 using Teuchos::isend;
7491 using Teuchos::RCP;
7492 using Teuchos::TypeNameTraits;
7493 using Teuchos::wait;
7494 using std::endl;
7495 typedef global_ordinal_type GO;
7496 typedef int pid_type;
7497
7498 // Treat the Map as a 1-column "multivector." This differs
7499 // from the previous two-column format, in which column 0 held
7500 // the GIDs, and column 1 held the corresponding PIDs. It
7501 // differs because printing that format requires knowing the
7502 // entire first column -- that is, all the GIDs -- in advance.
7503 // Sending messages from each process one at a time saves
7504 // memory, but it means that Process 0 doesn't ever have all
7505 // the GIDs at once.
7506 //
7507 // We pack the entries as ptrdiff_t, since this should be the
7508 // biggest signed built-in integer type that can hold any GO
7509 // or pid_type (= int) quantity without overflow. Test this
7510 // assumption at run time.
7511 typedef ptrdiff_t int_type;
7512 TEUCHOS_TEST_FOR_EXCEPTION(
7513 sizeof (GO) > sizeof (int_type), std::logic_error,
7514 "The global ordinal type GO=" << TypeNameTraits<GO>::name ()
7515 << " is too big for ptrdiff_t. sizeof(GO) = " << sizeof (GO)
7516 << " > sizeof(ptrdiff_t) = " << sizeof (ptrdiff_t) << ".");
7517 TEUCHOS_TEST_FOR_EXCEPTION(
7518 sizeof (pid_type) > sizeof (int_type), std::logic_error,
7519 "The (MPI) process rank type pid_type=" <<
7520 TypeNameTraits<pid_type>::name () << " is too big for ptrdiff_t. "
7521 "sizeof(pid_type) = " << sizeof (pid_type) << " > sizeof(ptrdiff_t)"
7522 " = " << sizeof (ptrdiff_t) << ".");
7523
7524 const Comm<int>& comm = * (map.getComm ());
7525 const int myRank = comm.getRank ();
7526 const int numProcs = comm.getSize ();
7527
7528 if (! err.is_null ()) {
7529 err->pushTab ();
7530 }
7531 if (debug) {
7532 std::ostringstream os;
7533 os << myRank << ": writeMap" << endl;
7534 *err << os.str ();
7535 }
7536 if (! err.is_null ()) {
7537 err->pushTab ();
7538 }
7539
7540 const size_t myNumRows = map.getNodeNumElements ();
7541 // Use a different tag for the "size" messages than for the
7542 // "data" messages, in order to help us debug any mix-ups.
7543 const int sizeTag = 1337;
7544 const int dataTag = 1338;
7545
7546 // Process 0 pipelines nonblocking receives with file output.
7547 //
7548 // Constraints:
7549 // - Process 0 can't post a receive for another process'
7550 // actual data, until it posts and waits on the receive
7551 // from that process with the amount of data to receive.
7552 // (We could just post receives with a max data size, but
7553 // I feel uncomfortable about that.)
7554 // - The C++ standard library doesn't allow nonblocking
7555 // output to an std::ostream.
7556 //
7557 // Process 0: Post receive-size receives from Processes 1 and 2.
7558 // Process 1: Post send-size send to Process 0.
7559 // Process 2: Post send-size send to Process 0.
7560 //
7561 // All processes: Pack my GIDs and PIDs.
7562 //
7563 // Process 1:
7564 // - Post send-data send to Process 0.
7565 // - Wait on my send-size send to Process 0.
7566 //
7567 // Process 0:
7568 // - Print MatrixMarket header.
7569 // - Print my GIDs and PIDs.
7570 // - Wait on receive-size receive from Process 1.
7571 // - Post receive-data receive from Process 1.
7572 //
7573 // For each process p = 1, 2, ... numProcs-1:
7574 // If I am Process 0:
7575 // - Post receive-size receive from Process p + 2
7576 // - Wait on receive-size receive from Process p + 1
7577 // - Post receive-data receive from Process p + 1
7578 // - Wait on receive-data receive from Process p
7579 // - Write data from Process p.
7580 // Else if I am Process p:
7581 // - Wait on my send-data send.
7582 // Else if I am Process p+1:
7583 // - Post send-data send to Process 0.
7584 // - Wait on my send-size send.
7585 // Else if I am Process p+2:
7586 // - Post send-size send to Process 0.
7587 //
7588 // Pipelining has three goals here:
7589 // 1. Overlap communication (the receives) with file I/O
7590 // 2. Give Process 0 a chance to prepost some receives,
7591 // before sends show up, by packing local data before
7592 // posting sends
7593 // 3. Don't post _all_ receives or _all_ sends, because that
7594 // wouldn't be memory scalable. (Just because we can't
7595 // see how much memory MPI consumes, doesn't mean that it
7596 // doesn't consume any!)
7597
7598 // These are used on every process. sendReqSize[0] holds the
7599 // number of rows on this process, and sendReqBuf holds this
7600 // process' data. Process 0 packs into sendReqBuf, but
7601 // doesn't send; it only uses that for printing. All other
7602 // processes send both of these to Process 0.
7603 RCP<CommRequest<int> > sendReqSize, sendReqData;
7604
7605 // These are used only on Process 0, for received data. Keep
7606 // 3 of each, and treat the arrays as circular buffers. When
7607 // receiving from Process p, the corresponding array index
7608 // here is p % 3.
7609 Array<ArrayRCP<int_type> > recvSizeBufs (3);
7610 Array<ArrayRCP<int_type> > recvDataBufs (3);
7611 Array<RCP<CommRequest<int> > > recvSizeReqs (3);
7612 Array<RCP<CommRequest<int> > > recvDataReqs (3);
7613
7614 // Buffer for nonblocking send of the "send size."
7615 ArrayRCP<int_type> sendDataSize (1);
7616 sendDataSize[0] = myNumRows;
7617
7618 if (myRank == 0) {
7619 if (debug) {
7620 std::ostringstream os;
7621 os << myRank << ": Post receive-size receives from "
7622 "Procs 1 and 2: tag = " << sizeTag << endl;
7623 *err << os.str ();
7624 }
7625 // Process 0: Post receive-size receives from Processes 1 and 2.
7626 recvSizeBufs[0].resize (1);
7627 (recvSizeBufs[0])[0] = -1; // error flag
7628 recvSizeBufs[1].resize (1);
7629 (recvSizeBufs[1])[0] = -1; // error flag
7630 recvSizeBufs[2].resize (1);
7631 (recvSizeBufs[2])[0] = -1; // error flag
7632 if (numProcs > 1) {
7633 recvSizeReqs[1] =
7634 ireceive<int, int_type> (recvSizeBufs[1], 1, sizeTag, comm);
7635 }
7636 if (numProcs > 2) {
7637 recvSizeReqs[2] =
7638 ireceive<int, int_type> (recvSizeBufs[2], 2, sizeTag, comm);
7639 }
7640 }
7641 else if (myRank == 1 || myRank == 2) {
7642 if (debug) {
7643 std::ostringstream os;
7644 os << myRank << ": Post send-size send: size = "
7645 << sendDataSize[0] << ", tag = " << sizeTag << endl;
7646 *err << os.str ();
7647 }
7648 // Prime the pipeline by having Processes 1 and 2 start
7649 // their send-size sends. We don't want _all_ the processes
7650 // to start their send-size sends, because that wouldn't be
7651 // memory scalable.
7652 sendReqSize = isend<int, int_type> (sendDataSize, 0, sizeTag, comm);
7653 }
7654 else {
7655 if (debug) {
7656 std::ostringstream os;
7657 os << myRank << ": Not posting my send-size send yet" << endl;
7658 *err << os.str ();
7659 }
7660 }
7661
7662 //
7663 // Pack my GIDs and PIDs. Each (GID,PID) pair gets packed
7664 // consecutively, for better locality.
7665 //
7666
7667 if (debug) {
7668 std::ostringstream os;
7669 os << myRank << ": Pack my GIDs and PIDs" << endl;
7670 *err << os.str ();
7671 }
7672
7673 ArrayRCP<int_type> sendDataBuf (myNumRows * 2);
7674
7675 if (map.isContiguous ()) {
7676 const int_type myMinGblIdx =
7677 static_cast<int_type> (map.getMinGlobalIndex ());
7678 for (size_t k = 0; k < myNumRows; ++k) {
7679 const int_type gid = myMinGblIdx + static_cast<int_type> (k);
7680 const int_type pid = static_cast<int_type> (myRank);
7681 sendDataBuf[2*k] = gid;
7682 sendDataBuf[2*k+1] = pid;
7683 }
7684 }
7685 else {
7686 ArrayView<const GO> myGblInds = map.getNodeElementList ();
7687 for (size_t k = 0; k < myNumRows; ++k) {
7688 const int_type gid = static_cast<int_type> (myGblInds[k]);
7689 const int_type pid = static_cast<int_type> (myRank);
7690 sendDataBuf[2*k] = gid;
7691 sendDataBuf[2*k+1] = pid;
7692 }
7693 }
7694
7695 if (debug) {
7696 std::ostringstream os;
7697 os << myRank << ": Done packing my GIDs and PIDs" << endl;
7698 *err << os.str ();
7699 }
7700
7701 if (myRank == 1) {
7702 // Process 1: post send-data send to Process 0.
7703 if (debug) {
7704 *err << myRank << ": Post send-data send: tag = " << dataTag
7705 << endl;
7706 }
7707 sendReqData = isend<int, int_type> (sendDataBuf, 0, dataTag, comm);
7708 }
7709
7710 if (myRank == 0) {
7711 if (debug) {
7712 *err << myRank << ": Write MatrixMarket header" << endl;
7713 }
7714
7715 // Process 0: Write the MatrixMarket header.
7716 // Description section explains each column.
7717 std::ostringstream hdr;
7718
7719 // Print the Matrix Market header. MultiVector stores data
7720 // nonsymmetrically, hence "general" in the banner line.
7721 hdr << "%%MatrixMarket matrix array integer general" << endl
7722 << "% Format: Version 2.0" << endl
7723 << "%" << endl
7724 << "% This file encodes a Tpetra::Map." << endl
7725 << "% It is stored as a dense vector, with twice as many " << endl
7726 << "% entries as the global number of GIDs (global indices)." << endl
7727 << "% (GID, PID) pairs are stored contiguously, where the PID " << endl
7728 << "% is the rank of the process owning that GID." << endl
7729 << (2 * map.getGlobalNumElements ()) << " " << 1 << endl;
7730 out << hdr.str ();
7731
7732 if (debug) {
7733 std::ostringstream os;
7734 os << myRank << ": Write my GIDs and PIDs" << endl;
7735 *err << os.str ();
7736 }
7737
7738 // Write Process 0's data to the output stream.
7739 // Matrix Market prints dense matrices in column-major order.
7740 const int_type printNumRows = myNumRows;
7741 ArrayView<const int_type> printData = sendDataBuf ();
7742 for (int_type k = 0; k < printNumRows; ++k) {
7743 const int_type gid = printData[2*k];
7744 const int_type pid = printData[2*k+1];
7745 out << gid << endl << pid << endl;
7746 }
7747 }
7748
7749 if (myRank == 0) {
7750 // Wait on receive-size receive from Process 1.
7751 const int recvRank = 1;
7752 const int circBufInd = recvRank % 3;
7753 if (debug) {
7754 std::ostringstream os;
7755 os << myRank << ": Wait on receive-size receive from Process "
7756 << recvRank << endl;
7757 *err << os.str ();
7758 }
7759 if (numProcs > 1) {
7760 wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7761
7762 // We received the number of rows of data. (The data
7763 // come in two columns.)
7764 const int_type recvNumRows = (recvSizeBufs[circBufInd])[0];
7765 if (debug && recvNumRows == -1) {
7766 std::ostringstream os;
7767 os << myRank << ": Result of receive-size receive from Process "
7768 << recvRank << " is -1. This should never happen, and "
7769 "suggests that the receive never got posted. Please report "
7770 "this bug to the Tpetra developers." << endl;
7771 *err << os.str ();
7772 }
7773
7774 // Post receive-data receive from Process 1.
7775 recvDataBufs[circBufInd].resize (recvNumRows * 2);
7776 if (debug) {
7777 std::ostringstream os;
7778 os << myRank << ": Post receive-data receive from Process "
7779 << recvRank << ": tag = " << dataTag << ", buffer size = "
7780 << recvDataBufs[circBufInd].size () << endl;
7781 *err << os.str ();
7782 }
7783 if (! recvSizeReqs[circBufInd].is_null ()) {
7784 std::ostringstream os;
7785 os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7786 "null, before posting the receive-data receive from Process "
7787 << recvRank << ". This should never happen. Please report "
7788 "this bug to the Tpetra developers." << endl;
7789 *err << os.str ();
7790 }
7791 recvDataReqs[circBufInd] =
7792 ireceive<int, int_type> (recvDataBufs[circBufInd],
7793 recvRank, dataTag, comm);
7794 } // numProcs > 1
7795 }
7796 else if (myRank == 1) {
7797 // Wait on my send-size send.
7798 if (debug) {
7799 std::ostringstream os;
7800 os << myRank << ": Wait on my send-size send" << endl;
7801 *err << os.str ();
7802 }
7803 wait<int> (comm, outArg (sendReqSize));
7804 }
7805
7806 //
7807 // Pipeline loop
7808 //
7809 for (int p = 1; p < numProcs; ++p) {
7810 if (myRank == 0) {
7811 if (p + 2 < numProcs) {
7812 // Post receive-size receive from Process p + 2.
7813 const int recvRank = p + 2;
7814 const int circBufInd = recvRank % 3;
7815 if (debug) {
7816 std::ostringstream os;
7817 os << myRank << ": Post receive-size receive from Process "
7818 << recvRank << ": tag = " << sizeTag << endl;
7819 *err << os.str ();
7820 }
7821 if (! recvSizeReqs[circBufInd].is_null ()) {
7822 std::ostringstream os;
7823 os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7824 << "null, for the receive-size receive from Process "
7825 << recvRank << "! This may mean that this process never "
7826 << "finished waiting for the receive from Process "
7827 << (recvRank - 3) << "." << endl;
7828 *err << os.str ();
7829 }
7830 recvSizeReqs[circBufInd] =
7831 ireceive<int, int_type> (recvSizeBufs[circBufInd],
7832 recvRank, sizeTag, comm);
7833 }
7834
7835 if (p + 1 < numProcs) {
7836 const int recvRank = p + 1;
7837 const int circBufInd = recvRank % 3;
7838
7839 // Wait on receive-size receive from Process p + 1.
7840 if (debug) {
7841 std::ostringstream os;
7842 os << myRank << ": Wait on receive-size receive from Process "
7843 << recvRank << endl;
7844 *err << os.str ();
7845 }
7846 wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7847
7848 // We received the number of rows of data. (The data
7849 // come in two columns.)
7850 const int_type recvNumRows = (recvSizeBufs[circBufInd])[0];
7851 if (debug && recvNumRows == -1) {
7852 std::ostringstream os;
7853 os << myRank << ": Result of receive-size receive from Process "
7854 << recvRank << " is -1. This should never happen, and "
7855 "suggests that the receive never got posted. Please report "
7856 "this bug to the Tpetra developers." << endl;
7857 *err << os.str ();
7858 }
7859
7860 // Post receive-data receive from Process p + 1.
7861 recvDataBufs[circBufInd].resize (recvNumRows * 2);
7862 if (debug) {
7863 std::ostringstream os;
7864 os << myRank << ": Post receive-data receive from Process "
7865 << recvRank << ": tag = " << dataTag << ", buffer size = "
7866 << recvDataBufs[circBufInd].size () << endl;
7867 *err << os.str ();
7868 }
7869 if (! recvDataReqs[circBufInd].is_null ()) {
7870 std::ostringstream os;
7871 os << myRank << ": recvDataReqs[" << circBufInd << "] is not "
7872 << "null, for the receive-data receive from Process "
7873 << recvRank << "! This may mean that this process never "
7874 << "finished waiting for the receive from Process "
7875 << (recvRank - 3) << "." << endl;
7876 *err << os.str ();
7877 }
7878 recvDataReqs[circBufInd] =
7879 ireceive<int, int_type> (recvDataBufs[circBufInd],
7880 recvRank, dataTag, comm);
7881 }
7882
7883 // Wait on receive-data receive from Process p.
7884 const int recvRank = p;
7885 const int circBufInd = recvRank % 3;
7886 if (debug) {
7887 std::ostringstream os;
7888 os << myRank << ": Wait on receive-data receive from Process "
7889 << recvRank << endl;
7890 *err << os.str ();
7891 }
7892 wait<int> (comm, outArg (recvDataReqs[circBufInd]));
7893
7894 // Write Process p's data. Number of rows lives in
7895 // recvSizeBufs[circBufInd], and the actual data live in
7896 // recvDataBufs[circBufInd]. Do this after posting receives,
7897 // in order to expose overlap of comm. with file I/O.
7898 if (debug) {
7899 std::ostringstream os;
7900 os << myRank << ": Write GIDs and PIDs from Process "
7901 << recvRank << endl;
7902 *err << os.str () << endl;
7903 }
7904 const int_type printNumRows = (recvSizeBufs[circBufInd])[0];
7905 if (debug && printNumRows == -1) {
7906 std::ostringstream os;
7907 os << myRank << ": Result of receive-size receive from Process "
7908 << recvRank << " was -1. This should never happen, and "
7909 "suggests that its receive-size receive was never posted. "
7910 "Please report this bug to the Tpetra developers." << endl;
7911 *err << os.str ();
7912 }
7913 if (debug && printNumRows > 0 && recvDataBufs[circBufInd].is_null ()) {
7914 std::ostringstream os;
7915 os << myRank << ": Result of receive-size receive from Proc "
7916 << recvRank << " was " << printNumRows << " > 0, but "
7917 "recvDataBufs[" << circBufInd << "] is null. This should "
7918 "never happen. Please report this bug to the Tpetra "
7919 "developers." << endl;
7920 *err << os.str ();
7921 }
7922 ArrayView<const int_type> printData = (recvDataBufs[circBufInd]) ();
7923 for (int_type k = 0; k < printNumRows; ++k) {
7924 const int_type gid = printData[2*k];
7925 const int_type pid = printData[2*k+1];
7926 out << gid << endl << pid << endl;
7927 }
7928 }
7929 else if (myRank == p) { // Process p
7930 // Wait on my send-data send.
7931 if (debug) {
7932 std::ostringstream os;
7933 os << myRank << ": Wait on my send-data send" << endl;
7934 *err << os.str ();
7935 }
7936 wait<int> (comm, outArg (sendReqData));
7937 }
7938 else if (myRank == p + 1) { // Process p + 1
7939 // Post send-data send to Process 0.
7940 if (debug) {
7941 std::ostringstream os;
7942 os << myRank << ": Post send-data send: tag = " << dataTag
7943 << endl;
7944 *err << os.str ();
7945 }
7946 sendReqData = isend<int, int_type> (sendDataBuf, 0, dataTag, comm);
7947 // Wait on my send-size send.
7948 if (debug) {
7949 std::ostringstream os;
7950 os << myRank << ": Wait on my send-size send" << endl;
7951 *err << os.str ();
7952 }
7953 wait<int> (comm, outArg (sendReqSize));
7954 }
7955 else if (myRank == p + 2) { // Process p + 2
7956 // Post send-size send to Process 0.
7957 if (debug) {
7958 std::ostringstream os;
7959 os << myRank << ": Post send-size send: size = "
7960 << sendDataSize[0] << ", tag = " << sizeTag << endl;
7961 *err << os.str ();
7962 }
7963 sendReqSize = isend<int, int_type> (sendDataSize, 0, sizeTag, comm);
7964 }
7965 }
7966
7967 if (! err.is_null ()) {
7968 err->popTab ();
7969 }
7970 if (debug) {
7971 *err << myRank << ": writeMap: Done" << endl;
7972 }
7973 if (! err.is_null ()) {
7974 err->popTab ();
7975 }
7976 }
7977
7979 static void
7980 writeMapFile (const std::string& filename,
7981 const map_type& map)
7982 {
7983 const int myRank = map.getComm ()->getRank ();
7984 std::ofstream out;
7985 if (myRank == 0) { // Only open the file on Proc 0.
7986 out.open (filename.c_str());
7987 }
7988 writeMap (out, map);
7989 // We can rely on the destructor of the output stream to close
7990 // the file on scope exit, even if writeDense() throws an
7991 // exception.
7992 }
7993
7994 private:
8018 static void
8019 printAsComment (std::ostream& out, const std::string& str)
8020 {
8021 using std::endl;
8022 std::istringstream inpstream (str);
8023 std::string line;
8024
8025 while (getline (inpstream, line)) {
8026 if (! line.empty()) {
8027 // Note that getline() doesn't store '\n', so we have to
8028 // append the endline ourselves.
8029 if (line[0] == '%') { // Line starts with a comment character.
8030 out << line << endl;
8031 }
8032 else { // Line doesn't start with a comment character.
8033 out << "%% " << line << endl;
8034 }
8035 }
8036 }
8037 }
8038
8039 public:
8040
8059 static void
8060 writeOperator(const std::string& fileName, operator_type const &A) {
8061 Teuchos::ParameterList pl;
8062 writeOperator(fileName, A, pl);
8063 }
8064
8085 static void
8086 writeOperator (std::ostream& out, const operator_type& A) {
8087 Teuchos::ParameterList pl;
8088 writeOperator (out, A, pl);
8089 }
8090
8127 static void
8128 writeOperator (const std::string& fileName,
8129 const operator_type& A,
8130 const Teuchos::ParameterList& params)
8131 {
8132 std::ofstream out;
8133 std::string tmpFile = "__TMP__" + fileName;
8134 const int myRank = A.getDomainMap()->getComm()->getRank();
8135 bool precisionChanged=false;
8136 int oldPrecision;
8137 // The number of nonzero entries in a Tpetra::Operator is
8138 // unknown until probing is completed. In order to write a
8139 // MatrixMarket header, we write the matrix to a temporary
8140 // file.
8141 //
8142 // FIXME (mfh 23 May 2015) IT WASN'T MY IDEA TO WRITE TO A
8143 // TEMPORARY FILE.
8144 if (myRank==0) {
8145 if (std::ifstream(tmpFile))
8146 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error,
8147 "writeOperator: temporary file " << tmpFile << " already exists");
8148 out.open(tmpFile.c_str());
8149 if (params.isParameter("precision")) {
8150 oldPrecision = out.precision(params.get<int>("precision"));
8151 precisionChanged=true;
8152 }
8153 }
8154
8155 const std::string header = writeOperatorImpl(out, A, params);
8156
8157 if (myRank==0) {
8158 if (precisionChanged)
8159 out.precision(oldPrecision);
8160 out.close();
8161 out.open(fileName.c_str(), std::ios::binary);
8162 bool printMatrixMarketHeader = true;
8163 if (params.isParameter("print MatrixMarket header"))
8164 printMatrixMarketHeader = params.get<bool>("print MatrixMarket header");
8165 if (printMatrixMarketHeader && myRank == 0) {
8166 // Write header to final file.
8167 out << header;
8168 }
8169 // Append matrix from temporary to final file.
8170 std::ifstream src(tmpFile, std::ios_base::binary);
8171 out << src.rdbuf();
8172 src.close();
8173 // Delete the temporary file.
8174 remove(tmpFile.c_str());
8175 }
8176 }
8177
8216 static void
8217 writeOperator (std::ostream& out,
8218 const operator_type& A,
8219 const Teuchos::ParameterList& params)
8220 {
8221 const int myRank = A.getDomainMap ()->getComm ()->getRank ();
8222
8223 // The number of nonzero entries in a Tpetra::Operator is
8224 // unknown until probing is completed. In order to write a
8225 // MatrixMarket header, we write the matrix to a temporary
8226 // output stream.
8227 //
8228 // NOTE (mfh 23 May 2015): Writing to a temporary output
8229 // stream may double the memory usage, depending on whether
8230 // 'out' is a file stream or an in-memory output stream (e.g.,
8231 // std::ostringstream). It might be wise to use a temporary
8232 // file instead. However, please look carefully at POSIX
8233 // functions for safe creation of temporary files. Don't just
8234 // prepend "__TMP__" to the filename and hope for the best.
8235 // Furthermore, it should be valid to call the std::ostream
8236 // overload of this method even when Process 0 does not have
8237 // access to a file system.
8238 std::ostringstream tmpOut;
8239 if (myRank == 0) {
8240 if (params.isParameter ("precision") && params.isType<int> ("precision")) {
8241 (void) tmpOut.precision (params.get<int> ("precision"));
8242 }
8243 }
8244
8245 const std::string header = writeOperatorImpl (tmpOut, A, params);
8246
8247 if (myRank == 0) {
8248 bool printMatrixMarketHeader = true;
8249 if (params.isParameter ("print MatrixMarket header") &&
8250 params.isType<bool> ("print MatrixMarket header")) {
8251 printMatrixMarketHeader = params.get<bool> ("print MatrixMarket header");
8252 }
8253 if (printMatrixMarketHeader && myRank == 0) {
8254 out << header; // write header to final output stream
8255 }
8256 // Append matrix from temporary output stream to final output stream.
8257 //
8258 // NOTE (mfh 23 May 2015) This might use a lot of memory.
8259 // However, we should not use temporary files in this
8260 // method. Since it does not access the file system (unlike
8261 // the overload that takes a file name), it should not
8262 // require the file system at all.
8263 //
8264 // If memory usage becomes a problem, one thing we could do
8265 // is write the entries of the Operator one column (or a few
8266 // columns) at a time. The Matrix Market sparse format does
8267 // not impose an order on its entries, so it would be OK to
8268 // write them in that order.
8269 out << tmpOut.str ();
8270 }
8271 }
8272
8273 private:
8274
8282 static std::string
8283 writeOperatorImpl (std::ostream& os,
8284 const operator_type& A,
8285 const Teuchos::ParameterList& params)
8286 {
8287 using Teuchos::RCP;
8288 using Teuchos::rcp;
8289 using Teuchos::ArrayRCP;
8290 using Teuchos::Array;
8291
8292 typedef local_ordinal_type LO;
8293 typedef global_ordinal_type GO;
8294 typedef scalar_type Scalar;
8295 typedef Teuchos::OrdinalTraits<LO> TLOT;
8296 typedef Teuchos::OrdinalTraits<GO> TGOT;
8297 typedef Tpetra::Import<LO, GO, node_type> import_type;
8299
8300 const map_type& domainMap = *(A.getDomainMap());
8301 RCP<const map_type> rangeMap = A.getRangeMap();
8302 RCP<const Teuchos::Comm<int> > comm = rangeMap->getComm();
8303 const int myRank = comm->getRank();
8304 const size_t numProcs = comm->getSize();
8305
8306 size_t numMVs = 10;
8307 if (params.isParameter("probing size"))
8308 numMVs = params.get<int>("probing size");
8309
8310 GO globalNnz = 0;
8311 GO minColGid = domainMap.getMinAllGlobalIndex();
8312 GO maxColGid = domainMap.getMaxAllGlobalIndex();
8313 // Rather than replicating the domainMap on all processors, we instead
8314 // iterate from the min GID to the max GID. If the map is gappy,
8315 // there will be invalid GIDs, i.e., GIDs no one has. This will require
8316 // unnecessary matvecs against potentially zero vectors.
8317 GO numGlobElts = maxColGid - minColGid + TGOT::one();
8318 GO numChunks = numGlobElts / numMVs;
8319 GO rem = numGlobElts % numMVs;
8320 GO indexBase = rangeMap->getIndexBase();
8321
8322 int offsetToUseInPrinting = 1 - indexBase; // default is 1-based indexing
8323 if (params.isParameter("zero-based indexing")) {
8324 if (params.get<bool>("zero-based indexing") == true)
8325 offsetToUseInPrinting = -indexBase; // If 0-based, use as-is. If 1-based, subtract 1.
8326 }
8327
8328 // Create map that replicates the range map on pid 0 and is empty for all other pids
8329 size_t numLocalRangeEntries = rangeMap->getNodeNumElements();
8330
8331 // Create contiguous source map
8332 RCP<const map_type> allGidsMap = rcp(new map_type(TGOT::invalid(), numLocalRangeEntries,
8333 indexBase, comm));
8334 // Create vector based on above map. Populate it with GIDs corresponding to this pid's GIDs in rangeMap.
8335 mv_type_go allGids(allGidsMap,1);
8336 Teuchos::ArrayRCP<GO> allGidsData = allGids.getDataNonConst(0);
8337
8338 for (size_t i=0; i<numLocalRangeEntries; i++)
8339 allGidsData[i] = rangeMap->getGlobalElement(i);
8340 allGidsData = Teuchos::null;
8341
8342 // Create target map that is nontrivial only on pid 0
8343 GO numTargetMapEntries=TGOT::zero();
8344 Teuchos::Array<GO> importGidList;
8345 if (myRank==0) {
8346 numTargetMapEntries = rangeMap->getGlobalNumElements();
8347 importGidList.reserve(numTargetMapEntries);
8348 for (GO j=0; j<numTargetMapEntries; ++j) importGidList.push_back(j + indexBase);
8349 } else {
8350 importGidList.reserve(numTargetMapEntries);
8351 }
8352 RCP<map_type> importGidMap = rcp(new map_type(TGOT::invalid(), importGidList(), indexBase, comm));
8353
8354 // Import all rangeMap GIDs to pid 0
8355 import_type gidImporter(allGidsMap, importGidMap);
8356 mv_type_go importedGids(importGidMap, 1);
8357 importedGids.doImport(allGids, gidImporter, INSERT);
8358
8359 // The following import map will be non-trivial only on pid 0.
8360 ArrayRCP<const GO> importedGidsData = importedGids.getData(0);
8361 RCP<const map_type> importMap = rcp(new map_type(TGOT::invalid(), importedGidsData(), indexBase, comm) );
8362
8363 // Importer from original range map to pid 0
8364 import_type importer(rangeMap, importMap);
8365 // Target vector on pid 0
8366 RCP<mv_type> colsOnPid0 = rcp(new mv_type(importMap,numMVs));
8367
8368 RCP<mv_type> ei = rcp(new mv_type(A.getDomainMap(),numMVs)); //probing vector
8369 RCP<mv_type> colsA = rcp(new mv_type(A.getRangeMap(),numMVs)); //columns of A revealed by probing
8370
8371 Array<GO> globalColsArray, localColsArray;
8372 globalColsArray.reserve(numMVs);
8373 localColsArray.reserve(numMVs);
8374
8375 ArrayRCP<ArrayRCP<Scalar> > eiData(numMVs);
8376 for (size_t i=0; i<numMVs; ++i)
8377 eiData[i] = ei->getDataNonConst(i);
8378
8379 // //////////////////////////////////////
8380 // Discover A by chunks
8381 // //////////////////////////////////////
8382 for (GO k=0; k<numChunks; ++k) {
8383 for (size_t j=0; j<numMVs; ++j ) {
8384 //GO curGlobalCol = maxColGid - numMVs + j + TGOT::one();
8385 GO curGlobalCol = minColGid + k*numMVs + j;
8386 globalColsArray.push_back(curGlobalCol);
8387 //TODO extract the g2l map outside of this loop loop
8388 LO curLocalCol = domainMap.getLocalElement(curGlobalCol);
8389 if (curLocalCol != TLOT::invalid()) {
8390 eiData[j][curLocalCol] = TGOT::one();
8391 localColsArray.push_back(curLocalCol);
8392 }
8393 }
8394 //TODO Do the views eiData need to be released prior to the matvec?
8395
8396 // probe
8397 A.apply(*ei,*colsA);
8398
8399 colsOnPid0->doImport(*colsA,importer,INSERT);
8400
8401 if (myRank==0)
8402 globalNnz += writeColumns(os,*colsOnPid0, numMVs, importedGidsData(),
8403 globalColsArray, offsetToUseInPrinting);
8404
8405 //zero out the ei's
8406 for (size_t j=0; j<numMVs; ++j ) {
8407 for (int i=0; i<localColsArray.size(); ++i)
8408 eiData[j][localColsArray[i]] = TGOT::zero();
8409 }
8410 globalColsArray.clear();
8411 localColsArray.clear();
8412
8413 }
8414
8415 // //////////////////////////////////////
8416 // Handle leftover part of A
8417 // //////////////////////////////////////
8418 if (rem > 0) {
8419 for (int j=0; j<rem; ++j ) {
8420 GO curGlobalCol = maxColGid - rem + j + TGOT::one();
8421 globalColsArray.push_back(curGlobalCol);
8422 //TODO extract the g2l map outside of this loop loop
8423 LO curLocalCol = domainMap.getLocalElement(curGlobalCol);
8424 if (curLocalCol != TLOT::invalid()) {
8425 eiData[j][curLocalCol] = TGOT::one();
8426 localColsArray.push_back(curLocalCol);
8427 }
8428 }
8429 //TODO Do the views eiData need to be released prior to the matvec?
8430
8431 // probe
8432 A.apply(*ei,*colsA);
8433
8434 colsOnPid0->doImport(*colsA,importer,INSERT);
8435 if (myRank==0)
8436 globalNnz += writeColumns(os,*colsOnPid0, rem, importedGidsData(),
8437 globalColsArray, offsetToUseInPrinting);
8438
8439 //zero out the ei's
8440 for (int j=0; j<rem; ++j ) {
8441 for (int i=0; i<localColsArray.size(); ++i)
8442 eiData[j][localColsArray[i]] = TGOT::zero();
8443 }
8444 globalColsArray.clear();
8445 localColsArray.clear();
8446
8447 }
8448
8449 // Return the Matrix Market header. It includes the header
8450 // line (that starts with "%%"), some comments, and the triple
8451 // of matrix dimensions and number of nonzero entries. We
8452 // don't actually print this here, because we don't know the
8453 // number of nonzero entries until after probing.
8454 std::ostringstream oss;
8455 if (myRank == 0) {
8456 oss << "%%MatrixMarket matrix coordinate ";
8457 if (Teuchos::ScalarTraits<typename operator_type::scalar_type>::isComplex) {
8458 oss << "complex";
8459 } else {
8460 oss << "real";
8461 }
8462 oss << " general" << std::endl;
8463 oss << "% Tpetra::Operator" << std::endl;
8464 std::time_t now = std::time(NULL);
8465 oss << "% time stamp: " << ctime(&now);
8466 oss << "% written from " << numProcs << " processes" << std::endl;
8467 size_t numRows = rangeMap->getGlobalNumElements();
8468 size_t numCols = domainMap.getGlobalNumElements();
8469 oss << numRows << " " << numCols << " " << globalNnz << std::endl;
8470 }
8471
8472 return oss.str ();
8473 }
8474
8475 static global_ordinal_type
8476 writeColumns(std::ostream& os, mv_type const &colsA, size_t const &numCols,
8477 Teuchos::ArrayView<const global_ordinal_type> const &rowGids,
8478 Teuchos::Array<global_ordinal_type> const &colsArray,
8479 global_ordinal_type const & indexBase) {
8480
8481 typedef global_ordinal_type GO;
8482 typedef scalar_type Scalar;
8483 typedef Teuchos::ScalarTraits<Scalar> STS;
8484
8485 GO nnz=0;
8486 const Scalar zero = STS::zero();
8487 const size_t numRows = colsA.getGlobalLength();
8488 for (size_t j=0; j<numCols; ++j) {
8489 Teuchos::ArrayRCP<const Scalar> const curCol = colsA.getData(j);
8490 const GO J = colsArray[j];
8491 for (size_t i=0; i<numRows; ++i) {
8492 const Scalar val = curCol[i];
8493 if (val!=zero) {
8494 os << rowGids[i]+indexBase << " " << J+indexBase << " " << val << std::endl;
8495 ++nnz;
8496 }
8497 }
8498 }
8499
8500 return nnz;
8501
8502 }
8503
8504 public:
8505
8506 }; // class Writer
8507
8508 } // namespace MatrixMarket
8509} // namespace Tpetra
8510
8511#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 > getNodeElementList() 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 getNodeNumElements() 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.
SparseMatrixType::global_ordinal_type global_ordinal_type
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< 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)
Read Map (as a MultiVector) from the given input stream, with optional debugging output stream.
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< 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< 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)
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 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< 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)
Read dense matrix (as a MultiVector) 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< 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< const map_type > readMapFile(const std::string &filename, const Teuchos::RCP< const comm_type > &comm, const bool tolerant=false, const bool debug=false)
Read Map (as a MultiVector) from the given Matrix Market file.
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.
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)
Read Map (as a MultiVector) from the given input stream.
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 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.